relion 0.2.0 → 0.3.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.
Files changed (42) hide show
  1. package/dist/cli.js +64 -0
  2. package/dist/index.d.ts +231 -0
  3. package/dist/index.js +652 -0
  4. package/package.json +31 -50
  5. package/src/cli.js +0 -6
  6. package/src/commands.js +0 -176
  7. package/src/defaults.js +0 -60
  8. package/src/index.js +0 -75
  9. package/src/lib/checkpoint.js +0 -23
  10. package/src/lib/configuration.js +0 -35
  11. package/src/lib/detect-package-manager.js +0 -52
  12. package/src/lib/format-commit-message.js +0 -4
  13. package/src/lib/latest-semver-tag.js +0 -34
  14. package/src/lib/lifecycles/bump.js +0 -242
  15. package/src/lib/lifecycles/changelog.js +0 -106
  16. package/src/lib/lifecycles/commit.js +0 -67
  17. package/src/lib/lifecycles/tag.js +0 -61
  18. package/src/lib/print-error.js +0 -15
  19. package/src/lib/run-exec.js +0 -20
  20. package/src/lib/run-execFile.js +0 -20
  21. package/src/lib/run-lifecycle-script.js +0 -18
  22. package/src/lib/stringify-package.js +0 -34
  23. package/src/lib/updaters/index.js +0 -130
  24. package/src/lib/updaters/types/csproj.js +0 -13
  25. package/src/lib/updaters/types/gradle.js +0 -16
  26. package/src/lib/updaters/types/json.js +0 -25
  27. package/src/lib/updaters/types/maven.js +0 -43
  28. package/src/lib/updaters/types/openapi.js +0 -15
  29. package/src/lib/updaters/types/plain-text.js +0 -7
  30. package/src/lib/updaters/types/python.js +0 -30
  31. package/src/lib/updaters/types/yaml.js +0 -15
  32. package/src/lib/write-file.js +0 -6
  33. package/src/preset/constants.js +0 -16
  34. package/src/preset/index.js +0 -19
  35. package/src/preset/parser.js +0 -11
  36. package/src/preset/templates/commit.hbs +0 -19
  37. package/src/preset/templates/footer.hbs +0 -10
  38. package/src/preset/templates/header.hbs +0 -10
  39. package/src/preset/templates/index.js +0 -13
  40. package/src/preset/templates/main.hbs +0 -21
  41. package/src/preset/whatBump.js +0 -33
  42. package/src/preset/writer.js +0 -201
