@workflow/next 5.0.0-beta.4 → 5.0.0-beta.41

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 (40) hide show
  1. package/dist/builder-eager.d.ts +1 -1
  2. package/dist/builder-eager.d.ts.map +1 -1
  3. package/dist/builder-eager.js +377 -220
  4. package/dist/builder.d.ts +1 -4
  5. package/dist/builder.d.ts.map +1 -1
  6. package/dist/builder.js +2 -28
  7. package/dist/index.d.ts +8 -1
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +333 -55
  10. package/dist/loader.d.ts +5 -0
  11. package/dist/loader.d.ts.map +1 -1
  12. package/dist/loader.js +15 -341
  13. package/dist/runtime.d.ts +1 -1
  14. package/dist/runtime.d.ts.map +1 -1
  15. package/dist/runtime.js +2 -2
  16. package/dist/swc-plugin-cache.d.ts +7 -0
  17. package/dist/swc-plugin-cache.d.ts.map +1 -0
  18. package/dist/swc-plugin-cache.js +23 -0
  19. package/dist/watch-ignore.d.ts +51 -0
  20. package/dist/watch-ignore.d.ts.map +1 -0
  21. package/dist/watch-ignore.js +264 -0
  22. package/dist/watch-rebuild.d.ts +63 -0
  23. package/dist/watch-rebuild.d.ts.map +1 -0
  24. package/dist/watch-rebuild.js +399 -0
  25. package/docs/api-reference/with-workflow.mdx +56 -2
  26. package/docs/next.mdx +12 -6
  27. package/package.json +10 -7
  28. package/dist/builder-deferred.d.ts +0 -2
  29. package/dist/builder-deferred.d.ts.map +0 -1
  30. package/dist/builder-deferred.js +0 -1401
  31. package/dist/builder-deferred.js.map +0 -1
  32. package/dist/builder-eager.js.map +0 -1
  33. package/dist/builder.js.map +0 -1
  34. package/dist/index.js.map +0 -1
  35. package/dist/loader.js.map +0 -1
  36. package/dist/runtime.js.map +0 -1
  37. package/dist/socket-server.d.ts +0 -48
  38. package/dist/socket-server.d.ts.map +0 -1
  39. package/dist/socket-server.js +0 -154
  40. package/dist/socket-server.js.map +0 -1
@@ -7,25 +7,33 @@ exports.getNextBuilderEager = getNextBuilderEager;
7
7
  const node_fs_1 = require("node:fs");
8
8
  const promises_1 = require("node:fs/promises");
9
9
  const node_path_1 = require("node:path");
10
- const watchpack_1 = __importDefault(require("watchpack"));
10
+ const chokidar_1 = __importDefault(require("chokidar"));
11
+ const watch_ignore_js_1 = require("./watch-ignore.js");
12
+ const watch_rebuild_js_1 = require("./watch-rebuild.js");
11
13
  let CachedNextBuilderEager;
14
+ const importEsm = new Function('specifier', 'return import(specifier)');
12
15
  // Create the eager Next builder dynamically by extending the ESM BaseBuilder.
13
16
  // Exported as getNextBuilderEager() to allow CommonJS modules to import from
14
17
  // the ESM @workflow/builders package via dynamic import at runtime.
