relion 0.1.1 → 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.
- package/dist/cli.js +64 -0
- package/dist/index.d.ts +231 -0
- package/dist/index.js +652 -0
- package/package.json +65 -73
- package/CHANGELOG.md +0 -47
- package/bin/cli.js +0 -9
- package/src/commands.js +0 -190
- package/src/defaults.js +0 -68
- package/src/index.js +0 -152
- package/src/lib/checkpoint.js +0 -23
- package/src/lib/configuration.js +0 -35
- package/src/lib/detect-package-manager.js +0 -49
- package/src/lib/format-commit-message.js +0 -4
- package/src/lib/latest-semver-tag.js +0 -34
- package/src/lib/lifecycles/bump.js +0 -234
- package/src/lib/lifecycles/changelog.js +0 -105
- package/src/lib/lifecycles/commit.js +0 -67
- package/src/lib/lifecycles/tag.js +0 -59
- package/src/lib/print-error.js +0 -15
- package/src/lib/run-exec.js +0 -19
- package/src/lib/run-execFile.js +0 -19
- package/src/lib/run-lifecycle-script.js +0 -18
- package/src/lib/stringify-package.js +0 -34
- package/src/lib/updaters/index.js +0 -127
- package/src/lib/updaters/types/csproj.js +0 -13
- package/src/lib/updaters/types/gradle.js +0 -16
- package/src/lib/updaters/types/json.js +0 -25
- package/src/lib/updaters/types/maven.js +0 -43
- package/src/lib/updaters/types/openapi.js +0 -15
- package/src/lib/updaters/types/plain-text.js +0 -7
- package/src/lib/updaters/types/python.js +0 -30
- package/src/lib/updaters/types/yaml.js +0 -15
- package/src/lib/write-file.js +0 -6
- package/src/preset/constants.js +0 -16
- package/src/preset/index.js +0 -19
- package/src/preset/parser.js +0 -11
- package/src/preset/templates/commit.hbs +0 -19
- package/src/preset/templates/footer.hbs +0 -10
- package/src/preset/templates/header.hbs +0 -10
- package/src/preset/templates/index.js +0 -13
- package/src/preset/templates/main.hbs +0 -21
- package/src/preset/whatBump.js +0 -32
- 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##   [` 📦 {{tag}} `]({{repo.homepage}}/{{#if prevTag}}compare/{{prevTag}}...{{tag}}{{else}}commits/{{tag}}{{/if}})\n\n{{/header}}\n{{#each commitGroups}}\n### {{{repeat ' ' 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#####    🔗 [Full Commit History: {{#if prevTag}}`{{prevTag}}` → `{{tag}}`]({{repo.homepage}}/compare/{{prevTag}}...{{tag}}){{else}}`{{tag}}`]({{repo.homepage}}/commits/{{tag}}){{/if}}  /  _{{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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
|