package/dist/index.js ADDED
@@ -0,0 +1,652 @@
1
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
2
+ import Handlebars from "handlebars";
3
+ import semver from "semver";
4
+ import { execSync } from "node:child_process";
5
+
6
+ //#region src/lifecycles/bump.ts
7
+ const bump = (config) => {
8
+ if (!config.bump) return;
9
+ const bumpFiles = config.bump, newVersion = config.context.newVersion;
10
+ bumpFiles.forEach((versionedFile) => {
11
+ const fileContent = readFileSync(versionedFile.filePath, "utf8");
12
+ const updatedContent = fileContent.replace(versionedFile.versionPattern, `$1${newVersion}$3`);
13
+ if (!config.dryRun) writeFileSync(versionedFile.filePath, updatedContent, "utf8");
14
+ console.log(`Updated version in '${versionedFile.filePath}' to '${newVersion}'`);
15
+ });
16
+ };
17
+
18
+ //#endregion
19
+ //#region src/defaults.ts
20
+ const defaultConfig = {
21
+ bump: false,
22
+ changelog: false,
23
+ commit: false,
24
+ tag: false,
25
+ versionSourceFile: "./package.json",
26
+ newTagFormat: "v{{newVersion}}",
27
+ prevReleaseTagPattern: /^v(?<version>\d+\.\d+\.\d+)/,
28
+ zeroMajorBreakingIsMinor: true,
29
+ dryRun: false,
30
+ context: {
31
+ commitHyperlink: true,
32
+ refHyperlink: true
33
+ },
34
+ commitsParser: {
35
+ headerPattern: /^(?<type>\w+)(?:\((?<scope>.+)\))?(?<bang>!)?: (?<subject>.+)/s,
36
+ breakingChangesPattern: /BREAKING CHANGES?:\s*(?<content>.+)/s,
37
+ breakingChangeListPattern: /- (.+)/g,
38
+ tagPattern: /tag: (?<tag>.*?)[,)]/g,
39
+ coAuthorPattern: /Co-authored-by: (?<name>.+?) <(?<email>.+)>/g,
40
+ signerPattern: /Signed-off-by: (?<name>.+?) <(?<email>.+)>/g,
41
+ ghEmailPattern: /^(?:\d+\+)?(?<username>.+)@users\.noreply\.github\.com$/,
42
+ remoteUrlPattern: /^(https:\/\/|git@)(?<host>[^/:]+)[/:](?<owner>.+?)\/(?<name>.+?)(?:\..*)?$/,
43
+ refPattern: /^(?<action>.+?) (?<labels>.+)$/gm,
44
+ refLabelPattern: /(?:(?<owner>\S+?)\/(?<repo>\S+?))?#(?<number>\d+)/g,
45
+ refActionPattern: /Fixes|Closes|Refs/i,
46
+ dateSource: "authorDate",
47
+ dateFormat: "YYYY-MM-DD"
48
+ }
49
+ };
50
+ const defaultChangelogSections = {
51
+ breaking: {
52
+ title: "⚠️ BREAKING CHANGES",
53
+ commitType: "breaking"
54
+ },
55
+ feat: {
56
+ title: "✨ Features",
57
+ commitType: "feat"
58
+ },
59
+ fix: {
60
+ title: "🩹 Fixes",
61
+ commitType: "fix"
62
+ },
63
+ perf: {
64
+ title: "⚡ Performance",
65
+ commitType: "perf"
66
+ },
67
+ refactor: {
68
+ title: "🚜 Refactoring",
69
+ commitType: "refactor"
70
+ },
71
+ docs: {
72
+ title: "📚 Documentation",
73
+ commitType: "docs"
74
+ },
75
+ style: {
76
+ title: "🎨 Formatting",
77
+ commitType: "style"
78
+ },
79
+ build: {
80
+ title: "📦 Build",
81
+ commitType: "build"
82
+ },
83
+ ci: {
84
+ title: "🚀 CI",
85
+ commitType: "ci"
86
+ },
87
+ revert: {
88
+ title: "♻️ Reverts",
89
+ commitType: "revert"
90
+ },
91
+ deps: {
92
+ title: "🧩 Dependencies",
93
+ commitType: "chore",
94
+ filter: (commit$1) => !!commit$1.scope?.includes("deps")
95
+ },
96
+ chore: {
97
+ title: "🛠️ Chores",
98
+ commitType: "chore"
99
+ },
100
+ test: {
101
+ title: "🧪 Tests",
102
+ commitType: "test"
103
+ },
104
+ misc: {
105
+ title: "⚙️ Miscellaneous",
106
+ commitType: "*"
107
+ },
108
+ [Symbol.iterator]() {
109
+ return Object.values(this)[Symbol.iterator]();
110
+ }
111
+ };
112
+ const defaultChangelogOptions = {
113
+ stdout: false,
114
+ outputFile: "./CHANGELOG.md",
115
+ commitRange: "unreleased",
116
+ sections: [...defaultChangelogSections],
117
+ header: "# Changelog\n\n\n",
118
+ prevReleaseHeaderPattern: /^##.*?\d+\.\d+\.\d+/m,
119
+ helpers: { repeat: (string, n) => string.repeat(n) },
120
+ partials: {}
121
+ };
122
+ const defaultCommitOptions = {
123
+ message: "release({{repo.name}}): {{newTag}}",
124
+ signOff: false,
125
+ gpgSign: false,
126
+ stageAll: true,
127
+ extraArgs: ""
128
+ };
129
+ const defaultTagOptions = {
130
+ name: "{{newTag}}",
131
+ message: "release({{repo.name}}): {{newTag}}",
132
+ gpgSign: false,
133
+ force: false,
134
+ extraArgs: ""
135
+ };
136
+ const defaultVersionedFiles = [{
137
+ filePathRegex: /package\.json$/,
138
+ versionPattern: /(^.*?"version".*?")(.*?)(")/s
139
+ }, {
140
+ filePathRegex: /package-lock\.json$/,
141
+ versionPattern: /(^.*?"version".*?"|"packages".*?"".*"version".*?")(.*?)(")/gs
142
+ }];
143
+
144
+ //#endregion
145
+ //#region src/utils/config-resolver.ts
146
+ const resolveConfig = async (userConfig) => {
147
+ const profileMergedConfig = mergeProfileConfig(userConfig);
148
+ const mergedConfig = mergeWithDefaults(profileMergedConfig);
149
+ const transformedConfig = transformVersionedFiles(mergedConfig);
150
+ const contextualConfig = await fillContext(transformedConfig);
151
+ const finalConfig = resolveTemplates(contextualConfig);
152
+ return finalConfig;
153
+ };
154
+ const mergeProfileConfig = (baseConfig) => {
155
+ const profileName = baseConfig.profile;
156
+ if (!profileName) return baseConfig;
157
+ const profileConfig = baseConfig[`_${profileName}`];
158
+ if (!profileConfig) throw new Error(`Profile "${profileName}" not found in configuration.`);
159
+ const mergeOption = (propKey, ...nestedPropKeys) => {
160
+ const isPlainObject = (value) => Object.prototype.toString.call(value) === "[object Object]";
161
+ const mergeObjects = (baseObj, overrideObject) => {
162
+ const isBasePlainObject = isPlainObject(baseObj);
163
+ const isOverridePlainObject = isPlainObject(overrideObject);
164
+ if (isBasePlainObject && isOverridePlainObject) return {
165
+ ...baseObj,
166
+ ...overrideObject
167
+ };
168
+ else if (!isBasePlainObject && isOverridePlainObject) return overrideObject;
169
+ else if (isBasePlainObject && !isOverridePlainObject) return baseObj;
170
+ };
171
+ const baseConfigProp = baseConfig[propKey];
172
+ const profileConfigProp = profileConfig[propKey];
173
+ const result = mergeObjects(baseConfigProp, profileConfigProp);
174
+ if (result === void 0) return void 0;
175
+ nestedPropKeys.forEach((key) => {
176
+ result[key] = mergeObjects(baseConfigProp?.[key], profileConfigProp?.[key]);
177
+ });
178
+ return result;
179
+ };
180
+ return {
181
+ ...baseConfig,
182
+ ...profileConfig,
183
+ commitsParser: mergeOption("commitsParser"),
184
+ changelog: mergeOption("changelog", "partials", "helpers"),
185
+ commit: mergeOption("commit"),
186
+ tag: mergeOption("tag"),
187
+ context: mergeOption("context")
188
+ };
189
+ };
190
+ const mergeWithDefaults = (userConfig) => {
191
+ const resolveOptions = (optionsName, options, defaults, ...subObjects) => {
192
+ if (options == void 0 || options === false) return false;
193
+ if (options === true) return defaults;
194
+ if (typeof options !== "object") throw new Error(`Invalid value for ${optionsName}. It should be a boolean or an object.`);
195
+ const result = {
196
+ ...defaults,
197
+ ...options
198
+ };
199
+ subObjects.forEach((subObjectKey) => result[subObjectKey] = {
200
+ ...defaults[subObjectKey],
201
+ ...options[subObjectKey]
202
+ });
203
+ return result;
204
+ };
205
+ return {
206
+ ...defaultConfig,
207
+ ...userConfig,
208
+ commitsParser: {
209
+ ...defaultConfig.commitsParser,
210
+ ...userConfig.commitsParser
211
+ },
212
+ changelog: resolveOptions("changelog", userConfig.changelog, defaultChangelogOptions, "partials", "helpers"),
213
+ commit: resolveOptions("commit", userConfig.commit, defaultCommitOptions),
214
+ tag: resolveOptions("tag", userConfig.tag, defaultTagOptions)
215
+ };
216
+ };
217
+ const transformVersionedFiles = (config) => {
218
+ const resolveVersionedFile = (filePath) => {
219
+ const matchingDefaultVersionFile = defaultVersionedFiles.find((defaultFile) => defaultFile.filePathRegex.test(filePath));
220
+ if (matchingDefaultVersionFile) return {
221
+ filePath,
222
+ versionPattern: matchingDefaultVersionFile.versionPattern
223
+ };
224
+ else throw new Error(`File ${filePath} doesn't match any default versioned files. Please provide a custom version pattern for this file.`);
225
+ };
226
+ const resolveBump = (bump$1) => {
227
+ if (bump$1 === false) return false;
228
+ if (bump$1 === true) return [versionSourceFile];
229
+ if (Array.isArray(bump$1)) return [versionSourceFile, ...bump$1.map((bumpFile) => typeof bumpFile === "string" ? resolveVersionedFile(bumpFile) : bumpFile)];
230
+ throw new Error("Invalid value for bump. It should be a boolean or an array.");
231
+ };
232
+ const versionSourceFile = typeof config.versionSourceFile === "string" ? resolveVersionedFile(config.versionSourceFile) : config.versionSourceFile;
233
+ return {
234
+ ...config,
235
+ versionSourceFile,
236
+ bump: resolveBump(config.bump),
237
+ changelog: config.changelog === false ? false : {
238
+ ...config.changelog,
239
+ compiledPartials: Object.fromEntries(Object.entries(config.changelog.partials).map(([key, template]) => [key, Handlebars.compile(template)]))
240
+ }
241
+ };
242
+ };
243
+ const fillContext = async (config) => {
244
+ const resolvedContext = config.context ?? {};
245
+ const repoInfo = getRepoInfo(config.commitsParser.remoteUrlPattern);
246
+ resolvedContext.repo = {
247
+ ...repoInfo,
248
+ ...resolvedContext.repo
249
+ };
250
+ const commitRange = config.changelog ? config.changelog.commitRange : "unreleased";
251
+ resolvedContext.commits = config.context?.commits ? await Promise.all(config.context.commits.map(async (commit$1) => {
252
+ return typeof commit$1 === "object" && "message" in commit$1 || typeof commit$1 === "string" ? (await parseCommits([commit$1], config.commitsParser, config.prevReleaseTagPattern))[0] : commit$1;
253
+ })) : await parseCommits(commitRange, config.commitsParser, config.prevReleaseTagPattern);
254
+ resolvedContext.currentVersion ??= parseVersion(config.versionSourceFile);
255
+ resolvedContext.currentTag ??= getVersionTags(config.prevReleaseTagPattern)[0];
256
+ resolvedContext.newVersion ??= await determineNextVersion(config, resolvedContext.currentVersion);
257
+ resolvedContext.newTag ??= compileTemplate(config.newTagFormat, resolvedContext);
258
+ const contextualConfig = {
259
+ ...config,
260
+ context: resolvedContext
261
+ };
262
+ resolvedContext.releases = config.changelog ? groupCommitsByReleases(resolvedContext.commits, config.changelog.sections, contextualConfig) : null;
263
+ return contextualConfig;
264
+ };
265
+ const groupCommitsByReleases = (commits, sections, config) => {
266
+ const releases = {};
267
+ commits.forEach((commit$1) => {
268
+ const releaseTag = commit$1.tags?.find((tag$1) => config.prevReleaseTagPattern.test(tag$1));
269
+ if (releaseTag) releases[releaseTag] ??= {
270
+ tag: releaseTag,
271
+ version: config.prevReleaseTagPattern.exec(releaseTag)?.groups?.version,
272
+ date: commit$1.date,
273
+ commits: [commit$1]
274
+ };
275
+ else {
276
+ const latestReleaseTag = Object.keys(releases).at(-1);
277
+ if (latestReleaseTag) releases[latestReleaseTag].commits.push(commit$1);
278
+ else releases[config.context.newTag] = {
279
+ tag: config.context.newTag,
280
+ version: config.context.newVersion,
281
+ date: commit$1.date,
282
+ commits: [commit$1]
283
+ };
284
+ }
285
+ });
286
+ return Object.values(releases).map((release) => groupReleaseCommitsBySections(release, sections));
287
+ };
288
+ const groupReleaseCommitsBySections = (release, sections) => {
289
+ const { commits,...releaseWithoutCommits } = release;
290
+ return {
291
+ ...releaseWithoutCommits,
292
+ commitGroups: groupCommitsBySections(commits, sections)
293
+ };
294
+ };
295
+ const groupCommitsBySections = (commits, sections) => {
296
+ const commitGroups = Object.fromEntries(sections.map((section) => [section.title, []]));
297
+ commits.forEach((commit$1) => {
298
+ const isBreaking = !!commit$1.breakingChanges;
299
+ let isGrouped = false;
300
+ let isBreakingGrouped = false;
301
+ for (const section of sections) {
302
+ if (section.filter && !section.filter(commit$1)) continue;
303
+ const sectionTypes = [section.commitType].flat();
304
+ if (isBreaking && !isBreakingGrouped && sectionTypes.includes("breaking")) {
305
+ commitGroups[section.title].push(commit$1);
306
+ isBreakingGrouped = true;
307
+ continue;
308
+ }
309
+ if (!isGrouped && (sectionTypes.includes(commit$1.type) || sectionTypes.includes("*"))) {
310
+ commitGroups[section.title].push(commit$1);
311
+ isGrouped = true;
312
+ }
313
+ if (isGrouped && (!isBreaking || isBreakingGrouped)) return;
314
+ }
315
+ });
316
+ Object.keys(commitGroups).forEach((key) => {
317
+ if (!commitGroups[key].length) delete commitGroups[key];
318
+ });
319
+ return Object.entries(commitGroups).map(([title, commits$1]) => ({
320
+ title,
321
+ commits: commits$1
322
+ }));
323
+ };
324
+ const resolveTemplates = (config) => {
325
+ return {
326
+ ...config,
327
+ commit: config.commit ? {
328
+ ...config.commit,
329
+ message: compileTemplate(config.commit.message, config.context)
330
+ } : config.commit,
331
+ tag: config.tag ? {
332
+ ...config.tag,
333
+ name: compileTemplate(config.tag.name, config.context),
334
+ message: compileTemplate(config.tag.message, config.context)
335
+ } : config.tag
336
+ };
337
+ };
338
+ const compileTemplate = (value, context) => {
339
+ const compile = Handlebars.compile(value);
340
+ return compile(context);
341
+ };
342
+
343
+ //#endregion
344
+ //#region src/utils/version-manager.ts
345
+ const parseVersion = (versionedFile) => {
346
+ const fileContent = readFileSync(versionedFile.filePath, "utf8");
347
+ const version = versionedFile.versionPattern.exec(fileContent)?.[2];
348
+ if (!version) throw new Error(`Version not found in '${versionedFile.filePath}' with pattern '${versionedFile.versionPattern}'`);
349
+ if (!semver.valid(version)) throw new Error(`Invalid version format in '${versionedFile.filePath}': '${version}'`);
350
+ console.log(`Current version from '${versionedFile.filePath}': '${version}'`);
351
+ return version;
352
+ };
353
+ const determineNextVersion = async (config, currentVersion) => {
354
+ if (config.releaseVersion) {
355
+ if (!semver.valid(config.releaseVersion)) throw new Error(`Invalid release version format: '${config.releaseVersion}'`);
356
+ return config.releaseVersion;
357
+ }
358
+ let releaseType;
359
+ if (config.releaseType) releaseType = config.releaseType;
360
+ else {
361
+ const unreleasedCommits = await parseCommits("unreleased", config.commitsParser, config.prevReleaseTagPattern);
362
+ releaseType = calculateReleaseType(unreleasedCommits);
363
+ if (config.zeroMajorBreakingIsMinor && semver.major(currentVersion) === 0 && releaseType === "major") releaseType = "minor";
364
+ }
365
+ const newVersion = increaseVersion(currentVersion, releaseType);
366
+ console.log(`Determined new version: '${newVersion}' (release type: '${releaseType}')`);
367
+ return newVersion;
368
+ };
369
+ const calculateReleaseType = (commits) => {
370
+ const hasBreakingChange = commits.some((commit$1) => commit$1.breakingChanges);
371
+ if (hasBreakingChange) return "major";
372
+ const hasFeature = commits.some((commit$1) => commit$1.type === "feat");
373
+ if (hasFeature) return "minor";
374
+ return "patch";
375
+ };
376
+ const increaseVersion = (currentVersion, releaseType) => semver.inc(currentVersion, releaseType) ?? (() => {
377
+ throw new Error(`Failed to calculate new version from '${currentVersion}' with release type '${releaseType}'`);
378
+ })();
379
+
380
+ //#endregion
381
+ //#region src/enums.ts
382
+ let GpgSigLabel = /* @__PURE__ */ function(GpgSigLabel$1) {
383
+ GpgSigLabel$1["G"] = "valid";
384
+ GpgSigLabel$1["B"] = "bad";
385
+ GpgSigLabel$1["U"] = "valid, unknown validity";
386
+ GpgSigLabel$1["X"] = "valid, expired";
387
+ GpgSigLabel$1["Y"] = "valid, made by expired key";
388
+ GpgSigLabel$1["R"] = "valid, made by revoked key";
389
+ GpgSigLabel$1["E"] = "cannot check (missing key)";
390
+ GpgSigLabel$1["N"] = "no signature";
391
+ return GpgSigLabel$1;
392
+ }({});
393
+
394
+ //#endregion
395
+ //#region src/utils/commits-parser.ts
396
+ const parseCommits = async (arg1, commitsParser, prevReleaseTagPattern) => {
397
+ const rawCommits = Array.isArray(arg1) ? arg1 : getRawCommits(arg1, prevReleaseTagPattern);
398
+ const parser = commitsParser;
399
+ return (await Promise.all(rawCommits.map(async (commit$1) => {
400
+ if (typeof commit$1 === "string") commit$1 = { message: commit$1 };
401
+ const { hash, tagRefs } = commit$1;
402
+ const message = commit$1.message.trim();
403
+ if (!message) throw new Error(`Message is missing for commit: ${JSON.stringify(commit$1)}`);
404
+ let parsedMessage;
405
+ try {
406
+ parsedMessage = parseCommitMessage(message, parser);
407
+ } catch (error) {
408
+ console.warn(`Error parsing commit '${hash ?? "<no hash>"}':`, error.message);
409
+ return;
410
+ }
411
+ const { type, scope, subject, body, breakingChanges, footer } = parsedMessage;
412
+ const tags = tagRefs ? [...tagRefs.matchAll(parser.tagPattern)].map((m) => m.groups?.tag ?? "") : [];
413
+ const signers = footer ? [...footer.matchAll(parser.signerPattern)].map((m) => m.groups) : [];
414
+ const authors = [];
415
+ const addAuthor = (contributor) => {
416
+ if (!authors.some((a) => a.email === contributor.email)) authors.push(contributor);
417
+ };
418
+ const author = commit$1.authorName && commit$1.authorEmail ? getContributorDetails({
419
+ name: commit$1.authorName,
420
+ email: commit$1.authorEmail
421
+ }, signers) : void 0;
422
+ if (author) addAuthor(author);
423
+ const committer = commit$1.committerName && commit$1.committerEmail ? getContributorDetails({
424
+ name: commit$1.committerName,
425
+ email: commit$1.committerEmail
426
+ }, signers) : void 0;
427
+ if (committer) addAuthor(committer);
428
+ const coAuthors = footer ? [...footer.matchAll(parser.coAuthorPattern)].map((m) => m.groups).map((coAuthor) => getContributorDetails(coAuthor, signers)) : [];
429
+ coAuthors.forEach((coAuthor) => addAuthor(coAuthor));
430
+ const refs = await parseRefs(footer ?? "", parser);
431
+ const gpgSig = commit$1.gpgSigCode ? {
432
+ code: commit$1.gpgSigCode,
433
+ label: GpgSigLabel[commit$1.gpgSigCode],
434
+ keyId: commit$1.gpgSigKeyId
435
+ } : void 0;
436
+ let date = commit$1[parser.dateSource === "committerDate" ? "committerTs" : "authorTs"];
437
+ if (typeof date === "string") date = formatDate(/* @__PURE__ */ new Date(+date * 1e3), parser.dateFormat);
438
+ const parsedCommit = {
439
+ hash,
440
+ type,
441
+ scope,
442
+ subject,
443
+ body,
444
+ breakingChanges,
445
+ footer,
446
+ committer,
447
+ gpgSig,
448
+ date,
449
+ tags: tags.length ? tags : void 0,
450
+ authors: authors.length ? authors : void 0,
451
+ refs: refs.length ? refs : void 0
452
+ };
453
+ return parsedCommit;
454
+ }))).filter((commit$1) => commit$1 !== void 0);
455
+ };
456
+ const parseCommitMessage = (message, parser) => {
457
+ const [header, ...details] = message.split("\n\n");
458
+ const headerMatch = parser.headerPattern.exec(header);
459
+ if (!headerMatch?.groups) throw new Error(`Commit header '${header}' doesn't match expected format`);
460
+ const { type, scope, bang, subject } = headerMatch.groups;
461
+ let breakingChanges;
462
+ const breakingChangesPart = details.find((detail) => parser.breakingChangesPattern.test(detail));
463
+ if (breakingChangesPart) {
464
+ breakingChanges = parseBreakingChanges(breakingChangesPart, parser);
465
+ details.splice(details.indexOf(breakingChangesPart), 1);
466
+ } else if (bang) breakingChanges = subject;
467
+ const footerStart = details.findIndex((detail) => detail.match(parser.refActionPattern) ?? detail.match(parser.coAuthorPattern) ?? detail.match(parser.signerPattern));
468
+ const [body, footer] = footerStart === -1 ? [details.join("\n\n"), ""] : [details.slice(0, footerStart).join("\n\n"), details.slice(footerStart).join("\n\n")];
469
+ return {
470
+ type,
471
+ scope: scope || void 0,
472
+ subject,
473
+ body: body || void 0,
474
+ breakingChanges,
475
+ footer: footer || void 0
476
+ };
477
+ };
478
+ const parseBreakingChanges = (value, parser) => {
479
+ const breakingChanges = parser.breakingChangesPattern.exec(value)?.groups?.content;
480
+ if (!breakingChanges) throw new Error(`Failed to extract breaking changes content from '${value}' using pattern "${parser.breakingChangesPattern}"`);
481
+ const breakingChangeList = [...breakingChanges.matchAll(parser.breakingChangeListPattern)];
482
+ return breakingChangeList.length ? breakingChangeList.map((m) => m[1]) : breakingChanges;
483
+ };
484
+ const getContributorDetails = (contributor, signers) => {
485
+ const hasSignedOff = signers.some((signer) => signer.email === contributor.email && signer.name === contributor.name);
486
+ return {
487
+ ...contributor,
488
+ hasSignedOff,
489
+ ghLogin: contributor.name,
490
+ ghUrl: `https://github.com/${contributor.name}`
491
+ };
492
+ };
493
+ const parseRefs = async (value, parser) => await Promise.all([...value.matchAll(parser.refPattern)].map((m) => m.groups).filter((rawRef) => parser.refActionPattern.test(rawRef.action)).flatMap((rawRef) => [...rawRef.labels.matchAll(parser.refLabelPattern)].map((m) => m.groups).filter((label) => !!label.number).map((label) => ({
494
+ action: rawRef.action,
495
+ owner: label.owner,
496
+ repo: label.repo,
497
+ number: label.number
498
+ }))));
499
+ const formatDate = (date, format) => {
500
+ const pad = (num) => num.toString().padStart(2, "0");
501
+ const dateParts = {
502
+ YYYY: date.getUTCFullYear().toString(),
503
+ MM: pad(date.getUTCMonth() + 1),
504
+ DD: pad(date.getUTCDate()),
505
+ HH: pad(date.getUTCHours()),
506
+ mm: pad(date.getUTCMinutes()),
507
+ ss: pad(date.getUTCSeconds())
508
+ };
509
+ return format.replace(/YYYY|MM|DD|HH|mm|ss/g, (k) => dateParts[k]);
510
+ };
511
+
512
+ //#endregion
513
+ //#region src/utils/git-utils.ts
514
+ const commitLogFormat = `##COMMIT##%n#HASH# %h%n#MSG# %B%n#REFS# %d%n#AUTHOR-NAME# %an%n#AUTHOR-EMAIL# %ae%n#AUTHOR-DATE# %at%n#COMMITTER-NAME# %cn%n#COMMITTER-EMAIL# %ce%n#COMMITTER-DATE# %ct%n#GPGSIG-CODE# %G?%n#GPGSIG-KEYID# %GK%n`;
515
+ const rawCommitPattern = /##COMMIT##\n#HASH# (?<hash>.+)?\n#MSG# (?<message>[\s\S]*?)\n#REFS#\s+(?<tagRefs>.+)?\n#AUTHOR-NAME# (?<authorName>.+)?\n#AUTHOR-EMAIL# (?<authorEmail>.+)?\n#AUTHOR-DATE# (?<authorTs>.+)?\n#COMMITTER-NAME# (?<committerName>.+)?\n#COMMITTER-EMAIL# (?<committerEmail>.+)?\n#COMMITTER-DATE# (?<committerTs>.+)?\n#GPGSIG-CODE# (?<gpgSigCode>.+)?\n#GPGSIG-KEYID# (?<gpgSigKeyId>.+)?/g;
516
+ const getRepoInfo = (remoteUrlPattern) => {
517
+ const remoteUrl = execSync("git remote get-url origin", { encoding: "utf8" }).trim();
518
+ const remoteUrlMatch = remoteUrlPattern.exec(remoteUrl);
519
+ if (!remoteUrlMatch?.groups) throw new Error(`Couldn't parse remote URL: ` + remoteUrl);
520
+ const { host, owner, name } = remoteUrlMatch.groups;
521
+ const homepage = `https://${host}/${owner}/${name}`;
522
+ return {
523
+ host,
524
+ owner,
525
+ name,
526
+ homepage
527
+ };
528
+ };
529
+ const getRawCommits = (commitRange, prevReleaseTagPattern) => {
530
+ const firstCommitHash = getFirstCommitHash();
531
+ const versionTags = getVersionTags(prevReleaseTagPattern);
532
+ let from, to;
533
+ if (typeof commitRange === "string") {
534
+ from = {
535
+ all: firstCommitHash,
536
+ unreleased: versionTags[0] ?? firstCommitHash
537
+ }[commitRange];
538
+ if (!from) throw new Error(`Invalid commit range: '${commitRange}'`);
539
+ to = "HEAD";
540
+ } else if ("from" in commitRange || "to" in commitRange) {
541
+ const fromValue = "from" in commitRange ? commitRange.from : "firstCommit";
542
+ from = fromValue === "firstCommit" ? firstCommitHash : fromValue;
543
+ to = "to" in commitRange ? commitRange.to : "HEAD";
544
+ } else if ("versionTag" in commitRange) {
545
+ const targetTagIndex = versionTags.indexOf(commitRange.versionTag);
546
+ if (targetTagIndex === -1) throw new Error(`Version tag '${commitRange.versionTag}' not found`);
547
+ from = versionTags[targetTagIndex];
548
+ to = versionTags[targetTagIndex + 1] ?? "HEAD";
549
+ } else throw new Error(`Invalid commit range provided`);
550
+ const gitLogCommits = execSync(`git log ${from}..${to} --pretty="${commitLogFormat}"`, { encoding: "utf8" });
551
+ return [...gitLogCommits.matchAll(rawCommitPattern)].map((m) => m.groups);
552
+ };
553
+ const getFirstCommitHash = () => execSync("git rev-list --max-parents=0 HEAD", { encoding: "utf8" }).trim();
554
+ const getVersionTags = (tagPattern) => {
555
+ const rawTags = execSync("git tag --sort=-creatordate", { encoding: "utf8" });
556
+ return rawTags.split("\n").filter((tag$1) => tagPattern.test(tag$1));
557
+ };
558
+
559
+ //#endregion
560
+ //#region src/templates/release.hbs
561
+ var release_default = "{{#>header}}\n## &ensp; [` 📦 {{tag}} `]({{repo.homepage}}/{{#if prevTag}}compare/{{prevTag}}...{{tag}}{{else}}commits/{{tag}}{{/if}})\n\n{{/header}}\n{{#each commitGroups}}\n### {{{repeat '&nbsp;' 5}}}{{title}}\n{{#each commits}}\n* {{#if scope}}`{{scope}}` {{/if}}{{{subject}}} {{#if ../../commitHyperlink}}[`{{hash}}`]({{../../repo.homepage}}/commit/{{hash}}){{else}}{{hash}}{{/if}}\n{{/each}}\n\n{{/each}}\n##### &emsp;&ensp;&nbsp; 🔗 [Full Commit History: {{#if prevTag}}`{{prevTag}}` → `{{tag}}`]({{repo.homepage}}/compare/{{prevTag}}...{{tag}}){{else}}`{{tag}}`]({{repo.homepage}}/commits/{{tag}}){{/if}} &ensp;/&ensp; _{{date}}_\n\n\n";
562
+
563
+ //#endregion
564
+ //#region src/lifecycles/changelog.ts
565
+ const changelog = (config) => {
566
+ if (!config.changelog) return;
567
+ const options = config.changelog;
568
+ const releases = config.context.releases;
569
+ if (!releases) return;
570
+ const versionTags = getVersionTags(config.prevReleaseTagPattern);
571
+ Handlebars.registerPartial(options.compiledPartials);
572
+ Handlebars.registerHelper(options.helpers);
573
+ let result = options.header;
574
+ releases.forEach((release, index) => {
575
+ const prevRelease = releases[index + 1];
576
+ let prevTag, prevVersion;
577
+ if (prevRelease) {
578
+ prevTag = prevRelease.tag;
579
+ prevVersion = getVersionFromTag(prevTag, config.prevReleaseTagPattern);
580
+ } else {
581
+ const targetTagIndex = versionTags.indexOf(release.tag);
582
+ if (targetTagIndex === -1) {
583
+ prevTag = config.context.currentTag;
584
+ prevVersion = getVersionFromTag(prevTag, config.prevReleaseTagPattern);
585
+ } else {
586
+ prevTag = versionTags[targetTagIndex + 1];
587
+ prevVersion = prevTag && getVersionFromTag(prevTag, config.prevReleaseTagPattern);
588
+ }
589
+ }
590
+ const releaseContext = {
591
+ ...release,
592
+ ...config.context,
593
+ prevTag,
594
+ prevVersion
595
+ };
596
+ const rendered = renderTemplate(release_default, releaseContext);
597
+ result += rendered;
598
+ });
599
+ if (options.stdout) console.log(`Generated changelog:\n${result}`);
600
+ if (options.outputFile) {
601
+ console.log(`Writing changelog to file '${options.outputFile}'`);
602
+ if (!config.dryRun) writeToChangelogFile(options.outputFile, result, options.prevReleaseHeaderPattern);
603
+ }
604
+ };
605
+ const writeToChangelogFile = (outputFile, content, prevReleaseHeaderPattern) => {
606
+ const changelogContent = existsSync(outputFile) ? readFileSync(outputFile, { encoding: "utf8" }) : "";
607
+ const prevReleaseStart = changelogContent.search(prevReleaseHeaderPattern);
608
+ const headlessChangelog = changelogContent.slice(prevReleaseStart);
609
+ const newChangelog = content + headlessChangelog;
610
+ writeFileSync(outputFile, newChangelog, { encoding: "utf8" });
611
+ };
612
+ const renderTemplate = (template, releaseContext) => {
613
+ const compile = Handlebars.compile(template);
614
+ return compile(releaseContext);
615
+ };
616
+ const getVersionFromTag = (tag$1, tagPattern) => {
617
+ return tagPattern.exec(tag$1)?.groups?.version;
618
+ };
619
+
620
+ //#endregion
621
+ //#region src/lifecycles/commit.ts
622
+ const commit = (config) => {
623
+ if (!config.commit) return;
624
+ const options = config.commit;
625
+ console.log("Committing with options:", options);
626
+ if (options.stageAll && !config.dryRun) execSync("git add -A", { stdio: "inherit" });
627
+ if (!config.dryRun) execSync(`git commit -m "${options.message}" ${options.signOff ? "-s" : ""} ${options.gpgSign ? "-S" : ""} ${options.extraArgs}`, { stdio: "inherit" });
628
+ };
629
+
630
+ //#endregion
631
+ //#region src/lifecycles/tag.ts
632
+ const tag = (config) => {
633
+ if (!config.tag) return;
634
+ const options = config.tag;
635
+ console.log("Tagging with options:", options);
636
+ if (!config.dryRun) execSync(`git tag -a ${options.name} -m "${options.message}" ${options.gpgSign ? "-s" : ""} ${options.force ? "-f" : ""} ${options.extraArgs}`, { stdio: "inherit" });
637
+ };
638
+
639
+ //#endregion
640
+ //#region src/relion.ts
641
+ async function relion(userConfig) {
642
+ const config = await resolveConfig(userConfig);
643
+ bump(config);
644
+ changelog(config);
645
+ commit(config);
646
+ tag(config);
647
+ }
648
+ const defineConfig = (config) => config;
649
+
650
+ //#endregion
651
+ export { relion as default, defineConfig };
652
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJuYW1lcyI6WyJkZWZhdWx0Q29uZmlnOiBNZXJnZWRDb25maWciLCJkZWZhdWx0Q2hhbmdlbG9nU2VjdGlvbnM6IERlZmF1bHRDaGFuZ2Vsb2dTZWN0aW9ucyIsImNvbW1pdCIsImRlZmF1bHRDaGFuZ2Vsb2dPcHRpb25zOiBDb21wbGV0ZUNoYW5nZWxvZ09wdGlvbnMiLCJkZWZhdWx0Q29tbWl0T3B0aW9uczogQ29tcGxldGVDb21taXRPcHRpb25zIiwiZGVmYXVsdFRhZ09wdGlvbnM6IENvbXBsZXRlVGFnT3B0aW9ucyIsImRlZmF1bHRWZXJzaW9uZWRGaWxlczogRGVmYXVsdFZlcnNpb25lZEZpbGVbXSIsInJlc3VsdDogUmVxdWlyZWQ8VD4iLCJidW1wIiwiY29tbWl0IiwicmVsZWFzZXM6IFJlY29yZDxzdHJpbmcsIFJlbGVhc2VXaXRoRmxhdENvbW1pdHM+IiwidGFnIiwiY29tbWl0R3JvdXBzOiBSZWNvcmQ8c3RyaW5nLCBDb21taXRbXT4iLCJjb21taXRzIiwicmVsZWFzZVR5cGU6IFJlbGVhc2VUeXBlIiwiY29tbWl0IiwiY29tbWl0IiwiYXV0aG9yczogQ29udHJpYnV0b3JbXSIsImRhdGVQYXJ0czogUmVjb3JkPHN0cmluZywgc3RyaW5nPiIsImZyb206IHN0cmluZyIsInRvOiBzdHJpbmciLCJ0YWciLCJwcmV2VGFnOiBzdHJpbmcgfCB1bmRlZmluZWQiLCJwcmV2VmVyc2lvbjogc3RyaW5nIHwgdW5kZWZpbmVkIiwicmVsZWFzZUNvbnRleHQ6IFJlbGVhc2VDb250ZXh0IiwicmVsZWFzZVRlbXBsYXRlIiwidGFnIl0sInNvdXJjZXMiOlsiLi4vc3JjL2xpZmVjeWNsZXMvYnVtcC50cyIsIi4uL3NyYy9kZWZhdWx0cy50cyIsIi4uL3NyYy91dGlscy9jb25maWctcmVzb2x2ZXIudHMiLCIuLi9zcmMvdXRpbHMvdmVyc2lvbi1tYW5hZ2VyLnRzIiwiLi4vc3JjL2VudW1zLnRzIiwiLi4vc3JjL3V0aWxzL2NvbW1pdHMtcGFyc2VyLnRzIiwiLi4vc3JjL3V0aWxzL2dpdC11dGlscy50cyIsIi4uL3NyYy90ZW1wbGF0ZXMvcmVsZWFzZS5oYnMiLCIuLi9zcmMvbGlmZWN5Y2xlcy9jaGFuZ2Vsb2cudHMiLCIuLi9zcmMvbGlmZWN5Y2xlcy9jb21taXQudHMiLCIuLi9zcmMvbGlmZWN5Y2xlcy90YWcudHMiLCIuLi9zcmMvcmVsaW9uLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IHJlYWRGaWxlU3luYywgd3JpdGVGaWxlU3luYyB9IGZyb20gJ25vZGU6ZnMnXG5pbXBvcnQgdHlwZSB7IFJlc29sdmVkQ29uZmlnIH0gZnJvbSAnQC90eXBlcydcblxuZXhwb3J0IGNvbnN0IGJ1bXAgPSAoY29uZmlnOiBSZXNvbHZlZENvbmZpZyk6IHZvaWQgPT4ge1xuXHRpZiAoIWNvbmZpZy5idW1wKSByZXR1cm5cblx0Y29uc3QgYnVtcEZpbGVzID0gY29uZmlnLmJ1bXAsIG5ld1ZlcnNpb24gPSBjb25maWcuY29udGV4dC5uZXdWZXJzaW9uXG5cdGJ1bXBGaWxlcy5mb3JFYWNoKCh2ZXJzaW9uZWRGaWxlKSA9PiB7XG5cdFx0Y29uc3QgZmlsZUNvbnRlbnQgPSByZWFkRmlsZVN5bmModmVyc2lvbmVkRmlsZS5maWxlUGF0aCwgJ3V0ZjgnKVxuXHRcdGNvbnN0IHVwZGF0ZWRDb250ZW50ID0gZmlsZUNvbnRlbnQucmVwbGFjZSh2ZXJzaW9uZWRGaWxlLnZlcnNpb25QYXR0ZXJuLCBgJDEke25ld1ZlcnNpb259JDNgKVxuXHRcdGlmICghY29uZmlnLmRyeVJ1bikgd3JpdGVGaWxlU3luYyh2ZXJzaW9uZWRGaWxlLmZpbGVQYXRoLCB1cGRhdGVkQ29udGVudCwgJ3V0ZjgnKVxuXHRcdGNvbnNvbGUubG9nKGBVcGRhdGVkIHZlcnNpb24gaW4gJyR7dmVyc2lvbmVkRmlsZS5maWxlUGF0aH0nIHRvICcke25ld1ZlcnNpb259J2ApXG5cdH0pXG59IiwiaW1wb3J0IHR5cGUgeyBNZXJnZWRDb25maWcsIERlZmF1bHRWZXJzaW9uZWRGaWxlLCBDb21wbGV0ZUNoYW5nZWxvZ09wdGlvbnMsIENvbXBsZXRlQ29tbWl0T3B0aW9ucywgQ29tcGxldGVUYWdPcHRpb25zLCBEZWZhdWx0Q2hhbmdlbG9nU2VjdGlvbnMgfSBmcm9tICdAL3R5cGVzJ1xuXG5leHBvcnQgY29uc3QgZGVmYXVsdENvbmZpZzogTWVyZ2VkQ29uZmlnID0ge1xuXHRidW1wOiBmYWxzZSxcblx0Y2hhbmdlbG9nOiBmYWxzZSxcblx0Y29tbWl0OiBmYWxzZSxcblx0dGFnOiBmYWxzZSxcblx0dmVyc2lvblNvdXJjZUZpbGU6ICcuL3BhY2thZ2UuanNvbicsXG5cdG5ld1RhZ0Zvcm1hdDogJ3Z7e25ld1ZlcnNpb259fScsXG5cdHByZXZSZWxlYXNlVGFnUGF0dGVybjogL152KD88dmVyc2lvbj5cXGQrXFwuXFxkK1xcLlxcZCspLyxcblx0emVyb01ham9yQnJlYWtpbmdJc01pbm9yOiB0cnVlLFxuXHRkcnlSdW46IGZhbHNlLFxuXHRjb250ZXh0OiB7XG5cdFx0Y29tbWl0SHlwZXJsaW5rOiB0cnVlLFxuXHRcdHJlZkh5cGVybGluazogdHJ1ZSxcblx0fSxcblx0Y29tbWl0c1BhcnNlcjoge1xuXHRcdGhlYWRlclBhdHRlcm46IC9eKD88dHlwZT5cXHcrKSg/OlxcKCg/PHNjb3BlPi4rKVxcKSk/KD88YmFuZz4hKT86ICg/PHN1YmplY3Q+LispL3MsXG5cdFx0YnJlYWtpbmdDaGFuZ2VzUGF0dGVybjogL0JSRUFLSU5HIENIQU5HRVM/OlxccyooPzxjb250ZW50Pi4rKS9zLFxuXHRcdGJyZWFraW5nQ2hhbmdlTGlzdFBhdHRlcm46IC8tICguKykvZyxcblx0XHR0YWdQYXR0ZXJuOiAvdGFnOiAoPzx0YWc+Lio/KVssKV0vZyxcblx0XHRjb0F1dGhvclBhdHRlcm46IC9Dby1hdXRob3JlZC1ieTogKD88bmFtZT4uKz8pIDwoPzxlbWFpbD4uKyk+L2csXG5cdFx0c2lnbmVyUGF0dGVybjogL1NpZ25lZC1vZmYtYnk6ICg/PG5hbWU+Lis/KSA8KD88ZW1haWw+LispPi9nLFxuXHRcdGdoRW1haWxQYXR0ZXJuOiAvXig/OlxcZCtcXCspPyg/PHVzZXJuYW1lPi4rKUB1c2Vyc1xcLm5vcmVwbHlcXC5naXRodWJcXC5jb20kLyxcblx0XHRyZW1vdGVVcmxQYXR0ZXJuOiAvXihodHRwczpcXC9cXC98Z2l0QCkoPzxob3N0PlteLzpdKylbLzpdKD88b3duZXI+Lis/KVxcLyg/PG5hbWU+Lis/KSg/OlxcLi4qKT8kLyxcblx0XHRyZWZQYXR0ZXJuOiAvXig/PGFjdGlvbj4uKz8pICg/PGxhYmVscz4uKykkL2dtLFxuXHRcdHJlZkxhYmVsUGF0dGVybjogLyg/Oig/PG93bmVyPlxcUys/KVxcLyg/PHJlcG8+XFxTKz8pKT8jKD88bnVtYmVyPlxcZCspL2csXG5cdFx0cmVmQWN0aW9uUGF0dGVybjogL0ZpeGVzfENsb3Nlc3xSZWZzL2ksXG5cdFx0ZGF0ZVNvdXJjZTogJ2F1dGhvckRhdGUnLFxuXHRcdGRhdGVGb3JtYXQ6ICdZWVlZLU1NLUREJyxcblx0fSxcbn1cblxuZXhwb3J0IGNvbnN0IGRlZmF1bHRDaGFuZ2Vsb2dTZWN0aW9uczogRGVmYXVsdENoYW5nZWxvZ1NlY3Rpb25zID0ge1xuXHRicmVha2luZzogeyB0aXRsZTogJ+KaoO+4jyBCUkVBS0lORyBDSEFOR0VTJywgY29tbWl0VHlwZTogJ2JyZWFraW5nJyB9LFxuXHRmZWF0OiB7IHRpdGxlOiAn4pyoIEZlYXR1cmVzJywgY29tbWl0VHlwZTogJ2ZlYXQnIH0sXG5cdGZpeDogeyB0aXRsZTogJ/CfqbkgRml4ZXMnLCBjb21taXRUeXBlOiAnZml4JyB9LFxuXHRwZXJmOiB7IHRpdGxlOiAn4pqhIFBlcmZvcm1hbmNlJywgY29tbWl0VHlwZTogJ3BlcmYnIH0sXG5cdHJlZmFjdG9yOiB7IHRpdGxlOiAn8J+anCBSZWZhY3RvcmluZycsIGNvbW1pdFR5cGU6ICdyZWZhY3RvcicgfSxcblx0ZG9jczogeyB0aXRsZTogJ/Cfk5ogRG9jdW1lbnRhdGlvbicsIGNvbW1pdFR5cGU6ICdkb2NzJyB9LFxuXHRzdHlsZTogeyB0aXRsZTogJ/CfjqggRm9ybWF0dGluZycsIGNvbW1pdFR5cGU6ICdzdHlsZScgfSxcblx0YnVpbGQ6IHsgdGl0bGU6ICfwn5OmIEJ1aWxkJywgY29tbWl0VHlwZTogJ2J1aWxkJyB9LFxuXHRjaTogeyB0aXRsZTogJ/CfmoAgQ0knLCBjb21taXRUeXBlOiAnY2knIH0sXG5cdHJldmVydDogeyB0aXRsZTogJ+KZu++4jyBSZXZlcnRzJywgY29tbWl0VHlwZTogJ3JldmVydCcgfSxcblx0ZGVwczogeyB0aXRsZTogJ/Cfp6kgRGVwZW5kZW5jaWVzJywgY29tbWl0VHlwZTogJ2Nob3JlJyxcblx0XHRmaWx0ZXI6IGNvbW1pdCA9PiAhIWNvbW1pdC5zY29wZT8uaW5jbHVkZXMoJ2RlcHMnKSB9LFxuXHRjaG9yZTogeyB0aXRsZTogJ/Cfm6DvuI8gQ2hvcmVzJywgY29tbWl0VHlwZTogJ2Nob3JlJyB9LFxuXHR0ZXN0OiB7IHRpdGxlOiAn8J+nqiBUZXN0cycsIGNvbW1pdFR5cGU6ICd0ZXN0JyB9LFxuXHRtaXNjOiB7IHRpdGxlOiAn4pqZ77iPIE1pc2NlbGxhbmVvdXMnLCBjb21taXRUeXBlOiAnKicgfSxcblx0W1N5bWJvbC5pdGVyYXRvcl0oKSB7XG5cdFx0cmV0dXJuIE9iamVjdC52YWx1ZXModGhpcylbU3ltYm9sLml0ZXJhdG9yXSgpXG5cdH0sXG59XG5cbmV4cG9ydCBjb25zdCBkZWZhdWx0Q2hhbmdlbG9nT3B0aW9uczogQ29tcGxldGVDaGFuZ2Vsb2dPcHRpb25zID0ge1xuXHRzdGRvdXQ6IGZhbHNlLFxuXHRvdXRwdXRGaWxlOiAnLi9DSEFOR0VMT0cubWQnLFxuXHRjb21taXRSYW5nZTogJ3VucmVsZWFzZWQnLFxuXHRzZWN0aW9uczogWy4uLmRlZmF1bHRDaGFuZ2Vsb2dTZWN0aW9uc10sXG5cdGhlYWRlcjogJyMgQ2hhbmdlbG9nXFxuXFxuXFxuJyxcblx0cHJldlJlbGVhc2VIZWFkZXJQYXR0ZXJuOiAvXiMjLio/XFxkK1xcLlxcZCtcXC5cXGQrL20sXG5cdGhlbHBlcnM6IHtcblx0XHRyZXBlYXQ6IChzdHJpbmc6IHN0cmluZywgbjogbnVtYmVyKSA9PiBzdHJpbmcucmVwZWF0KG4pLFxuXHR9LFxuXHRwYXJ0aWFsczoge30sXG59XG5cbmV4cG9ydCBjb25zdCBkZWZhdWx0Q29tbWl0T3B0aW9uczogQ29tcGxldGVDb21taXRPcHRpb25zID0ge1xuXHRtZXNzYWdlOiAncmVsZWFzZSh7e3JlcG8ubmFtZX19KToge3tuZXdUYWd9fScsXG5cdHNpZ25PZmY6IGZhbHNlLFxuXHRncGdTaWduOiBmYWxzZSxcblx0c3RhZ2VBbGw6IHRydWUsXG5cdGV4dHJhQXJnczogJycsXG59XG5cbmV4cG9ydCBjb25zdCBkZWZhdWx0VGFnT3B0aW9uczogQ29tcGxldGVUYWdPcHRpb25zID0ge1xuXHRuYW1lOiAne3tuZXdUYWd9fScsXG5cdG1lc3NhZ2U6ICdyZWxlYXNlKHt7cmVwby5uYW1lfX0pOiB7e25ld1RhZ319Jyxcblx0Z3BnU2lnbjogZmFsc2UsXG5cdGZvcmNlOiBmYWxzZSxcblx0ZXh0cmFBcmdzOiAnJyxcbn1cblxuZXhwb3J0IGNvbnN0IGRlZmF1bHRWZXJzaW9uZWRGaWxlczogRGVmYXVsdFZlcnNpb25lZEZpbGVbXSA9IFtcblx0e1xuXHRcdGZpbGVQYXRoUmVnZXg6IC9wYWNrYWdlXFwuanNvbiQvLFxuXHRcdHZlcnNpb25QYXR0ZXJuOiAvKF4uKj9cInZlcnNpb25cIi4qP1wiKSguKj8pKFwiKS9zLFxuXHR9LFxuXHR7XG5cdFx0ZmlsZVBhdGhSZWdleDogL3BhY2thZ2UtbG9ja1xcLmpzb24kLyxcblx0XHR2ZXJzaW9uUGF0dGVybjogLyheLio/XCJ2ZXJzaW9uXCIuKj9cInxcInBhY2thZ2VzXCIuKj9cIlwiLipcInZlcnNpb25cIi4qP1wiKSguKj8pKFwiKS9ncyxcblx0fSxcbl0iLCJpbXBvcnQgeyBwYXJzZVZlcnNpb24sIGRldGVybWluZU5leHRWZXJzaW9uLCBnZXRWZXJzaW9uVGFncywgZ2V0UmVwb0luZm8sIHBhcnNlQ29tbWl0cyB9IGZyb20gJ0AvdXRpbHMnXG5pbXBvcnQgdHlwZSB7IFVzZXJDb25maWcsIFJlc29sdmVkQ29uZmlnLCBUcmFuc2Zvcm1lZENvbmZpZywgVmVyc2lvbmVkRmlsZSwgTWVyZ2VkQ29uZmlnLCBSZXNvbHZlZENvbnRleHQsIEZhbHNlT3JDb21wbGV0ZSwgQ29udGV4dHVhbENvbmZpZywgUmVzb2x2ZWRDaGFuZ2Vsb2dTZWN0aW9uLCBDaGFuZ2Vsb2dTZWN0aW9uRGVmaW5pdGlvbiwgQ29tbWl0LCBSZWxlYXNlV2l0aEZsYXRDb21taXRzLCBSZWxlYXNlV2l0aEdyb3VwZWRDb21taXRzIH0gZnJvbSAnQC90eXBlcydcbmltcG9ydCB7IGRlZmF1bHRDb25maWcsIGRlZmF1bHRWZXJzaW9uZWRGaWxlcywgZGVmYXVsdENoYW5nZWxvZ09wdGlvbnMsIGRlZmF1bHRDb21taXRPcHRpb25zLCBkZWZhdWx0VGFnT3B0aW9ucyB9IGZyb20gJ0AvZGVmYXVsdHMnXG5pbXBvcnQgSGFuZGxlYmFycyBmcm9tICdoYW5kbGViYXJzJ1xuXG5leHBvcnQgY29uc3QgcmVzb2x2ZUNvbmZpZyA9IGFzeW5jICh1c2VyQ29uZmlnOiBVc2VyQ29uZmlnKTogUHJvbWlzZTxSZXNvbHZlZENvbmZpZz4gPT4ge1xuXHRjb25zdCBwcm9maWxlTWVyZ2VkQ29uZmlnID0gbWVyZ2VQcm9maWxlQ29uZmlnKHVzZXJDb25maWcpXG5cdGNvbnN0IG1lcmdlZENvbmZpZyA9IG1lcmdlV2l0aERlZmF1bHRzKHByb2ZpbGVNZXJnZWRDb25maWcpXG5cdGNvbnN0IHRyYW5zZm9ybWVkQ29uZmlnID0gdHJhbnNmb3JtVmVyc2lvbmVkRmlsZXMobWVyZ2VkQ29uZmlnKVxuXHRjb25zdCBjb250ZXh0dWFsQ29uZmlnID0gYXdhaXQgZmlsbENvbnRleHQodHJhbnNmb3JtZWRDb25maWcpXG5cdGNvbnN0IGZpbmFsQ29uZmlnID0gcmVzb2x2ZVRlbXBsYXRlcyhjb250ZXh0dWFsQ29uZmlnKVxuXHRyZXR1cm4gZmluYWxDb25maWdcbn1cblxuY29uc3QgbWVyZ2VQcm9maWxlQ29uZmlnID0gKGJhc2VDb25maWc6IFVzZXJDb25maWcpOiBVc2VyQ29uZmlnID0+IHtcblx0Y29uc3QgcHJvZmlsZU5hbWUgPSBiYXNlQ29uZmlnLnByb2ZpbGVcblx0aWYgKCFwcm9maWxlTmFtZSkgcmV0dXJuIGJhc2VDb25maWdcblxuXHRjb25zdCBwcm9maWxlQ29uZmlnID0gYmFzZUNvbmZpZ1tgXyR7cHJvZmlsZU5hbWV9YF1cblx0aWYgKCFwcm9maWxlQ29uZmlnKSB0aHJvdyBuZXcgRXJyb3IoYFByb2ZpbGUgXCIke3Byb2ZpbGVOYW1lfVwiIG5vdCBmb3VuZCBpbiBjb25maWd1cmF0aW9uLmApXG5cblx0Y29uc3QgbWVyZ2VPcHRpb24gPSA8VCBleHRlbmRzIGtleW9mIFVzZXJDb25maWc+KHByb3BLZXk6IFQsIC4uLm5lc3RlZFByb3BLZXlzOiBzdHJpbmdbXSk6IFVzZXJDb25maWdbVF0gPT4ge1xuXHRcdHR5cGUgUGxhaW5PYmplY3QgPSBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPlxuXG5cdFx0Y29uc3QgaXNQbGFpbk9iamVjdCA9ICh2YWx1ZTogdW5rbm93bik6IHZhbHVlIGlzIFBsYWluT2JqZWN0ID0+XG5cdFx0XHRPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwodmFsdWUpID09PSAnW29iamVjdCBPYmplY3RdJ1xuXG5cdFx0Y29uc3QgbWVyZ2VPYmplY3RzID0gKGJhc2VPYmo6IHVua25vd24sIG92ZXJyaWRlT2JqZWN0OiB1bmtub3duKTogdW5rbm93biA9PiB7XG5cdFx0XHRjb25zdCBpc0Jhc2VQbGFpbk9iamVjdCA9IGlzUGxhaW5PYmplY3QoYmFzZU9iailcblx0XHRcdGNvbnN0IGlzT3ZlcnJpZGVQbGFpbk9iamVjdCA9IGlzUGxhaW5PYmplY3Qob3ZlcnJpZGVPYmplY3QpXG5cdFx0XHRpZiAoaXNCYXNlUGxhaW5PYmplY3QgJiYgaXNPdmVycmlkZVBsYWluT2JqZWN0KSB7XG5cdFx0XHRcdHJldHVybiB7IC4uLmJhc2VPYmosIC4uLm92ZXJyaWRlT2JqZWN0IH1cblx0XHRcdH0gZWxzZSBpZiAoIWlzQmFzZVBsYWluT2JqZWN0ICYmIGlzT3ZlcnJpZGVQbGFpbk9iamVjdCkge1xuXHRcdFx0XHRyZXR1cm4gb3ZlcnJpZGVPYmplY3Rcblx0XHRcdH0gZWxzZSBpZiAoaXNCYXNlUGxhaW5PYmplY3QgJiYgIWlzT3ZlcnJpZGVQbGFpbk9iamVjdCkge1xuXHRcdFx0XHRyZXR1cm4gYmFzZU9ialxuXHRcdFx0fVxuXHRcdH1cblxuXHRcdGNvbnN0IGJhc2VDb25maWdQcm9wID0gYmFzZUNvbmZpZ1twcm9wS2V5XSBhcyBQbGFpbk9iamVjdCB8IHVuZGVmaW5lZFxuXHRcdGNvbnN0IHByb2ZpbGVDb25maWdQcm9wID0gcHJvZmlsZUNvbmZpZ1twcm9wS2V5XSBhcyBQbGFpbk9iamVjdCB8IHVuZGVmaW5lZFxuXHRcdGNvbnN0IHJlc3VsdCA9IG1lcmdlT2JqZWN0cyhiYXNlQ29uZmlnUHJvcCwgcHJvZmlsZUNvbmZpZ1Byb3ApIGFzIFBsYWluT2JqZWN0IHwgdW5kZWZpbmVkXG5cdFx0aWYgKHJlc3VsdCA9PT0gdW5kZWZpbmVkKSByZXR1cm4gdW5kZWZpbmVkXG5cblx0XHRuZXN0ZWRQcm9wS2V5cy5mb3JFYWNoKChrZXkpID0+IHtcblx0XHRcdHJlc3VsdFtrZXldID0gbWVyZ2VPYmplY3RzKGJhc2VDb25maWdQcm9wPy5ba2V5XSwgcHJvZmlsZUNvbmZpZ1Byb3A/LltrZXldKVxuXHRcdH0pXG5cblx0XHRyZXR1cm4gcmVzdWx0IGFzIFVzZXJDb25maWdbVF1cblx0fVxuXG5cdHJldHVybiB7XG5cdFx0Li4uYmFzZUNvbmZpZywgLi4ucHJvZmlsZUNvbmZpZyxcblx0XHRjb21taXRzUGFyc2VyOiBtZXJnZU9wdGlvbignY29tbWl0c1BhcnNlcicpLFxuXHRcdGNoYW5nZWxvZzogbWVyZ2VPcHRpb24oJ2NoYW5nZWxvZycsICdwYXJ0aWFscycsICdoZWxwZXJzJyksXG5cdFx0Y29tbWl0OiBtZXJnZU9wdGlvbignY29tbWl0JyksXG5cdFx0dGFnOiBtZXJnZU9wdGlvbigndGFnJyksXG5cdFx0Y29udGV4dDogbWVyZ2VPcHRpb24oJ2NvbnRleHQnKSxcblx0fVxufVxuXG5jb25zdCBtZXJnZVdpdGhEZWZhdWx0cyA9ICh1c2VyQ29uZmlnOiBVc2VyQ29uZmlnKTogTWVyZ2VkQ29uZmlnID0+IHtcblx0Y29uc3QgcmVzb2x2ZU9wdGlvbnMgPSA8VD4ob3B0aW9uc05hbWU6IHN0cmluZywgb3B0aW9uczogYm9vbGVhbiB8IFQgfCB1bmRlZmluZWQsIGRlZmF1bHRzOiBSZXF1aXJlZDxUPiwgLi4uc3ViT2JqZWN0czogKGtleW9mIFQpW10pOiBGYWxzZU9yQ29tcGxldGU8VD4gPT4ge1xuXHRcdGlmIChvcHRpb25zID09IHVuZGVmaW5lZCB8fCBvcHRpb25zID09PSBmYWxzZSkgcmV0dXJuIGZhbHNlXG5cdFx0aWYgKG9wdGlvbnMgPT09IHRydWUpIHJldHVybiBkZWZhdWx0c1xuXHRcdGlmICh0eXBlb2Ygb3B0aW9ucyAhPT0gJ29iamVjdCcpIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCB2YWx1ZSBmb3IgJHtvcHRpb25zTmFtZX0uIEl0IHNob3VsZCBiZSBhIGJvb2xlYW4gb3IgYW4gb2JqZWN0LmApXG5cdFx0Y29uc3QgcmVzdWx0OiBSZXF1aXJlZDxUPiA9IHsgLi4uZGVmYXVsdHMsIC4uLm9wdGlvbnMgfVxuXHRcdHN1Yk9iamVjdHMuZm9yRWFjaChzdWJPYmplY3RLZXkgPT4gcmVzdWx0W3N1Yk9iamVjdEtleV0gPSB7IC4uLmRlZmF1bHRzW3N1Yk9iamVjdEtleV0sIC4uLm9wdGlvbnNbc3ViT2JqZWN0S2V5XSB9KVxuXHRcdHJldHVybiByZXN1bHRcblx0fVxuXG5cdHJldHVybiB7XG5cdFx0Li4uZGVmYXVsdENvbmZpZywgLi4udXNlckNvbmZpZyxcblx0XHRjb21taXRzUGFyc2VyOiB7IC4uLmRlZmF1bHRDb25maWcuY29tbWl0c1BhcnNlciwgLi4udXNlckNvbmZpZy5jb21taXRzUGFyc2VyIH0sXG5cdFx0Y2hhbmdlbG9nOiByZXNvbHZlT3B0aW9ucygnY2hhbmdlbG9nJywgdXNlckNvbmZpZy5jaGFuZ2Vsb2csIGRlZmF1bHRDaGFuZ2Vsb2dPcHRpb25zLCAncGFydGlhbHMnLCAnaGVscGVycycpLFxuXHRcdGNvbW1pdDogcmVzb2x2ZU9wdGlvbnMoJ2NvbW1pdCcsIHVzZXJDb25maWcuY29tbWl0LCBkZWZhdWx0Q29tbWl0T3B0aW9ucyksXG5cdFx0dGFnOiByZXNvbHZlT3B0aW9ucygndGFnJywgdXNlckNvbmZpZy50YWcsIGRlZmF1bHRUYWdPcHRpb25zKSxcblx0fVxufVxuXG5jb25zdCB0cmFuc2Zvcm1WZXJzaW9uZWRGaWxlcyA9IChjb25maWc6IE1lcmdlZENvbmZpZyk6IFRyYW5zZm9ybWVkQ29uZmlnID0+IHtcblx0Y29uc3QgcmVzb2x2ZVZlcnNpb25lZEZpbGUgPSAoZmlsZVBhdGg6IHN0cmluZyk6IFZlcnNpb25lZEZpbGUgPT4ge1xuXHRcdGNvbnN0IG1hdGNoaW5nRGVmYXVsdFZlcnNpb25GaWxlID0gZGVmYXVsdFZlcnNpb25lZEZpbGVzLmZpbmQoZGVmYXVsdEZpbGUgPT5cblx0XHRcdGRlZmF1bHRGaWxlLmZpbGVQYXRoUmVnZXgudGVzdChmaWxlUGF0aCkpXG5cdFx0aWYgKG1hdGNoaW5nRGVmYXVsdFZlcnNpb25GaWxlKSB7XG5cdFx0XHRyZXR1cm4geyBmaWxlUGF0aCwgdmVyc2lvblBhdHRlcm46IG1hdGNoaW5nRGVmYXVsdFZlcnNpb25GaWxlLnZlcnNpb25QYXR0ZXJuIH1cblx0XHR9IGVsc2Uge1xuXHRcdFx0dGhyb3cgbmV3IEVycm9yKFxuXHRcdFx0XHRgRmlsZSAke2ZpbGVQYXRofSBkb2Vzbid0IG1hdGNoIGFueSBkZWZhdWx0IHZlcnNpb25lZCBmaWxlcy4gYFxuXHRcdFx0XHQrICdQbGVhc2UgcHJvdmlkZSBhIGN1c3RvbSB2ZXJzaW9uIHBhdHRlcm4gZm9yIHRoaXMgZmlsZS4nLFxuXHRcdFx0KVxuXHRcdH1cblx0fVxuXG5cdGNvbnN0IHJlc29sdmVCdW1wID0gKGJ1bXA6IE1lcmdlZENvbmZpZ1snYnVtcCddKTogZmFsc2UgfCBWZXJzaW9uZWRGaWxlW10gPT4ge1xuXHRcdGlmIChidW1wID09PSBmYWxzZSkgcmV0dXJuIGZhbHNlXG5cdFx0aWYgKGJ1bXAgPT09IHRydWUpIHJldHVybiBbdmVyc2lvblNvdXJjZUZpbGVdXG5cdFx0aWYgKEFycmF5LmlzQXJyYXkoYnVtcCkpIHJldHVybiBbXG5cdFx0XHR2ZXJzaW9uU291cmNlRmlsZSxcblx0XHRcdC4uLihidW1wLm1hcChidW1wRmlsZSA9PlxuXHRcdFx0XHR0eXBlb2YgYnVtcEZpbGUgPT09ICdzdHJpbmcnID8gcmVzb2x2ZVZlcnNpb25lZEZpbGUoYnVtcEZpbGUpIDogYnVtcEZpbGUsXG5cdFx0XHQpKSxcblx0XHRdXG5cdFx0dGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIHZhbHVlIGZvciBidW1wLiBJdCBzaG91bGQgYmUgYSBib29sZWFuIG9yIGFuIGFycmF5LicpXG5cdH1cblxuXHRjb25zdCB2ZXJzaW9uU291cmNlRmlsZSA9IHR5cGVvZiBjb25maWcudmVyc2lvblNvdXJjZUZpbGUgPT09ICdzdHJpbmcnXG5cdFx0PyByZXNvbHZlVmVyc2lvbmVkRmlsZShjb25maWcudmVyc2lvblNvdXJjZUZpbGUpXG5cdFx0OiBjb25maWcudmVyc2lvblNvdXJjZUZpbGVcblxuXHRyZXR1cm4ge1xuXHRcdC4uLmNvbmZpZyxcblx0XHR2ZXJzaW9uU291cmNlRmlsZSxcblx0XHRidW1wOiByZXNvbHZlQnVtcChjb25maWcuYnVtcCksXG5cdFx0Y2hhbmdlbG9nOiBjb25maWcuY2hhbmdlbG9nID09PSBmYWxzZVxuXHRcdFx0PyBmYWxzZVxuXHRcdFx0OiB7IC4uLmNvbmZpZy5jaGFuZ2Vsb2csXG5cdFx0XHRcdGNvbXBpbGVkUGFydGlhbHM6IE9iamVjdC5mcm9tRW50cmllcyhPYmplY3QuZW50cmllcyhjb25maWcuY2hhbmdlbG9nLnBhcnRpYWxzKS5tYXAoKFtrZXksIHRlbXBsYXRlXSkgPT4gW2tleSwgSGFuZGxlYmFycy5jb21waWxlKHRlbXBsYXRlKV0pKSxcblx0XHRcdH0sXG5cdH1cbn1cblxuY29uc3QgZmlsbENvbnRleHQgPSBhc3luYyAoY29uZmlnOiBUcmFuc2Zvcm1lZENvbmZpZyk6IFByb21pc2U8Q29udGV4dHVhbENvbmZpZz4gPT4ge1xuXHRjb25zdCByZXNvbHZlZENvbnRleHQgPSAoY29uZmlnLmNvbnRleHQgPz8ge30pIGFzIFBhcnRpYWw8UmVzb2x2ZWRDb250ZXh0PlxuXG5cdGNvbnN0IHJlcG9JbmZvID0gZ2V0UmVwb0luZm8oY29uZmlnLmNvbW1pdHNQYXJzZXIucmVtb3RlVXJsUGF0dGVybilcblx0cmVzb2x2ZWRDb250ZXh0LnJlcG8gPSB7IC4uLnJlcG9JbmZvLCAuLi5yZXNvbHZlZENvbnRleHQucmVwbyB9XG5cblx0Y29uc3QgY29tbWl0UmFuZ2UgPSBjb25maWcuY2hhbmdlbG9nID8gY29uZmlnLmNoYW5nZWxvZy5jb21taXRSYW5nZSA6ICd1bnJlbGVhc2VkJ1xuXG5cdHJlc29sdmVkQ29udGV4dC5jb21taXRzID0gY29uZmlnLmNvbnRleHQ/LmNvbW1pdHNcblx0XHQ/IGF3YWl0IFByb21pc2UuYWxsKGNvbmZpZy5jb250ZXh0LmNvbW1pdHMubWFwKGFzeW5jIChjb21taXQpID0+IHtcblx0XHRcdHJldHVybiAoKHR5cGVvZiBjb21taXQgPT09ICdvYmplY3QnICYmICdtZXNzYWdlJyBpbiBjb21taXQpIHx8IHR5cGVvZiBjb21taXQgPT09ICdzdHJpbmcnKVxuXHRcdFx0XHQ/IChhd2FpdCBwYXJzZUNvbW1pdHMoW2NvbW1pdF0sIGNvbmZpZy5jb21taXRzUGFyc2VyLCBjb25maWcucHJldlJlbGVhc2VUYWdQYXR0ZXJuKSlbMF1cblx0XHRcdFx0OiBjb21taXRcblx0XHR9KSlcblx0XHQ6IGF3YWl0IHBhcnNlQ29tbWl0cyhjb21taXRSYW5nZSwgY29uZmlnLmNvbW1pdHNQYXJzZXIsIGNvbmZpZy5wcmV2UmVsZWFzZVRhZ1BhdHRlcm4pXG5cblx0cmVzb2x2ZWRDb250ZXh0LmN1cnJlbnRWZXJzaW9uID8/PSBwYXJzZVZlcnNpb24oY29uZmlnLnZlcnNpb25Tb3VyY2VGaWxlKVxuXHRyZXNvbHZlZENvbnRleHQuY3VycmVudFRhZyA/Pz0gZ2V0VmVyc2lvblRhZ3MoY29uZmlnLnByZXZSZWxlYXNlVGFnUGF0dGVybilbMF1cblx0cmVzb2x2ZWRDb250ZXh0Lm5ld1ZlcnNpb24gPz89IGF3YWl0IGRldGVybWluZU5leHRWZXJzaW9uKGNvbmZpZywgcmVzb2x2ZWRDb250ZXh0LmN1cnJlbnRWZXJzaW9uKVxuXHRyZXNvbHZlZENvbnRleHQubmV3VGFnID8/PSBjb21waWxlVGVtcGxhdGUoY29uZmlnLm5ld1RhZ0Zvcm1hdCwgcmVzb2x2ZWRDb250ZXh0IGFzIFJlc29sdmVkQ29udGV4dClcblxuXHRjb25zdCBjb250ZXh0dWFsQ29uZmlnID0geyAuLi5jb25maWcsIGNvbnRleHQ6IHJlc29sdmVkQ29udGV4dCBhcyBSZXNvbHZlZENvbnRleHQgfVxuXG5cdHJlc29sdmVkQ29udGV4dC5yZWxlYXNlcyA9IGNvbmZpZy5jaGFuZ2Vsb2dcblx0XHQ/IGdyb3VwQ29tbWl0c0J5UmVsZWFzZXMocmVzb2x2ZWRDb250ZXh0LmNvbW1pdHMsIGNvbmZpZy5jaGFuZ2Vsb2cuc2VjdGlvbnMsIGNvbnRleHR1YWxDb25maWcpXG5cdFx0OiBudWxsXG5cblx0cmV0dXJuIGNvbnRleHR1YWxDb25maWdcbn1cblxuY29uc3QgZ3JvdXBDb21taXRzQnlSZWxlYXNlcyA9IChjb21taXRzOiBDb21taXRbXSwgc2VjdGlvbnM6IENoYW5nZWxvZ1NlY3Rpb25EZWZpbml0aW9uW10sIGNvbmZpZzogQ29udGV4dHVhbENvbmZpZyk6IFJlbGVhc2VXaXRoR3JvdXBlZENvbW1pdHNbXSA9PiB7XG5cdGNvbnN0IHJlbGVhc2VzOiBSZWNvcmQ8c3RyaW5nLCBSZWxlYXNlV2l0aEZsYXRDb21taXRzPiA9IHt9XG5cblx0Y29tbWl0cy5mb3JFYWNoKChjb21taXQpID0+IHtcblx0XHRjb25zdCByZWxlYXNlVGFnID0gY29tbWl0LnRhZ3M/LmZpbmQodGFnID0+IGNvbmZpZy5wcmV2UmVsZWFzZVRhZ1BhdHRlcm4udGVzdCh0YWcpKVxuXHRcdGlmIChyZWxlYXNlVGFnKSB7XG5cdFx0XHRyZWxlYXNlc1tyZWxlYXNlVGFnXSA/Pz0ge1xuXHRcdFx0XHR0YWc6IHJlbGVhc2VUYWcsXG5cdFx0XHRcdHZlcnNpb246IGNvbmZpZy5wcmV2UmVsZWFzZVRhZ1BhdHRlcm4uZXhlYyhyZWxlYXNlVGFnKT8uZ3JvdXBzPy52ZXJzaW9uLFxuXHRcdFx0XHRkYXRlOiBjb21taXQuZGF0ZSxcblx0XHRcdFx0Y29tbWl0czogW2NvbW1pdF0sXG5cdFx0XHR9XG5cdFx0fSBlbHNlIHtcblx0XHRcdGNvbnN0IGxhdGVzdFJlbGVhc2VUYWcgPSBPYmplY3Qua2V5cyhyZWxlYXNlcykuYXQoLTEpXG5cdFx0XHRpZiAobGF0ZXN0UmVsZWFzZVRhZykge1xuXHRcdFx0XHRyZWxlYXNlc1tsYXRlc3RSZWxlYXNlVGFnXS5jb21taXRzLnB1c2goY29tbWl0KVxuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0cmVsZWFzZXNbY29uZmlnLmNvbnRleHQubmV3VGFnXSA9IHtcblx0XHRcdFx0XHR0YWc6IGNvbmZpZy5jb250ZXh0Lm5ld1RhZyxcblx0XHRcdFx0XHR2ZXJzaW9uOiBjb25maWcuY29udGV4dC5uZXdWZXJzaW9uLFxuXHRcdFx0XHRcdGRhdGU6IGNvbW1pdC5kYXRlLFxuXHRcdFx0XHRcdGNvbW1pdHM6IFtjb21taXRdLFxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXHR9KVxuXG5cdHJldHVybiBPYmplY3QudmFsdWVzKHJlbGVhc2VzKS5tYXAocmVsZWFzZSA9PiBncm91cFJlbGVhc2VDb21taXRzQnlTZWN0aW9ucyhyZWxlYXNlLCBzZWN0aW9ucykpXG59XG5cbmNvbnN0IGdyb3VwUmVsZWFzZUNvbW1pdHNCeVNlY3Rpb25zID0gKHJlbGVhc2U6IFJlbGVhc2VXaXRoRmxhdENvbW1pdHMsIHNlY3Rpb25zOiBDaGFuZ2Vsb2dTZWN0aW9uRGVmaW5pdGlvbltdKTogUmVsZWFzZVdpdGhHcm91cGVkQ29tbWl0cyA9PiB7XG5cdGNvbnN0IHsgY29tbWl0cywgLi4ucmVsZWFzZVdpdGhvdXRDb21taXRzIH0gPSByZWxlYXNlXG5cdHJldHVybiB7XG5cdFx0Li4ucmVsZWFzZVdpdGhvdXRDb21taXRzLFxuXHRcdGNvbW1pdEdyb3VwczogZ3JvdXBDb21taXRzQnlTZWN0aW9ucyhjb21taXRzLCBzZWN0aW9ucyksXG5cdH1cbn1cblxuY29uc3QgZ3JvdXBDb21taXRzQnlTZWN0aW9ucyA9IChjb21taXRzOiBDb21taXRbXSwgc2VjdGlvbnM6IENoYW5nZWxvZ1NlY3Rpb25EZWZpbml0aW9uW10pOiBSZXNvbHZlZENoYW5nZWxvZ1NlY3Rpb25bXSA9PiB7XG5cdGNvbnN0IGNvbW1pdEdyb3VwczogUmVjb3JkPHN0cmluZywgQ29tbWl0W10+ID0gT2JqZWN0LmZyb21FbnRyaWVzKHNlY3Rpb25zLm1hcChzZWN0aW9uID0+IFtzZWN0aW9uLnRpdGxlLCBbXV0pKVxuXG5cdGNvbW1pdHMuZm9yRWFjaCgoY29tbWl0KSA9PiB7XG5cdFx0Y29uc3QgaXNCcmVha2luZyA9ICEhY29tbWl0LmJyZWFraW5nQ2hhbmdlc1xuXHRcdGxldCBpc0dyb3VwZWQgPSBmYWxzZVxuXHRcdGxldCBpc0JyZWFraW5nR3JvdXBlZCA9IGZhbHNlXG5cblx0XHRmb3IgKGNvbnN0IHNlY3Rpb24gb2Ygc2VjdGlvbnMpIHtcblx0XHRcdGlmIChzZWN0aW9uLmZpbHRlciAmJiAhc2VjdGlvbi5maWx0ZXIoY29tbWl0KSkgY29udGludWVcblxuXHRcdFx0Y29uc3Qgc2VjdGlvblR5cGVzID0gW3NlY3Rpb24uY29tbWl0VHlwZV0uZmxhdCgpXG5cblx0XHRcdGlmIChpc0JyZWFraW5nICYmICFpc0JyZWFraW5nR3JvdXBlZCAmJiBzZWN0aW9uVHlwZXMuaW5jbHVkZXMoJ2JyZWFraW5nJykpIHtcblx0XHRcdFx0Y29tbWl0R3JvdXBzW3NlY3Rpb24udGl0bGVdLnB1c2goY29tbWl0KVxuXHRcdFx0XHRpc0JyZWFraW5nR3JvdXBlZCA9IHRydWVcblx0XHRcdFx0Y29udGludWVcblx0XHRcdH1cblxuXHRcdFx0aWYgKCFpc0dyb3VwZWQgJiYgKHNlY3Rpb25UeXBlcy5pbmNsdWRlcyhjb21taXQudHlwZSkgfHwgc2VjdGlvblR5cGVzLmluY2x1ZGVzKCcqJykpKSB7XG5cdFx0XHRcdGNvbW1pdEdyb3Vwc1tzZWN0aW9uLnRpdGxlXS5wdXNoKGNvbW1pdClcblx0XHRcdFx0aXNHcm91cGVkID0gdHJ1ZVxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoaXNHcm91cGVkICYmICghaXNCcmVha2luZyB8fCBpc0JyZWFraW5nR3JvdXBlZCkpIHJldHVyblxuXHRcdH1cblx0fSlcblxuXHRPYmplY3Qua2V5cyhjb21taXRHcm91cHMpLmZvckVhY2goKGtleSkgPT4ge1xuXHRcdGlmICghY29tbWl0R3JvdXBzW2tleV0ubGVuZ3RoKSBkZWxldGUgY29tbWl0R3JvdXBzW2tleV1cblx0fSlcblxuXHRyZXR1cm4gT2JqZWN0LmVudHJpZXMoY29tbWl0R3JvdXBzKS5tYXAoKFt0aXRsZSwgY29tbWl0c10pID0+ICh7IHRpdGxlLCBjb21taXRzIH0pKVxufVxuXG5jb25zdCByZXNvbHZlVGVtcGxhdGVzID0gKGNvbmZpZzogQ29udGV4dHVhbENvbmZpZyk6IFJlc29sdmVkQ29uZmlnID0+IHtcblx0cmV0dXJuIHtcblx0XHQuLi5jb25maWcsXG5cdFx0Y29tbWl0OiBjb25maWcuY29tbWl0XG5cdFx0XHQ/IHsgLi4uY29uZmlnLmNvbW1pdCwgbWVzc2FnZTogY29tcGlsZVRlbXBsYXRlKGNvbmZpZy5jb21taXQubWVzc2FnZSwgY29uZmlnLmNvbnRleHQpIH1cblx0XHRcdDogY29uZmlnLmNvbW1pdCxcblx0XHR0YWc6IGNvbmZpZy50YWdcblx0XHRcdD8ge1xuXHRcdFx0XHQuLi5jb25maWcudGFnLFxuXHRcdFx0XHRuYW1lOiBjb21waWxlVGVtcGxhdGUoY29uZmlnLnRhZy5uYW1lLCBjb25maWcuY29udGV4dCksXG5cdFx0XHRcdG1lc3NhZ2U6IGNvbXBpbGVUZW1wbGF0ZShjb25maWcudGFnLm1lc3NhZ2UsIGNvbmZpZy5jb250ZXh0KSxcblx0XHRcdH1cblx0XHRcdDogY29uZmlnLnRhZyxcblx0fVxufVxuXG5jb25zdCBjb21waWxlVGVtcGxhdGUgPSAodmFsdWU6IHN0cmluZywgY29udGV4dDogUmVzb2x2ZWRDb250ZXh0KTogc3RyaW5nID0+IHtcblx0Y29uc3QgY29tcGlsZSA9IEhhbmRsZWJhcnMuY29tcGlsZSh2YWx1ZSlcblx0cmV0dXJuIGNvbXBpbGUoY29udGV4dClcbn0iLCJpbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdub2RlOmZzJ1xuaW1wb3J0IHNlbXZlciBmcm9tICdzZW12ZXInXG5pbXBvcnQgdHlwZSB7IFJlbGVhc2VUeXBlLCBDb21taXQsIFZlcnNpb25lZEZpbGUsIFRyYW5zZm9ybWVkQ29uZmlnIH0gZnJvbSAnQC90eXBlcydcbmltcG9ydCB7IHBhcnNlQ29tbWl0cyB9IGZyb20gJ0AvdXRpbHMnXG5cbmV4cG9ydCBjb25zdCBwYXJzZVZlcnNpb24gPSAodmVyc2lvbmVkRmlsZTogVmVyc2lvbmVkRmlsZSk6IHN0cmluZyA9PiB7XG5cdGNvbnN0IGZpbGVDb250ZW50ID0gcmVhZEZpbGVTeW5jKHZlcnNpb25lZEZpbGUuZmlsZVBhdGgsICd1dGY4Jylcblx0Y29uc3QgdmVyc2lvbiA9IHZlcnNpb25lZEZpbGUudmVyc2lvblBhdHRlcm4uZXhlYyhmaWxlQ29udGVudCk/LlsyXVxuXHRpZiAoIXZlcnNpb24pIHRocm93IG5ldyBFcnJvcihgVmVyc2lvbiBub3QgZm91bmQgaW4gJyR7dmVyc2lvbmVkRmlsZS5maWxlUGF0aH0nIHdpdGggcGF0dGVybiAnJHt2ZXJzaW9uZWRGaWxlLnZlcnNpb25QYXR0ZXJufSdgKVxuXHRpZiAoIXNlbXZlci52YWxpZCh2ZXJzaW9uKSkgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIHZlcnNpb24gZm9ybWF0IGluICcke3ZlcnNpb25lZEZpbGUuZmlsZVBhdGh9JzogJyR7dmVyc2lvbn0nYClcblx0Y29uc29sZS5sb2coYEN1cnJlbnQgdmVyc2lvbiBmcm9tICcke3ZlcnNpb25lZEZpbGUuZmlsZVBhdGh9JzogJyR7dmVyc2lvbn0nYClcblx0cmV0dXJuIHZlcnNpb25cbn1cblxuZXhwb3J0IGNvbnN0IGRldGVybWluZU5leHRWZXJzaW9uID0gYXN5bmMgKGNvbmZpZzogVHJhbnNmb3JtZWRDb25maWcsIGN1cnJlbnRWZXJzaW9uOiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4gPT4ge1xuXHRpZiAoY29uZmlnLnJlbGVhc2VWZXJzaW9uKSB7XG5cdFx0aWYgKCFzZW12ZXIudmFsaWQoY29uZmlnLnJlbGVhc2VWZXJzaW9uKSkge1xuXHRcdFx0dGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIHJlbGVhc2UgdmVyc2lvbiBmb3JtYXQ6ICcke2NvbmZpZy5yZWxlYXNlVmVyc2lvbn0nYClcblx0XHR9XG5cdFx0cmV0dXJuIGNvbmZpZy5yZWxlYXNlVmVyc2lvblxuXHR9XG5cdGxldCByZWxlYXNlVHlwZTogUmVsZWFzZVR5cGVcblx0aWYgKGNvbmZpZy5yZWxlYXNlVHlwZSkge1xuXHRcdHJlbGVhc2VUeXBlID0gY29uZmlnLnJlbGVhc2VUeXBlXG5cdH0gZWxzZSB7XG5cdFx0Y29uc3QgdW5yZWxlYXNlZENvbW1pdHMgPSBhd2FpdCBwYXJzZUNvbW1pdHMoJ3VucmVsZWFzZWQnLCBjb25maWcuY29tbWl0c1BhcnNlciwgY29uZmlnLnByZXZSZWxlYXNlVGFnUGF0dGVybilcblx0XHRyZWxlYXNlVHlwZSA9IGNhbGN1bGF0ZVJlbGVhc2VUeXBlKHVucmVsZWFzZWRDb21taXRzKVxuXHRcdGlmIChjb25maWcuemVyb01ham9yQnJlYWtpbmdJc01pbm9yICYmIHNlbXZlci5tYWpvcihjdXJyZW50VmVyc2lvbikgPT09IDAgJiYgcmVsZWFzZVR5cGUgPT09ICdtYWpvcicpIHJlbGVhc2VUeXBlID0gJ21pbm9yJ1xuXHR9XG5cdGNvbnN0IG5ld1ZlcnNpb24gPSBpbmNyZWFzZVZlcnNpb24oY3VycmVudFZlcnNpb24sIHJlbGVhc2VUeXBlKVxuXHRjb25zb2xlLmxvZyhgRGV0ZXJtaW5lZCBuZXcgdmVyc2lvbjogJyR7bmV3VmVyc2lvbn0nIChyZWxlYXNlIHR5cGU6ICcke3JlbGVhc2VUeXBlfScpYClcblx0cmV0dXJuIG5ld1ZlcnNpb25cbn1cblxuY29uc3QgY2FsY3VsYXRlUmVsZWFzZVR5cGUgPSAoY29tbWl0czogQ29tbWl0W10pOiBSZWxlYXNlVHlwZSA9PiB7XG5cdGNvbnN0IGhhc0JyZWFraW5nQ2hhbmdlID0gY29tbWl0cy5zb21lKGNvbW1pdCA9PiBjb21taXQuYnJlYWtpbmdDaGFuZ2VzKVxuXHRpZiAoaGFzQnJlYWtpbmdDaGFuZ2UpIHJldHVybiAnbWFqb3InXG5cblx0Y29uc3QgaGFzRmVhdHVyZSA9IGNvbW1pdHMuc29tZShjb21taXQgPT4gY29tbWl0LnR5cGUgPT09ICdmZWF0Jylcblx0aWYgKGhhc0ZlYXR1cmUpIHJldHVybiAnbWlub3InXG5cblx0cmV0dXJuICdwYXRjaCdcbn1cblxuY29uc3QgaW5jcmVhc2VWZXJzaW9uID0gKGN1cnJlbnRWZXJzaW9uOiBzdHJpbmcsIHJlbGVhc2VUeXBlOiBSZWxlYXNlVHlwZSk6IHN0cmluZyA9PlxuXHRzZW12ZXIuaW5jKGN1cnJlbnRWZXJzaW9uLCByZWxlYXNlVHlwZSkgPz8gKCgpID0+IHtcblx0XHR0aHJvdyBuZXcgRXJyb3IoYEZhaWxlZCB0byBjYWxjdWxhdGUgbmV3IHZlcnNpb24gZnJvbSAnJHtjdXJyZW50VmVyc2lvbn0nIHdpdGggcmVsZWFzZSB0eXBlICcke3JlbGVhc2VUeXBlfSdgKVxuXHR9KSgpIiwiZXhwb3J0IGVudW0gR3BnU2lnTGFiZWwge1xuXHRHID0gJ3ZhbGlkJyxcblx0QiA9ICdiYWQnLFxuXHRVID0gJ3ZhbGlkLCB1bmtub3duIHZhbGlkaXR5Jyxcblx0WCA9ICd2YWxpZCwgZXhwaXJlZCcsXG5cdFkgPSAndmFsaWQsIG1hZGUgYnkgZXhwaXJlZCBrZXknLFxuXHRSID0gJ3ZhbGlkLCBtYWRlIGJ5IHJldm9rZWQga2V5Jyxcblx0RSA9ICdjYW5ub3QgY2hlY2sgKG1pc3Npbmcga2V5KScsXG5cdE4gPSAnbm8gc2lnbmF0dXJlJyxcbn1cblxuZXhwb3J0IGVudW0gUmVmVHlwZSB7XG5cdGlzc3VlID0gJ2lzc3VlJyxcblx0cHIgPSAnUFInLFxufSIsImltcG9ydCB0eXBlIHsgQ29tcGxldGVDb21taXRzUGFyc2VyLCBDb21taXQsIFJhd0NvbW1pdCwgUmF3UmVmZXJlbmNlLCBSZWZMYWJlbCwgUmVmZXJlbmNlLCBDb250cmlidXRvciwgQ29tbWl0TWVzc2FnZSwgQ29tbWl0UmFuZ2UgfSBmcm9tICdAL3R5cGVzJ1xuaW1wb3J0IHsgR3BnU2lnTGFiZWwgfSBmcm9tICdAL2VudW1zJ1xuaW1wb3J0IHsgZ2V0UmF3Q29tbWl0cyB9IGZyb20gJ0AvdXRpbHMnXG5cbi8vIGNvbnN0IGNvbW1pdFN0b3JlOiBSZWNvcmQ8c3RyaW5nLCBDb21taXQ+ID0ge31cblxuZXhwb3J0IGNvbnN0IHBhcnNlQ29tbWl0cyA9IGFzeW5jIChhcmcxOiBDb21taXRSYW5nZSB8IFJhd0NvbW1pdFtdLCBjb21taXRzUGFyc2VyOiBDb21wbGV0ZUNvbW1pdHNQYXJzZXIsIHByZXZSZWxlYXNlVGFnUGF0dGVybjogUmVnRXhwKTogUHJvbWlzZTxDb21taXRbXT4gPT4ge1xuXHRjb25zdCByYXdDb21taXRzID0gQXJyYXkuaXNBcnJheShhcmcxKSA/IGFyZzEgOiBnZXRSYXdDb21taXRzKGFyZzEsIHByZXZSZWxlYXNlVGFnUGF0dGVybilcblx0Y29uc3QgcGFyc2VyID0gY29tbWl0c1BhcnNlclxuXG5cdHJldHVybiAoYXdhaXQgUHJvbWlzZS5hbGwocmF3Q29tbWl0cy5tYXAoYXN5bmMgKGNvbW1pdCkgPT4ge1xuXHRcdGlmICh0eXBlb2YgY29tbWl0ID09PSAnc3RyaW5nJykgY29tbWl0ID0geyBtZXNzYWdlOiBjb21taXQgfVxuXG5cdFx0Y29uc3QgeyBoYXNoLCB0YWdSZWZzIH0gPSBjb21taXRcblxuXHRcdGNvbnN0IG1lc3NhZ2UgPSBjb21taXQubWVzc2FnZS50cmltKClcblx0XHRpZiAoIW1lc3NhZ2UpIHRocm93IG5ldyBFcnJvcihgTWVzc2FnZSBpcyBtaXNzaW5nIGZvciBjb21taXQ6ICR7SlNPTi5zdHJpbmdpZnkoY29tbWl0KX1gKVxuXG5cdFx0bGV0IHBhcnNlZE1lc3NhZ2Vcblx0XHR0cnkge1xuXHRcdFx0cGFyc2VkTWVzc2FnZSA9IHBhcnNlQ29tbWl0TWVzc2FnZShtZXNzYWdlLCBwYXJzZXIpXG5cdFx0fSBjYXRjaCAoZXJyb3IpIHtcblx0XHRcdGNvbnNvbGUud2FybihgRXJyb3IgcGFyc2luZyBjb21taXQgJyR7aGFzaCA/PyAnPG5vIGhhc2g+J30nOmAsIChlcnJvciBhcyBFcnJvcikubWVzc2FnZSlcblx0XHRcdHJldHVyblxuXHRcdH1cblx0XHRjb25zdCB7IHR5cGUsIHNjb3BlLCBzdWJqZWN0LCBib2R5LCBicmVha2luZ0NoYW5nZXMsIGZvb3RlciB9ID0gcGFyc2VkTWVzc2FnZVxuXHRcdGNvbnN0IHRhZ3MgPSB0YWdSZWZzID8gWy4uLnRhZ1JlZnMubWF0Y2hBbGwocGFyc2VyLnRhZ1BhdHRlcm4pXS5tYXAobSA9PiBtLmdyb3Vwcz8udGFnID8/ICcnKSA6IFtdXG5cblx0XHRjb25zdCBzaWduZXJzID0gZm9vdGVyXG5cdFx0XHQ/IFsuLi5mb290ZXIubWF0Y2hBbGwocGFyc2VyLnNpZ25lclBhdHRlcm4pXS5tYXAobSA9PiBtLmdyb3VwcyBhcyB1bmtub3duIGFzIENvbnRyaWJ1dG9yKVxuXHRcdFx0OiBbXVxuXG5cdFx0Y29uc3QgYXV0aG9yczogQ29udHJpYnV0b3JbXSA9IFtdXG5cdFx0Y29uc3QgYWRkQXV0aG9yID0gKGNvbnRyaWJ1dG9yOiBDb250cmlidXRvcik6IHZvaWQgPT4ge1xuXHRcdFx0aWYgKCFhdXRob3JzLnNvbWUoYSA9PiBhLmVtYWlsID09PSBjb250cmlidXRvci5lbWFpbCkpIGF1dGhvcnMucHVzaChjb250cmlidXRvcilcblx0XHR9XG5cblx0XHRjb25zdCBhdXRob3IgPSBjb21taXQuYXV0aG9yTmFtZSAmJiBjb21taXQuYXV0aG9yRW1haWxcblx0XHRcdD8gZ2V0Q29udHJpYnV0b3JEZXRhaWxzKHsgbmFtZTogY29tbWl0LmF1dGhvck5hbWUsIGVtYWlsOiBjb21taXQuYXV0aG9yRW1haWwgfSwgc2lnbmVycylcblx0XHRcdDogdW5kZWZpbmVkXG5cdFx0aWYgKGF1dGhvcikgYWRkQXV0aG9yKGF1dGhvcilcblxuXHRcdGNvbnN0IGNvbW1pdHRlciA9IGNvbW1pdC5jb21taXR0ZXJOYW1lICYmIGNvbW1pdC5jb21taXR0ZXJFbWFpbFxuXHRcdFx0PyBnZXRDb250cmlidXRvckRldGFpbHMoeyBuYW1lOiBjb21taXQuY29tbWl0dGVyTmFtZSwgZW1haWw6IGNvbW1pdC5jb21taXR0ZXJFbWFpbCB9LCBzaWduZXJzKVxuXHRcdFx0OiB1bmRlZmluZWRcblx0XHRpZiAoY29tbWl0dGVyKSBhZGRBdXRob3IoY29tbWl0dGVyKVxuXG5cdFx0Y29uc3QgY29BdXRob3JzID0gZm9vdGVyXG5cdFx0XHQ/IFsuLi5mb290ZXIubWF0Y2hBbGwocGFyc2VyLmNvQXV0aG9yUGF0dGVybildLm1hcChtID0+IG0uZ3JvdXBzIGFzIHVua25vd24gYXMgQ29udHJpYnV0b3IpXG5cdFx0XHRcdC5tYXAoY29BdXRob3IgPT4gZ2V0Q29udHJpYnV0b3JEZXRhaWxzKGNvQXV0aG9yLCBzaWduZXJzKSlcblx0XHRcdDogW11cblx0XHRjb0F1dGhvcnMuZm9yRWFjaChjb0F1dGhvciA9PiBhZGRBdXRob3IoY29BdXRob3IpKVxuXG5cdFx0Y29uc3QgcmVmcyA9IGF3YWl0IHBhcnNlUmVmcygoZm9vdGVyID8/ICcnKSwgcGFyc2VyKVxuXG5cdFx0Y29uc3QgZ3BnU2lnID0gY29tbWl0LmdwZ1NpZ0NvZGVcblx0XHRcdD8ge1xuXHRcdFx0XHRjb2RlOiBjb21taXQuZ3BnU2lnQ29kZSxcblx0XHRcdFx0bGFiZWw6IEdwZ1NpZ0xhYmVsW2NvbW1pdC5ncGdTaWdDb2RlXSxcblx0XHRcdFx0a2V5SWQ6IGNvbW1pdC5ncGdTaWdLZXlJZCxcblx0XHRcdH1cblx0XHRcdDogdW5kZWZpbmVkXG5cblx0XHRsZXQgZGF0ZSA9IGNvbW1pdFtwYXJzZXIuZGF0ZVNvdXJjZSA9PT0gJ2NvbW1pdHRlckRhdGUnID8gJ2NvbW1pdHRlclRzJyA6ICdhdXRob3JUcyddXG5cdFx0aWYgKHR5cGVvZiBkYXRlID09PSAnc3RyaW5nJykgZGF0ZSA9IGZvcm1hdERhdGUobmV3IERhdGUoK2RhdGUgKiAxMDAwKSwgcGFyc2VyLmRhdGVGb3JtYXQpXG5cblx0XHRjb25zdCBwYXJzZWRDb21taXQgPSB7IGhhc2gsIHR5cGUsIHNjb3BlLCBzdWJqZWN0LCBib2R5LCBicmVha2luZ0NoYW5nZXMsIGZvb3RlciwgY29tbWl0dGVyLCBncGdTaWcsIGRhdGUsXG5cdFx0XHR0YWdzOiB0YWdzLmxlbmd0aCA/IHRhZ3MgOiB1bmRlZmluZWQsXG5cdFx0XHRhdXRob3JzOiBhdXRob3JzLmxlbmd0aCA/IGF1dGhvcnMgOiB1bmRlZmluZWQsXG5cdFx0XHRyZWZzOiByZWZzLmxlbmd0aCA/IHJlZnMgOiB1bmRlZmluZWQsXG5cdFx0fVxuXHRcdC8vIGlmIChoYXNoICYmICEoaGFzaCBpbiBjb21taXRTdG9yZSkpIGNvbW1pdFN0b3JlW2hhc2hdID0gcGFyc2VkQ29tbWl0XG5cdFx0Ly8gY29uc29sZS5sb2coT2JqZWN0LmtleXMoY29tbWl0U3RvcmUpLmxlbmd0aCwgJ2NvbW1pdHMgaW4gc3RvcmUnKVxuXHRcdHJldHVybiBwYXJzZWRDb21taXRcblx0fSkpKS5maWx0ZXIoY29tbWl0ID0+IGNvbW1pdCAhPT0gdW5kZWZpbmVkKVxufVxuXG5jb25zdCBwYXJzZUNvbW1pdE1lc3NhZ2UgPSAobWVzc2FnZTogc3RyaW5nLCBwYXJzZXI6IENvbXBsZXRlQ29tbWl0c1BhcnNlcik6IENvbW1pdE1lc3NhZ2UgPT4ge1xuXHRjb25zdCBbaGVhZGVyLCAuLi5kZXRhaWxzXSA9IG1lc3NhZ2Uuc3BsaXQoJ1xcblxcbicpXG5cblx0Y29uc3QgaGVhZGVyTWF0Y2ggPSBwYXJzZXIuaGVhZGVyUGF0dGVybi5leGVjKGhlYWRlcilcblx0aWYgKCFoZWFkZXJNYXRjaD8uZ3JvdXBzKSB0aHJvdyBuZXcgRXJyb3IoYENvbW1pdCBoZWFkZXIgJyR7aGVhZGVyfScgZG9lc24ndCBtYXRjaCBleHBlY3RlZCBmb3JtYXRgKVxuXHRjb25zdCB7IHR5cGUsIHNjb3BlLCBiYW5nLCBzdWJqZWN0IH0gPSBoZWFkZXJNYXRjaC5ncm91cHNcblxuXHRsZXQgYnJlYWtpbmdDaGFuZ2VzXG5cdGNvbnN0IGJyZWFraW5nQ2hhbmdlc1BhcnQgPSBkZXRhaWxzLmZpbmQoZGV0YWlsID0+IHBhcnNlci5icmVha2luZ0NoYW5nZXNQYXR0ZXJuLnRlc3QoZGV0YWlsKSlcblx0aWYgKGJyZWFraW5nQ2hhbmdlc1BhcnQpIHtcblx0XHRicmVha2luZ0NoYW5nZXMgPSBwYXJzZUJyZWFraW5nQ2hhbmdlcyhicmVha2luZ0NoYW5nZXNQYXJ0LCBwYXJzZXIpXG5cdFx0ZGV0YWlscy5zcGxpY2UoZGV0YWlscy5pbmRleE9mKGJyZWFraW5nQ2hhbmdlc1BhcnQpLCAxKVxuXHR9IGVsc2UgaWYgKGJhbmcpIHtcblx0XHRicmVha2luZ0NoYW5nZXMgPSBzdWJqZWN0XG5cdH1cblxuXHRjb25zdCBmb290ZXJTdGFydCA9IGRldGFpbHMuZmluZEluZGV4KGRldGFpbCA9PlxuXHRcdGRldGFpbC5tYXRjaChwYXJzZXIucmVmQWN0aW9uUGF0dGVybilcblx0XHQ/PyBkZXRhaWwubWF0Y2gocGFyc2VyLmNvQXV0aG9yUGF0dGVybilcblx0XHQ/PyBkZXRhaWwubWF0Y2gocGFyc2VyLnNpZ25lclBhdHRlcm4pKVxuXHRjb25zdCBbYm9keSwgZm9vdGVyXSA9IGZvb3RlclN0YXJ0ID09PSAtMVxuXHRcdD8gW2RldGFpbHMuam9pbignXFxuXFxuJyksICcnXVxuXHRcdDogW2RldGFpbHMuc2xpY2UoMCwgZm9vdGVyU3RhcnQpLmpvaW4oJ1xcblxcbicpLCBkZXRhaWxzLnNsaWNlKGZvb3RlclN0YXJ0KS5qb2luKCdcXG5cXG4nKV1cblxuXHRyZXR1cm4ge1xuXHRcdHR5cGUsXG5cdFx0c2NvcGU6IHNjb3BlIHx8IHVuZGVmaW5lZCxcblx0XHRzdWJqZWN0LFxuXHRcdGJvZHk6IGJvZHkgfHwgdW5kZWZpbmVkLFxuXHRcdGJyZWFraW5nQ2hhbmdlcyxcblx0XHRmb290ZXI6IGZvb3RlciB8fCB1bmRlZmluZWQsXG5cdH1cbn1cblxuY29uc3QgcGFyc2VCcmVha2luZ0NoYW5nZXMgPSAodmFsdWU6IHN0cmluZywgcGFyc2VyOiBDb21wbGV0ZUNvbW1pdHNQYXJzZXIpOiBDb21taXRbJ2JyZWFraW5nQ2hhbmdlcyddID0+IHtcblx0Y29uc3QgYnJlYWtpbmdDaGFuZ2VzID0gcGFyc2VyLmJyZWFraW5nQ2hhbmdlc1BhdHRlcm4uZXhlYyh2YWx1ZSk/Lmdyb3Vwcz8uY29udGVudFxuXHRpZiAoIWJyZWFraW5nQ2hhbmdlcykgdGhyb3cgbmV3IEVycm9yKGBGYWlsZWQgdG8gZXh0cmFjdCBicmVha2luZyBjaGFuZ2VzIGNvbnRlbnQgZnJvbSAnJHt2YWx1ZX0nIHVzaW5nIHBhdHRlcm4gXCIke3BhcnNlci5icmVha2luZ0NoYW5nZXNQYXR0ZXJufVwiYClcblxuXHRjb25zdCBicmVha2luZ0NoYW5nZUxpc3QgPSBbLi4uYnJlYWtpbmdDaGFuZ2VzLm1hdGNoQWxsKHBhcnNlci5icmVha2luZ0NoYW5nZUxpc3RQYXR0ZXJuKV1cblxuXHRyZXR1cm4gYnJlYWtpbmdDaGFuZ2VMaXN0Lmxlbmd0aFxuXHRcdD8gYnJlYWtpbmdDaGFuZ2VMaXN0Lm1hcChtID0+IG1bMV0pXG5cdFx0OiBicmVha2luZ0NoYW5nZXNcbn1cblxuY29uc3QgZ2V0Q29udHJpYnV0b3JEZXRhaWxzID0gKGNvbnRyaWJ1dG9yOiBDb250cmlidXRvciwgc2lnbmVyczogQ29udHJpYnV0b3JbXSk6IENvbnRyaWJ1dG9yID0+IHtcblx0Y29uc3QgaGFzU2lnbmVkT2ZmID0gc2lnbmVycy5zb21lKHNpZ25lciA9PiBzaWduZXIuZW1haWwgPT09IGNvbnRyaWJ1dG9yLmVtYWlsICYmIHNpZ25lci5uYW1lID09PSBjb250cmlidXRvci5uYW1lKVxuXHRyZXR1cm4ge1xuXHRcdC4uLmNvbnRyaWJ1dG9yLFxuXHRcdGhhc1NpZ25lZE9mZixcblx0XHRnaExvZ2luOiBjb250cmlidXRvci5uYW1lLFxuXHRcdGdoVXJsOiBgaHR0cHM6Ly9naXRodWIuY29tLyR7Y29udHJpYnV0b3IubmFtZX1gLFxuXHR9XG59XG5cbmNvbnN0IHBhcnNlUmVmcyA9IGFzeW5jICh2YWx1ZTogc3RyaW5nLCBwYXJzZXI6IENvbXBsZXRlQ29tbWl0c1BhcnNlcik6IFByb21pc2U8UmVmZXJlbmNlW10+ID0+XG5cdGF3YWl0IFByb21pc2UuYWxsKFsuLi52YWx1ZS5tYXRjaEFsbChwYXJzZXIucmVmUGF0dGVybildLm1hcChtID0+IG0uZ3JvdXBzIGFzIHVua25vd24gYXMgUmF3UmVmZXJlbmNlKVxuXHRcdC5maWx0ZXIocmF3UmVmID0+IHBhcnNlci5yZWZBY3Rpb25QYXR0ZXJuLnRlc3QocmF3UmVmLmFjdGlvbikpXG5cdFx0LmZsYXRNYXAocmF3UmVmID0+XG5cdFx0XHRbLi4ucmF3UmVmLmxhYmVscy5tYXRjaEFsbChwYXJzZXIucmVmTGFiZWxQYXR0ZXJuKV0ubWFwKG0gPT4gbS5ncm91cHMgYXMgdW5rbm93biBhcyBSZWZMYWJlbClcblx0XHRcdFx0LmZpbHRlcihsYWJlbCA9PiAhIWxhYmVsLm51bWJlcilcblx0XHRcdFx0Lm1hcChsYWJlbCA9PiAoe1xuXHRcdFx0XHRcdGFjdGlvbjogcmF3UmVmLmFjdGlvbixcblx0XHRcdFx0XHRvd25lcjogbGFiZWwub3duZXIsXG5cdFx0XHRcdFx0cmVwbzogbGFiZWwucmVwbyxcblx0XHRcdFx0XHRudW1iZXI6IGxhYmVsLm51bWJlcixcblx0XHRcdFx0fSkpLFxuXHRcdCksXG5cdClcblxuY29uc3QgZm9ybWF0RGF0ZSA9IChkYXRlOiBEYXRlLCBmb3JtYXQ6IHN0cmluZyk6IHN0cmluZyA9PiB7XG5cdGNvbnN0IHBhZCA9IChudW06IG51bWJlcikgPT4gbnVtLnRvU3RyaW5nKCkucGFkU3RhcnQoMiwgJzAnKVxuXG5cdGNvbnN0IGRhdGVQYXJ0czogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHtcblx0XHRZWVlZOiBkYXRlLmdldFVUQ0Z1bGxZZWFyKCkudG9TdHJpbmcoKSxcblx0XHRNTTogcGFkKGRhdGUuZ2V0VVRDTW9udGgoKSArIDEpLFxuXHRcdEREOiBwYWQoZGF0ZS5nZXRVVENEYXRlKCkpLFxuXHRcdEhIOiBwYWQoZGF0ZS5nZXRVVENIb3VycygpKSxcblx0XHRtbTogcGFkKGRhdGUuZ2V0VVRDTWludXRlcygpKSxcblx0XHRzczogcGFkKGRhdGUuZ2V0VVRDU2Vjb25kcygpKSxcblx0fVxuXG5cdHJldHVybiBmb3JtYXQucmVwbGFjZSgvWVlZWXxNTXxERHxISHxtbXxzcy9nLCBrID0+IGRhdGVQYXJ0c1trXSlcbn0iLCJpbXBvcnQgeyBleGVjU3luYyB9IGZyb20gJ25vZGU6Y2hpbGRfcHJvY2VzcydcbmltcG9ydCB0eXBlIHsgQ29tbWl0UmFuZ2UsIFJhd0NvbW1pdCwgUmVwb0luZm8gfSBmcm9tICdAL3R5cGVzJ1xuXG5jb25zdCBjb21taXRMb2dGb3JtYXQgPSBgIyNDT01NSVQjIyVuI0hBU0gjICVoJW4jTVNHIyAlQiVuI1JFRlMjICVkJW4jQVVUSE9SLU5BTUUjICVhbiVuI0FVVEhPUi1FTUFJTCMgJWFlJW4jQVVUSE9SLURBVEUjICVhdCVuI0NPTU1JVFRFUi1OQU1FIyAlY24lbiNDT01NSVRURVItRU1BSUwjICVjZSVuI0NPTU1JVFRFUi1EQVRFIyAlY3QlbiNHUEdTSUctQ09ERSMgJUc/JW4jR1BHU0lHLUtFWUlEIyAlR0slbmBcbmNvbnN0IHJhd0NvbW1pdFBhdHRlcm4gPSAvIyNDT01NSVQjI1xcbiNIQVNIIyAoPzxoYXNoPi4rKT9cXG4jTVNHIyAoPzxtZXNzYWdlPltcXHNcXFNdKj8pXFxuI1JFRlMjXFxzKyg/PHRhZ1JlZnM+LispP1xcbiNBVVRIT1ItTkFNRSMgKD88YXV0aG9yTmFtZT4uKyk/XFxuI0FVVEhPUi1FTUFJTCMgKD88YXV0aG9yRW1haWw+LispP1xcbiNBVVRIT1ItREFURSMgKD88YXV0aG9yVHM+LispP1xcbiNDT01NSVRURVItTkFNRSMgKD88Y29tbWl0dGVyTmFtZT4uKyk/XFxuI0NPTU1JVFRFUi1FTUFJTCMgKD88Y29tbWl0dGVyRW1haWw+LispP1xcbiNDT01NSVRURVItREFURSMgKD88Y29tbWl0dGVyVHM+LispP1xcbiNHUEdTSUctQ09ERSMgKD88Z3BnU2lnQ29kZT4uKyk/XFxuI0dQR1NJRy1LRVlJRCMgKD88Z3BnU2lnS2V5SWQ+LispPy9nXG5cbmV4cG9ydCBjb25zdCBnZXRSZXBvSW5mbyA9IChyZW1vdGVVcmxQYXR0ZXJuOiBSZWdFeHApOiBSZXBvSW5mbyA9PiB7XG5cdGNvbnN0IHJlbW90ZVVybCA9IGV4ZWNTeW5jKCdnaXQgcmVtb3RlIGdldC11cmwgb3JpZ2luJywgeyBlbmNvZGluZzogJ3V0ZjgnIH0pLnRyaW0oKVxuXHRjb25zdCByZW1vdGVVcmxNYXRjaCA9IHJlbW90ZVVybFBhdHRlcm4uZXhlYyhyZW1vdGVVcmwpXG5cdGlmICghcmVtb3RlVXJsTWF0Y2g/Lmdyb3VwcykgdGhyb3cgbmV3IEVycm9yKGBDb3VsZG4ndCBwYXJzZSByZW1vdGUgVVJMOiBgICsgcmVtb3RlVXJsKVxuXG5cdGNvbnN0IHsgaG9zdCwgb3duZXIsIG5hbWUgfSA9IHJlbW90ZVVybE1hdGNoLmdyb3Vwc1xuXHRjb25zdCBob21lcGFnZSA9IGBodHRwczovLyR7aG9zdH0vJHtvd25lcn0vJHtuYW1lfWBcblxuXHRyZXR1cm4geyBob3N0LCBvd25lciwgbmFtZSwgaG9tZXBhZ2UgfVxufVxuXG5leHBvcnQgY29uc3QgZ2V0UmF3Q29tbWl0cyA9IChjb21taXRSYW5nZTogQ29tbWl0UmFuZ2UsIHByZXZSZWxlYXNlVGFnUGF0dGVybjogUmVnRXhwKTogUmF3Q29tbWl0W10gPT4ge1xuXHRjb25zdCBmaXJzdENvbW1pdEhhc2ggPSBnZXRGaXJzdENvbW1pdEhhc2goKVxuXHRjb25zdCB2ZXJzaW9uVGFncyA9IGdldFZlcnNpb25UYWdzKHByZXZSZWxlYXNlVGFnUGF0dGVybilcblxuXHRsZXQgZnJvbTogc3RyaW5nLCB0bzogc3RyaW5nXG5cdGlmICh0eXBlb2YgY29tbWl0UmFuZ2UgPT09ICdzdHJpbmcnKSB7XG5cdFx0ZnJvbSA9IHtcblx0XHRcdGFsbDogZmlyc3RDb21taXRIYXNoLFxuXHRcdFx0dW5yZWxlYXNlZDogdmVyc2lvblRhZ3NbMF0gPz8gZmlyc3RDb21taXRIYXNoLFxuXHRcdH1bY29tbWl0UmFuZ2VdXG5cdFx0aWYgKCFmcm9tKSB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgY29tbWl0IHJhbmdlOiAnJHtjb21taXRSYW5nZX0nYClcblx0XHR0byA9ICdIRUFEJ1xuXHR9IGVsc2UgaWYgKCdmcm9tJyBpbiBjb21taXRSYW5nZSB8fCAndG8nIGluIGNvbW1pdFJhbmdlKSB7XG5cdFx0Y29uc3QgZnJvbVZhbHVlID0gJ2Zyb20nIGluIGNvbW1pdFJhbmdlID8gY29tbWl0UmFuZ2UuZnJvbSA6ICdmaXJzdENvbW1pdCdcblx0XHRmcm9tID0gZnJvbVZhbHVlID09PSAnZmlyc3RDb21taXQnID8gZmlyc3RDb21taXRIYXNoIDogZnJvbVZhbHVlXG5cdFx0dG8gPSAndG8nIGluIGNvbW1pdFJhbmdlID8gY29tbWl0UmFuZ2UudG8gOiAnSEVBRCdcblx0fSBlbHNlIGlmICgndmVyc2lvblRhZycgaW4gY29tbWl0UmFuZ2UpIHtcblx0XHRjb25zdCB0YXJnZXRUYWdJbmRleCA9IHZlcnNpb25UYWdzLmluZGV4T2YoY29tbWl0UmFuZ2UudmVyc2lvblRhZylcblx0XHRpZiAodGFyZ2V0VGFnSW5kZXggPT09IC0xKSB0aHJvdyBuZXcgRXJyb3IoYFZlcnNpb24gdGFnICcke2NvbW1pdFJhbmdlLnZlcnNpb25UYWd9JyBub3QgZm91bmRgKVxuXHRcdGZyb20gPSB2ZXJzaW9uVGFnc1t0YXJnZXRUYWdJbmRleF1cblx0XHR0byA9IHZlcnNpb25UYWdzW3RhcmdldFRhZ0luZGV4ICsgMV0gPz8gJ0hFQUQnXG5cdH0gZWxzZSB7XG5cdFx0dGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIGNvbW1pdCByYW5nZSBwcm92aWRlZGApXG5cdH1cblxuXHRjb25zdCBnaXRMb2dDb21taXRzID0gZXhlY1N5bmMoYGdpdCBsb2cgJHtmcm9tfS4uJHt0b30gLS1wcmV0dHk9XCIke2NvbW1pdExvZ0Zvcm1hdH1cImAsIHsgZW5jb2Rpbmc6ICd1dGY4JyB9KVxuXHRyZXR1cm4gWy4uLmdpdExvZ0NvbW1pdHMubWF0Y2hBbGwocmF3Q29tbWl0UGF0dGVybildLm1hcChtID0+IG0uZ3JvdXBzIGFzIFJhd0NvbW1pdClcbn1cblxuY29uc3QgZ2V0Rmlyc3RDb21taXRIYXNoID0gKCk6IHN0cmluZyA9PiBleGVjU3luYygnZ2l0IHJldi1saXN0IC0tbWF4LXBhcmVudHM9MCBIRUFEJywgeyBlbmNvZGluZzogJ3V0ZjgnIH0pLnRyaW0oKVxuXG5leHBvcnQgY29uc3QgZ2V0VmVyc2lvblRhZ3MgPSAodGFnUGF0dGVybjogUmVnRXhwKTogc3RyaW5nW10gPT4ge1xuXHRjb25zdCByYXdUYWdzID0gZXhlY1N5bmMoJ2dpdCB0YWcgLS1zb3J0PS1jcmVhdG9yZGF0ZScsIHsgZW5jb2Rpbmc6ICd1dGY4JyB9KVxuXHRyZXR1cm4gcmF3VGFncy5zcGxpdCgnXFxuJykuZmlsdGVyKHRhZyA9PiB0YWdQYXR0ZXJuLnRlc3QodGFnKSlcbn0iLCJcInt7Iz5oZWFkZXJ9fVxcbiMjICZlbnNwOyBbYCDwn5OmIHt7dGFnfX0gIGBdKHt7cmVwby5ob21lcGFnZX19L3t7I2lmIHByZXZUYWd9fWNvbXBhcmUve3twcmV2VGFnfX0uLi57e3RhZ319e3tlbHNlfX1jb21taXRzL3t7dGFnfX17ey9pZn19KVxcblxcbnt7L2hlYWRlcn19XFxue3sjZWFjaCBjb21taXRHcm91cHN9fVxcbiMjIyB7e3tyZXBlYXQgJyZuYnNwOycgNX19fXt7dGl0bGV9fVxcbnt7I2VhY2ggY29tbWl0c319XFxuKiB7eyNpZiBzY29wZX19YHt7c2NvcGV9fWAge3svaWZ9fXt7e3N1YmplY3R9fX0ge3sjaWYgLi4vLi4vY29tbWl0SHlwZXJsaW5rfX1bYHt7aGFzaH19YF0oe3suLi8uLi9yZXBvLmhvbWVwYWdlfX0vY29tbWl0L3t7aGFzaH19KXt7ZWxzZX19e3toYXNofX17ey9pZn19XFxue3svZWFjaH19XFxuXFxue3svZWFjaH19XFxuIyMjIyMgJmVtc3A7JmVuc3A7Jm5ic3A7IPCflJcgW0Z1bGwgQ29tbWl0IEhpc3Rvcnk6IHt7I2lmIHByZXZUYWd9fWB7e3ByZXZUYWd9fWAg4oaSIGB7e3RhZ319YF0oe3tyZXBvLmhvbWVwYWdlfX0vY29tcGFyZS97e3ByZXZUYWd9fS4uLnt7dGFnfX0pe3tlbHNlfX1ge3t0YWd9fWBdKHt7cmVwby5ob21lcGFnZX19L2NvbW1pdHMve3t0YWd9fSl7ey9pZn19ICZlbnNwOy8mZW5zcDsgX3t7ZGF0ZX19X1xcblxcblxcblwiIiwiaW1wb3J0IHsgZ2V0VmVyc2lvblRhZ3MgfSBmcm9tICdAL3V0aWxzJ1xuaW1wb3J0IHR5cGUgeyBSZWxlYXNlQ29udGV4dCwgUmVsZWFzZVdpdGhHcm91cGVkQ29tbWl0cywgUmVzb2x2ZWRDb25maWcgfSBmcm9tICdAL3R5cGVzJ1xuaW1wb3J0IHsgZXhpc3RzU3luYywgcmVhZEZpbGVTeW5jLCB3cml0ZUZpbGVTeW5jIH0gZnJvbSAnbm9kZTpmcydcbmltcG9ydCBIYW5kbGViYXJzIGZyb20gJ2hhbmRsZWJhcnMnXG5pbXBvcnQgcmVsZWFzZVRlbXBsYXRlIGZyb20gJ0AvdGVtcGxhdGVzL3JlbGVhc2UuaGJzJ1xuXG5leHBvcnQgY29uc3QgY2hhbmdlbG9nID0gKGNvbmZpZzogUmVzb2x2ZWRDb25maWcpOiB2b2lkID0+IHtcblx0aWYgKCFjb25maWcuY2hhbmdlbG9nKSByZXR1cm5cblxuXHRjb25zdCBvcHRpb25zID0gY29uZmlnLmNoYW5nZWxvZ1xuXHRjb25zdCByZWxlYXNlcyA9IGNvbmZpZy5jb250ZXh0LnJlbGVhc2VzXG5cdGlmICghcmVsZWFzZXMpIHJldHVyblxuXG5cdGNvbnN0IHZlcnNpb25UYWdzID0gZ2V0VmVyc2lvblRhZ3MoY29uZmlnLnByZXZSZWxlYXNlVGFnUGF0dGVybilcblxuXHRIYW5kbGViYXJzLnJlZ2lzdGVyUGFydGlhbChvcHRpb25zLmNvbXBpbGVkUGFydGlhbHMpXG5cdEhhbmRsZWJhcnMucmVnaXN0ZXJIZWxwZXIob3B0aW9ucy5oZWxwZXJzKVxuXG5cdGxldCByZXN1bHQgPSBvcHRpb25zLmhlYWRlclxuXHRyZWxlYXNlcy5mb3JFYWNoKChyZWxlYXNlOiBSZWxlYXNlV2l0aEdyb3VwZWRDb21taXRzLCBpbmRleDogbnVtYmVyKSA9PiB7XG5cdFx0Y29uc3QgcHJldlJlbGVhc2UgPSByZWxlYXNlc1tpbmRleCArIDFdIGFzIFJlbGVhc2VXaXRoR3JvdXBlZENvbW1pdHMgfCB1bmRlZmluZWRcblx0XHRsZXQgcHJldlRhZzogc3RyaW5nIHwgdW5kZWZpbmVkLCBwcmV2VmVyc2lvbjogc3RyaW5nIHwgdW5kZWZpbmVkXG5cdFx0aWYgKHByZXZSZWxlYXNlKSB7XG5cdFx0XHRwcmV2VGFnID0gcHJldlJlbGVhc2UudGFnXG5cdFx0XHRwcmV2VmVyc2lvbiA9IGdldFZlcnNpb25Gcm9tVGFnKHByZXZUYWcsIGNvbmZpZy5wcmV2UmVsZWFzZVRhZ1BhdHRlcm4pXG5cdFx0fSBlbHNlIHtcblx0XHRcdGNvbnN0IHRhcmdldFRhZ0luZGV4ID0gdmVyc2lvblRhZ3MuaW5kZXhPZihyZWxlYXNlLnRhZylcblx0XHRcdGlmICh0YXJnZXRUYWdJbmRleCA9PT0gLTEpIHtcblx0XHRcdFx0cHJldlRhZyA9IGNvbmZpZy5jb250ZXh0LmN1cnJlbnRUYWdcblx0XHRcdFx0cHJldlZlcnNpb24gPSBnZXRWZXJzaW9uRnJvbVRhZyhwcmV2VGFnLCBjb25maWcucHJldlJlbGVhc2VUYWdQYXR0ZXJuKVxuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0cHJldlRhZyA9IHZlcnNpb25UYWdzW3RhcmdldFRhZ0luZGV4ICsgMV1cblx0XHRcdFx0cHJldlZlcnNpb24gPSBwcmV2VGFnICYmIGdldFZlcnNpb25Gcm9tVGFnKHByZXZUYWcsIGNvbmZpZy5wcmV2UmVsZWFzZVRhZ1BhdHRlcm4pXG5cdFx0XHR9XG5cdFx0fVxuXHRcdGNvbnN0IHJlbGVhc2VDb250ZXh0OiBSZWxlYXNlQ29udGV4dCA9IHtcblx0XHRcdC4uLnJlbGVhc2UsXG5cdFx0XHQuLi5jb25maWcuY29udGV4dCxcblx0XHRcdHByZXZUYWcsXG5cdFx0XHRwcmV2VmVyc2lvbixcblx0XHR9XG5cdFx0Y29uc3QgcmVuZGVyZWQgPSByZW5kZXJUZW1wbGF0ZShyZWxlYXNlVGVtcGxhdGUsIHJlbGVhc2VDb250ZXh0KVxuXHRcdHJlc3VsdCArPSByZW5kZXJlZFxuXHR9KVxuXG5cdGlmIChvcHRpb25zLnN0ZG91dCkge1xuXHRcdGNvbnNvbGUubG9nKGBHZW5lcmF0ZWQgY2hhbmdlbG9nOlxcbiR7cmVzdWx0fWApXG5cdH1cblx0aWYgKG9wdGlvbnMub3V0cHV0RmlsZSkge1xuXHRcdGNvbnNvbGUubG9nKGBXcml0aW5nIGNoYW5nZWxvZyB0byBmaWxlICcke29wdGlvbnMub3V0cHV0RmlsZX0nYClcblx0XHRpZiAoIWNvbmZpZy5kcnlSdW4pIHdyaXRlVG9DaGFuZ2Vsb2dGaWxlKG9wdGlvbnMub3V0cHV0RmlsZSwgcmVzdWx0LCBvcHRpb25zLnByZXZSZWxlYXNlSGVhZGVyUGF0dGVybilcblx0fVxufVxuXG5jb25zdCB3cml0ZVRvQ2hhbmdlbG9nRmlsZSA9IChvdXRwdXRGaWxlOiBzdHJpbmcsIGNvbnRlbnQ6IHN0cmluZywgcHJldlJlbGVhc2VIZWFkZXJQYXR0ZXJuOiBSZWdFeHApOiB2b2lkID0+IHtcblx0Y29uc3QgY2hhbmdlbG9nQ29udGVudCA9IGV4aXN0c1N5bmMob3V0cHV0RmlsZSkgPyByZWFkRmlsZVN5bmMob3V0cHV0RmlsZSwgeyBlbmNvZGluZzogJ3V0ZjgnIH0pIDogJydcblx0Y29uc3QgcHJldlJlbGVhc2VTdGFydCA9IGNoYW5nZWxvZ0NvbnRlbnQuc2VhcmNoKHByZXZSZWxlYXNlSGVhZGVyUGF0dGVybilcblx0Y29uc3QgaGVhZGxlc3NDaGFuZ2Vsb2cgPSBjaGFuZ2Vsb2dDb250ZW50LnNsaWNlKHByZXZSZWxlYXNlU3RhcnQpXG5cdGNvbnN0IG5ld0NoYW5nZWxvZyA9IGNvbnRlbnQgKyBoZWFkbGVzc0NoYW5nZWxvZ1xuXHR3cml0ZUZpbGVTeW5jKG91dHB1dEZpbGUsIG5ld0NoYW5nZWxvZywgeyBlbmNvZGluZzogJ3V0ZjgnIH0pXG59XG5cbmNvbnN0IHJlbmRlclRlbXBsYXRlID0gKHRlbXBsYXRlOiBzdHJpbmcsIHJlbGVhc2VDb250ZXh0OiBSZWxlYXNlQ29udGV4dCk6IHN0cmluZyA9PiB7XG5cdGNvbnN0IGNvbXBpbGUgPSBIYW5kbGViYXJzLmNvbXBpbGUodGVtcGxhdGUpXG5cdHJldHVybiBjb21waWxlKHJlbGVhc2VDb250ZXh0KVxufVxuXG5jb25zdCBnZXRWZXJzaW9uRnJvbVRhZyA9ICh0YWc6IHN0cmluZywgdGFnUGF0dGVybjogUmVnRXhwKTogc3RyaW5nIHwgdW5kZWZpbmVkID0+IHtcblx0cmV0dXJuIHRhZ1BhdHRlcm4uZXhlYyh0YWcpPy5ncm91cHM/LnZlcnNpb25cbn0iLCJpbXBvcnQgeyBleGVjU3luYyB9IGZyb20gJ25vZGU6Y2hpbGRfcHJvY2VzcydcbmltcG9ydCB0eXBlIHsgUmVzb2x2ZWRDb25maWcgfSBmcm9tICdAL3R5cGVzJ1xuXG5leHBvcnQgY29uc3QgY29tbWl0ID0gKGNvbmZpZzogUmVzb2x2ZWRDb25maWcpOiB2b2lkID0+IHtcblx0aWYgKCFjb25maWcuY29tbWl0KSByZXR1cm5cblx0Y29uc3Qgb3B0aW9ucyA9IGNvbmZpZy5jb21taXRcblx0Y29uc29sZS5sb2coJ0NvbW1pdHRpbmcgd2l0aCBvcHRpb25zOicsIG9wdGlvbnMpXG5cdGlmIChvcHRpb25zLnN0YWdlQWxsICYmICFjb25maWcuZHJ5UnVuKSBleGVjU3luYygnZ2l0IGFkZCAtQScsIHsgc3RkaW86ICdpbmhlcml0JyB9KVxuXHRpZiAoIWNvbmZpZy5kcnlSdW4pIGV4ZWNTeW5jKGBnaXQgY29tbWl0IC1tIFwiJHtvcHRpb25zLm1lc3NhZ2V9XCIgJHtvcHRpb25zLnNpZ25PZmYgPyAnLXMnIDogJyd9ICR7b3B0aW9ucy5ncGdTaWduID8gJy1TJyA6ICcnfSAke29wdGlvbnMuZXh0cmFBcmdzfWAsIHsgc3RkaW86ICdpbmhlcml0JyB9KVxufSIsImltcG9ydCB7IGV4ZWNTeW5jIH0gZnJvbSAnbm9kZTpjaGlsZF9wcm9jZXNzJ1xuaW1wb3J0IHR5cGUgeyBSZXNvbHZlZENvbmZpZyB9IGZyb20gJ0AvdHlwZXMnXG5cbmV4cG9ydCBjb25zdCB0YWcgPSAoY29uZmlnOiBSZXNvbHZlZENvbmZpZyk6IHZvaWQgPT4ge1xuXHRpZiAoIWNvbmZpZy50YWcpIHJldHVyblxuXHRjb25zdCBvcHRpb25zID0gY29uZmlnLnRhZ1xuXHRjb25zb2xlLmxvZygnVGFnZ2luZyB3aXRoIG9wdGlvbnM6Jywgb3B0aW9ucylcblx0aWYgKCFjb25maWcuZHJ5UnVuKSBleGVjU3luYyhgZ2l0IHRhZyAtYSAke29wdGlvbnMubmFtZX0gLW0gXCIke29wdGlvbnMubWVzc2FnZX1cIiAke29wdGlvbnMuZ3BnU2lnbiA/ICctcycgOiAnJ30gJHtvcHRpb25zLmZvcmNlID8gJy1mJyA6ICcnfSAke29wdGlvbnMuZXh0cmFBcmdzfWAsIHsgc3RkaW86ICdpbmhlcml0JyB9KVxufSIsImltcG9ydCB7IGJ1bXAsIGNvbW1pdCwgdGFnLCBjaGFuZ2Vsb2cgfSBmcm9tICdAL2xpZmVjeWNsZXMnXG5pbXBvcnQgeyByZXNvbHZlQ29uZmlnIH0gZnJvbSAnQC91dGlscydcbmltcG9ydCB0eXBlIHsgVXNlckNvbmZpZyB9IGZyb20gJ0AvdHlwZXMnXG5cbmV4cG9ydCBkZWZhdWx0IGFzeW5jIGZ1bmN0aW9uIHJlbGlvbih1c2VyQ29uZmlnOiBVc2VyQ29uZmlnKSB7XG5cdGNvbnN0IGNvbmZpZyA9IGF3YWl0IHJlc29sdmVDb25maWcodXNlckNvbmZpZylcblx0YnVtcChjb25maWcpXG5cdGNoYW5nZWxvZyhjb25maWcpXG5cdGNvbW1pdChjb25maWcpXG5cdHRhZyhjb25maWcpXG59XG5cbmV4cG9ydCBjb25zdCBkZWZpbmVDb25maWcgPSAoY29uZmlnOiBVc2VyQ29uZmlnKTogVXNlckNvbmZpZyA9PiBjb25maWciXSwibWFwcGluZ3MiOiI7Ozs7OztBQUdBLE1BQWEsUUFBUSxXQUFpQztBQUNyRCxLQUFJLENBQUMsT0FBTyxLQUFNO0NBQ2xCLE1BQU0sWUFBWSxPQUFPLE1BQU0sYUFBYSxPQUFPLFFBQVE7QUFDM0QsV0FBVSxTQUFTLGtCQUFrQjtFQUNwQyxNQUFNLGNBQWMsYUFBYSxjQUFjLFVBQVU7RUFDekQsTUFBTSxpQkFBaUIsWUFBWSxRQUFRLGNBQWMsZ0JBQWdCLEtBQUssV0FBVztBQUN6RixNQUFJLENBQUMsT0FBTyxPQUFRLGVBQWMsY0FBYyxVQUFVLGdCQUFnQjtBQUMxRSxVQUFRLElBQUksdUJBQXVCLGNBQWMsU0FBUyxRQUFRLFdBQVc7Ozs7OztBQ1IvRSxNQUFhQSxnQkFBOEI7Q0FDMUMsTUFBTTtDQUNOLFdBQVc7Q0FDWCxRQUFRO0NBQ1IsS0FBSztDQUNMLG1CQUFtQjtDQUNuQixjQUFjO0NBQ2QsdUJBQXVCO0NBQ3ZCLDBCQUEwQjtDQUMxQixRQUFRO0NBQ1IsU0FBUztFQUNSLGlCQUFpQjtFQUNqQixjQUFjOztDQUVmLGVBQWU7RUFDZCxlQUFlO0VBQ2Ysd0JBQXdCO0VBQ3hCLDJCQUEyQjtFQUMzQixZQUFZO0VBQ1osaUJBQWlCO0VBQ2pCLGVBQWU7RUFDZixnQkFBZ0I7RUFDaEIsa0JBQWtCO0VBQ2xCLFlBQVk7RUFDWixpQkFBaUI7RUFDakIsa0JBQWtCO0VBQ2xCLFlBQVk7RUFDWixZQUFZOzs7QUFJZCxNQUFhQywyQkFBcUQ7Q0FDakUsVUFBVTtFQUFFLE9BQU87RUFBdUIsWUFBWTs7Q0FDdEQsTUFBTTtFQUFFLE9BQU87RUFBYyxZQUFZOztDQUN6QyxLQUFLO0VBQUUsT0FBTztFQUFZLFlBQVk7O0NBQ3RDLE1BQU07RUFBRSxPQUFPO0VBQWlCLFlBQVk7O0NBQzVDLFVBQVU7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