15
- async function getNextBuilderEager() {
18
+ async function getNextBuilderEager(buildersModule) {
16
19
  if (CachedNextBuilderEager) {
17
20
  return CachedNextBuilderEager;
18
21
  }
19
- const { BaseBuilder: BaseBuilderClass, STEP_QUEUE_TRIGGER, WORKFLOW_QUEUE_TRIGGER,
20
- // biome-ignore lint/security/noGlobalEval: Need to use eval here to avoid TypeScript from transpiling the import statement into `require()`
21
- } = (await eval('import("@workflow/builders")'));
22
+ const { BaseBuilder: BaseBuilderClass, getWorkflowQueueTrigger, detectWorkflowPatterns, parentHasChild, } = buildersModule ??
23
+ (await importEsm('@workflow/builders'));
22
24
  class NextBuilder extends BaseBuilderClass {
23
25
  async build() {
24
26
  const outputDir = await this.findAppDirectory();
25
27
  const workflowGeneratedDir = (0, node_path_1.join)(outputDir, '.well-known/workflow/v1');
26
28
  // Ensure output directories exist
27
29
  await (0, promises_1.mkdir)(workflowGeneratedDir, { recursive: true });
28
- // ignore the generated assets
30
+ if (!this.config.watch) {
31
+ // Production build caches may still contain the retired step route.
32
+ await (0, promises_1.rm)((0, node_path_1.join)(workflowGeneratedDir, 'step'), {
33
+ recursive: true,
34
+ force: true,
35
+ });
36
+ }
29
37
  await (0, promises_1.writeFile)((0, node_path_1.join)(workflowGeneratedDir, '.gitignore'), '*');
30
38
  const inputFiles = await this.getInputFiles();
31
39
  const tsconfigPath = await this.findTsConfigPath();
@@ -34,53 +42,55 @@ async function getNextBuilderEager() {
34
42
  workflowGeneratedDir,
35
43
  tsconfigPath,
36
44
  };
37
- const { manifest: stepsManifest, context: stepsBuildContext } = await this.buildStepsFunction(options);
38
- const workflowsBundle = await this.buildWorkflowsFunction(options);
45
+ // V2: Build combined route (replaces separate step + flow routes)
46
+ const combinedResult = await this.buildCombinedFunction(options);
39
47
  await this.buildWebhookRoute({ workflowGeneratedDir });
40
- // Merge manifests from both bundles
41
- const manifest = {
42
- steps: { ...stepsManifest.steps, ...workflowsBundle?.manifest?.steps },
43
- workflows: {
44
- ...stepsManifest.workflows,
45
- ...workflowsBundle?.manifest?.workflows,
46
- },
47
- classes: {
48
- ...stepsManifest.classes,
49
- ...workflowsBundle?.manifest?.classes,
50
- },
48
+ const writeManifest = async (sourceManifest) => {
49
+ const manifest = {
50
+ steps: { ...sourceManifest?.steps },
51
+ workflows: { ...sourceManifest?.workflows },
52
+ classes: { ...sourceManifest?.classes },
53
+ };
54
+ // Write manifest
55
+ const workflowBundlePath = (0, node_path_1.join)(workflowGeneratedDir, 'flow/route.js');
56
+ const manifestJson = await this.createManifest({
57
+ workflowBundlePath,
58
+ manifestDir: workflowGeneratedDir,
59
+ manifest,
60
+ });
61
+ // Expose manifest as a static file when WORKFLOW_PUBLIC_MANIFEST=1.
62
+ if (this.shouldExposePublicManifest && manifestJson) {
63
+ const publicManifestDir = (0, node_path_1.join)(this.config.workingDir, 'public/.well-known/workflow/v1');
64
+ await (0, promises_1.mkdir)(publicManifestDir, { recursive: true });
65
+ if (process.env.VERCEL_DEPLOYMENT_ID === undefined) {
66
+ await (0, promises_1.writeFile)((0, node_path_1.join)(publicManifestDir, '.gitignore'), '*');
67
+ }
68
+ await (0, promises_1.copyFile)((0, node_path_1.join)(workflowGeneratedDir, 'manifest.json'), (0, node_path_1.join)(publicManifestDir, 'manifest.json'));
69
+ }
51
70
  };
52
- // Write unified manifest to workflow generated directory
53
- const workflowBundlePath = (0, node_path_1.join)(workflowGeneratedDir, 'flow/route.js');
54
- const manifestJson = await this.createManifest({
55
- workflowBundlePath,
56
- manifestDir: workflowGeneratedDir,
57
- manifest,
58
- });
59
- // Expose manifest as a static file when WORKFLOW_PUBLIC_MANIFEST=1.
60
- // Next.js serves files from public/ at the root URL.
61
- if (this.shouldExposePublicManifest && manifestJson) {
62
- const publicManifestDir = (0, node_path_1.join)(this.config.workingDir, 'public/.well-known/workflow/v1');
63
- await (0, promises_1.mkdir)(publicManifestDir, { recursive: true });
64
- await (0, promises_1.copyFile)((0, node_path_1.join)(workflowGeneratedDir, 'manifest.json'), (0, node_path_1.join)(publicManifestDir, 'manifest.json'));
65
- }
71
+ await writeManifest(combinedResult?.manifest);
66
72
  await this.writeFunctionsConfig(outputDir);
67
73
  if (this.config.watch) {
68
- if (!stepsBuildContext) {
69
- throw new Error('Invariant: expected steps build context in watch mode');
70
- }
71
- if (!workflowsBundle?.interimBundleCtx ||
72
- !workflowsBundle?.bundleFinal) {
73
- throw new Error('Invariant: expected workflows bundle in watch mode');
74
+ // TODO: implement watch mode for combined bundle
75
+ // For now, fall back to full rebuild on file changes
76
+ if (!combinedResult?.interimBundleCtx || !combinedResult.bundleFinal) {
77
+ throw new Error('Invariant: expected workflow build context in watch mode');
74
78
  }
75
- let stepsCtx = stepsBuildContext;
76
- // These are safe to assert as non-null because we checked above
79
+ // Step registrations may be emitted as source imports without an
80
+ // esbuild context when externalizeNonSteps is enabled.
81
+ let stepsCtx = combinedResult.stepsContext;
77
82
  let workflowsCtx = {
78
- interimBundleCtx: workflowsBundle.interimBundleCtx,
79
- bundleFinal: workflowsBundle.bundleFinal,
83
+ interimBundleCtx: combinedResult.interimBundleCtx,
84
+ bundleFinal: combinedResult.bundleFinal,
80
85
  };
81
- const normalizePath = (pathname) => pathname.replace(/\\/g, '/');
82
- const knownFiles = new Set();
83
- let previousTimeInfo = new Map();
86
+ let discoveredEntries = combinedResult.discoveredEntries;
87
+ let stepsManifest = combinedResult.stepsManifest;
88
+ let workflowsManifest = combinedResult.workflowsManifest;
89
+ const stepsOutfile = (0, node_path_1.join)(workflowGeneratedDir, 'flow', '__step_registrations.js');
90
+ const normalizePath = (pathname) => ((0, node_path_1.isAbsolute)(pathname)
91
+ ? pathname
92
+ : (0, node_path_1.resolve)(this.config.workingDir, pathname)).replace(/\\/g, '/');
93
+ const sourceSnapshots = new Map();
84
94
  const watchableExtensions = new Set([
85
95
  '.js',
86
96
  '.jsx',
@@ -91,55 +101,26 @@ async function getNextBuilderEager() {
91
101
  '.cjs',
92
102
  '.mjs',
93
103
  ]);
94
- const ignoredPathFragments = [
95
- '/.git/',
96
- '/node_modules/',
97
- '/.next/',
98
- '/.turbo/',
99
- '/.vercel/',
100
- '/dist/',
101
- '/build/',
102
- '/out/',
103
- '/.cache/',
104
- '/.yarn/',
105
- '/.pnpm-store/',
106
- '/.parcel-cache/',
107
- '/.well-known/workflow/',
108
- ];
109
104
  const normalizedGeneratedDir = workflowGeneratedDir.replace(/\\/g, '/');
110
- ignoredPathFragments.push(normalizedGeneratedDir);
111
- // There is a node.js bug on MacOS which causes closing file watchers to be really slow.
112
- // This limits the number of watchers to mitigate the issue.
113
- // https://github.com/nodejs/node/issues/29949
114
- process.env.WATCHPACK_WATCHER_LIMIT =
115
- process.platform === 'darwin' ? '20' : undefined;
116
- const watcher = new watchpack_1.default({
117
- // Watchpack default is 200ms which adds 200ms of dead time on bootup.
118
- aggregateTimeout: 5,
119
- ignored: (pathname) => {
120
- const normalizedPath = pathname.replace(/\\/g, '/');
121
- const extension = (0, node_path_1.extname)(normalizedPath);
122
- if (extension && !watchableExtensions.has(extension)) {
123
- return true;
124
- }
125
- if (normalizedPath.startsWith(normalizedGeneratedDir)) {
126
- return true;
127
- }
128
- for (const fragment of ignoredPathFragments) {
129
- if (normalizedPath.includes(fragment)) {
130
- return true;
131
- }
132
- }
133
- return false;
134
- },
105
+ const normalizedDistDir = normalizePath(this.config.distDir);
106
+ // Prune the dev watch set to keep chokidar from registering an
107
+ // fs.watch per directory across the whole project tree (chokidar 4
108
+ // dropped fsevents, so on macOS that exhausts the fd limit -> EMFILE
109
+ // on large monorepos). This honors `.gitignore` and the
110
+ // WORKFLOW_DEV_WATCH_IGNORED_PATHS env var in addition to the
111
+ // built-in fragments. The generated workflow dir is passed as an
112
+ // extra fragment so it is pruned regardless of `.gitignore`.
113
+ const isIgnoredWatchPath = (0, watch_ignore_js_1.createWatchIgnorePredicate)({
114
+ workingDir: this.config.workingDir,
115
+ projectRoot: this.transformProjectRoot,
116
+ extraFragments: [normalizedGeneratedDir],
135
117
  });
136
- const readTimeInfoEntries = () => {
137
- const rawEntries = watcher.getTimeInfoEntries();
138
- const normalizedEntries = new Map();
139
- for (const [path, info] of rawEntries) {
140
- normalizedEntries.set(normalizePath(path), info);
118
+ const hasIgnoredPathFragment = (normalizedPath) => {
119
+ if (normalizedPath === normalizedDistDir ||
120
+ normalizedPath.startsWith(`${normalizedDistDir}/`)) {
121
+ return true;
141
122
  }
142
- return normalizedEntries;
123
+ return isIgnoredWatchPath(normalizedPath);
143
124
  };
144
125
  let rebuildQueue = Promise.resolve();
145
126
  const enqueue = (task) => {
@@ -148,143 +129,333 @@ async function getNextBuilderEager() {
148
129
  });
149
130
  return rebuildQueue;
150
131
  };
132
+ const readSourceSnapshot = (file) => (0, watch_rebuild_js_1.createSourceSnapshot)({ file, detectWorkflowPatterns });
133
+ const refreshSourceSnapshots = () => (0, watch_rebuild_js_1.replaceSourceSnapshots)({
134
+ discoveredEntries,
135
+ inputFiles: options.inputFiles,
136
+ normalizePath,
137
+ readSnapshot: readSourceSnapshot,
138
+ sourceSnapshots,
139
+ });
140
+ const mergeCombinedManifest = (nextStepsManifest) => ({
141
+ ...nextStepsManifest,
142
+ workflows: {
143
+ ...nextStepsManifest.workflows,
144
+ ...workflowsManifest.workflows,
145
+ },
146
+ classes: {
147
+ ...nextStepsManifest.classes,
148
+ ...workflowsManifest.classes,
149
+ },
150
+ });
151
+ const hotRebuild = async (refreshStepRegistrations) => {
152
+ if (refreshStepRegistrations) {
153
+ if (stepsCtx) {
154
+ await stepsCtx.rebuild();
155
+ }
156
+ else {
157
+ stepsManifest = await this.createStepSourceRegistrationFile({
158
+ inputFiles: options.inputFiles,
159
+ outfile: stepsOutfile,
160
+ tsconfigPath,
161
+ discoveredEntries,
162
+ });
163
+ }
164
+ }
165
+ const workflowResult = await workflowsCtx.interimBundleCtx.rebuild();
166
+ const workflowOutput = workflowResult.outputFiles?.[0]?.text;
167
+ if (!workflowOutput) {
168
+ throw new Error('Invariant: expected workflow output from hot rebuild');
169
+ }
170
+ await workflowsCtx.bundleFinal(workflowOutput);
171
+ await writeManifest(mergeCombinedManifest(stepsManifest));
172
+ };
151
173
  const fullRebuild = async () => {
174
+ this.clearDiscoveredEntriesCache();
152
175
  const newInputFiles = await this.getInputFiles();
153
176
  options.inputFiles = newInputFiles;
154
- await stepsCtx.dispose();
155
- const { context: newStepsCtx } = await this.buildStepsFunction(options);
156
- if (!newStepsCtx) {
157
- throw new Error('Invariant: expected steps build context after rebuild');
158
- }
159
- stepsCtx = newStepsCtx;
177
+ await stepsCtx?.dispose();
160
178
  await workflowsCtx.interimBundleCtx.dispose();
161
- const newWorkflowsCtx = await this.buildWorkflowsFunction(options);
162
- if (!newWorkflowsCtx?.interimBundleCtx ||
163
- !newWorkflowsCtx?.bundleFinal) {
179
+ const newCombined = await this.buildCombinedFunction(options);
180
+ stepsCtx = newCombined.stepsContext;
181
+ discoveredEntries = newCombined.discoveredEntries;
182
+ stepsManifest = newCombined.stepsManifest;
183
+ workflowsManifest = newCombined.workflowsManifest;
184
+ if (!newCombined?.interimBundleCtx || !newCombined?.bundleFinal) {
164
185
  throw new Error('Invariant: expected workflows bundle context after rebuild');
165
186
  }
166
187
  workflowsCtx = {
167
- interimBundleCtx: newWorkflowsCtx.interimBundleCtx,
168
- bundleFinal: newWorkflowsCtx.bundleFinal,
188
+ interimBundleCtx: newCombined.interimBundleCtx,
189
+ bundleFinal: newCombined.bundleFinal,
169
190
  };
191
+ await writeManifest(newCombined.manifest);
192
+ await refreshSourceSnapshots();
170
193
  };
171
- const logBuildMessages = (result, label) => {
172
- const logByType = (messages, method) => {
173
- if (!messages || messages.length === 0) {
194
+ const isWatchableFile = (path) => watchableExtensions.has((0, node_path_1.extname)(path));
195
+ const readKnownFiles = async () => {
196
+ const files = new Set();
197
+ const aliases = new Map();
198
+ const relevantFiles = (0, watch_rebuild_js_1.getRelevantFiles)({
199
+ discoveredEntries,
200
+ inputFiles: options.inputFiles,
201
+ normalizePath,
202
+ });
203
+ const addKnownFile = async (filePath) => {
204
+ let realFilePath = filePath;
205
+ try {
206
+ realFilePath = normalizePath(await (0, promises_1.realpath)(filePath));
207
+ }
208
+ catch { }
209
+ const canonicalPath = relevantFiles.has(realFilePath)
210
+ ? realFilePath
211
+ : filePath;
212
+ files.add(canonicalPath);
213
+ aliases.set(filePath, canonicalPath);
214
+ aliases.set(realFilePath, canonicalPath);
215
+ return canonicalPath;
216
+ };
217
+ const visit = async (directory) => {
218
+ let dirents;
219
+ try {
220
+ dirents = await (0, promises_1.readdir)(directory, { withFileTypes: true });
221
+ }
222
+ catch {
174
223
  return;
175
224
  }
176
- const descriptor = method === 'error' ? 'errors' : 'warnings';
177
- console[method](`${descriptor} while rebuilding ${label}`);
178
- for (const message of messages) {
179
- console[method](message);
225
+ await Promise.all(dirents.map(async (dirent) => {
226
+ const filePath = normalizePath((0, node_path_1.join)(directory, dirent.name));
227
+ if (hasIgnoredPathFragment(filePath)) {
228
+ return;
229
+ }
230
+ if (dirent.isDirectory()) {
231
+ await visit(filePath);
232
+ return;
233
+ }
234
+ let stats;
235
+ try {
236
+ stats = await (0, promises_1.stat)(filePath);
237
+ }
238
+ catch {
239
+ return;
240
+ }
241
+ if (stats.isDirectory()) {
242
+ await visit(filePath);
243
+ return;
244
+ }
245
+ if (!stats.isFile() || !isWatchableFile(filePath)) {
246
+ return;
247
+ }
248
+ await addKnownFile(filePath);
249
+ }));
250
+ };
251
+ await visit(this.config.workingDir);
252
+ return { files, aliases, addKnownFile };
253
+ };
254
+ const mergeFileChanges = (left, right) => ({
255
+ addedFiles: unique([...left.addedFiles, ...right.addedFiles]),
256
+ modifiedFiles: unique([
257
+ ...left.modifiedFiles,
258
+ ...right.modifiedFiles,
259
+ ]),
260
+ removedFiles: unique([...left.removedFiles, ...right.removedFiles]),
261
+ });
262
+ const unique = (paths) => [...new Set(paths)];
263
+ const classifyFileChanges = ({ changedFiles, knownFiles, removedFiles, }) => {
264
+ const addedFiles = [];
265
+ const modifiedFiles = [];
266
+ for (const file of unique(changedFiles)) {
267
+ if (knownFiles.has(file)) {
268
+ modifiedFiles.push(file);
269
+ }
270
+ else {
271
+ addedFiles.push(file);
272
+ knownFiles.add(file);
180
273
  }
274
+ }
275
+ for (const file of removedFiles) {
276
+ knownFiles.delete(file);
277
+ }
278
+ return {
279
+ addedFiles,
280
+ modifiedFiles,
281
+ removedFiles: unique(removedFiles),
181
282
  };
182
- logByType(result.errors, 'error');
183
- logByType(result.warnings, 'warn');
184
283
  };
185
- const rebuildExistingFiles = async () => {
186
- const rebuiltStepStart = Date.now();
187
- const stepsResult = await stepsCtx.rebuild();
188
- logBuildMessages(stepsResult, 'steps bundle');
189
- console.log('Rebuilt steps bundle', `${Date.now() - rebuiltStepStart}ms`);
190
- const rebuiltWorkflowStart = Date.now();
191
- const workflowResult = await workflowsCtx.interimBundleCtx.rebuild();
192
- logBuildMessages(workflowResult, 'workflows bundle');
193
- if (!workflowResult.outputFiles ||
194
- workflowResult.outputFiles.length === 0) {
195
- console.error('No output generated while rebuilding workflows bundle');
196
- return;
284
+ const hasFileChanges = ({ addedFiles, modifiedFiles, removedFiles, }) => addedFiles.length > 0 ||
285
+ modifiedFiles.length > 0 ||
286
+ removedFiles.length > 0;
287
+ const logDevHmr = (...args) => {
288
+ if (process.env.WORKFLOW_DEV_HMR_LOGS === '1') {
289
+ console.log(...args);
197
290
  }
198
- await workflowsCtx.bundleFinal(workflowResult.outputFiles[0].text);
199
- console.log('Rebuilt workflow bundle', `${Date.now() - rebuiltWorkflowStart}ms`);
200
291
  };
201
- const isWatchableFile = (path) => watchableExtensions.has((0, node_path_1.extname)(path));
202
- const getComparableTimestamp = (entry) => entry.timestamp ?? entry.safeTime;
203
- const findRemovedFiles = (currentEntries, previousEntries) => {
204
- const removed = [];
205
- for (const path of previousEntries.keys()) {
206
- if (!currentEntries.has(path) && isWatchableFile(path)) {
207
- removed.push(path);
292
+ await refreshSourceSnapshots();
293
+ let { files: knownFiles, aliases: knownFileAliases, addKnownFile: rememberKnownFile, } = await readKnownFiles();
294
+ const refreshKnownFiles = async () => {
295
+ const nextKnown = await readKnownFiles();
296
+ knownFiles = nextKnown.files;
297
+ knownFileAliases = nextKnown.aliases;
298
+ rememberKnownFile = nextKnown.addKnownFile;
299
+ };
300
+ const processFileChanges = async (fileChanges) => {
301
+ if (!hasFileChanges(fileChanges)) {
302
+ return;
303
+ }
304
+ const decision = await (0, watch_rebuild_js_1.classifyRebuild)({
305
+ discoveredEntries,
306
+ fileChanges,
307
+ inputFiles: options.inputFiles,
308
+ normalizePath,
309
+ parentHasChild,
310
+ readSnapshot: readSourceSnapshot,
311
+ sourceSnapshots,
312
+ });
313
+ if (decision.kind === 'none') {
314
+ logDevHmr('workflow dev hmr: skip');
315
+ for (const [file, snapshot] of decision.snapshots || []) {
316
+ sourceSnapshots.set(file, snapshot);
208
317
  }
318
+ return;
319
+ }
320
+ if (decision.kind === 'full') {
321
+ logDevHmr('workflow dev hmr: full rediscovery');
322
+ await fullRebuild();
323
+ await refreshKnownFiles();
324
+ return;
325
+ }
326
+ logDevHmr(`workflow dev hmr: hot rebuild${decision.refreshStepRegistrations ? ' with step registration refresh' : ''}`);
327
+ await hotRebuild(decision.refreshStepRegistrations);
328
+ for (const [file, snapshot] of decision.snapshots) {
329
+ sourceSnapshots.set(file, snapshot);
209
330
  }
210
- return removed;
211
331
  };
212
- const findAddedAndModifiedFiles = (currentEntries, previousEntries) => {
213
- const added = [];
214
- const modified = [];
215
- for (const [path, info] of currentEntries) {
216
- if (!isWatchableFile(path)) {
217
- continue;
218
- }
219
- const previous = previousEntries.get(path);
220
- if (!previous) {
221
- added.push(path);
222
- continue;
223
- }
224
- if (getComparableTimestamp(info) !== getComparableTimestamp(previous)) {
225
- modified.push(path);
226
- }
332
+ let pendingFileChanges = {
333
+ addedFiles: [],
334
+ modifiedFiles: [],
335
+ removedFiles: [],
336
+ };
337
+ let flushTimer;
338
+ const scheduleFileChanges = (fileChanges) => {
339
+ pendingFileChanges = mergeFileChanges(pendingFileChanges, fileChanges);
340
+ if (flushTimer) {
341
+ return;
227
342
  }
228
- return { added, modified };
343
+ flushTimer = setTimeout(() => {
344
+ const fileChanges = pendingFileChanges;
345
+ pendingFileChanges = {
346
+ addedFiles: [],
347
+ modifiedFiles: [],
348
+ removedFiles: [],
349
+ };
350
+ flushTimer = undefined;
351
+ enqueue(() => processFileChanges(fileChanges));
352
+ }, 10);
229
353
  };
230
- const determineFileChanges = (currentEntries, previousEntries) => {
231
- const removedFiles = findRemovedFiles(currentEntries, previousEntries);
232
- const { added, modified } = findAddedAndModifiedFiles(currentEntries, previousEntries);
233
- return {
234
- addedFiles: added,
235
- modifiedFiles: modified,
236
- removedFiles,
237
- };
354
+ const resolveExistingEventPath = async (pathname) => {
355
+ const normalizedPath = normalizePath(pathname);
356
+ if (!isWatchableFile(normalizedPath)) {
357
+ return;
358
+ }
359
+ const knownPath = knownFileAliases.get(normalizedPath);
360
+ if (knownPath) {
361
+ return knownPath;
362
+ }
363
+ try {
364
+ const realFilePath = normalizePath(await (0, promises_1.realpath)(normalizedPath));
365
+ return knownFileAliases.get(realFilePath) ?? normalizedPath;
366
+ }
367
+ catch {
368
+ return normalizedPath;
369
+ }
238
370
  };
239
- let isInitial = true;
240
- watcher.on('aggregated', () => {
241
- const currentEntries = readTimeInfoEntries();
242
- const { addedFiles, modifiedFiles, removedFiles } = determineFileChanges(currentEntries, previousTimeInfo);
243
- previousTimeInfo = currentEntries;
244
- if (isInitial) {
245
- isInitial = false;
371
+ const handleFileAdded = async (pathname) => {
372
+ const normalizedPath = normalizePath(pathname);
373
+ if (!isWatchableFile(normalizedPath)) {
246
374
  return;
247
375
  }
248
- if (addedFiles.length === 0 &&
249
- modifiedFiles.length === 0 &&
250
- removedFiles.length === 0) {
376
+ const existingPath = await resolveExistingEventPath(normalizedPath);
377
+ const wasKnown = existingPath ? knownFiles.has(existingPath) : false;
378
+ const canonicalPath = await rememberKnownFile(normalizedPath);
379
+ knownFiles.add(canonicalPath);
380
+ scheduleFileChanges({
381
+ addedFiles: wasKnown ? [] : [canonicalPath],
382
+ modifiedFiles: wasKnown ? [canonicalPath] : [],
383
+ removedFiles: [],
384
+ });
385
+ };
386
+ const handleFileChanged = async (pathname) => {
387
+ const canonicalPath = await resolveExistingEventPath(pathname);
388
+ if (!canonicalPath) {
251
389
  return;
252
390
  }
253
- for (const removal of removedFiles) {
254
- knownFiles.delete(removal);
391
+ const fileChanges = classifyFileChanges({
392
+ changedFiles: [canonicalPath],
393
+ knownFiles,
394
+ removedFiles: [],
395
+ });
396
+ if (!knownFileAliases.has(canonicalPath)) {
397
+ await rememberKnownFile(canonicalPath);
255
398
  }
256
- for (const added of addedFiles) {
257
- knownFiles.add(added);
399
+ scheduleFileChanges(fileChanges);
400
+ };
401
+ const handleFileRemoved = (pathname) => {
402
+ const normalizedPath = normalizePath(pathname);
403
+ if (!isWatchableFile(normalizedPath)) {
404
+ return;
258
405
  }
259
- enqueue(async () => {
260
- if (addedFiles.length > 0 || removedFiles.length > 0) {
261
- await fullRebuild();
262
- return;
263
- }
264
- if (modifiedFiles.length > 0) {
265
- await rebuildExistingFiles();
266
- }
406
+ const canonicalPath = knownFileAliases.get(normalizedPath) ?? normalizedPath;
407
+ const fileChanges = classifyFileChanges({
408
+ changedFiles: [],
409
+ knownFiles,
410
+ removedFiles: [canonicalPath],
267
411
  });
412
+ knownFileAliases.delete(normalizedPath);
413
+ scheduleFileChanges(fileChanges);
414
+ };
415
+ const watcher = chokidar_1.default.watch(this.config.workingDir, {
416
+ ignoreInitial: true,
417
+ followSymlinks: true,
418
+ ignored: (pathname) => {
419
+ const normalizedPath = normalizePath(String(pathname));
420
+ const extension = (0, node_path_1.extname)(normalizedPath);
421
+ if (extension && !watchableExtensions.has(extension)) {
422
+ return true;
423
+ }
424
+ return hasIgnoredPathFragment(normalizedPath);
425
+ },
426
+ });
427
+ watcher.on('add', (pathname) => {
428
+ void handleFileAdded(pathname);
268
429
  });
269
- watcher.watch({
270
- directories: [this.config.workingDir],
271
- startTime: 0,
430
+ watcher.on('change', (pathname) => {
431
+ void handleFileChanged(pathname);
432
+ });
433
+ watcher.on('unlink', (pathname) => {
434
+ handleFileRemoved(pathname);
435
+ });
436
+ watcher.on('error', (error) => {
437
+ console.error('Workflow dev watcher error', error);
438
+ });
439
+ watcher.on('ready', () => {
440
+ logDevHmr('workflow dev hmr: ready');
272
441
  });
273
442
  }
274
443
  }
275
444
  async getInputFiles() {
276
445
  const inputFiles = await super.getInputFiles();
277
- return inputFiles.filter((item) => {
278
- // Match App Router entrypoints: route.ts, page.ts, layout.ts in app/ or src/app/ directories
279
- // Matches: /app/page.ts, /app/dashboard/page.ts, /src/app/route.ts, etc.
280
- if (item.match(/(^|.*[/\\])(app|src[/\\]app)([/\\](route|page|layout)\.|[/\\].*[/\\](route|page|layout)\.)/)) {
446
+ return inputFiles.filter((file) => {
447
+ const entry = (0, node_path_1.relative)(this.config.workingDir, file).replaceAll('\\', '/');
448
+ // Match App Router route, page, and layout entrypoints in app/ or src/app/.
449
+ if (/^(?:app|src\/app)\/(?:.*\/)?(?:route|page|layout)\./.test(entry)) {
281
450
  return true;
282
451
  }
283
- // Match Pages Router entrypoints: files in pages/ or src/pages/
284
- if (item.match(/[/\\](pages|src[/\\]pages)[/\\]/)) {
452
+ // Match every Pages Router entrypoint in pages/ or src/pages/.
453
+ if (/^(?:pages|src\/pages)\//.test(entry)) {
285
454
  return true;
286
455
  }
287
- return false;
456
+ // Match Next.js root entrypoints at the project root or under src/.
457
+ return ['instrumentation', 'middleware', 'proxy'].some((name) => this.config.pageExtensions.some((extension) => entry === `${name}.${extension}` ||
458
+ entry === `src/${name}.${extension}`));
288
459
  });
289
460
  }
290
461
  async writeFunctionsConfig(outputDir) {
@@ -292,46 +463,32 @@ async function getNextBuilderEager() {
292
463
  if (process.env.NODE_ENV === 'development') {
293
464
  return;
294
465
  }
466
+ // V2 combined config: single trigger handles both workflow and step execution.
467
+ // The step route no longer needs its own trigger since steps are executed
468
+ // inline by the combined handler or queued back to __wkf_workflow_* with stepId.
295
469
  const generatedConfig = {
296
470
  version: '0',
297
- steps: {
298
- maxDuration: 'max',
299
- experimentalTriggers: [STEP_QUEUE_TRIGGER],
300
- },
301
471
  workflows: {
302
472
  maxDuration: 'max',
303
- experimentalTriggers: [WORKFLOW_QUEUE_TRIGGER],
473
+ experimentalTriggers: [getWorkflowQueueTrigger()],
304
474
  },
305
475
  };
306
- // We write this file to the generated directory for
307
- // the Next.js builder to consume
308
476
  await (0, promises_1.writeFile)((0, node_path_1.join)(outputDir, '.well-known/workflow/v1/config.json'), JSON.stringify(generatedConfig, null, 2));
309
477
  }
310
- async buildStepsFunction({ inputFiles, workflowGeneratedDir, tsconfigPath, }) {
311
- // Create steps bundle
312
- const stepsRouteDir = (0, node_path_1.join)(workflowGeneratedDir, 'step');
313
- await (0, promises_1.mkdir)(stepsRouteDir, { recursive: true });
314
- return await this.createStepsBundle({
315
- // If any dynamic requires are used when bundling with ESM
316
- // esbuild will create a too dynamic wrapper around require
317
- // which turbopack/webpack fail to analyze. If we externalize
318
- // correctly this shouldn't be an issue although we might want
319
- // to use cjs as alternative to avoid
478
+ /**
479
+ * V2: Build combined route that handles both workflow and step execution.
480
+ */
481
+ async buildCombinedFunction({ inputFiles, workflowGeneratedDir, tsconfigPath, }) {
482
+ const flowRouteDir = (0, node_path_1.join)(workflowGeneratedDir, 'flow');
483
+ await (0, promises_1.mkdir)(flowRouteDir, { recursive: true });
484
+ return await this.createCombinedBundle({
320
485
  format: 'esm',
321
486
  inputFiles,
322
- outfile: (0, node_path_1.join)(stepsRouteDir, 'route.js'),
323
- externalizeNonSteps: true,
324
- tsconfigPath,
325
- });
326
- }
327
- async buildWorkflowsFunction({ inputFiles, workflowGeneratedDir, tsconfigPath, }) {
328
- const workflowsRouteDir = (0, node_path_1.join)(workflowGeneratedDir, 'flow');
329
- await (0, promises_1.mkdir)(workflowsRouteDir, { recursive: true });
330
- return await this.createWorkflowsBundle({
331
- format: 'esm',
332
- outfile: (0, node_path_1.join)(workflowsRouteDir, 'route.js'),
487
+ stepsOutfile: (0, node_path_1.join)(flowRouteDir, '__step_registrations.js'),
488
+ flowOutfile: (0, node_path_1.join)(flowRouteDir, 'route.js'),
333
489
  bundleFinalOutput: false,
334
- inputFiles,
490
+ externalizeNonSteps: true,
491
+ sourceStepRegistrationImports: true,
335
492
  tsconfigPath,
336
493
  });
337
494
  }
@@ -389,4 +546,4 @@ async function getNextBuilderEager() {
389
546
  CachedNextBuilderEager = NextBuilder;
390
547
  return NextBuilder;
391
548
  }
392
- //# sourceMappingURL=builder-eager.js.map
549
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnVpbGRlci1lYWdlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9idWlsZGVyLWVhZ2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBb0NBLGtEQStyQkM7QUFudUJELHFDQUFpRDtBQUNqRCwrQ0FTMEI7QUFDMUIseUNBQXlFO0FBS3pFLHdEQUFnQztBQUVoQyx1REFBK0Q7QUFDL0QseURBTzRCO0FBRTVCLElBQUksc0JBQTJCLENBQUM7QUFDaEMsTUFBTSxTQUFTLEdBQUcsSUFBSSxRQUFRLENBQUMsV0FBVyxFQUFFLDBCQUEwQixDQUV2RCxDQUFDO0FBRWhCLDhFQUE4RTtBQUM5RSw2RUFBNkU7QUFDN0Usb0VBQW9FO0FBQzdELEtBQUssVUFBVSxtQkFBbUIsQ0FDdkMsY0FBb0Q7SUFFcEQsSUFBSSxzQkFBc0IsRUFBRSxDQUFDO1FBQzNCLE9BQU8sc0JBQXNCLENBQUM7SUFDaEMsQ0FBQztJQUVELE1BQU0sRUFDSixXQUFXLEVBQUUsZ0JBQWdCLEVBQzdCLHVCQUF1QixFQUN2QixzQkFBc0IsRUFDdEIsY0FBYyxHQUNmLEdBQUcsY0FBYztRQUNsQixDQUFDLE1BQU0sU0FBUyxDQUFzQyxvQkFBb0IsQ0FBQyxDQUFDLENBQUM7SUFFN0UsTUFBTSxXQUFZLFNBQVEsZ0JBQWdCO1FBTXhDLEtBQUssQ0FBQyxLQUFLO1lBQ1QsTUFBTSxTQUFTLEdBQUcsTUFBTSxJQUFJLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztZQUNoRCxNQUFNLG9CQUFvQixHQUFHLElBQUEsZ0JBQUksRUFBQyxTQUFTLEVBQUUseUJBQXlCLENBQUMsQ0FBQztZQUV4RSxrQ0FBa0M7WUFDbEMsTUFBTSxJQUFBLGdCQUFLLEVBQUMsb0JBQW9CLEVBQUUsRUFBRSxTQUFTLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztZQUN2RCxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUUsQ0FBQztnQkFDdkIsb0VBQW9FO2dCQUNwRSxNQUFNLElBQUEsYUFBRSxFQUFDLElBQUEsZ0JBQUksRUFBQyxvQkFBb0IsRUFBRSxNQUFNLENBQUMsRUFBRTtvQkFDM0MsU0FBUyxFQUFFLElBQUk7b0JBQ2YsS0FBSyxFQUFFLElBQUk7aUJBQ1osQ0FBQyxDQUFDO1lBQ0wsQ0FBQztZQUNELE1BQU0sSUFBQSxvQkFBUyxFQUFDLElBQUEsZ0JBQUksRUFBQyxvQkFBb0IsRUFBRSxZQUFZLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQztZQUUvRCxNQUFNLFVBQVUsR0FBRyxNQUFNLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztZQUM5QyxNQUFNLFlBQVksR0FBRyxNQUFNLElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO1lBRW5ELE1BQU0sT0FBTyxHQUFHO2dCQUNkLFVBQVU7Z0JBQ1Ysb0JBQW9CO2dCQUNwQixZQUFZO2FBQ2IsQ0FBQztZQUVGLGtFQUFrRTtZQUNsRSxNQUFNLGNBQWMsR0FBRyxNQUFNLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUNqRSxNQUFNLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxFQUFFLG9CQUFvQixFQUFFLENBQUMsQ0FBQztZQUV2RCxNQUFNLGFBQWEsR0FBRyxLQUFLLEVBQ3pCLGNBQTRDLEVBQzVDLEVBQUU7Z0JBQ0YsTUFBTSxRQUFRLEdBQUc7b0JBQ2YsS0FBSyxFQUFFLEVBQUUsR0FBRyxjQUFjLEVBQUUsS0FBSyxFQUFFO29CQUNuQyxTQUFTLEVBQUUsRUFBRSxHQUFHLGNBQWMsRUFBRSxTQUFTLEVBQUU7b0JBQzNDLE9BQU8sRUFBRSxFQUFFLEdBQUcsY0FBYyxFQUFFLE9BQU8sRUFBRTtpQkFDeEMsQ0FBQztnQkFFRixpQkFBaUI7Z0JBQ2pCLE1BQU0sa0JBQWtCLEdBQUcsSUFBQSxnQkFBSSxFQUFDLG9CQUFvQixFQUFFLGVBQWUsQ0FBQyxDQUFDO2dCQUN2RSxNQUFNLFlBQVksR0FBRyxNQUFNLElBQUksQ0FBQyxjQUFjLENBQUM7b0JBQzdDLGtCQUFrQjtvQkFDbEIsV0FBVyxFQUFFLG9CQUFvQjtvQkFDakMsUUFBUTtpQkFDVCxDQUFDLENBQUM7Z0JBRUgsb0VBQW9FO2dCQUNwRSxJQUFJLElBQUksQ0FBQywwQkFBMEIsSUFBSSxZQUFZLEVBQUUsQ0FBQztvQkFDcEQsTUFBTSxpQkFBaUIsR0FBRyxJQUFBLGdCQUFJLEVBQzVCLElBQUksQ0FBQyxNQUFNLENBQUMsVUFBVSxFQUN0QixnQ0FBZ0MsQ0FDakMsQ0FBQztvQkFDRixNQUFNLElBQUEsZ0JBQUssRUFBQyxpQkFBaUIsRUFBRSxFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO29CQUNwRCxJQUFJLE9BQU8sQ0FBQyxHQUFHLENBQUMsb0JBQW9CLEtBQUssU0FBUyxFQUFFLENBQUM7d0JBQ25ELE1BQU0sSUFBQSxvQkFBUyxFQUFDLElBQUEsZ0JBQUksRUFBQyxpQkFBaUIsRUFBRSxZQUFZLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQztvQkFDOUQsQ0FBQztvQkFDRCxNQUFNLElBQUEsbUJBQVEsRUFDWixJQUFBLGdCQUFJLEVBQUMsb0JBQW9CLEVBQUUsZUFBZSxDQUFDLEVBQzNDLElBQUEsZ0JBQUksRUFBQyxpQkFBaUIsRUFBRSxlQUFlLENBQUMsQ0FDekMsQ0FBQztnQkFDSixDQUFDO1lBQ0gsQ0FBQyxDQUFDO1lBRUYsTUFBTSxhQUFhLENBQUMsY0FBYyxFQUFFLFFBQVEsQ0FBQyxDQUFDO1lBRTlDLE1BQU0sSUFBSSxDQUFDLG9CQUFvQixDQUFDLFNBQVMsQ0FBQyxDQUFDO1lBRTNDLElBQUksSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUUsQ0FBQztnQkFDdEIsaURBQWlEO2dCQUNqRCxxREFBcUQ7Z0JBQ3JELElBQUksQ0FBQyxjQUFjLEVBQUUsZ0JBQWdCLElBQUksQ0FBQyxjQUFjLENBQUMsV0FBVyxFQUFFLENBQUM7b0JBQ3JFLE1BQU0sSUFBSSxLQUFLLENBQ2IsMERBQTBELENBQzNELENBQUM7Z0JBQ0osQ0FBQztnQkFFRCxpRUFBaUU7Z0JBQ2pFLHVEQUF1RDtnQkFDdkQsSUFBSSxRQUFRLEdBQUcsY0FBYyxDQUFDLFlBQVksQ0FBQztnQkFDM0MsSUFBSSxZQUFZLEdBQUc7b0JBQ2pCLGdCQUFnQixFQUFFLGNBQWMsQ0FBQyxnQkFBZ0I7b0JBQ2pELFdBQVcsRUFBRSxjQUFjLENBQUMsV0FBVztpQkFDeEMsQ0FBQztnQkFDRixJQUFJLGlCQUFpQixHQUFHLGNBQWMsQ0FBQyxpQkFBaUIsQ0FBQztnQkFDekQsSUFBSSxhQUFhLEdBQUcsY0FBYyxDQUFDLGFBQWEsQ0FBQztnQkFDakQsSUFBSSxpQkFBaUIsR0FBRyxjQUFjLENBQUMsaUJBQWlCLENBQUM7Z0JBQ3pELE1BQU0sWUFBWSxHQUFHLElBQUEsZ0JBQUksRUFDdkIsb0JBQW9CLEVBQ3BCLE1BQU0sRUFDTix5QkFBeUIsQ0FDMUIsQ0FBQztnQkFFRixNQUFNLGFBQWEsR0FBRyxDQUFDLFFBQWdCLEVBQUUsRUFBRSxDQUN6QyxDQUFDLElBQUEsc0JBQVUsRUFBQyxRQUFRLENBQUM7b0JBQ25CLENBQUMsQ0FBQyxRQUFRO29CQUNWLENBQUMsQ0FBQyxJQUFBLG1CQUFPLEVBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxVQUFVLEVBQUUsUUFBUSxDQUFDLENBQzVDLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSxHQUFHLENBQUMsQ0FBQztnQkFDeEIsTUFBTSxlQUFlLEdBQUcsSUFBSSxHQUFHLEVBQTBCLENBQUM7Z0JBRTFELE1BQU0sbUJBQW1CLEdBQUcsSUFBSSxHQUFHLENBQUM7b0JBQ2xDLEtBQUs7b0JBQ0wsTUFBTTtvQkFDTixLQUFLO29CQUNMLE1BQU07b0JBQ04sTUFBTTtvQkFDTixNQUFNO29CQUNOLE1BQU07b0JBQ04sTUFBTTtpQkFDUCxDQUFDLENBQUM7Z0JBQ0gsTUFBTSxzQkFBc0IsR0FBRyxvQkFBb0IsQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLEdBQUcsQ0FBQyxDQUFDO2dCQUN4RSxNQUFNLGlCQUFpQixHQUFHLGFBQWEsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDO2dCQUU3RCwrREFBK0Q7Z0JBQy9ELG1FQUFtRTtnQkFDbkUscUVBQXFFO2dCQUNyRSx3REFBd0Q7Z0JBQ3hELDhEQUE4RDtnQkFDOUQsaUVBQWlFO2dCQUNqRSw2REFBNkQ7Z0JBQzdELE1BQU0sa0JBQWtCLEdBQUcsSUFBQSw0Q0FBMEIsRUFBQztvQkFDcEQsVUFBVSxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsVUFBVTtvQkFDbEMsV0FBVyxFQUFFLElBQUksQ0FBQyxvQkFBb0I7b0JBQ3RDLGNBQWMsRUFBRSxDQUFDLHNCQUFzQixDQUFDO2lCQUN6QyxDQUFDLENBQUM7Z0JBRUgsTUFBTSxzQkFBc0IsR0FBRyxDQUFDLGNBQXNCLEVBQUUsRUFBRTtvQkFDeEQsSUFDRSxjQUFjLEtBQUssaUJBQWlCO3dCQUNwQyxjQUFjLENBQUMsVUFBVSxDQUFDLEdBQUcsaUJBQWlCLEdBQUcsQ0FBQyxFQUNsRCxDQUFDO3dCQUNELE9BQU8sSUFBSSxDQUFDO29CQUNkLENBQUM7b0JBQ0QsT0FBTyxrQkFBa0IsQ0FBQyxjQUFjLENBQUMsQ0FBQztnQkFDNUMsQ0FBQyxDQUFDO2dCQUVGLElBQUksWUFBWSxHQUFHLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQztnQkFFckMsTUFBTSxPQUFPLEdBQUcsQ0FBQyxJQUF5QixFQUFFLEVBQUU7b0JBQzVDLFlBQVksR0FBRyxZQUFZLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFO3dCQUNyRCxPQUFPLENBQUMsS0FBSyxDQUFDLCtCQUErQixFQUFFLEtBQUssQ0FBQyxDQUFDO29CQUN4RCxDQUFDLENBQUMsQ0FBQztvQkFDSCxPQUFPLFlBQVksQ0FBQztnQkFDdEIsQ0FBQyxDQUFDO2dCQUVGLE1BQU0sa0JBQWtCLEdBQUcsQ0FBQyxJQUFZLEVBQUUsRUFBRSxDQUMxQyxJQUFBLHVDQUFvQixFQUFDLEVBQUUsSUFBSSxFQUFFLHNCQUFzQixFQUFFLENBQUMsQ0FBQztnQkFFekQsTUFBTSxzQkFBc0IsR0FBRyxHQUFHLEVBQUUsQ0FDbEMsSUFBQSx5Q0FBc0IsRUFBQztvQkFDckIsaUJBQWlCO29CQUNqQixVQUFVLEVBQUUsT0FBTyxDQUFDLFVBQVU7b0JBQzlCLGFBQWE7b0JBQ2IsWUFBWSxFQUFFLGtCQUFrQjtvQkFDaEMsZUFBZTtpQkFDaEIsQ0FBQyxDQUFDO2dCQUVMLE1BQU0scUJBQXFCLEdBQUcsQ0FDNUIsaUJBQW1DLEVBQ2pCLEVBQUUsQ0FBQyxDQUFDO29CQUN0QixHQUFHLGlCQUFpQjtvQkFDcEIsU0FBUyxFQUFFO3dCQUNULEdBQUcsaUJBQWlCLENBQUMsU0FBUzt3QkFDOUIsR0FBRyxpQkFBaUIsQ0FBQyxTQUFTO3FCQUMvQjtvQkFDRCxPQUFPLEVBQUU7d0JBQ1AsR0FBRyxpQkFBaUIsQ0FBQyxPQUFPO3dCQUM1QixHQUFHLGlCQUFpQixDQUFDLE9BQU87cUJBQzdCO2lCQUNGLENBQUMsQ0FBQztnQkFFSCxNQUFNLFVBQVUsR0FBRyxLQUFLLEVBQUUsd0JBQWlDLEVBQUUsRUFBRTtvQkFDN0QsSUFBSSx3QkFBd0IsRUFBRSxDQUFDO3dCQUM3QixJQUFJLFFBQVEsRUFBRSxDQUFDOzRCQUNiLE1BQU0sUUFBUSxDQUFDLE9BQU8sRUFBRSxDQUFDO3dCQUMzQixDQUFDOzZCQUFNLENBQUM7NEJBQ04sYUFBYSxHQUFHLE1BQU0sSUFBSSxDQUFDLGdDQUFnQyxDQUFDO2dDQUMxRCxVQUFVLEVBQUUsT0FBTyxDQUFDLFVBQVU7Z0NBQzlCLE9BQU8sRUFBRSxZQUFZO2dDQUNyQixZQUFZO2dDQUNaLGlCQUFpQjs2QkFDbEIsQ0FBQyxDQUFDO3dCQUNMLENBQUM7b0JBQ0gsQ0FBQztvQkFFRCxNQUFNLGNBQWMsR0FBRyxNQUFNLFlBQVksQ0FBQyxnQkFBZ0IsQ0FBQyxPQUFPLEVBQUUsQ0FBQztvQkFDckUsTUFBTSxjQUFjLEdBQUcsY0FBYyxDQUFDLFdBQVcsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQztvQkFDN0QsSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO3dCQUNwQixNQUFNLElBQUksS0FBSyxDQUNiLHNEQUFzRCxDQUN2RCxDQUFDO29CQUNKLENBQUM7b0JBRUQsTUFBTSxZQUFZLENBQUMsV0FBVyxDQUFDLGNBQWMsQ0FBQyxDQUFDO29CQUMvQyxNQUFNLGFBQWEsQ0FBQyxxQkFBcUIsQ0FBQyxhQUFhLENBQUMsQ0FBQyxDQUFDO2dCQUM1RCxDQUFDLENBQUM7Z0JBRUYsTUFBTSxXQUFXLEdBQUcsS0FBSyxJQUFJLEVBQUU7b0JBQzdCLElBQUksQ0FBQywyQkFBMkIsRUFBRSxDQUFDO29CQUNuQyxNQUFNLGFBQWEsR0FBRyxNQUFNLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztvQkFDakQsT0FBTyxDQUFDLFVBQVUsR0FBRyxhQUFhLENBQUM7b0JBRW5DLE1BQU0sUUFBUSxFQUFFLE9BQU8sRUFBRSxDQUFDO29CQUMxQixNQUFNLFlBQVksQ0FBQyxnQkFBZ0IsQ0FBQyxPQUFPLEVBQUUsQ0FBQztvQkFFOUMsTUFBTSxXQUFXLEdBQUcsTUFBTSxJQUFJLENBQUMscUJBQXFCLENBQUMsT0FBTyxDQUFDLENBQUM7b0JBQzlELFFBQVEsR0FBRyxXQUFXLENBQUMsWUFBWSxDQUFDO29CQUNwQyxpQkFBaUIsR0FBRyxXQUFXLENBQUMsaUJBQWlCLENBQUM7b0JBQ2xELGFBQWEsR0FBRyxXQUFXLENBQUMsYUFBYSxDQUFDO29CQUMxQyxpQkFBaUIsR0FBRyxXQUFXLENBQUMsaUJBQWlCLENBQUM7b0JBRWxELElBQUksQ0FBQyxXQUFXLEVBQUUsZ0JBQWdCLElBQUksQ0FBQyxXQUFXLEVBQUUsV0FBVyxFQUFFLENBQUM7d0JBQ2hFLE1BQU0sSUFBSSxLQUFLLENBQ2IsNERBQTRELENBQzdELENBQUM7b0JBQ0osQ0FBQztvQkFDRCxZQUFZLEdBQUc7d0JBQ2IsZ0JBQWdCLEVBQUUsV0FBVyxDQUFDLGdCQUFnQjt3QkFDOUMsV0FBVyxFQUFFLFdBQVcsQ0FBQyxXQUFXO3FCQUNyQyxDQUFDO29CQUVGLE1BQU0sYUFBYSxDQUFDLFdBQVcsQ0FBQyxRQUFRLENBQUMsQ0FBQztvQkFDMUMsTUFBTSxzQkFBc0IsRUFBRSxDQUFDO2dCQUNqQyxDQUFDLENBQUM7Z0JBRUYsTUFBTSxlQUFlLEdBQUcsQ0FBQyxJQUFZLEVBQUUsRUFBRSxDQUN2QyxtQkFBbUIsQ0FBQyxHQUFHLENBQUMsSUFBQSxtQkFBTyxFQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7Z0JBRXpDLE1BQU0sY0FBYyxHQUFHLEtBQUssSUFBSSxFQUFFO29CQUNoQyxNQUFNLEtBQUssR0FBRyxJQUFJLEdBQUcsRUFBVSxDQUFDO29CQUNoQyxNQUFNLE9BQU8sR0FBRyxJQUFJLEdBQUcsRUFBa0IsQ0FBQztvQkFDMUMsTUFBTSxhQUFhLEdBQUcsSUFBQSxtQ0FBZ0IsRUFBQzt3QkFDckMsaUJBQWlCO3dCQUNqQixVQUFVLEVBQUUsT0FBTyxDQUFDLFVBQVU7d0JBQzlCLGFBQWE7cUJBQ2QsQ0FBQyxDQUFDO29CQUVILE1BQU0sWUFBWSxHQUFHLEtBQUssRUFBRSxRQUFnQixFQUFFLEVBQUU7d0JBQzlDLElBQUksWUFBWSxHQUFHLFFBQVEsQ0FBQzt3QkFDNUIsSUFBSSxDQUFDOzRCQUNILFlBQVksR0FBRyxhQUFhLENBQUMsTUFBTSxJQUFBLG1CQUFRLEVBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQzt3QkFDekQsQ0FBQzt3QkFBQyxNQUFNLENBQUMsQ0FBQSxDQUFDO3dCQUVWLE1BQU0sYUFBYSxHQUFHLGFBQWEsQ0FBQyxHQUFHLENBQUMsWUFBWSxDQUFDOzRCQUNuRCxDQUFDLENBQUMsWUFBWTs0QkFDZCxDQUFDLENBQUMsUUFBUSxDQUFDO3dCQUNiLEtBQUssQ0FBQyxHQUFHLENBQUMsYUFBYSxDQUFDLENBQUM7d0JBQ3pCLE9BQU8sQ0FBQyxHQUFHLENBQUMsUUFBUSxFQUFFLGFBQWEsQ0FBQyxDQUFDO3dCQUNyQyxPQUFPLENBQUMsR0FBRyxDQUFDLFlBQVksRUFBRSxhQUFhLENBQUMsQ0FBQzt3QkFDekMsT0FBTyxhQUFhLENBQUM7b0JBQ3ZCLENBQUMsQ0FBQztvQkFFRixNQUFNLEtBQUssR0FBRyxLQUFLLEVBQUUsU0FBaUIsRUFBaUIsRUFBRTt3QkFDdkQsSUFBSSxPQUF5QixDQUFDO3dCQUM5QixJQUFJLENBQUM7NEJBQ0gsT0FBTyxHQUFHLE1BQU0sSUFBQSxrQkFBTyxFQUFDLFNBQVMsRUFBRSxFQUFFLGFBQWEsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO3dCQUM5RCxDQUFDO3dCQUFDLE1BQU0sQ0FBQzs0QkFDUCxPQUFPO3dCQUNULENBQUM7d0JBRUQsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUNmLE9BQU8sQ0FBQyxHQUFHLENBQUMsS0FBSyxFQUFFLE1BQU0sRUFBRSxFQUFFOzRCQUMzQixNQUFNLFFBQVEsR0FBRyxhQUFhLENBQUMsSUFBQSxnQkFBSSxFQUFDLFNBQVMsRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQzs0QkFDN0QsSUFBSSxzQkFBc0IsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDO2dDQUNyQyxPQUFPOzRCQUNULENBQUM7NEJBRUQsSUFBSSxNQUFNLENBQUMsV0FBVyxFQUFFLEVBQUUsQ0FBQztnQ0FDekIsTUFBTSxLQUFLLENBQUMsUUFBUSxDQUFDLENBQUM7Z0NBQ3RCLE9BQU87NEJBQ1QsQ0FBQzs0QkFFRCxJQUFJLEtBQXVDLENBQUM7NEJBQzVDLElBQUksQ0FBQztnQ0FDSCxLQUFLLEdBQUcsTUFBTSxJQUFBLGVBQUksRUFBQyxRQUFRLENBQUMsQ0FBQzs0QkFDL0IsQ0FBQzs0QkFBQyxNQUFNLENBQUM7Z0NBQ1AsT0FBTzs0QkFDVCxDQUFDOzRCQUVELElBQUksS0FBSyxDQUFDLFdBQVcsRUFBRSxFQUFFLENBQUM7Z0NBQ3hCLE1BQU0sS0FBSyxDQUFDLFFBQVEsQ0FBQyxDQUFDO2dDQUN0QixPQUFPOzRCQUNULENBQUM7NEJBRUQsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLGVBQWUsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDO2dDQUNsRCxPQUFPOzRCQUNULENBQUM7NEJBRUQsTUFBTSxZQUFZLENBQUMsUUFBUSxDQUFDLENBQUM7d0JBQy9CLENBQUMsQ0FBQyxDQUNILENBQUM7b0JBQ0osQ0FBQyxDQUFDO29CQUVGLE1BQU0sS0FBSyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDLENBQUM7b0JBQ3BDLE9BQU8sRUFBRSxLQUFLLEVBQUUsT0FBTyxFQUFFLFlBQVksRUFBRSxDQUFDO2dCQUMxQyxDQUFDLENBQUM7Z0JBRUYsTUFBTSxnQkFBZ0IsR0FBRyxDQUN2QixJQUFpQixFQUNqQixLQUFrQixFQUNMLEVBQUUsQ0FBQyxDQUFDO29CQUNqQixVQUFVLEVBQUUsTUFBTSxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsVUFBVSxFQUFFLEdBQUcsS0FBSyxDQUFDLFVBQVUsQ0FBQyxDQUFDO29CQUM3RCxhQUFhLEVBQUUsTUFBTSxDQUFDO3dCQUNwQixHQUFHLElBQUksQ0FBQyxhQUFhO3dCQUNyQixHQUFHLEtBQUssQ0FBQyxhQUFhO3FCQUN2QixDQUFDO29CQUNGLFlBQVksRUFBRSxNQUFNLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxZQUFZLEVBQUUsR0FBRyxLQUFLLENBQUMsWUFBWSxDQUFDLENBQUM7aUJBQ3BFLENBQUMsQ0FBQztnQkFFSCxNQUFNLE1BQU0sR0FBRyxDQUFDLEtBQWUsRUFBRSxFQUFFLENBQUMsQ0FBQyxHQUFHLElBQUksR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7Z0JBRXhELE1BQU0sbUJBQW1CLEdBQUcsQ0FBQyxFQUMzQixZQUFZLEVBQ1osVUFBVSxFQUNWLFlBQVksR0FLYixFQUFlLEVBQUU7b0JBQ2hCLE1BQU0sVUFBVSxHQUFhLEVBQUUsQ0FBQztvQkFDaEMsTUFBTSxhQUFhLEdBQWEsRUFBRSxDQUFDO29CQUVuQyxLQUFLLE1BQU0sSUFBSSxJQUFJLE1BQU0sQ0FBQyxZQUFZLENBQUMsRUFBRSxDQUFDO3dCQUN4QyxJQUFJLFVBQVUsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQzs0QkFDekIsYUFBYSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQzt3QkFDM0IsQ0FBQzs2QkFBTSxDQUFDOzRCQUNOLFVBQVUsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7NEJBQ3RCLFVBQVUsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUM7d0JBQ3ZCLENBQUM7b0JBQ0gsQ0FBQztvQkFFRCxLQUFLLE1BQU0sSUFBSSxJQUFJLFlBQVksRUFBRSxDQUFDO3dCQUNoQyxVQUFVLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDO29CQUMxQixDQUFDO29CQUVELE9BQU87d0JBQ0wsVUFBVTt3QkFDVixhQUFhO3dCQUNiLFlBQVksRUFBRSxNQUFNLENBQUMsWUFBWSxDQUFDO3FCQUNuQyxDQUFDO2dCQUNKLENBQUMsQ0FBQztnQkFFRixNQUFNLGNBQWMsR0FBRyxDQUFDLEVBQ3RCLFVBQVUsRUFDVixhQUFhLEVBQ2IsWUFBWSxHQUNBLEVBQUUsRUFBRSxDQUNoQixVQUFVLENBQUMsTUFBTSxHQUFHLENBQUM7b0JBQ3JCLGFBQWEsQ0FBQyxNQUFNLEdBQUcsQ0FBQztvQkFDeEIsWUFBWSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUM7Z0JBQzFCLE1BQU0sU0FBUyxHQUFHLENBQUMsR0FBRyxJQUFlLEVBQUUsRUFBRTtvQkFDdkMsSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLHFCQUFxQixLQUFLLEdBQUcsRUFBRSxDQUFDO3dCQUM5QyxPQUFPLENBQUMsR0FBRyxDQUFDLEdBQUcsSUFBSSxDQUFDLENBQUM7b0JBQ3ZCLENBQUM7Z0JBQ0gsQ0FBQyxDQUFDO2dCQUVGLE1BQU0sc0JBQXNCLEVBQUUsQ0FBQztnQkFDL0IsSUFBSSxFQUNGLEtBQUssRUFBRSxVQUFVLEVBQ2pCLE9BQU8sRUFBRSxnQkFBZ0IsRUFDekIsWUFBWSxFQUFFLGlCQUFpQixHQUNoQyxHQUFHLE1BQU0sY0FBYyxFQUFFLENBQUM7Z0JBRTNCLE1BQU0saUJBQWlCLEdBQUcsS0FBSyxJQUFJLEVBQUU7b0JBQ25DLE1BQU0sU0FBUyxHQUFHLE1BQU0sY0FBYyxFQUFFLENBQUM7b0JBQ3pDLFVBQVUsR0FBRyxTQUFTLENBQUMsS0FBSyxDQUFDO29CQUM3QixnQkFBZ0IsR0FBRyxTQUFTLENBQUMsT0FBTyxDQUFDO29CQUNyQyxpQkFBaUIsR0FBRyxTQUFTLENBQUMsWUFBWSxDQUFDO2dCQUM3QyxDQUFDLENBQUM7Z0JBRUYsTUFBTSxrQkFBa0IsR0FBRyxLQUFLLEVBQUUsV0FBd0IsRUFBRSxFQUFFO29CQUM1RCxJQUFJLENBQUMsY0FBYyxDQUFDLFdBQVcsQ0FBQyxFQUFFLENBQUM7d0JBQ2pDLE9BQU87b0JBQ1QsQ0FBQztvQkFFRCxNQUFNLFFBQVEsR0FBRyxNQUFNLElBQUEsa0NBQWUsRUFBQzt3QkFDckMsaUJBQWlCO3dCQUNqQixXQUFXO3dCQUNYLFVBQVUsRUFBRSxPQUFPLENBQUMsVUFBVTt3QkFDOUIsYUFBYTt3QkFDYixjQUFjO3dCQUNkLFlBQVksRUFBRSxrQkFBa0I7d0JBQ2hDLGVBQWU7cUJBQ2hCLENBQUMsQ0FBQztvQkFDSCxJQUFJLFFBQVEsQ0FBQyxJQUFJLEtBQUssTUFBTSxFQUFFLENBQUM7d0JBQzdCLFNBQVMsQ0FBQyx3QkFBd0IsQ0FBQyxDQUFDO3dCQUNwQyxLQUFLLE1BQU0sQ0FBQyxJQUFJLEVBQUUsUUFBUSxDQUFDLElBQUksUUFBUSxDQUFDLFNBQVMsSUFBSSxFQUFFLEVBQUUsQ0FBQzs0QkFDeEQsZUFBZSxDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUUsUUFBUSxDQUFDLENBQUM7d0JBQ3RDLENBQUM7d0JBQ0QsT0FBTztvQkFDVCxDQUFDO29CQUNELElBQUksUUFBUSxDQUFDLElBQUksS0FBSyxNQUFNLEVBQUUsQ0FBQzt3QkFDN0IsU0FBUyxDQUFDLG9DQUFvQyxDQUFDLENBQUM7d0JBQ2hELE1BQU0sV0FBVyxFQUFFLENBQUM7d0JBQ3BCLE1BQU0saUJBQWlCLEVBQUUsQ0FBQzt3QkFDMUIsT0FBTztvQkFDVCxDQUFDO29CQUVELFNBQVMsQ0FDUCxnQ0FBZ0MsUUFBUSxDQUFDLHdCQUF3QixDQUFDLENBQUMsQ0FBQyxpQ0FBaUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQzdHLENBQUM7b0JBQ0YsTUFBTSxVQUFVLENBQUMsUUFBUSxDQUFDLHdCQUF3QixDQUFDLENBQUM7b0JBQ3BELEtBQUssTUFBTSxDQUFDLElBQUksRUFBRSxRQUFRLENBQUMsSUFBSSxRQUFRLENBQUMsU0FBUyxFQUFFLENBQUM7d0JBQ2xELGVBQWUsQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLFFBQVEsQ0FBQyxDQUFDO29CQUN0QyxDQUFDO2dCQUNILENBQUMsQ0FBQztnQkFFRixJQUFJLGtCQUFrQixHQUFnQjtvQkFDcEMsVUFBVSxFQUFFLEVBQUU7b0JBQ2QsYUFBYSxFQUFFLEVBQUU7b0JBQ2pCLFlBQVksRUFBRSxFQUFFO2lCQUNqQixDQUFDO2dCQUNGLElBQUksVUFBcUQsQ0FBQztnQkFFMUQsTUFBTSxtQkFBbUIsR0FBRyxDQUFDLFdBQXdCLEVBQUUsRUFBRTtvQkFDdkQsa0JBQWtCLEdBQUcsZ0JBQWdCLENBQ25DLGtCQUFrQixFQUNsQixXQUFXLENBQ1osQ0FBQztvQkFDRixJQUFJLFVBQVUsRUFBRSxDQUFDO3dCQUNmLE9BQU87b0JBQ1QsQ0FBQztvQkFDRCxVQUFVLEdBQUcsVUFBVSxDQUFDLEdBQUcsRUFBRTt3QkFDM0IsTUFBTSxXQUFXLEdBQUcsa0JBQWtCLENBQUM7d0JBQ3ZDLGtCQUFrQixHQUFHOzRCQUNuQixVQUFVLEVBQUUsRUFBRTs0QkFDZCxhQUFhLEVBQUUsRUFBRTs0QkFDakIsWUFBWSxFQUFFLEVBQUU7eUJBQ2pCLENBQUM7d0JBQ0YsVUFBVSxHQUFHLFNBQVMsQ0FBQzt3QkFDdkIsT0FBTyxDQUFDLEdBQUcsRUFBRSxDQUFDLGtCQUFrQixDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUM7b0JBQ2pELENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQztnQkFDVCxDQUFDLENBQUM7Z0JBRUYsTUFBTSx3QkFBd0IsR0FBRyxLQUFLLEVBQUUsUUFBZ0IsRUFBRSxFQUFFO29CQUMxRCxNQUFNLGNBQWMsR0FBRyxhQUFhLENBQUMsUUFBUSxDQUFDLENBQUM7b0JBQy9DLElBQUksQ0FBQyxlQUFlLENBQUMsY0FBYyxDQUFDLEVBQUUsQ0FBQzt3QkFDckMsT0FBTztvQkFDVCxDQUFDO29CQUVELE1BQU0sU0FBUyxHQUFHLGdCQUFnQixDQUFDLEdBQUcsQ0FBQyxjQUFjLENBQUMsQ0FBQztvQkFDdkQsSUFBSSxTQUFTLEVBQUUsQ0FBQzt3QkFDZCxPQUFPLFNBQVMsQ0FBQztvQkFDbkIsQ0FBQztvQkFFRCxJQUFJLENBQUM7d0JBQ0gsTUFBTSxZQUFZLEdBQUcsYUFBYSxDQUFDLE1BQU0sSUFBQSxtQkFBUSxFQUFDLGNBQWMsQ0FBQyxDQUFDLENBQUM7d0JBQ25FLE9BQU8sZ0JBQWdCLENBQUMsR0FBRyxDQUFDLFlBQVksQ0FBQyxJQUFJLGNBQWMsQ0FBQztvQkFDOUQsQ0FBQztvQkFBQyxNQUFNLENBQUM7d0JBQ1AsT0FBTyxjQUFjLENBQUM7b0JBQ3hCLENBQUM7Z0JBQ0gsQ0FBQyxDQUFDO2dCQUVGLE1BQU0sZUFBZSxHQUFHLEtBQUssRUFBRSxRQUFnQixFQUFFLEVBQUU7b0JBQ2pELE1BQU0sY0FBYyxHQUFHLGFBQWEsQ0FBQyxRQUFRLENBQUMsQ0FBQztvQkFDL0MsSUFBSSxDQUFDLGVBQWUsQ0FBQyxjQUFjLENBQUMsRUFBRSxDQUFDO3dCQUNyQyxPQUFPO29CQUNULENBQUM7b0JBRUQsTUFBTSxZQUFZLEdBQUcsTUFBTSx3QkFBd0IsQ0FBQyxjQUFjLENBQUMsQ0FBQztvQkFDcEUsTUFBTSxRQUFRLEdBQUcsWUFBWSxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLFlBQVksQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUM7b0JBQ3JFLE1BQU0sYUFBYSxHQUFHLE1BQU0saUJBQWlCLENBQUMsY0FBYyxDQUFDLENBQUM7b0JBQzlELFVBQVUsQ0FBQyxHQUFHLENBQUMsYUFBYSxDQUFDLENBQUM7b0JBQzlCLG1CQUFtQixDQUFDO3dCQUNsQixVQUFVLEVBQUUsUUFBUSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsYUFBYSxDQUFDO3dCQUMzQyxhQUFhLEVBQUUsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFO3dCQUM5QyxZQUFZLEVBQUUsRUFBRTtxQkFDakIsQ0FBQyxDQUFDO2dCQUNMLENBQUMsQ0FBQztnQkFFRixNQUFNLGlCQUFpQixHQUFHLEtBQUssRUFBRSxRQUFnQixFQUFFLEVBQUU7b0JBQ25ELE1BQU0sYUFBYSxHQUFHLE1BQU0sd0JBQXdCLENBQUMsUUFBUSxDQUFDLENBQUM7b0JBQy9ELElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQzt3QkFDbkIsT0FBTztvQkFDVCxDQUFDO29CQUVELE1BQU0sV0FBVyxHQUFHLG1CQUFtQixDQUFDO3dCQUN0QyxZQUFZLEVBQUUsQ0FBQyxhQUFhLENBQUM7d0JBQzdCLFVBQVU7d0JBQ1YsWUFBWSxFQUFFLEVBQUU7cUJBQ2pCLENBQUMsQ0FBQztvQkFDSCxJQUFJLENBQUMsZ0JBQWdCLENBQUMsR0FBRyxDQUFDLGFBQWEsQ0FBQyxFQUFFLENBQUM7d0JBQ3pDLE1BQU0saUJBQWlCLENBQUMsYUFBYSxDQUFDLENBQUM7b0JBQ3pDLENBQUM7b0JBQ0QsbUJBQW1CLENBQUMsV0FBVyxDQUFDLENBQUM7Z0JBQ25DLENBQUMsQ0FBQztnQkFFRixNQUFNLGlCQUFpQixHQUFHLENBQUMsUUFBZ0IsRUFBRSxFQUFFO29CQUM3QyxNQUFNLGNBQWMsR0FBRyxhQUFhLENBQUMsUUFBUSxDQUFDLENBQUM7b0JBQy9DLElBQUksQ0FBQyxlQUFlLENBQUMsY0FBYyxDQUFDLEVBQUUsQ0FBQzt3QkFDckMsT0FBTztvQkFDVCxDQUFDO29CQUVELE1BQU0sYUFBYSxHQUNqQixnQkFBZ0IsQ0FBQyxHQUFHLENBQUMsY0FBYyxDQUFDLElBQUksY0FBYyxDQUFDO29CQUN6RCxNQUFNLFdBQVcsR0FBRyxtQkFBbUIsQ0FBQzt3QkFDdEMsWUFBWSxFQUFFLEVBQUU7d0JBQ2hCLFVBQVU7d0JBQ1YsWUFBWSxFQUFFLENBQUMsYUFBYSxDQUFDO3FCQUM5QixDQUFDLENBQUM7b0JBQ0gsZ0JBQWdCLENBQUMsTUFBTSxDQUFDLGNBQWMsQ0FBQyxDQUFDO29CQUN4QyxtQkFBbUIsQ0FBQyxXQUFXLENBQUMsQ0FBQztnQkFDbkMsQ0FBQyxDQUFDO2dCQUVGLE1BQU0sT0FBTyxHQUFHLGtCQUFRLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsVUFBVSxFQUFFO29CQUNyRCxhQUFhLEVBQUUsSUFBSTtvQkFDbkIsY0FBYyxFQUFFLElBQUk7b0JBQ3BCLE9BQU8sRUFBRSxDQUFDLFFBQVEsRUFBRSxFQUFFO3dCQUNwQixNQUFNLGNBQWMsR0FBRyxhQUFhLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUM7d0JBQ3ZELE1BQU0sU0FBUyxHQUFHLElBQUEsbUJBQU8sRUFBQyxjQUFjLENBQUMsQ0FBQzt3QkFDMUMsSUFBSSxTQUFTLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxHQUFHLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQzs0QkFDckQsT0FBTyxJQUFJLENBQUM7d0JBQ2QsQ0FBQzt3QkFDRCxPQUFPLHNCQUFzQixDQUFDLGNBQWMsQ0FBQyxDQUFDO29CQUNoRCxDQUFDO2lCQUNGLENBQUMsQ0FBQztnQkFFSCxPQUFPLENBQUMsRUFBRSxDQUFDLEtBQUssRUFBRSxDQUFDLFFBQVEsRUFBRSxFQUFFO29CQUM3QixLQUFLLGVBQWUsQ0FBQyxRQUFRLENBQUMsQ0FBQztnQkFDakMsQ0FBQyxDQUFDLENBQUM7Z0JBQ0gsT0FBTyxDQUFDLEVBQUUsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxRQUFRLEVBQUUsRUFBRTtvQkFDaEMsS0FBSyxpQkFBaUIsQ0FBQyxRQUFRLENBQUMsQ0FBQztnQkFDbkMsQ0FBQyxDQUFDLENBQUM7Z0JBQ0gsT0FBTyxDQUFDLEVBQUUsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxRQUFRLEVBQUUsRUFBRTtvQkFDaEMsaUJBQWlCLENBQUMsUUFBUSxDQUFDLENBQUM7Z0JBQzlCLENBQUMsQ0FBQyxDQUFDO2dCQUNILE9BQU8sQ0FBQyxFQUFFLENBQUMsT0FBTyxFQUFFLENBQUMsS0FBSyxFQUFFLEVBQUU7b0JBQzVCLE9BQU8sQ0FBQyxLQUFLLENBQUMsNEJBQTRCLEVBQUUsS0FBSyxDQUFDLENBQUM7Z0JBQ3JELENBQUMsQ0FBQyxDQUFDO2dCQUNILE9BQU8sQ0FBQyxFQUFFLENBQUMsT0FBTyxFQUFFLEdBQUcsRUFBRTtvQkFDdkIsU0FBUyxDQUFDLHlCQUF5QixDQUFDLENBQUM7Z0JBQ3ZDLENBQUMsQ0FBQyxDQUFDO1lBQ0wsQ0FBQztRQUNILENBQUM7UUFFUyxLQUFLLENBQUMsYUFBYTtZQUMzQixNQUFNLFVBQVUsR0FBRyxNQUFNLEtBQUssQ0FBQyxhQUFhLEVBQUUsQ0FBQztZQUMvQyxPQUFPLFVBQVUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRTtnQkFDaEMsTUFBTSxLQUFLLEdBQUcsSUFBQSxvQkFBUSxFQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsVUFBVSxFQUFFLElBQUksQ0FBQyxDQUFDLFVBQVUsQ0FDN0QsSUFBSSxFQUNKLEdBQUcsQ0FDSixDQUFDO2dCQUVGLDRFQUE0RTtnQkFDNUUsSUFBSSxxREFBcUQsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztvQkFDdEUsT0FBTyxJQUFJLENBQUM7Z0JBQ2QsQ0FBQztnQkFFRCwrREFBK0Q7Z0JBQy9ELElBQUkseUJBQXlCLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7b0JBQzFDLE9BQU8sSUFBSSxDQUFDO2dCQUNkLENBQUM7Z0JBRUQsb0VBQW9FO2dCQUNwRSxPQUFPLENBQUMsaUJBQWlCLEVBQUUsWUFBWSxFQUFFLE9BQU8sQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFLENBQzlELElBQUksQ0FBQyxNQUFNLENBQUMsY0FBYyxDQUFDLElBQUksQ0FDN0IsQ0FBQyxTQUFTLEVBQUUsRUFBRSxDQUNaLEtBQUssS0FBSyxHQUFHLElBQUksSUFBSSxTQUFTLEVBQUU7b0JBQ2hDLEtBQUssS0FBSyxPQUFPLElBQUksSUFBSSxTQUFTLEVBQUUsQ0FDdkMsQ0FDRixDQUFDO1lBQ0osQ0FBQyxDQUFDLENBQUM7UUFDTCxDQUFDO1FBRU8sS0FBSyxDQUFDLG9CQUFvQixDQUFDLFNBQWlCO1lBQ2xELDJEQUEyRDtZQUMzRCxJQUFJLE9BQU8sQ0FBQyxHQUFHLENBQUMsUUFBUSxLQUFLLGFBQWEsRUFBRSxDQUFDO2dCQUMzQyxPQUFPO1lBQ1QsQ0FBQztZQUVELCtFQUErRTtZQUMvRSwwRUFBMEU7WUFDMUUsaUZBQWlGO1lBQ2pGLE1BQU0sZUFBZSxHQUFHO2dCQUN0QixPQUFPLEVBQUUsR0FBRztnQkFDWixTQUFTLEVBQUU7b0JBQ1QsV0FBVyxFQUFFLEtBQUs7b0JBQ2xCLG9CQUFvQixFQUFFLENBQUMsdUJBQXVCLEVBQUUsQ0FBQztpQkFDbEQ7YUFDRixDQUFDO1lBRUYsTUFBTSxJQUFBLG9CQUFTLEVBQ2IsSUFBQSxnQkFBSSxFQUFDLFNBQVMsRUFBRSxxQ0FBcUMsQ0FBQyxFQUN0RCxJQUFJLENBQUMsU0FBUyxDQUFDLGVBQWUsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQ3pDLENBQUM7UUFDSixDQUFDO1FBRUQ7O1dBRUc7UUFDSyxLQUFLLENBQUMscUJBQXFCLENBQUMsRUFDbEMsVUFBVSxFQUNWLG9CQUFvQixFQUNwQixZQUFZLEdBS2I7WUFDQyxNQUFNLFlBQVksR0FBRyxJQUFBLGdCQUFJLEVBQUMsb0JBQW9CLEVBQUUsTUFBTSxDQUFDLENBQUM7WUFDeEQsTUFBTSxJQUFBLGdCQUFLLEVBQUMsWUFBWSxFQUFFLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7WUFFL0MsT0FBTyxNQUFNLElBQUksQ0FBQyxvQkFBb0IsQ0FBQztnQkFDckMsTUFBTSxFQUFFLEtBQUs7Z0JBQ2IsVUFBVTtnQkFDVixZQUFZLEVBQUUsSUFBQSxnQkFBSSxFQUFDLFlBQVksRUFBRSx5QkFBeUIsQ0FBQztnQkFDM0QsV0FBVyxFQUFFLElBQUEsZ0JBQUksRUFBQyxZQUFZLEVBQUUsVUFBVSxDQUFDO2dCQUMzQyxpQkFBaUIsRUFBRSxLQUFLO2dCQUN4QixtQkFBbUIsRUFBRSxJQUFJO2dCQUN6Qiw2QkFBNkIsRUFBRSxJQUFJO2dCQUNuQyxZQUFZO2FBQ2IsQ0FBQyxDQUFDO1FBQ0wsQ0FBQztRQUVPLEtBQUssQ0FBQyxpQkFBaUIsQ0FBQyxFQUM5QixvQkFBb0IsR0FHckI7WUFDQyxNQUFNLGdCQUFnQixHQUFHLElBQUEsZ0JBQUksRUFDM0Isb0JBQW9CLEVBQ3BCLDBCQUEwQixDQUMzQixDQUFDO1lBQ0YsTUFBTSxJQUFJLENBQUMsbUJBQW1CLENBQUM7Z0JBQzdCLE9BQU8sRUFBRSxnQkFBZ0I7Z0JBQ3pCLE1BQU0sRUFBRSxLQUFLLEVBQUUsZ0NBQWdDO2FBQ2hELENBQUMsQ0FBQztRQUNMLENBQUM7UUFFTyxLQUFLLENBQUMsZ0JBQWdCO1lBQzVCLE1BQU0sTUFBTSxHQUFHLElBQUEsbUJBQU8sRUFBQyxJQUFJLENBQUMsTUFBTSxDQUFDLFVBQVUsRUFBRSxLQUFLLENBQUMsQ0FBQztZQUN0RCxNQUFNLFNBQVMsR0FBRyxJQUFBLG1CQUFPLEVBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxVQUFVLEVBQUUsU0FBUyxDQUFDLENBQUM7WUFDN0QsTUFBTSxRQUFRLEdBQUcsSUFBQSxtQkFBTyxFQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsVUFBVSxFQUFFLE9BQU8sQ0FBQyxDQUFDO1lBQzFELE1BQU0sV0FBVyxHQUFHLElBQUEsbUJBQU8sRUFBQyxJQUFJLENBQUMsTUFBTSxDQUFDLFVBQVUsRUFBRSxXQUFXLENBQUMsQ0FBQztZQUVqRSxzREFBc0Q7WUFDdEQsTUFBTSxXQUFXLEdBQUcsS0FBSyxFQUFFLElBQVksRUFBb0IsRUFBRTtnQkFDM0QsSUFBSSxDQUFDO29CQUNILE1BQU0sSUFBQSxpQkFBTSxFQUFDLElBQUksRUFBRSxtQkFBUyxDQUFDLElBQUksQ0FBQyxDQUFDO29CQUNuQyxNQUFNLEtBQUssR0FBRyxNQUFNLElBQUEsZUFBSSxFQUFDLElBQUksQ0FBQyxDQUFDO29CQUMvQixJQUFJLENBQUMsS0FBSyxDQUFDLFdBQVcsRUFBRSxFQUFFLENBQUM7d0JBQ3pCLE1BQU0sSUFBSSxLQUFLLENBQUMsdUNBQXVDLElBQUksRUFBRSxDQUFDLENBQUM7b0JBQ2pFLENBQUM7b0JBQ0QsT0FBTyxJQUFJLENBQUM7Z0JBQ2QsQ0FBQztnQkFBQyxPQUFPLENBQUMsRUFBRSxDQUFDO29CQUNYLElBQUksQ0FBQyxZQUFZLEtBQUssSUFBSSxDQUFDLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxpQkFBaUIsQ0FBQyxFQUFFLENBQUM7d0JBQ2hFLE1BQU0sQ0FBQyxDQUFDO29CQUNWLENBQUM7b0JBQ0QsT0FBTyxLQUFLLENBQUM7Z0JBQ2YsQ0FBQztZQUNILENBQUMsQ0FBQztZQUVGLGdDQUFnQztZQUNoQyxJQUFJLE1BQU0sV0FBVyxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUM7Z0JBQzlCLE9BQU8sTUFBTSxDQUFDO1lBQ2hCLENBQUM7WUFFRCxvQ0FBb0M7WUFDcEMsSUFBSSxNQUFNLFdBQVcsQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDO2dCQUNqQyxPQUFPLFNBQVMsQ0FBQztZQUNuQixDQUFDO1lBRUQsa0ZBQWtGO1lBQ2xGLElBQUksTUFBTSxXQUFXLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQztnQkFDaEMsK0NBQStDO2dCQUMvQyxNQUFNLElBQUEsZ0JBQUssRUFBQyxNQUFNLEVBQUUsRUFBRSxTQUFTLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztnQkFDekMsT0FBTyxNQUFNLENBQUM7WUFDaEIsQ0FBQztZQUVELElBQUksTUFBTSxXQUFXLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQztnQkFDbkMsdURBQXVEO2dCQUN2RCxNQUFNLElBQUEsZ0JBQUssRUFBQyxTQUFTLEVBQUUsRUFBRSxTQUFTLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztnQkFDNUMsT0FBTyxTQUFTLENBQUM7WUFDbkIsQ0FBQztZQUVELE1BQU0sSUFBSSxLQUFLLENBQ2IscUhBQXFILENBQ3RILENBQUM7UUFDSixDQUFDO0tBQ0Y7SUFFRCxzQkFBc0IsR0FBRyxXQUFXLENBQUM7SUFDckMsT0FBTyxXQUFXLENBQUM7QUFDckIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGNvbnN0YW50cywgdHlwZSBEaXJlbnQgfSBmcm9tICdub2RlOmZzJztcbmltcG9ydCB7XG4gIGFjY2VzcyxcbiAgY29weUZpbGUsXG4gIG1rZGlyLFxuICByZWFkZGlyLFxuICByZWFscGF0aCxcbiAgcm0sXG4gIHN0YXQsXG4gIHdyaXRlRmlsZSxcbn0gZnJvbSAnbm9kZTpmcy9wcm9taXNlcyc7XG5pbXBvcnQgeyBleHRuYW1lLCBpc0Fic29sdXRlLCBqb2luLCByZWxhdGl2ZSwgcmVzb2x2ZSB9IGZyb20gJ25vZGU6cGF0aCc7XG5pbXBvcnQgdHlwZSB7XG4gIE5leHRDb25maWcgYXMgQnVpbGRlck5leHRDb25maWcsXG4gIFdvcmtmbG93TWFuaWZlc3QsXG59IGZyb20gJ0B3b3JrZmxvdy9idWlsZGVycyc7XG5pbXBvcnQgY2hva2lkYXIgZnJvbSAnY2hva2lkYXInO1xuaW1wb3J0IHR5cGUgeyBOZXh0Q29uZmlnIGFzIFByb2plY3ROZXh0Q29uZmlnIH0gZnJvbSAnbmV4dCc7XG5pbXBvcnQgeyBjcmVhdGVXYXRjaElnbm9yZVByZWRpY2F0ZSB9IGZyb20gJy4vd2F0Y2gtaWdub3JlLmpzJztcbmltcG9ydCB7XG4gIGNsYXNzaWZ5UmVidWlsZCxcbiAgY3JlYXRlU291cmNlU25hcHNob3QsXG4gIHR5cGUgRmlsZUNoYW5nZXMsXG4gIGdldFJlbGV2YW50RmlsZXMsXG4gIHJlcGxhY2VTb3VyY2VTbmFwc2hvdHMsXG4gIHR5cGUgU291cmNlU25hcHNob3QsXG59IGZyb20gJy4vd2F0Y2gtcmVidWlsZC5qcyc7XG5cbmxldCBDYWNoZWROZXh0QnVpbGRlckVhZ2VyOiBhbnk7XG5jb25zdCBpbXBvcnRFc20gPSBuZXcgRnVuY3Rpb24oJ3NwZWNpZmllcicsICdyZXR1cm4gaW1wb3J0KHNwZWNpZmllciknKSBhcyA8VD4oXG4gIHNwZWNpZmllcjogc3RyaW5nXG4pID0+IFByb21pc2U8VD47XG5cbi8vIENyZWF0ZSB0aGUgZWFnZXIgTmV4dCBidWlsZGVyIGR5bmFtaWNhbGx5IGJ5IGV4dGVuZGluZyB0aGUgRVNNIEJhc2VCdWlsZGVyLlxuLy8gRXhwb3J0ZWQgYXMgZ2V0TmV4dEJ1aWxkZXJFYWdlcigpIHRvIGFsbG93IENvbW1vbkpTIG1vZHVsZXMgdG8gaW1wb3J0IGZyb21cbi8vIHRoZSBFU00gQHdvcmtmbG93L2J1aWxkZXJzIHBhY2thZ2UgdmlhIGR5bmFtaWMgaW1wb3J0IGF0IHJ1bnRpbWUuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZ2V0TmV4dEJ1aWxkZXJFYWdlcihcbiAgYnVpbGRlcnNNb2R1bGU/OiB0eXBlb2YgaW1wb3J0KCdAd29ya2Zsb3cvYnVpbGRlcnMnKVxuKSB7XG4gIGlmIChDYWNoZWROZXh0QnVpbGRlckVhZ2VyKSB7XG4gICAgcmV0dXJuIENhY2hlZE5leHRCdWlsZGVyRWFnZXI7XG4gIH1cblxuICBjb25zdCB7XG4gICAgQmFzZUJ1aWxkZXI6IEJhc2VCdWlsZGVyQ2xhc3MsXG4gICAgZ2V0V29ya2Zsb3dRdWV1ZVRyaWdnZXIsXG4gICAgZGV0ZWN0V29ya2Zsb3dQYXR0ZXJucyxcbiAgICBwYXJlbnRIYXNDaGlsZCxcbiAgfSA9IGJ1aWxkZXJzTW9kdWxlID8/XG4gIChhd2FpdCBpbXBvcnRFc208dHlwZW9mIGltcG9ydCgnQHdvcmtmbG93L2J1aWxkZXJzJyk+KCdAd29ya2Zsb3cvYnVpbGRlcnMnKSk7XG5cbiAgY2xhc3MgTmV4dEJ1aWxkZXIgZXh0ZW5kcyBCYXNlQnVpbGRlckNsYXNzIHtcbiAgICBwcm90ZWN0ZWQgZGVjbGFyZSBjb25maWc6IEJ1aWxkZXJOZXh0Q29uZmlnICYge1xuICAgICAgcGFnZUV4dGVuc2lvbnM6IE5vbk51bGxhYmxlPFByb2plY3ROZXh0Q29uZmlnWydwYWdlRXh0ZW5zaW9ucyddPjtcbiAgICAgIGRpc3REaXI6IHN0cmluZztcbiAgICB9O1xuXG4gICAgYXN5bmMgYnVpbGQoKSB7XG4gICAgICBjb25zdCBvdXRwdXREaXIgPSBhd2FpdCB0aGlzLmZpbmRBcHBEaXJlY3RvcnkoKTtcbiAgICAgIGNvbnN0IHdvcmtmbG93R2VuZXJhdGVkRGlyID0gam9pbihvdXRwdXREaXIsICcud2VsbC1rbm93bi93b3JrZmxvdy92MScpO1xuXG4gICAgICAvLyBFbnN1cmUgb3V0cHV0IGRpcmVjdG9yaWVzIGV4aXN0XG4gICAgICBhd2FpdCBta2Rpcih3b3JrZmxvd0dlbmVyYXRlZERpciwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gICAgICBpZiAoIXRoaXMuY29uZmlnLndhdGNoKSB7XG4gICAgICAgIC8vIFByb2R1Y3Rpb24gYnVpbGQgY2FjaGVzIG1heSBzdGlsbCBjb250YWluIHRoZSByZXRpcmVkIHN0ZXAgcm91dGUuXG4gICAgICAgIGF3YWl0IHJtKGpvaW4od29ya2Zsb3dHZW5lcmF0ZWREaXIsICdzdGVwJyksIHtcbiAgICAgICAgICByZWN1cnNpdmU6IHRydWUsXG4gICAgICAgICAgZm9yY2U6IHRydWUsXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgICAgYXdhaXQgd3JpdGVGaWxlKGpvaW4od29ya2Zsb3dHZW5lcmF0ZWREaXIsICcuZ2l0aWdub3JlJyksICcqJyk7XG5cbiAgICAgIGNvbnN0IGlucHV0RmlsZXMgPSBhd2FpdCB0aGlzLmdldElucHV0RmlsZXMoKTtcbiAgICAgIGNvbnN0IHRzY29uZmlnUGF0aCA9IGF3YWl0IHRoaXMuZmluZFRzQ29uZmlnUGF0aCgpO1xuXG4gICAgICBjb25zdCBvcHRpb25zID0ge1xuICAgICAgICBpbnB1dEZpbGVzLFxuICAgICAgICB3b3JrZmxvd0dlbmVyYXRlZERpcixcbiAgICAgICAgdHNjb25maWdQYXRoLFxuICAgICAgfTtcblxuICAgICAgLy8gVjI6IEJ1aWxkIGNvbWJpbmVkIHJvdXRlIChyZXBsYWNlcyBzZXBhcmF0ZSBzdGVwICsgZmxvdyByb3V0ZXMpXG4gICAgICBjb25zdCBjb21iaW5lZFJlc3VsdCA9IGF3YWl0IHRoaXMuYnVpbGRDb21iaW5lZEZ1bmN0aW9uKG9wdGlvbnMpO1xuICAgICAgYXdhaXQgdGhpcy5idWlsZFdlYmhvb2tSb3V0ZSh7IHdvcmtmbG93R2VuZXJhdGVkRGlyIH0pO1xuXG4gICAgICBjb25zdCB3cml0ZU1hbmlmZXN0ID0gYXN5bmMgKFxuICAgICAgICBzb3VyY2VNYW5pZmVzdDogV29ya2Zsb3dNYW5pZmVzdCB8IHVuZGVmaW5lZFxuICAgICAgKSA9PiB7XG4gICAgICAgIGNvbnN0IG1hbmlmZXN0ID0ge1xuICAgICAgICAgIHN0ZXBzOiB7IC4uLnNvdXJjZU1hbmlmZXN0Py5zdGVwcyB9LFxuICAgICAgICAgIHdvcmtmbG93czogeyAuLi5zb3VyY2VNYW5pZmVzdD8ud29ya2Zsb3dzIH0sXG4gICAgICAgICAgY2xhc3NlczogeyAuLi5zb3VyY2VNYW5pZmVzdD8uY2xhc3NlcyB9LFxuICAgICAgICB9O1xuXG4gICAgICAgIC8vIFdyaXRlIG1hbmlmZXN0XG4gICAgICAgIGNvbnN0IHdvcmtmbG93QnVuZGxlUGF0aCA9IGpvaW4od29ya2Zsb3dHZW5lcmF0ZWREaXIsICdmbG93L3JvdXRlLmpzJyk7XG4gICAgICAgIGNvbnN0IG1hbmlmZXN0SnNvbiA9IGF3YWl0IHRoaXMuY3JlYXRlTWFuaWZlc3Qoe1xuICAgICAgICAgIHdvcmtmbG93QnVuZGxlUGF0aCxcbiAgICAgICAgICBtYW5pZmVzdERpcjogd29ya2Zsb3dHZW5lcmF0ZWREaXIsXG4gICAgICAgICAgbWFuaWZlc3QsXG4gICAgICAgIH0pO1xuXG4gICAgICAgIC8vIEV4cG9zZSBtYW5pZmVzdCBhcyBhIHN0YXRpYyBmaWxlIHdoZW4gV09SS0ZMT1dfUFVCTElDX01BTklGRVNUPTEuXG4gICAgICAgIGlmICh0aGlzLnNob3VsZEV4cG9zZVB1YmxpY01hbmlmZXN0ICYmIG1hbmlmZXN0SnNvbikge1xuICAgICAgICAgIGNvbnN0IHB1YmxpY01hbmlmZXN0RGlyID0gam9pbihcbiAgICAgICAgICAgIHRoaXMuY29uZmlnLndvcmtpbmdEaXIsXG4gICAgICAgICAgICAncHVibGljLy53ZWxsLWtub3duL3dvcmtmbG93L3YxJ1xuICAgICAgICAgICk7XG4gICAgICAgICAgYXdhaXQgbWtkaXIocHVibGljTWFuaWZlc3REaXIsIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuICAgICAgICAgIGlmIChwcm9jZXNzLmVudi5WRVJDRUxfREVQTE9ZTUVOVF9JRCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICBhd2FpdCB3cml0ZUZpbGUoam9pbihwdWJsaWNNYW5pZmVzdERpciwgJy5naXRpZ25vcmUnKSwgJyonKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgYXdhaXQgY29weUZpbGUoXG4gICAgICAgICAgICBqb2luKHdvcmtmbG93R2VuZXJhdGVkRGlyLCAnbWFuaWZlc3QuanNvbicpLFxuICAgICAgICAgICAgam9pbihwdWJsaWNNYW5pZmVzdERpciwgJ21hbmlmZXN0Lmpzb24nKVxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgIH07XG5cbiAgICAgIGF3YWl0IHdyaXRlTWFuaWZlc3QoY29tYmluZWRSZXN1bHQ/Lm1hbmlmZXN0KTtcblxuICAgICAgYXdhaXQgdGhpcy53cml0ZUZ1bmN0aW9uc0NvbmZpZyhvdXRwdXREaXIpO1xuXG4gICAgICBpZiAodGhpcy5jb25maWcud2F0Y2gpIHtcbiAgICAgICAgLy8gVE9ETzogaW1wbGVtZW50IHdhdGNoIG1vZGUgZm9yIGNvbWJpbmVkIGJ1bmRsZVxuICAgICAgICAvLyBGb3Igbm93LCBmYWxsIGJhY2sgdG8gZnVsbCByZWJ1aWxkIG9uIGZpbGUgY2hhbmdlc1xuICAgICAgICBpZiAoIWNvbWJpbmVkUmVzdWx0Py5pbnRlcmltQnVuZGxlQ3R4IHx8ICFjb21iaW5lZFJlc3VsdC5idW5kbGVGaW5hbCkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICAgICdJbnZhcmlhbnQ6IGV4cGVjdGVkIHdvcmtmbG93IGJ1aWxkIGNvbnRleHQgaW4gd2F0Y2ggbW9kZSdcbiAgICAgICAgICApO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gU3RlcCByZWdpc3RyYXRpb25zIG1heSBiZSBlbWl0dGVkIGFzIHNvdXJjZSBpbXBvcnRzIHdpdGhvdXQgYW5cbiAgICAgICAgLy8gZXNidWlsZCBjb250ZXh0IHdoZW4gZXh0ZXJuYWxpemVOb25TdGVwcyBpcyBlbmFibGVkLlxuICAgICAgICBsZXQgc3RlcHNDdHggPSBjb21iaW5lZFJlc3VsdC5zdGVwc0NvbnRleHQ7XG4gICAgICAgIGxldCB3b3JrZmxvd3NDdHggPSB7XG4gICAgICAgICAgaW50ZXJpbUJ1bmRsZUN0eDogY29tYmluZWRSZXN1bHQuaW50ZXJpbUJ1bmRsZUN0eCxcbiAgICAgICAgICBidW5kbGVGaW5hbDogY29tYmluZWRSZXN1bHQuYnVuZGxlRmluYWwsXG4gICAgICAgIH07XG4gICAgICAgIGxldCBkaXNjb3ZlcmVkRW50cmllcyA9IGNvbWJpbmVkUmVzdWx0LmRpc2NvdmVyZWRFbnRyaWVzO1xuICAgICAgICBsZXQgc3RlcHNNYW5pZmVzdCA9IGNvbWJpbmVkUmVzdWx0LnN0ZXBzTWFuaWZlc3Q7XG4gICAgICAgIGxldCB3b3JrZmxvd3NNYW5pZmVzdCA9IGNvbWJpbmVkUmVzdWx0LndvcmtmbG93c01hbmlmZXN0O1xuICAgICAgICBjb25zdCBzdGVwc091dGZpbGUgPSBqb2luKFxuICAgICAgICAgIHdvcmtmbG93R2VuZXJhdGVkRGlyLFxuICAgICAgICAgICdmbG93JyxcbiAgICAgICAgICAnX19zdGVwX3JlZ2lzdHJhdGlvbnMuanMnXG4gICAgICAgICk7XG5cbiAgICAgICAgY29uc3Qgbm9ybWFsaXplUGF0aCA9IChwYXRobmFtZTogc3RyaW5nKSA9PlxuICAgICAgICAgIChpc0Fic29sdXRlKHBhdGhuYW1lKVxuICAgICAgICAgICAgPyBwYXRobmFtZVxuICAgICAgICAgICAgOiByZXNvbHZlKHRoaXMuY29uZmlnLndvcmtpbmdEaXIsIHBhdGhuYW1lKVxuICAgICAgICAgICkucmVwbGFjZSgvXFxcXC9nLCAnLycpO1xuICAgICAgICBjb25zdCBzb3VyY2VTbmFwc2hvdHMgPSBuZXcgTWFwPHN0cmluZywgU291cmNlU25hcHNob3Q+KCk7XG5cbiAgICAgICAgY29uc3Qgd2F0Y2hhYmxlRXh0ZW5zaW9ucyA9IG5ldyBTZXQoW1xuICAgICAgICAgICcuanMnLFxuICAgICAgICAgICcuanN4JyxcbiAgICAgICAgICAnLnRzJyxcbiAgICAgICAgICAnLnRzeCcsXG4gICAgICAgICAgJy5tdHMnLFxuICAgICAgICAgICcuY3RzJyxcbiAgICAgICAgICAnLmNqcycsXG4gICAgICAgICAgJy5tanMnLFxuICAgICAgICBdKTtcbiAgICAgICAgY29uc3Qgbm9ybWFsaXplZEdlbmVyYXRlZERpciA9IHdvcmtmbG93R2VuZXJhdGVkRGlyLnJlcGxhY2UoL1xcXFwvZywgJy8nKTtcbiAgICAgICAgY29uc3Qgbm9ybWFsaXplZERpc3REaXIgPSBub3JtYWxpemVQYXRoKHRoaXMuY29uZmlnLmRpc3REaXIpO1xuXG4gICAgICAgIC8vIFBydW5lIHRoZSBkZXYgd2F0Y2ggc2V0IHRvIGtlZXAgY2hva2lkYXIgZnJvbSByZWdpc3RlcmluZyBhblxuICAgICAgICAvLyBmcy53YXRjaCBwZXIgZGlyZWN0b3J5IGFjcm9zcyB0aGUgd2hvbGUgcHJvamVjdCB0cmVlIChjaG9raWRhciA0XG4gICAgICAgIC8vIGRyb3BwZWQgZnNldmVudHMsIHNvIG9uIG1hY09TIHRoYXQgZXhoYXVzdHMgdGhlIGZkIGxpbWl0IC0+IEVNRklMRVxuICAgICAgICAvLyBvbiBsYXJnZSBtb25vcmVwb3MpLiBUaGlzIGhvbm9ycyBgLmdpdGlnbm9yZWAgYW5kIHRoZVxuICAgICAgICAvLyBXT1JLRkxPV19ERVZfV0FUQ0hfSUdOT1JFRF9QQVRIUyBlbnYgdmFyIGluIGFkZGl0aW9uIHRvIHRoZVxuICAgICAgICAvLyBidWlsdC1pbiBmcmFnbWVudHMuIFRoZSBnZW5lcmF0ZWQgd29ya2Zsb3cgZGlyIGlzIHBhc3NlZCBhcyBhblxuICAgICAgICAvLyBleHRyYSBmcmFnbWVudCBzbyBpdCBpcyBwcnVuZWQgcmVnYXJkbGVzcyBvZiBgLmdpdGlnbm9yZWAuXG4gICAgICAgIGNvbnN0IGlzSWdub3JlZFdhdGNoUGF0aCA9IGNyZWF0ZVdhdGNoSWdub3JlUHJlZGljYXRlKHtcbiAgICAgICAgICB3b3JraW5nRGlyOiB0aGlzLmNvbmZpZy53b3JraW5nRGlyLFxuICAgICAgICAgIHByb2plY3RSb290OiB0aGlzLnRyYW5zZm9ybVByb2plY3RSb290LFxuICAgICAgICAgIGV4dHJhRnJhZ21lbnRzOiBbbm9ybWFsaXplZEdlbmVyYXRlZERpcl0sXG4gICAgICAgIH0pO1xuXG4gICAgICAgIGNvbnN0IGhhc0lnbm9yZWRQYXRoRnJhZ21lbnQgPSAobm9ybWFsaXplZFBhdGg6IHN0cmluZykgPT4ge1xuICAgICAgICAgIGlmIChcbiAgICAgICAgICAgIG5vcm1hbGl6ZWRQYXRoID09PSBub3JtYWxpemVkRGlzdERpciB8fFxuICAgICAgICAgICAgbm9ybWFsaXplZFBhdGguc3RhcnRzV2l0aChgJHtub3JtYWxpemVkRGlzdERpcn0vYClcbiAgICAgICAgICApIHtcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4gaXNJZ25vcmVkV2F0Y2hQYXRoKG5vcm1hbGl6ZWRQYXRoKTtcbiAgICAgICAgfTtcblxuICAgICAgICBsZXQgcmVidWlsZFF1ZXVlID0gUHJvbWlzZS5yZXNvbHZlKCk7XG5cbiAgICAgICAgY29uc3QgZW5xdWV1ZSA9ICh0YXNrOiAoKSA9PiBQcm9taXNlPHZvaWQ+KSA9PiB7XG4gICAgICAgICAgcmVidWlsZFF1ZXVlID0gcmVidWlsZFF1ZXVlLnRoZW4odGFzaykuY2F0Y2goKGVycm9yKSA9PiB7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKCdGYWlsZWQgdG8gcHJvY2VzcyBmaWxlIGNoYW5nZScsIGVycm9yKTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgICByZXR1cm4gcmVidWlsZFF1ZXVlO1xuICAgICAgICB9O1xuXG4gICAgICAgIGNvbnN0IHJlYWRTb3VyY2VTbmFwc2hvdCA9IChmaWxlOiBzdHJpbmcpID0+XG4gICAgICAgICAgY3JlYXRlU291cmNlU25hcHNob3QoeyBmaWxlLCBkZXRlY3RXb3JrZmxvd1BhdHRlcm5zIH0pO1xuXG4gICAgICAgIGNvbnN0IHJlZnJlc2hTb3VyY2VTbmFwc2hvdHMgPSAoKSA9PlxuICAgICAgICAgIHJlcGxhY2VTb3VyY2VTbmFwc2hvdHMoe1xuICAgICAgICAgICAgZGlzY292ZXJlZEVudHJpZXMsXG4gICAgICAgICAgICBpbnB1dEZpbGVzOiBvcHRpb25zLmlucHV0RmlsZXMsXG4gICAgICAgICAgICBub3JtYWxpemVQYXRoLFxuICAgICAgICAgICAgcmVhZFNuYXBzaG90OiByZWFkU291cmNlU25hcHNob3QsXG4gICAgICAgICAgICBzb3VyY2VTbmFwc2hvdHMsXG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgY29uc3QgbWVyZ2VDb21iaW5lZE1hbmlmZXN0ID0gKFxuICAgICAgICAgIG5leHRTdGVwc01hbmlmZXN0OiBXb3JrZmxvd01hbmlmZXN0XG4gICAgICAgICk6IFdvcmtmbG93TWFuaWZlc3QgPT4gKHtcbiAgICAgICAgICAuLi5uZXh0U3RlcHNNYW5pZmVzdCxcbiAgICAgICAgICB3b3JrZmxvd3M6IHtcbiAgICAgICAgICAgIC4uLm5leHRTdGVwc01hbmlmZXN0LndvcmtmbG93cyxcbiAgICAgICAgICAgIC4uLndvcmtmbG93c01hbmlmZXN0LndvcmtmbG93cyxcbiAgICAgICAgICB9LFxuICAgICAgICAgIGNsYXNzZXM6IHtcbiAgICAgICAgICAgIC4uLm5leHRTdGVwc01hbmlmZXN0LmNsYXNzZXMsXG4gICAgICAgICAgICAuLi53b3JrZmxvd3NNYW5pZmVzdC5jbGFzc2VzLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0pO1xuXG4gICAgICAgIGNvbnN0IGhvdFJlYnVpbGQgPSBhc3luYyAocmVmcmVzaFN0ZXBSZWdpc3RyYXRpb25zOiBib29sZWFuKSA9PiB7XG4gICAgICAgICAgaWYgKHJlZnJlc2hTdGVwUmVnaXN0cmF0aW9ucykge1xuICAgICAgICAgICAgaWYgKHN0ZXBzQ3R4KSB7XG4gICAgICAgICAgICAgIGF3YWl0IHN0ZXBzQ3R4LnJlYnVpbGQoKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIHN0ZXBzTWFuaWZlc3QgPSBhd2FpdCB0aGlzLmNyZWF0ZVN0ZXBTb3VyY2VSZWdpc3RyYXRpb25GaWxlKHtcbiAgICAgICAgICAgICAgICBpbnB1dEZpbGVzOiBvcHRpb25zLmlucHV0RmlsZXMsXG4gICAgICAgICAgICAgICAgb3V0ZmlsZTogc3RlcHNPdXRmaWxlLFxuICAgICAgICAgICAgICAgIHRzY29uZmlnUGF0aCxcbiAgICAgICAgICAgICAgICBkaXNjb3ZlcmVkRW50cmllcyxcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgY29uc3Qgd29ya2Zsb3dSZXN1bHQgPSBhd2FpdCB3b3JrZmxvd3NDdHguaW50ZXJpbUJ1bmRsZUN0eC5yZWJ1aWxkKCk7XG4gICAgICAgICAgY29uc3Qgd29ya2Zsb3dPdXRwdXQgPSB3b3JrZmxvd1Jlc3VsdC5vdXRwdXRGaWxlcz8uWzBdPy50ZXh0O1xuICAgICAgICAgIGlmICghd29ya2Zsb3dPdXRwdXQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICAgICAgJ0ludmFyaWFudDogZXhwZWN0ZWQgd29ya2Zsb3cgb3V0cHV0IGZyb20gaG90IHJlYnVpbGQnXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGF3YWl0IHdvcmtmbG93c0N0eC5idW5kbGVGaW5hbCh3b3JrZmxvd091dHB1dCk7XG4gICAgICAgICAgYXdhaXQgd3JpdGVNYW5pZmVzdChtZXJnZUNvbWJpbmVkTWFuaWZlc3Qoc3RlcHNNYW5pZmVzdCkpO1xuICAgICAgICB9O1xuXG4gICAgICAgIGNvbnN0IGZ1bGxSZWJ1aWxkID0gYXN5bmMgKCkgPT4ge1xuICAgICAgICAgIHRoaXMuY2xlYXJEaXNjb3ZlcmVkRW50cmllc0NhY2hlKCk7XG4gICAgICAgICAgY29uc3QgbmV3SW5wdXRGaWxlcyA9IGF3YWl0IHRoaXMuZ2V0SW5wdXRGaWxlcygpO1xuICAgICAgICAgIG9wdGlvbnMuaW5wdXRGaWxlcyA9IG5ld0lucHV0RmlsZXM7XG5cbiAgICAgICAgICBhd2FpdCBzdGVwc0N0eD8uZGlzcG9zZSgpO1xuICAgICAgICAgIGF3YWl0IHdvcmtmbG93c0N0eC5pbnRlcmltQnVuZGxlQ3R4LmRpc3Bvc2UoKTtcblxuICAgICAgICAgIGNvbnN0IG5ld0NvbWJpbmVkID0gYXdhaXQgdGhpcy5idWlsZENvbWJpbmVkRnVuY3Rpb24ob3B0aW9ucyk7XG4gICAgICAgICAgc3RlcHNDdHggPSBuZXdDb21iaW5lZC5zdGVwc0NvbnRleHQ7XG4gICAgICAgICAgZGlzY292ZXJlZEVudHJpZXMgPSBuZXdDb21iaW5lZC5kaXNjb3ZlcmVkRW50cmllcztcbiAgICAgICAgICBzdGVwc01hbmlmZXN0ID0gbmV3Q29tYmluZWQuc3RlcHNNYW5pZmVzdDtcbiAgICAgICAgICB3b3JrZmxvd3NNYW5pZmVzdCA9IG5ld0NvbWJpbmVkLndvcmtmbG93c01hbmlmZXN0O1xuXG4gICAgICAgICAgaWYgKCFuZXdDb21iaW5lZD8uaW50ZXJpbUJ1bmRsZUN0eCB8fCAhbmV3Q29tYmluZWQ/LmJ1bmRsZUZpbmFsKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgICAgICdJbnZhcmlhbnQ6IGV4cGVjdGVkIHdvcmtmbG93cyBidW5kbGUgY29udGV4dCBhZnRlciByZWJ1aWxkJ1xuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgd29ya2Zsb3dzQ3R4ID0ge1xuICAgICAgICAgICAgaW50ZXJpbUJ1bmRsZUN0eDogbmV3Q29tYmluZWQuaW50ZXJpbUJ1bmRsZUN0eCxcbiAgICAgICAgICAgIGJ1bmRsZUZpbmFsOiBuZXdDb21iaW5lZC5idW5kbGVGaW5hbCxcbiAgICAgICAgICB9O1xuXG4gICAgICAgICAgYXdhaXQgd3JpdGVNYW5pZmVzdChuZXdDb21iaW5lZC5tYW5pZmVzdCk7XG4gICAgICAgICAgYXdhaXQgcmVmcmVzaFNvdXJjZVNuYXBzaG90cygpO1xuICAgICAgICB9O1xuXG4gICAgICAgIGNvbnN0IGlzV2F0Y2hhYmxlRmlsZSA9IChwYXRoOiBzdHJpbmcpID0+XG4gICAgICAgICAgd2F0Y2hhYmxlRXh0ZW5zaW9ucy5oYXMoZXh0bmFtZShwYXRoKSk7XG5cbiAgICAgICAgY29uc3QgcmVhZEtub3duRmlsZXMgPSBhc3luYyAoKSA9PiB7XG4gICAgICAgICAgY29uc3QgZmlsZXMgPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgICAgICAgICBjb25zdCBhbGlhc2VzID0gbmV3IE1hcDxzdHJpbmcsIHN0cmluZz4oKTtcbiAgICAgICAgICBjb25zdCByZWxldmFudEZpbGVzID0gZ2V0UmVsZXZhbnRGaWxlcyh7XG4gICAgICAgICAgICBkaXNjb3ZlcmVkRW50cmllcyxcbiAgICAgICAgICAgIGlucHV0RmlsZXM6IG9wdGlvbnMuaW5wdXRGaWxlcyxcbiAgICAgICAgICAgIG5vcm1hbGl6ZVBhdGgsXG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgICBjb25zdCBhZGRLbm93bkZpbGUgPSBhc3luYyAoZmlsZVBhdGg6IHN0cmluZykgPT4ge1xuICAgICAgICAgICAgbGV0IHJlYWxGaWxlUGF0aCA9IGZpbGVQYXRoO1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgcmVhbEZpbGVQYXRoID0gbm9ybWFsaXplUGF0aChhd2FpdCByZWFscGF0aChmaWxlUGF0aCkpO1xuICAgICAgICAgICAgfSBjYXRjaCB7fVxuXG4gICAgICAgICAgICBjb25zdCBjYW5vbmljYWxQYXRoID0gcmVsZXZhbnRGaWxlcy5oYXMocmVhbEZpbGVQYXRoKVxuICAgICAgICAgICAgICA/IHJlYWxGaWxlUGF0aFxuICAgICAgICAgICAgICA6IGZpbGVQYXRoO1xuICAgICAgICAgICAgZmlsZXMuYWRkKGNhbm9uaWNhbFBhdGgpO1xuICAgICAgICAgICAgYWxpYXNlcy5zZXQoZmlsZVBhdGgsIGNhbm9uaWNhbFBhdGgpO1xuICAgICAgICAgICAgYWxpYXNlcy5zZXQocmVhbEZpbGVQYXRoLCBjYW5vbmljYWxQYXRoKTtcbiAgICAgICAgICAgIHJldHVybiBjYW5vbmljYWxQYXRoO1xuICAgICAgICAgIH07XG5cbiAgICAgICAgICBjb25zdCB2aXNpdCA9IGFzeW5jIChkaXJlY3Rvcnk6IHN0cmluZyk6IFByb21pc2U8dm9pZD4gPT4ge1xuICAgICAgICAgICAgbGV0IGRpcmVudHM6IERpcmVudDxzdHJpbmc+W107XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICBkaXJlbnRzID0gYXdhaXQgcmVhZGRpcihkaXJlY3RvcnksIHsgd2l0aEZpbGVUeXBlczogdHJ1ZSB9KTtcbiAgICAgICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgICAgICAgICBkaXJlbnRzLm1hcChhc3luYyAoZGlyZW50KSA9PiB7XG4gICAgICAgICAgICAgICAgY29uc3QgZmlsZVBhdGggPSBub3JtYWxpemVQYXRoKGpvaW4oZGlyZWN0b3J5LCBkaXJlbnQubmFtZSkpO1xuICAgICAgICAgICAgICAgIGlmIChoYXNJZ25vcmVkUGF0aEZyYWdtZW50KGZpbGVQYXRoKSkge1xuICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGlmIChkaXJlbnQuaXNEaXJlY3RvcnkoKSkge1xuICAgICAgICAgICAgICAgICAgYXdhaXQgdmlzaXQoZmlsZVBhdGgpO1xuICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGxldCBzdGF0czogQXdhaXRlZDxSZXR1cm5UeXBlPHR5cGVvZiBzdGF0Pj47XG4gICAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAgIHN0YXRzID0gYXdhaXQgc3RhdChmaWxlUGF0aCk7XG4gICAgICAgICAgICAgICAgfSBjYXRjaCB7XG4gICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKHN0YXRzLmlzRGlyZWN0b3J5KCkpIHtcbiAgICAgICAgICAgICAgICAgIGF3YWl0IHZpc2l0KGZpbGVQYXRoKTtcbiAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZiAoIXN0YXRzLmlzRmlsZSgpIHx8ICFpc1dhdGNoYWJsZUZpbGUoZmlsZVBhdGgpKSB7XG4gICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgYXdhaXQgYWRkS25vd25GaWxlKGZpbGVQYXRoKTtcbiAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfTtcblxuICAgICAgICAgIGF3YWl0IHZpc2l0KHRoaXMuY29uZmlnLndvcmtpbmdEaXIpO1xuICAgICAgICAgIHJldHVybiB7IGZpbGVzLCBhbGlhc2VzLCBhZGRLbm93bkZpbGUgfTtcbiAgICAgICAgfTtcblxuICAgICAgICBjb25zdCBtZXJnZUZpbGVDaGFuZ2VzID0gKFxuICAgICAgICAgIGxlZnQ6IEZpbGVDaGFuZ2VzLFxuICAgICAgICAgIHJpZ2h0OiBGaWxlQ2hhbmdlc1xuICAgICAgICApOiBGaWxlQ2hhbmdlcyA9PiAoe1xuICAgICAgICAgIGFkZGVkRmlsZXM6IHVuaXF1ZShbLi4ubGVmdC5hZGRlZEZpbGVzLCAuLi5yaWdodC5hZGRlZEZpbGVzXSksXG4gICAgICAgICAgbW9kaWZpZWRGaWxlczogdW5pcXVlKFtcbiAgICAgICAgICAgIC4uLmxlZnQubW9kaWZpZWRGaWxlcyxcbiAgICAgICAgICAgIC4uLnJpZ2h0Lm1vZGlmaWVkRmlsZXMsXG4gICAgICAgICAgXSksXG4gICAgICAgICAgcmVtb3ZlZEZpbGVzOiB1bmlxdWUoWy4uLmxlZnQucmVtb3ZlZEZpbGVzLCAuLi5yaWdodC5yZW1vdmVkRmlsZXNdKSxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgY29uc3QgdW5pcXVlID0gKHBhdGhzOiBzdHJpbmdbXSkgPT4gWy4uLm5ldyBTZXQocGF0aHMpXTtcblxuICAgICAgICBjb25zdCBjbGFzc2lmeUZpbGVDaGFuZ2VzID0gKHtcbiAgICAgICAgICBjaGFuZ2VkRmlsZXMsXG4gICAgICAgICAga25vd25GaWxlcyxcbiAgICAgICAgICByZW1vdmVkRmlsZXMsXG4gICAgICAgIH06IHtcbiAgICAgICAgICBjaGFuZ2VkRmlsZXM6IHN0cmluZ1tdO1xuICAgICAgICAgIGtub3duRmlsZXM6IFNldDxzdHJpbmc+O1xuICAgICAgICAgIHJlbW92ZWRGaWxlczogc3RyaW5nW107XG4gICAgICAgIH0pOiBGaWxlQ2hhbmdlcyA9PiB7XG4gICAgICAgICAgY29uc3QgYWRkZWRGaWxlczogc3RyaW5nW10gPSBbXTtcbiAgICAgICAgICBjb25zdCBtb2RpZmllZEZpbGVzOiBzdHJpbmdbXSA9IFtdO1xuXG4gICAgICAgICAgZm9yIChjb25zdCBmaWxlIG9mIHVuaXF1ZShjaGFuZ2VkRmlsZXMpKSB7XG4gICAgICAgICAgICBpZiAoa25vd25GaWxlcy5oYXMoZmlsZSkpIHtcbiAgICAgICAgICAgICAgbW9kaWZpZWRGaWxlcy5wdXNoKGZpbGUpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgYWRkZWRGaWxlcy5wdXNoKGZpbGUpO1xuICAgICAgICAgICAgICBrbm93bkZpbGVzLmFkZChmaWxlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG5cbiAgICAgICAgICBmb3IgKGNvbnN0IGZpbGUgb2YgcmVtb3ZlZEZpbGVzKSB7XG4gICAgICAgICAgICBrbm93bkZpbGVzLmRlbGV0ZShmaWxlKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgYWRkZWRGaWxlcyxcbiAgICAgICAgICAgIG1vZGlmaWVkRmlsZXMsXG4gICAgICAgICAgICByZW1vdmVkRmlsZXM6IHVuaXF1ZShyZW1vdmVkRmlsZXMpLFxuICAgICAgICAgIH07XG4gICAgICAgIH07XG5cbiAgICAgICAgY29uc3QgaGFzRmlsZUNoYW5nZXMgPSAoe1xuICAgICAgICAgIGFkZGVkRmlsZXMsXG4gICAgICAgICAgbW9kaWZpZWRGaWxlcyxcbiAgICAgICAgICByZW1vdmVkRmlsZXMsXG4gICAgICAgIH06IEZpbGVDaGFuZ2VzKSA9PlxuICAgICAgICAgIGFkZGVkRmlsZXMubGVuZ3RoID4gMCB8fFxuICAgICAgICAgIG1vZGlmaWVkRmlsZXMubGVuZ3RoID4gMCB8fFxuICAgICAgICAgIHJlbW92ZWRGaWxlcy5sZW5ndGggPiAwO1xuICAgICAgICBjb25zdCBsb2dEZXZIbXIgPSAoLi4uYXJnczogdW5rbm93bltdKSA9PiB7XG4gICAgICAgICAgaWYgKHByb2Nlc3MuZW52LldPUktGTE9XX0RFVl9ITVJfTE9HUyA9PT0gJzEnKSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyguLi5hcmdzKTtcbiAgICAgICAgICB9XG4gICAgICAgIH07XG5cbiAgICAgICAgYXdhaXQgcmVmcmVzaFNvdXJjZVNuYXBzaG90cygpO1xuICAgICAgICBsZXQge1xuICAgICAgICAgIGZpbGVzOiBrbm93bkZpbGVzLFxuICAgICAgICAgIGFsaWFzZXM6IGtub3duRmlsZUFsaWFzZXMsXG4gICAgICAgICAgYWRkS25vd25GaWxlOiByZW1lbWJlcktub3duRmlsZSxcbiAgICAgICAgfSA9IGF3YWl0IHJlYWRLbm93bkZpbGVzKCk7XG5cbiAgICAgICAgY29uc3QgcmVmcmVzaEtub3duRmlsZXMgPSBhc3luYyAoKSA9PiB7XG4gICAgICAgICAgY29uc3QgbmV4dEtub3duID0gYXdhaXQgcmVhZEtub3duRmlsZXMoKTtcbiAgICAgICAgICBrbm93bkZpbGVzID0gbmV4dEtub3duLmZpbGVzO1xuICAgICAgICAgIGtub3duRmlsZUFsaWFzZXMgPSBuZXh0S25vd24uYWxpYXNlcztcbiAgICAgICAgICByZW1lbWJlcktub3duRmlsZSA9IG5leHRLbm93bi5hZGRLbm93bkZpbGU7XG4gICAgICAgIH07XG5cbiAgICAgICAgY29uc3QgcHJvY2Vzc0ZpbGVDaGFuZ2VzID0gYXN5bmMgKGZpbGVDaGFuZ2VzOiBGaWxlQ2hhbmdlcykgPT4ge1xuICAgICAgICAgIGlmICghaGFzRmlsZUNoYW5nZXMoZmlsZUNoYW5nZXMpKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgY29uc3QgZGVjaXNpb24gPSBhd2FpdCBjbGFzc2lmeVJlYnVpbGQoe1xuICAgICAgICAgICAgZGlzY292ZXJlZEVudHJpZXMsXG4gICAgICAgICAgICBmaWxlQ2hhbmdlcyxcbiAgICAgICAgICAgIGlucHV0RmlsZXM6IG9wdGlvbnMuaW5wdXRGaWxlcyxcbiAgICAgICAgICAgIG5vcm1hbGl6ZVBhdGgsXG4gICAgICAgICAgICBwYXJlbnRIYXNDaGlsZCxcbiAgICAgICAgICAgIHJlYWRTbmFwc2hvdDogcmVhZFNvdXJjZVNuYXBzaG90LFxuICAgICAgICAgICAgc291cmNlU25hcHNob3RzLFxuICAgICAgICAgIH0pO1xuICAgICAgICAgIGlmIChkZWNpc2lvbi5raW5kID09PSAnbm9uZScpIHtcbiAgICAgICAgICAgIGxvZ0Rldkhtcignd29ya2Zsb3cgZGV2IGhtcjogc2tpcCcpO1xuICAgICAgICAgICAgZm9yIChjb25zdCBbZmlsZSwgc25hcHNob3RdIG9mIGRlY2lzaW9uLnNuYXBzaG90cyB8fCBbXSkge1xuICAgICAgICAgICAgICBzb3VyY2VTbmFwc2hvdHMuc2V0KGZpbGUsIHNuYXBzaG90KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICB9XG4gICAgICAgICAgaWYgKGRlY2lzaW9uLmtpbmQgPT09ICdmdWxsJykge1xuICAgICAgICAgICAgbG9nRGV2SG1yKCd3b3JrZmxvdyBkZXYgaG1yOiBmdWxsIHJlZGlzY292ZXJ5Jyk7XG4gICAgICAgICAgICBhd2FpdCBmdWxsUmVidWlsZCgpO1xuICAgICAgICAgICAgYXdhaXQgcmVmcmVzaEtub3duRmlsZXMoKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBsb2dEZXZIbXIoXG4gICAgICAgICAgICBgd29ya2Zsb3cgZGV2IGhtcjogaG90IHJlYnVpbGQke2RlY2lzaW9uLnJlZnJlc2hTdGVwUmVnaXN0cmF0aW9ucyA/ICcgd2l0aCBzdGVwIHJlZ2lzdHJhdGlvbiByZWZyZXNoJyA6ICcnfWBcbiAgICAgICAgICApO1xuICAgICAgICAgIGF3YWl0IGhvdFJlYnVpbGQoZGVjaXNpb24ucmVmcmVzaFN0ZXBSZWdpc3RyYXRpb25zKTtcbiAgICAgICAgICBmb3IgKGNvbnN0IFtmaWxlLCBzbmFwc2hvdF0gb2YgZGVjaXNpb24uc25hcHNob3RzKSB7XG4gICAgICAgICAgICBzb3VyY2VTbmFwc2hvdHMuc2V0KGZpbGUsIHNuYXBzaG90KTtcbiAgICAgICAgICB9XG4gICAgICAgIH07XG5cbiAgICAgICAgbGV0IHBlbmRpbmdGaWxlQ2hhbmdlczogRmlsZUNoYW5nZXMgPSB7XG4gICAgICAgICAgYWRkZWRGaWxlczogW10sXG4gICAgICAgICAgbW9kaWZpZWRGaWxlczogW10sXG4gICAgICAgICAgcmVtb3ZlZEZpbGVzOiBbXSxcbiAgICAgICAgfTtcbiAgICAgICAgbGV0IGZsdXNoVGltZXI6IFJldHVyblR5cGU8dHlwZW9mIHNldFRpbWVvdXQ+IHwgdW5kZWZpbmVkO1xuXG4gICAgICAgIGNvbnN0IHNjaGVkdWxlRmlsZUNoYW5nZXMgPSAoZmlsZUNoYW5nZXM6IEZpbGVDaGFuZ2VzKSA9PiB7XG4gICAgICAgICAgcGVuZGluZ0ZpbGVDaGFuZ2VzID0gbWVyZ2VGaWxlQ2hhbmdlcyhcbiAgICAgICAgICAgIHBlbmRpbmdGaWxlQ2hhbmdlcyxcbiAgICAgICAgICAgIGZpbGVDaGFuZ2VzXG4gICAgICAgICAgKTtcbiAgICAgICAgICBpZiAoZmx1c2hUaW1lcikge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cbiAgICAgICAgICBmbHVzaFRpbWVyID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgICBjb25zdCBmaWxlQ2hhbmdlcyA9IHBlbmRpbmdGaWxlQ2hhbmdlcztcbiAgICAgICAgICAgIHBlbmRpbmdGaWxlQ2hhbmdlcyA9IHtcbiAgICAgICAgICAgICAgYWRkZWRGaWxlczogW10sXG4gICAgICAgICAgICAgIG1vZGlmaWVkRmlsZXM6IFtdLFxuICAgICAgICAgICAgICByZW1vdmVkRmlsZXM6IFtdLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIGZsdXNoVGltZXIgPSB1bmRlZmluZWQ7XG4gICAgICAgICAgICBlbnF1ZXVlKCgpID0+IHByb2Nlc3NGaWxlQ2hhbmdlcyhmaWxlQ2hhbmdlcykpO1xuICAgICAgICAgIH0sIDEwKTtcbiAgICAgICAgfTtcblxuICAgICAgICBjb25zdCByZXNvbHZlRXhpc3RpbmdFdmVudFBhdGggPSBhc3luYyAocGF0aG5hbWU6IHN0cmluZykgPT4ge1xuICAgICAgICAgIGNvbnN0IG5vcm1hbGl6ZWRQYXRoID0gbm9ybWFsaXplUGF0aChwYXRobmFtZSk7XG4gICAgICAgICAgaWYgKCFpc1dhdGNoYWJsZUZpbGUobm9ybWFsaXplZFBhdGgpKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgY29uc3Qga25vd25QYXRoID0ga25vd25GaWxlQWxpYXNlcy5nZXQobm9ybWFsaXplZFBhdGgpO1xuICAgICAgICAgIGlmIChrbm93blBhdGgpIHtcbiAgICAgICAgICAgIHJldHVybiBrbm93blBhdGg7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGNvbnN0IHJlYWxGaWxlUGF0aCA9IG5vcm1hbGl6ZVBhdGgoYXdhaXQgcmVhbHBhdGgobm9ybWFsaXplZFBhdGgpKTtcbiAgICAgICAgICAgIHJldHVybiBrbm93bkZpbGVBbGlhc2VzLmdldChyZWFsRmlsZVBhdGgpID8/IG5vcm1hbGl6ZWRQYXRoO1xuICAgICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgICAgcmV0dXJuIG5vcm1hbGl6ZWRQYXRoO1xuICAgICAgICAgIH1cbiAgICAgICAgfTtcblxuICAgICAgICBjb25zdCBoYW5kbGVGaWxlQWRkZWQgPSBhc3luYyAocGF0aG5hbWU6IHN0cmluZykgPT4ge1xuICAgICAgICAgIGNvbnN0IG5vcm1hbGl6ZWRQYXRoID0gbm9ybWFsaXplUGF0aChwYXRobmFtZSk7XG4gICAgICAgICAgaWYgKCFpc1dhdGNoYWJsZUZpbGUobm9ybWFsaXplZFBhdGgpKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgY29uc3QgZXhpc3RpbmdQYXRoID0gYXdhaXQgcmVzb2x2ZUV4aXN0aW5nRXZlbnRQYXRoKG5vcm1hbGl6ZWRQYXRoKTtcbiAgICAgICAgICBjb25zdCB3YXNLbm93biA9IGV4aXN0aW5nUGF0aCA/IGtub3duRmlsZXMuaGFzKGV4aXN0aW5nUGF0aCkgOiBmYWxzZTtcbiAgICAgICAgICBjb25zdCBjYW5vbmljYWxQYXRoID0gYXdhaXQgcmVtZW1iZXJLbm93bkZpbGUobm9ybWFsaXplZFBhdGgpO1xuICAgICAgICAgIGtub3duRmlsZXMuYWRkKGNhbm9uaWNhbFBhdGgpO1xuICAgICAgICAgIHNjaGVkdWxlRmlsZUNoYW5nZXMoe1xuICAgICAgICAgICAgYWRkZWRGaWxlczogd2FzS25vd24gPyBbXSA6IFtjYW5vbmljYWxQYXRoXSxcbiAgICAgICAgICAgIG1vZGlmaWVkRmlsZXM6IHdhc0tub3duID8gW2Nhbm9uaWNhbFBhdGhdIDogW10sXG4gICAgICAgICAgICByZW1vdmVkRmlsZXM6IFtdLFxuICAgICAgICAgIH0pO1xuICAgICAgICB9O1xuXG4gICAgICAgIGNvbnN0IGhhbmRsZUZpbGVDaGFuZ2VkID0gYXN5bmMgKHBhdGhuYW1lOiBzdHJpbmcpID0+IHtcbiAgICAgICAgICBjb25zdCBjYW5vbmljYWxQYXRoID0gYXdhaXQgcmVzb2x2ZUV4aXN0aW5nRXZlbnRQYXRoKHBhdGhuYW1lKTtcbiAgICAgICAgICBpZiAoIWNhbm9uaWNhbFBhdGgpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBjb25zdCBmaWxlQ2hhbmdlcyA9IGNsYXNzaWZ5RmlsZUNoYW5nZXMoe1xuICAgICAgICAgICAgY2hhbmdlZEZpbGVzOiBbY2Fub25pY2FsUGF0aF0sXG4gICAgICAgICAgICBrbm93bkZpbGVzLFxuICAgICAgICAgICAgcmVtb3ZlZEZpbGVzOiBbXSxcbiAgICAgICAgICB9KTtcbiAgICAgICAgICBpZiAoIWtub3duRmlsZUFsaWFzZXMuaGFzKGNhbm9uaWNhbFBhdGgpKSB7XG4gICAgICAgICAgICBhd2FpdCByZW1lbWJlcktub3duRmlsZShjYW5vbmljYWxQYXRoKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgc2NoZWR1bGVGaWxlQ2hhbmdlcyhmaWxlQ2hhbmdlcyk7XG4gICAgICAgIH07XG5cbiAgICAgICAgY29uc3QgaGFuZGxlRmlsZVJlbW92ZWQgPSAocGF0aG5hbWU6IHN0cmluZykgPT4ge1xuICAgICAgICAgIGNvbnN0IG5vcm1hbGl6ZWRQYXRoID0gbm9ybWFsaXplUGF0aChwYXRobmFtZSk7XG4gICAgICAgICAgaWYgKCFpc1dhdGNoYWJsZUZpbGUobm9ybWFsaXplZFBhdGgpKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgY29uc3QgY2Fub25pY2FsUGF0aCA9XG4gICAgICAgICAgICBrbm93bkZpbGVBbGlhc2VzLmdldChub3JtYWxpemVkUGF0aCkgPz8gbm9ybWFsaXplZFBhdGg7XG4gICAgICAgICAgY29uc3QgZmlsZUNoYW5nZXMgPSBjbGFzc2lmeUZpbGVDaGFuZ2VzKHtcbiAgICAgICAgICAgIGNoYW5nZWRGaWxlczogW10sXG4gICAgICAgICAgICBrbm93bkZpbGVzLFxuICAgICAgICAgICAgcmVtb3ZlZEZpbGVzOiBbY2Fub25pY2FsUGF0aF0sXG4gICAgICAgICAgfSk7XG4gICAgICAgICAga25vd25GaWxlQWxpYXNlcy5kZWxldGUobm9ybWFsaXplZFBhdGgpO1xuICAgICAgICAgIHNjaGVkdWxlRmlsZUNoYW5nZXMoZmlsZUNoYW5nZXMpO1xuICAgICAgICB9O1xuXG4gICAgICAgIGNvbnN0IHdhdGNoZXIgPSBjaG9raWRhci53YXRjaCh0aGlzLmNvbmZpZy53b3JraW5nRGlyLCB7XG4gICAgICAgICAgaWdub3JlSW5pdGlhbDogdHJ1ZSxcbiAgICAgICAgICBmb2xsb3dTeW1saW5rczogdHJ1ZSxcbiAgICAgICAgICBpZ25vcmVkOiAocGF0aG5hbWUpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IG5vcm1hbGl6ZWRQYXRoID0gbm9ybWFsaXplUGF0aChTdHJpbmcocGF0aG5hbWUpKTtcbiAgICAgICAgICAgIGNvbnN0IGV4dGVuc2lvbiA9IGV4dG5hbWUobm9ybWFsaXplZFBhdGgpO1xuICAgICAgICAgICAgaWYgKGV4dGVuc2lvbiAmJiAhd2F0Y2hhYmxlRXh0ZW5zaW9ucy5oYXMoZXh0ZW5zaW9uKSkge1xuICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBoYXNJZ25vcmVkUGF0aEZyYWdtZW50KG5vcm1hbGl6ZWRQYXRoKTtcbiAgICAgICAgICB9LFxuICAgICAgICB9KTtcblxuICAgICAgICB3YXRjaGVyLm9uKCdhZGQnLCAocGF0aG5hbWUpID0+IHtcbiAgICAgICAgICB2b2lkIGhhbmRsZUZpbGVBZGRlZChwYXRobmFtZSk7XG4gICAgICAgIH0pO1xuICAgICAgICB3YXRjaGVyLm9uKCdjaGFuZ2UnLCAocGF0aG5hbWUpID0+IHtcbiAgICAgICAgICB2b2lkIGhhbmRsZUZpbGVDaGFuZ2VkKHBhdGhuYW1lKTtcbiAgICAgICAgfSk7XG4gICAgICAgIHdhdGNoZXIub24oJ3VubGluaycsIChwYXRobmFtZSkgPT4ge1xuICAgICAgICAgIGhhbmRsZUZpbGVSZW1vdmVkKHBhdGhuYW1lKTtcbiAgICAgICAgfSk7XG4gICAgICAgIHdhdGNoZXIub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XG4gICAgICAgICAgY29uc29sZS5lcnJvcignV29ya2Zsb3cgZGV2IHdhdGNoZXIgZXJyb3InLCBlcnJvcik7XG4gICAgICAgIH0pO1xuICAgICAgICB3YXRjaGVyLm9uKCdyZWFkeScsICgpID0+IHtcbiAgICAgICAgICBsb2dEZXZIbXIoJ3dvcmtmbG93IGRldiBobXI6IHJlYWR5Jyk7XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH1cblxuICAgIHByb3RlY3RlZCBhc3luYyBnZXRJbnB1dEZpbGVzKCk6IFByb21pc2U8c3RyaW5nW10+IHtcbiAgICAgIGNvbnN0IGlucHV0RmlsZXMgPSBhd2FpdCBzdXBlci5nZXRJbnB1dEZpbGVzKCk7XG4gICAgICByZXR1cm4gaW5wdXRGaWxlcy5maWx0ZXIoKGZpbGUpID0+IHtcbiAgICAgICAgY29uc3QgZW50cnkgPSByZWxhdGl2ZSh0aGlzLmNvbmZpZy53b3JraW5nRGlyLCBmaWxlKS5yZXBsYWNlQWxsKFxuICAgICAgICAgICdcXFxcJyxcbiAgICAgICAgICAnLydcbiAgICAgICAgKTtcblxuICAgICAgICAvLyBNYXRjaCBBcHAgUm91dGVyIHJvdXRlLCBwYWdlLCBhbmQgbGF5b3V0IGVudHJ5cG9pbnRzIGluIGFwcC8gb3Igc3JjL2FwcC8uXG4gICAgICAgIGlmICgvXig/OmFwcHxzcmNcXC9hcHApXFwvKD86LipcXC8pPyg/OnJvdXRlfHBhZ2V8bGF5b3V0KVxcLi8udGVzdChlbnRyeSkpIHtcbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIE1hdGNoIGV2ZXJ5IFBhZ2VzIFJvdXRlciBlbnRyeXBvaW50IGluIHBhZ2VzLyBvciBzcmMvcGFnZXMvLlxuICAgICAgICBpZiAoL14oPzpwYWdlc3xzcmNcXC9wYWdlcylcXC8vLnRlc3QoZW50cnkpKSB7XG4gICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBNYXRjaCBOZXh0LmpzIHJvb3QgZW50cnlwb2ludHMgYXQgdGhlIHByb2plY3Qgcm9vdCBvciB1bmRlciBzcmMvLlxuICAgICAgICByZXR1cm4gWydpbnN0cnVtZW50YXRpb24nLCAnbWlkZGxld2FyZScsICdwcm94eSddLnNvbWUoKG5hbWUpID0+XG4gICAgICAgICAgdGhpcy5jb25maWcucGFnZUV4dGVuc2lvbnMuc29tZShcbiAgICAgICAgICAgIChleHRlbnNpb24pID0+XG4gICAgICAgICAgICAgIGVudHJ5ID09PSBgJHtuYW1lfS4ke2V4dGVuc2lvbn1gIHx8XG4gICAgICAgICAgICAgIGVudHJ5ID09PSBgc3JjLyR7bmFtZX0uJHtleHRlbnNpb259YFxuICAgICAgICAgIClcbiAgICAgICAgKTtcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgd3JpdGVGdW5jdGlvbnNDb25maWcob3V0cHV0RGlyOiBzdHJpbmcpIHtcbiAgICAgIC8vIHdlIGRvbid0IHJ1biB0aGlzIGluIGRldmVsb3BtZW50IG1vZGUgYXMgaXQncyBub3QgbmVlZGVkXG4gICAgICBpZiAocHJvY2Vzcy5lbnYuTk9ERV9FTlYgPT09ICdkZXZlbG9wbWVudCcpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICAvLyBWMiBjb21iaW5lZCBjb25maWc6IHNpbmdsZSB0cmlnZ2VyIGhhbmRsZXMgYm90aCB3b3JrZmxvdyBhbmQgc3RlcCBleGVjdXRpb24uXG4gICAgICAvLyBUaGUgc3RlcCByb3V0ZSBubyBsb25nZXIgbmVlZHMgaXRzIG93biB0cmlnZ2VyIHNpbmNlIHN0ZXBzIGFyZSBleGVjdXRlZFxuICAgICAgLy8gaW5saW5lIGJ5IHRoZSBjb21iaW5lZCBoYW5kbGVyIG9yIHF1ZXVlZCBiYWNrIHRvIF9fd2tmX3dvcmtmbG93Xyogd2l0aCBzdGVwSWQuXG4gICAgICBjb25zdCBnZW5lcmF0ZWRDb25maWcgPSB7XG4gICAgICAgIHZlcnNpb246ICcwJyxcbiAgICAgICAgd29ya2Zsb3dzOiB7XG4gICAgICAgICAgbWF4RHVyYXRpb246ICdtYXgnLFxuICAgICAgICAgIGV4cGVyaW1lbnRhbFRyaWdnZXJzOiBbZ2V0V29ya2Zsb3dRdWV1ZVRyaWdnZXIoKV0sXG4gICAgICAgIH0sXG4gICAgICB9O1xuXG4gICAgICBhd2FpdCB3cml0ZUZpbGUoXG4gICAgICAgIGpvaW4ob3V0cHV0RGlyLCAnLndlbGwta25vd24vd29ya2Zsb3cvdjEvY29uZmlnLmpzb24nKSxcbiAgICAgICAgSlNPTi5zdHJpbmdpZnkoZ2VuZXJhdGVkQ29uZmlnLCBudWxsLCAyKVxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBWMjogQnVpbGQgY29tYmluZWQgcm91dGUgdGhhdCBoYW5kbGVzIGJvdGggd29ya2Zsb3cgYW5kIHN0ZXAgZXhlY3V0aW9uLlxuICAgICAqL1xuICAgIHByaXZhdGUgYXN5bmMgYnVpbGRDb21iaW5lZEZ1bmN0aW9uKHtcbiAgICAgIGlucHV0RmlsZXMsXG4gICAgICB3b3JrZmxvd0dlbmVyYXRlZERpcixcbiAgICAgIHRzY29uZmlnUGF0aCxcbiAgICB9OiB7XG4gICAgICBpbnB1dEZpbGVzOiBzdHJpbmdbXTtcbiAgICAgIHdvcmtmbG93R2VuZXJhdGVkRGlyOiBzdHJpbmc7XG4gICAgICB0c2NvbmZpZ1BhdGg/OiBzdHJpbmc7XG4gICAgfSkge1xuICAgICAgY29uc3QgZmxvd1JvdXRlRGlyID0gam9pbih3b3JrZmxvd0dlbmVyYXRlZERpciwgJ2Zsb3cnKTtcbiAgICAgIGF3YWl0IG1rZGlyKGZsb3dSb3V0ZURpciwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG5cbiAgICAgIHJldHVybiBhd2FpdCB0aGlzLmNyZWF0ZUNvbWJpbmVkQnVuZGxlKHtcbiAgICAgICAgZm9ybWF0OiAnZXNtJyxcbiAgICAgICAgaW5wdXRGaWxlcyxcbiAgICAgICAgc3RlcHNPdXRmaWxlOiBqb2luKGZsb3dSb3V0ZURpciwgJ19fc3RlcF9yZWdpc3RyYXRpb25zLmpzJyksXG4gICAgICAgIGZsb3dPdXRmaWxlOiBqb2luKGZsb3dSb3V0ZURpciwgJ3JvdXRlLmpzJyksXG4gICAgICAgIGJ1bmRsZUZpbmFsT3V0cHV0OiBmYWxzZSxcbiAgICAgICAgZXh0ZXJuYWxpemVOb25TdGVwczogdHJ1ZSxcbiAgICAgICAgc291cmNlU3RlcFJlZ2lzdHJhdGlvbkltcG9ydHM6IHRydWUsXG4gICAgICAgIHRzY29uZmlnUGF0aCxcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgYnVpbGRXZWJob29rUm91dGUoe1xuICAgICAgd29ya2Zsb3dHZW5lcmF0ZWREaXIsXG4gICAgfToge1xuICAgICAgd29ya2Zsb3dHZW5lcmF0ZWREaXI6IHN0cmluZztcbiAgICB9KTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICBjb25zdCB3ZWJob29rUm91dGVGaWxlID0gam9pbihcbiAgICAgICAgd29ya2Zsb3dHZW5lcmF0ZWREaXIsXG4gICAgICAgICd3ZWJob29rL1t0b2tlbl0vcm91dGUuanMnXG4gICAgICApO1xuICAgICAgYXdhaXQgdGhpcy5jcmVhdGVXZWJob29rQnVuZGxlKHtcbiAgICAgICAgb3V0ZmlsZTogd2ViaG9va1JvdXRlRmlsZSxcbiAgICAgICAgYnVuZGxlOiBmYWxzZSwgLy8gTmV4dC5qcyBkb2Vzbid0IG5lZWQgYnVuZGxpbmdcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgZmluZEFwcERpcmVjdG9yeSgpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgICAgY29uc3QgYXBwRGlyID0gcmVzb2x2ZSh0aGlzLmNvbmZpZy53b3JraW5nRGlyLCAnYXBwJyk7XG4gICAgICBjb25zdCBzcmNBcHBEaXIgPSByZXNvbHZlKHRoaXMuY29uZmlnLndvcmtpbmdEaXIsICdzcmMvYXBwJyk7XG4gICAgICBjb25zdCBwYWdlc0RpciA9IHJlc29sdmUodGhpcy5jb25maWcud29ya2luZ0RpciwgJ3BhZ2VzJyk7XG4gICAgICBjb25zdCBzcmNQYWdlc0RpciA9IHJlc29sdmUodGhpcy5jb25maWcud29ya2luZ0RpciwgJ3NyYy9wYWdlcycpO1xuXG4gICAgICAvLyBIZWxwZXIgdG8gY2hlY2sgaWYgYSBwYXRoIGV4aXN0cyBhbmQgaXMgYSBkaXJlY3RvcnlcbiAgICAgIGNvbnN0IGlzRGlyZWN0b3J5ID0gYXN5bmMgKHBhdGg6IHN0cmluZyk6IFByb21pc2U8Ym9vbGVhbj4gPT4ge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGF3YWl0IGFjY2VzcyhwYXRoLCBjb25zdGFudHMuRl9PSyk7XG4gICAgICAgICAgY29uc3Qgc3RhdHMgPSBhd2FpdCBzdGF0KHBhdGgpO1xuICAgICAgICAgIGlmICghc3RhdHMuaXNEaXJlY3RvcnkoKSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBQYXRoIGV4aXN0cyBidXQgaXMgbm90IGEgZGlyZWN0b3J5OiAke3BhdGh9YCk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgaWYgKGUgaW5zdGFuY2VvZiBFcnJvciAmJiBlLm1lc3NhZ2UuaW5jbHVkZXMoJ25vdCBhIGRpcmVjdG9yeScpKSB7XG4gICAgICAgICAgICB0aHJvdyBlO1xuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgIH07XG5cbiAgICAgIC8vIENoZWNrIGlmIGFwcCBkaXJlY3RvcnkgZXhpc3RzXG4gICAgICBpZiAoYXdhaXQgaXNEaXJlY3RvcnkoYXBwRGlyKSkge1xuICAgICAgICByZXR1cm4gYXBwRGlyO1xuICAgICAgfVxuXG4gICAgICAvLyBDaGVjayBpZiBzcmMvYXBwIGRpcmVjdG9yeSBleGlzdHNcbiAgICAgIGlmIChhd2FpdCBpc0RpcmVjdG9yeShzcmNBcHBEaXIpKSB7XG4gICAgICAgIHJldHVybiBzcmNBcHBEaXI7XG4gICAgICB9XG5cbiAgICAgIC8vIElmIG5vIGFwcCBkaXJlY3RvcnkgZXhpc3RzLCBjaGVjayBmb3IgcGFnZXMgZGlyZWN0b3J5IGFuZCBjcmVhdGUgYXBwIG5leHQgdG8gaXRcbiAgICAgIGlmIChhd2FpdCBpc0RpcmVjdG9yeShwYWdlc0RpcikpIHtcbiAgICAgICAgLy8gQ3JlYXRlIGFwcCBkaXJlY3RvcnkgbmV4dCB0byBwYWdlcyBkaXJlY3RvcnlcbiAgICAgICAgYXdhaXQgbWtkaXIoYXBwRGlyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcbiAgICAgICAgcmV0dXJuIGFwcERpcjtcbiAgICAgIH1cblxuICAgICAgaWYgKGF3YWl0IGlzRGlyZWN0b3J5KHNyY1BhZ2VzRGlyKSkge1xuICAgICAgICAvLyBDcmVhdGUgc3JjL2FwcCBkaXJlY3RvcnkgbmV4dCB0byBzcmMvcGFnZXMgZGlyZWN0b3J5XG4gICAgICAgIGF3YWl0IG1rZGlyKHNyY0FwcERpciwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gICAgICAgIHJldHVybiBzcmNBcHBEaXI7XG4gICAgICB9XG5cbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgJ0NvdWxkIG5vdCBmaW5kIE5leHQuanMgYXBwIG9yIHBhZ2VzIGRpcmVjdG9yeS4gRXhwZWN0ZWQgb25lIG9mOiBcImFwcFwiLCBcInNyYy9hcHBcIiwgXCJwYWdlc1wiLCBvciBcInNyYy9wYWdlc1wiIHRvIGV4aXN0LidcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgQ2FjaGVkTmV4dEJ1aWxkZXJFYWdlciA9IE5leHRCdWlsZGVyO1xuICByZXR1cm4gTmV4dEJ1aWxkZXI7XG59XG4iXX0=