@workflow/builders 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 (123) hide show
  1. package/README.md +26 -0
  2. package/dist/apply-swc-transform.d.ts +7 -2
  3. package/dist/apply-swc-transform.d.ts.map +1 -1
  4. package/dist/apply-swc-transform.js +10 -4
  5. package/dist/base-builder-logging.test.d.ts +2 -0
  6. package/dist/base-builder-logging.test.d.ts.map +1 -0
  7. package/dist/base-builder-logging.test.js +99 -0
  8. package/dist/base-builder.d.ts +132 -13
  9. package/dist/base-builder.d.ts.map +1 -1
  10. package/dist/base-builder.js +788 -92
  11. package/dist/build-queue.js +1 -1
  12. package/dist/config-helpers.d.ts +4 -1
  13. package/dist/config-helpers.d.ts.map +1 -1
  14. package/dist/config-helpers.js +63 -1
  15. package/dist/config-helpers.test.d.ts +2 -0
  16. package/dist/config-helpers.test.d.ts.map +1 -0
  17. package/dist/config-helpers.test.js +17 -0
  18. package/dist/constants.d.ts +66 -5
  19. package/dist/constants.d.ts.map +1 -1
  20. package/dist/constants.js +106 -19
  21. package/dist/constants.test.d.ts +2 -0
  22. package/dist/constants.test.d.ts.map +1 -0
  23. package/dist/constants.test.js +90 -0
  24. package/dist/discover-entries-esbuild-plugin.d.ts +3 -1
  25. package/dist/discover-entries-esbuild-plugin.d.ts.map +1 -1
  26. package/dist/discover-entries-esbuild-plugin.js +24 -4
  27. package/dist/discover-entries-esbuild-plugin.test.js +1 -1
  28. package/dist/esbuild-tsconfig.js +1 -1
  29. package/dist/esbuild-tsconfig.test.js +1 -1
  30. package/dist/external-package-warning.test.d.ts +2 -0
  31. package/dist/external-package-warning.test.d.ts.map +1 -0
  32. package/dist/external-package-warning.test.js +219 -0
  33. package/dist/fast-discovery.d.ts +29 -0
  34. package/dist/fast-discovery.d.ts.map +1 -0
  35. package/dist/fast-discovery.js +771 -0
  36. package/dist/fast-discovery.test.d.ts +2 -0
  37. package/dist/fast-discovery.test.d.ts.map +1 -0
  38. package/dist/fast-discovery.test.js +453 -0
  39. package/dist/get-input-files.test.js +34 -2
  40. package/dist/index.d.ts +7 -4
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +8 -5
  43. package/dist/module-specifier.d.ts +20 -2
  44. package/dist/module-specifier.d.ts.map +1 -1
  45. package/dist/module-specifier.js +92 -17
  46. package/dist/module-specifier.test.js +45 -3
  47. package/dist/node-module-esbuild-plugin.d.ts.map +1 -1
  48. package/dist/node-module-esbuild-plugin.js +73 -23
  49. package/dist/node-module-esbuild-plugin.test.js +97 -1
  50. package/dist/optional-otel-api.d.ts +14 -0
  51. package/dist/optional-otel-api.d.ts.map +1 -0
  52. package/dist/optional-otel-api.js +14 -0
  53. package/dist/optional-typescript-alias.d.ts +2 -0
  54. package/dist/optional-typescript-alias.d.ts.map +1 -0
  55. package/dist/optional-typescript-alias.js +3 -0
  56. package/dist/optional-typescript.d.ts +3 -0
  57. package/dist/optional-typescript.d.ts.map +1 -0
  58. package/dist/optional-typescript.js +9 -0
  59. package/dist/optional-ws-native.d.ts +30 -0
  60. package/dist/optional-ws-native.d.ts.map +1 -0
  61. package/dist/optional-ws-native.js +33 -0
  62. package/dist/pseudo-package-esbuild-plugin.js +1 -1
  63. package/dist/pseudo-package-esbuild-plugin.test.js +1 -1
  64. package/dist/request-converter.js +1 -1
  65. package/dist/resolve-sourcemap.test.d.ts +2 -0
  66. package/dist/resolve-sourcemap.test.d.ts.map +1 -0
  67. package/dist/resolve-sourcemap.test.js +194 -0
  68. package/dist/serde-checker.js +1 -1
  69. package/dist/standalone.d.ts +0 -3
  70. package/dist/standalone.d.ts.map +1 -1
  71. package/dist/standalone.js +17 -41
  72. package/dist/step-source-registration.test.d.ts +2 -0
  73. package/dist/step-source-registration.test.d.ts.map +1 -0
  74. package/dist/step-source-registration.test.js +82 -0
  75. package/dist/swc-esbuild-plugin.d.ts +26 -0
  76. package/dist/swc-esbuild-plugin.d.ts.map +1 -1
  77. package/dist/swc-esbuild-plugin.js +124 -14
  78. package/dist/swc-esbuild-plugin.test.js +475 -6
  79. package/dist/transform-utils.d.ts.map +1 -1
  80. package/dist/transform-utils.js +45 -6
  81. package/dist/transform-utils.test.js +78 -6
  82. package/dist/types.d.ts +73 -2
  83. package/dist/types.d.ts.map +1 -1
  84. package/dist/types.js +1 -1
  85. package/dist/vercel-build-output-api.d.ts +0 -2
  86. package/dist/vercel-build-output-api.d.ts.map +1 -1
  87. package/dist/vercel-build-output-api.js +37 -60
  88. package/dist/workflow-alias.js +1 -1
  89. package/dist/workflow-alias.test.js +2 -2
  90. package/dist/workflows-extractor.js +8 -3
  91. package/dist/workflows-extractor.test.d.ts +2 -0
  92. package/dist/workflows-extractor.test.d.ts.map +1 -0
  93. package/dist/workflows-extractor.test.js +70 -0
  94. package/package.json +8 -7
  95. package/dist/apply-swc-transform.js.map +0 -1
  96. package/dist/base-builder.js.map +0 -1
  97. package/dist/build-queue.js.map +0 -1
  98. package/dist/config-helpers.js.map +0 -1
  99. package/dist/constants.js.map +0 -1
  100. package/dist/discover-entries-esbuild-plugin.js.map +0 -1
  101. package/dist/discover-entries-esbuild-plugin.test.js.map +0 -1
  102. package/dist/esbuild-tsconfig.js.map +0 -1
  103. package/dist/esbuild-tsconfig.test.js.map +0 -1
  104. package/dist/get-input-files.test.js.map +0 -1
  105. package/dist/index.js.map +0 -1
  106. package/dist/module-specifier.js.map +0 -1
  107. package/dist/module-specifier.test.js.map +0 -1
  108. package/dist/node-module-esbuild-plugin.js.map +0 -1
  109. package/dist/node-module-esbuild-plugin.test.js.map +0 -1
  110. package/dist/pseudo-package-esbuild-plugin.js.map +0 -1
  111. package/dist/pseudo-package-esbuild-plugin.test.js.map +0 -1
  112. package/dist/request-converter.js.map +0 -1
  113. package/dist/serde-checker.js.map +0 -1
  114. package/dist/standalone.js.map +0 -1
  115. package/dist/swc-esbuild-plugin.js.map +0 -1
  116. package/dist/swc-esbuild-plugin.test.js.map +0 -1
  117. package/dist/transform-utils.js.map +0 -1
  118. package/dist/transform-utils.test.js.map +0 -1
  119. package/dist/types.js.map +0 -1
  120. package/dist/vercel-build-output-api.js.map +0 -1
  121. package/dist/workflow-alias.js.map +0 -1
  122. package/dist/workflow-alias.test.js.map +0 -1
  123. package/dist/workflows-extractor.js.map +0 -1
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=fast-discovery.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fast-discovery.test.d.ts","sourceRoot":"","sources":["../src/fast-discovery.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,453 @@
1
+ import { mkdirSync, mkdtempSync, realpathSync, rmSync, writeFileSync, } from 'node:fs';
2
+ import { tmpdir } from 'node:os';
3
+ import { dirname, join } from 'node:path';
4
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
5
+ import { BaseBuilder } from './base-builder.js';
6
+ import { importParents, parentHasChild, } from './discover-entries-esbuild-plugin.js';
7
+ class TestBuilder extends BaseBuilder {
8
+ async build() {
9
+ // no-op
10
+ }
11
+ discoverEntriesPublic(inputs, outdir, tsconfigPath) {
12
+ return this.discoverEntries(inputs, outdir, tsconfigPath);
13
+ }
14
+ createRouteImportSpecifierPublic(file, routeDir) {
15
+ return this.createRouteImportSpecifier(file, routeDir);
16
+ }
17
+ }
18
+ const realTmpdir = realpathSync(tmpdir());
19
+ function normalize(path) {
20
+ return path.replace(/\\/g, '/');
21
+ }
22
+ function writeFile(path, contents) {
23
+ mkdirSync(dirname(path), { recursive: true });
24
+ writeFileSync(path, contents, 'utf-8');
25
+ }
26
+ function createBuilder(workingDir, overrides) {
27
+ const config = {
28
+ buildTarget: 'standalone',
29
+ workingDir,
30
+ dirs: ['.'],
31
+ stepsBundlePath: join(workingDir, 'steps.js'),
32
+ workflowsBundlePath: join(workingDir, 'workflows.js'),
33
+ webhookBundlePath: join(workingDir, 'webhook.js'),
34
+ ...overrides,
35
+ };
36
+ return new TestBuilder(config);
37
+ }
38
+ describe('fast workflow discovery', () => {
39
+ let testRoot;
40
+ beforeEach(() => {
41
+ testRoot = mkdtempSync(join(realTmpdir, 'workflow-fast-discovery-'));
42
+ importParents.clear();
43
+ });
44
+ afterEach(() => {
45
+ importParents.clear();
46
+ rmSync(testRoot, { recursive: true, force: true });
47
+ });
48
+ it('discovers transitive relative step imports and tracks the parent chain', async () => {
49
+ const entryFile = join(testRoot, 'src', 'entry.ts');
50
+ const workflowFile = join(testRoot, 'src', 'workflow.ts');
51
+ const stepFile = join(testRoot, 'src', 'step.ts');
52
+ writeFile(entryFile, `import './workflow';\n`);
53
+ writeFile(workflowFile, `import { doStep } from './step';\nvoid doStep;\n`);
54
+ writeFile(stepFile, `export async function doStep() {
55
+ 'use step';
56
+ return 1;
57
+ }
58
+ `);
59
+ const discovered = await createBuilder(testRoot).discoverEntriesPublic([entryFile], join(testRoot, 'out'));
60
+ expect(discovered.discoveredSteps).toEqual(new Set([normalize(stepFile)]));
61
+ expect(parentHasChild(normalize(entryFile), normalize(stepFile))).toBe(true);
62
+ });
63
+ it('discovers relative JS imports whose basename includes .step', async () => {
64
+ const entryFile = join(testRoot, 'src', 'entry.ts');
65
+ const workflowFile = join(testRoot, 'src', 'hello.step.js');
66
+ writeFile(entryFile, `import './hello.step';\n`);
67
+ writeFile(workflowFile, `export async function run() {
68
+ 'use workflow';
69
+ return 'ok';
70
+ }
71
+ `);
72
+ const discovered = await createBuilder(testRoot).discoverEntriesPublic([entryFile], join(testRoot, 'out'));
73
+ expect(discovered.discoveredWorkflows).toEqual(new Set([normalize(workflowFile)]));
74
+ expect(parentHasChild(normalize(entryFile), normalize(workflowFile))).toBe(true);
75
+ });
76
+ it('discovers workflow files reached through an imported package re-export', async () => {
77
+ const entryFile = join(testRoot, 'src', 'entry.ts');
78
+ const packageRoot = join(testRoot, 'node_modules', 'workflow-pkg');
79
+ const packageIndex = join(packageRoot, 'index.js');
80
+ const packageWorkflow = join(packageRoot, 'workflow.js');
81
+ writeFile(entryFile, `import { run } from 'workflow-pkg';\nvoid run;\n`);
82
+ writeFile(join(packageRoot, 'package.json'), JSON.stringify({
83
+ name: 'workflow-pkg',
84
+ version: '1.0.0',
85
+ main: 'index.js',
86
+ dependencies: {
87
+ workflow: '^1.0.0',
88
+ },
89
+ }));
90
+ writeFile(packageIndex, `export { run } from './workflow.js';\n`);
91
+ writeFile(packageWorkflow, `export async function run() {
92
+ "use workflow";
93
+ return "ok";
94
+ }
95
+ `);
96
+ const discovered = await createBuilder(testRoot).discoverEntriesPublic([entryFile], join(testRoot, 'out'));
97
+ expect(discovered.discoveredWorkflows).toEqual(new Set([normalize(packageWorkflow)]));
98
+ expect(parentHasChild(normalize(packageIndex), normalize(packageWorkflow))).toBe(true);
99
+ });
100
+ it('does not descend into node_modules when discoverWorkflowsInNodeModules is false', async () => {
101
+ const entryFile = join(testRoot, 'src', 'entry.ts');
102
+ const localWorkflow = join(testRoot, 'src', 'local-workflow.ts');
103
+ const packageRoot = join(testRoot, 'node_modules', 'workflow-pkg');
104
+ const packageIndex = join(packageRoot, 'index.js');
105
+ const packageWorkflow = join(packageRoot, 'workflow.js');
106
+ const packageStep = join(packageRoot, 'step.js');
107
+ writeFile(entryFile, `import './local-workflow';\nimport { run } from 'workflow-pkg';\nvoid run;\n`);
108
+ writeFile(localWorkflow, `export async function localRun() {
109
+ 'use workflow';
110
+ return 'ok';
111
+ }
112
+ `);
113
+ writeFile(join(packageRoot, 'package.json'), JSON.stringify({
114
+ name: 'workflow-pkg',
115
+ version: '1.0.0',
116
+ main: 'index.js',
117
+ dependencies: {
118
+ workflow: '^1.0.0',
119
+ },
120
+ }));
121
+ writeFile(packageIndex, `export { run } from './workflow.js';\nexport { doWork } from './step.js';\n`);
122
+ writeFile(packageWorkflow, `export async function run() {
123
+ "use workflow";
124
+ return "ok";
125
+ }
126
+ `);
127
+ writeFile(packageStep, `export async function doWork() {
128
+ "use step";
129
+ return "done";
130
+ }
131
+ `);
132
+ const discovered = await createBuilder(testRoot, {
133
+ discoverWorkflowsInNodeModules: false,
134
+ }).discoverEntriesPublic([entryFile], join(testRoot, 'out'));
135
+ // Local (non-node_modules) workflow is still discovered.
136
+ expect(discovered.discoveredWorkflows).toEqual(new Set([normalize(localWorkflow)]));
137
+ // The node_modules workflow and step are not registered.
138
+ expect(discovered.discoveredWorkflows.has(normalize(packageWorkflow))).toBe(false);
139
+ expect(discovered.discoveredSteps.has(normalize(packageStep))).toBe(false);
140
+ // The dependency's files are never read/scanned: the import graph is not
141
+ // descended into at all, so none of them show up as discovered files and
142
+ // the parent edge into the package is not recorded.
143
+ for (const file of [packageIndex, packageWorkflow, packageStep]) {
144
+ expect(discovered.discoveredFiles?.has(normalize(file))).toBe(false);
145
+ }
146
+ expect(parentHasChild(normalize(entryFile), normalize(packageIndex))).toBe(false);
147
+ });
148
+ it('still follows imports within node_modules so seeded package entries resolve their subtree', async () => {
149
+ // Mirrors how the SDK seeds `@workflow/core/runtime/run` (a node_modules
150
+ // file) as an entry point: descent is blocked from application code, but a
151
+ // node_modules file may still reach its own transitive files.
152
+ const entryFile = join(testRoot, 'src', 'entry.ts');
153
+ const packageRoot = join(testRoot, 'node_modules', 'seeded-pkg');
154
+ const packageIndex = join(packageRoot, 'index.js');
155
+ const packageWorkflow = join(packageRoot, 'workflow.js');
156
+ writeFile(entryFile, `export const noop = 1;\n`);
157
+ writeFile(join(packageRoot, 'package.json'), JSON.stringify({
158
+ name: 'seeded-pkg',
159
+ version: '1.0.0',
160
+ main: 'index.js',
161
+ dependencies: { workflow: '^1.0.0' },
162
+ }));
163
+ writeFile(packageIndex, `export { run } from './workflow.js';\n`);
164
+ writeFile(packageWorkflow, `export async function run() {
165
+ "use workflow";
166
+ return "ok";
167
+ }
168
+ `);
169
+ // Seed the node_modules index directly as an entry point (as the builder
170
+ // does for the SDK runtime serde entry).
171
+ const discovered = await createBuilder(testRoot, {
172
+ discoverWorkflowsInNodeModules: false,
173
+ }).discoverEntriesPublic([entryFile, packageIndex], join(testRoot, 'out'));
174
+ expect(discovered.discoveredWorkflows.has(normalize(packageWorkflow))).toBe(true);
175
+ expect(parentHasChild(normalize(packageIndex), normalize(packageWorkflow))).toBe(true);
176
+ });
177
+ it('discovers files reached through tsconfig path aliases', async () => {
178
+ const entryFile = join(testRoot, 'src', 'entry.ts');
179
+ const registryFile = join(testRoot, 'src', '_workflows.ts');
180
+ const workflowFile = join(testRoot, 'src', 'workflows', 'workflow.ts');
181
+ const tsconfigFile = join(testRoot, 'tsconfig.json');
182
+ writeFile(tsconfigFile, JSON.stringify({
183
+ compilerOptions: {
184
+ paths: {
185
+ '@/*': ['./src/*'],
186
+ },
187
+ },
188
+ }));
189
+ writeFile(entryFile, `import { allWorkflows } from '@/_workflows';\n`);
190
+ writeFile(registryFile, `import * as workflow from './workflows/workflow';
191
+ export const allWorkflows = { workflow };
192
+ `);
193
+ writeFile(workflowFile, `export async function run() {
194
+ 'use workflow';
195
+ return 'ok';
196
+ }
197
+ `);
198
+ const discovered = await createBuilder(testRoot).discoverEntriesPublic([entryFile], join(testRoot, 'out'), tsconfigFile);
199
+ expect(discovered.discoveredWorkflows).toEqual(new Set([normalize(workflowFile)]));
200
+ expect(parentHasChild(normalize(entryFile), normalize(workflowFile))).toBe(true);
201
+ });
202
+ it('discovers dotted files reached through tsconfig path aliases', async () => {
203
+ const entryFile = join(testRoot, 'src', 'entry.ts');
204
+ const registryFile = join(testRoot, 'src', 'workflows', 'hello.index.ts');
205
+ const workflowFile = join(testRoot, 'src', 'workflows', 'hello.ts');
206
+ const tsconfigFile = join(testRoot, 'tsconfig.json');
207
+ writeFile(tsconfigFile, JSON.stringify({
208
+ compilerOptions: {
209
+ paths: {
210
+ '@/*': ['./src/*'],
211
+ },
212
+ },
213
+ }));
214
+ writeFile(entryFile, `import { helloWorkflow } from '@/workflows/hello.index';\n`);
215
+ writeFile(registryFile, `export { helloWorkflow } from './hello';\n`);
216
+ writeFile(workflowFile, `export async function helloWorkflow() {
217
+ 'use workflow';
218
+ return 'ok';
219
+ }
220
+ `);
221
+ const discovered = await createBuilder(testRoot).discoverEntriesPublic([entryFile], join(testRoot, 'out'), tsconfigFile);
222
+ expect(discovered.discoveredWorkflows).toEqual(new Set([normalize(workflowFile)]));
223
+ });
224
+ it('ignores non-source files reached through tsconfig path aliases', async () => {
225
+ const entryFile = join(testRoot, 'src', 'entry.ts');
226
+ const assetFile = join(testRoot, 'src', 'styles', 'app.css');
227
+ const tsconfigFile = join(testRoot, 'tsconfig.json');
228
+ writeFile(tsconfigFile, JSON.stringify({
229
+ compilerOptions: {
230
+ paths: {
231
+ '@/*': ['./src/*'],
232
+ },
233
+ },
234
+ }));
235
+ writeFile(entryFile, `import '@/styles/app.css';\n`);
236
+ writeFile(assetFile, `'use workflow';\n`);
237
+ const discovered = await createBuilder(testRoot).discoverEntriesPublic([entryFile], join(testRoot, 'out'), tsconfigFile);
238
+ expect(discovered.discoveredWorkflows).toEqual(new Set());
239
+ expect(discovered.discoveredFiles).toEqual(new Set([normalize(entryFile)]));
240
+ });
241
+ it('discovers path aliases inherited through tsconfig extends', async () => {
242
+ const entryFile = join(testRoot, 'src', 'entry.ts');
243
+ const workflowFile = join(testRoot, 'src', 'workflows', 'workflow.ts');
244
+ const baseTsconfigFile = join(testRoot, 'tsconfig.base.json');
245
+ const tsconfigFile = join(testRoot, 'tsconfig.json');
246
+ writeFile(baseTsconfigFile, JSON.stringify({
247
+ compilerOptions: {
248
+ baseUrl: '.',
249
+ paths: {
250
+ '@base/*': ['./src/*'],
251
+ },
252
+ },
253
+ }));
254
+ writeFile(tsconfigFile, JSON.stringify({
255
+ extends: './tsconfig.base.json',
256
+ }));
257
+ writeFile(entryFile, `import { run } from '@base/workflows/workflow';\n`);
258
+ writeFile(workflowFile, `export async function run() {
259
+ 'use workflow';
260
+ return 'ok';
261
+ }
262
+ `);
263
+ const discovered = await createBuilder(testRoot).discoverEntriesPublic([entryFile], join(testRoot, 'out'), tsconfigFile);
264
+ expect(discovered.discoveredWorkflows).toEqual(new Set([normalize(workflowFile)]));
265
+ });
266
+ it('discovers path aliases with multiple wildcards', async () => {
267
+ const entryFile = join(testRoot, 'src', 'entry.ts');
268
+ const workflowFile = join(testRoot, 'src', 'features', 'billing', 'flows', 'charge.ts');
269
+ const tsconfigFile = join(testRoot, 'tsconfig.json');
270
+ writeFile(tsconfigFile, JSON.stringify({
271
+ compilerOptions: {
272
+ paths: {
273
+ '@feature/*/workflow/*': ['./src/features/*/flows/*'],
274
+ },
275
+ },
276
+ }));
277
+ writeFile(entryFile, `import { charge } from '@feature/billing/workflow/charge';\n`);
278
+ writeFile(workflowFile, `export async function charge() {
279
+ 'use workflow';
280
+ return 'ok';
281
+ }
282
+ `);
283
+ const discovered = await createBuilder(testRoot).discoverEntriesPublic([entryFile], join(testRoot, 'out'), tsconfigFile);
284
+ expect(discovered.discoveredWorkflows).toEqual(new Set([normalize(workflowFile)]));
285
+ });
286
+ it('ignores imports that only appear inside comments', async () => {
287
+ const entryFile = join(testRoot, 'src', 'entry.ts');
288
+ const registryFile = join(testRoot, 'src', '_workflows.ts');
289
+ const workflowFile = join(testRoot, 'src', 'workflows', 'simple.ts');
290
+ writeFile(entryFile, `import './_workflows';\n`);
291
+ writeFile(registryFile, `// import * as simple from './workflows/simple';
292
+
293
+ export const allWorkflows = {
294
+ 'workflows/simple.ts': simple,
295
+ } as const;
296
+ `);
297
+ writeFile(workflowFile, `export async function simple() {
298
+ 'use workflow';
299
+ }
300
+ `);
301
+ const discovered = await createBuilder(testRoot).discoverEntriesPublic([entryFile], join(testRoot, 'out'));
302
+ expect(discovered.discoveredWorkflows).toEqual(new Set());
303
+ expect(discovered.discoveredFiles).toEqual(new Set([normalize(entryFile), normalize(registryFile)]));
304
+ });
305
+ it('does not treat regex literals as comments', async () => {
306
+ const entryFile = join(testRoot, 'src', 'entry.ts');
307
+ const registryFile = join(testRoot, 'src', '_workflows.ts');
308
+ const workflowFile = join(testRoot, 'src', 'workflows', 'simple.ts');
309
+ writeFile(entryFile, `import './_workflows';\n`);
310
+ writeFile(registryFile, `const commentStartChars = /[/*]/;
311
+ const protocol = /https?:\\/\\//;
312
+ import './workflows/simple';
313
+ `);
314
+ writeFile(workflowFile, `export async function simple() {
315
+ 'use workflow';
316
+ }
317
+ `);
318
+ const discovered = await createBuilder(testRoot).discoverEntriesPublic([entryFile], join(testRoot, 'out'));
319
+ expect(discovered.discoveredWorkflows).toEqual(new Set([normalize(workflowFile)]));
320
+ });
321
+ it('uses nearest nested jsconfig aliases in monorepo packages', async () => {
322
+ const rootTsconfigFile = join(testRoot, 'tsconfig.json');
323
+ const packageRoot = join(testRoot, 'packages', 'app');
324
+ const entryFile = join(packageRoot, 'src', 'entry.js');
325
+ const workflowFile = join(packageRoot, 'src', 'workflow.js');
326
+ writeFile(rootTsconfigFile, JSON.stringify({
327
+ compilerOptions: {
328
+ paths: {
329
+ '@root/*': ['./root/*'],
330
+ },
331
+ },
332
+ }));
333
+ writeFile(join(packageRoot, 'jsconfig.json'), JSON.stringify({
334
+ compilerOptions: {
335
+ paths: {
336
+ '#/*': ['./src/*'],
337
+ },
338
+ },
339
+ }));
340
+ writeFile(entryFile, `import { run } from '#/workflow';\n`);
341
+ writeFile(workflowFile, `export async function run() {
342
+ "use workflow";
343
+ return "ok";
344
+ }
345
+ `);
346
+ const discovered = await createBuilder(testRoot).discoverEntriesPublic([entryFile], join(testRoot, 'out'));
347
+ expect(discovered.discoveredWorkflows).toEqual(new Set([normalize(workflowFile)]));
348
+ });
349
+ it('only treats serde files as registration candidates when they define static serde methods', async () => {
350
+ const entryFile = join(testRoot, 'src', 'entry.ts');
351
+ const reducerFile = join(testRoot, 'src', 'reducer.ts');
352
+ const serdeFile = join(testRoot, 'src', 'serde.ts');
353
+ writeFile(entryFile, `import './reducer';
354
+ import './serde';
355
+ `);
356
+ writeFile(reducerFile, `import { WORKFLOW_SERIALIZE } from '@workflow/serde';
357
+
358
+ export function reducer(value: unknown) {
359
+ return value?.constructor?.[WORKFLOW_SERIALIZE];
360
+ }
361
+ `);
362
+ writeFile(serdeFile, `import { WORKFLOW_SERIALIZE as WS } from '@workflow/serde';
363
+
364
+ export class Value {
365
+ static classId = 'Value';
366
+ static [WS](value: Value) {
367
+ return value;
368
+ }
369
+ }
370
+ `);
371
+ const discovered = await createBuilder(testRoot).discoverEntriesPublic([entryFile], join(testRoot, 'out'));
372
+ expect(discovered.discoveredSerdeFiles).toEqual(new Set([normalize(serdeFile)]));
373
+ });
374
+ it('categorizes step, workflow, and serde usage independently', async () => {
375
+ const entryFile = join(testRoot, 'src', 'entry.ts');
376
+ const stepFile = join(testRoot, 'src', 'step.ts');
377
+ const workflowFile = join(testRoot, 'src', 'workflow.ts');
378
+ const serdeFile = join(testRoot, 'src', 'serde.ts');
379
+ writeFile(entryFile, `import './step';
380
+ import './workflow';
381
+ import './serde';
382
+ `);
383
+ writeFile(stepFile, `export async function runStep() {
384
+ 'use step';
385
+ return 'ok';
386
+ }
387
+ `);
388
+ writeFile(workflowFile, `export async function runWorkflow() {
389
+ 'use workflow';
390
+ return 'ok';
391
+ }
392
+ `);
393
+ writeFile(serdeFile, `export class Value {
394
+ static classId = 'Value';
395
+ static [Symbol.for('workflow-serialize')](value: Value) {
396
+ return value;
397
+ }
398
+ }
399
+ `);
400
+ const discovered = await createBuilder(testRoot).discoverEntriesPublic([entryFile], join(testRoot, 'out'));
401
+ expect(discovered.discoveredSteps).toEqual(new Set([normalize(stepFile)]));
402
+ expect(discovered.discoveredWorkflows).toEqual(new Set([normalize(workflowFile)]));
403
+ expect(discovered.discoveredSerdeFiles).toEqual(new Set([normalize(serdeFile)]));
404
+ });
405
+ it('ignores serde examples that only appear inside comments', async () => {
406
+ const entryFile = join(testRoot, 'src', 'entry.ts');
407
+ const docsFile = join(testRoot, 'src', 'docs.ts');
408
+ writeFile(entryFile, `import './docs';\n`);
409
+ writeFile(docsFile, `/**
410
+ * import { WORKFLOW_SERIALIZE } from '@workflow/serde';
411
+ *
412
+ * class Example {
413
+ * static [WORKFLOW_SERIALIZE](value) {
414
+ * return value;
415
+ * }
416
+ * }
417
+ */
418
+ export const WORKFLOW_SERIALIZE = Symbol.for('workflow-serialize');
419
+ `);
420
+ const discovered = await createBuilder(testRoot).discoverEntriesPublic([entryFile], join(testRoot, 'out'));
421
+ expect(discovered.discoveredSerdeFiles).toEqual(new Set());
422
+ });
423
+ it('relativizes nested package step registration imports', () => {
424
+ const routeDir = join(testRoot, 'app', '.well-known', 'workflow', 'v1');
425
+ const directPackageFile = join(testRoot, 'node_modules', 'direct-pkg', 'step.js');
426
+ const nestedPackageFile = join(testRoot, 'node_modules', 'parent-pkg', 'node_modules', 'nested-pkg', 'step.js');
427
+ writeFile(join(testRoot, 'package.json'), JSON.stringify({
428
+ dependencies: {
429
+ 'direct-pkg': '1.0.0',
430
+ },
431
+ }));
432
+ writeFile(join(testRoot, 'node_modules', 'direct-pkg', 'package.json'), JSON.stringify({
433
+ name: 'direct-pkg',
434
+ version: '1.0.0',
435
+ exports: {
436
+ './step': './step.js',
437
+ },
438
+ }));
439
+ writeFile(directPackageFile, `export const step = true;\n`);
440
+ writeFile(join(testRoot, 'node_modules', 'parent-pkg', 'node_modules', 'nested-pkg', 'package.json'), JSON.stringify({
441
+ name: 'nested-pkg',
442
+ version: '1.0.0',
443
+ exports: {
444
+ './step': './step.js',
445
+ },
446
+ }));
447
+ writeFile(nestedPackageFile, `export const step = true;\n`);
448
+ const builder = createBuilder(testRoot);
449
+ expect(builder.createRouteImportSpecifierPublic(directPackageFile, routeDir)).toBe('direct-pkg/step');
450
+ expect(builder.createRouteImportSpecifierPublic(nestedPackageFile, routeDir)).toBe('../../../../node_modules/parent-pkg/node_modules/nested-pkg/step.js');
451
+ });
452
+ });
453
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmFzdC1kaXNjb3ZlcnkudGVzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9mYXN0LWRpc2NvdmVyeS50ZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTCxTQUFTLEVBQ1QsV0FBVyxFQUNYLFlBQVksRUFDWixNQUFNLEVBQ04sYUFBYSxHQUNkLE1BQU0sU0FBUyxDQUFDO0FBQ2pCLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxTQUFTLENBQUM7QUFDakMsT0FBTyxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFDMUMsT0FBTyxFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxFQUFFLEVBQUUsTUFBTSxRQUFRLENBQUM7QUFDckUsT0FBTyxFQUFFLFdBQVcsRUFBMEIsTUFBTSxtQkFBbUIsQ0FBQztBQUN4RSxPQUFPLEVBQ0wsYUFBYSxFQUNiLGNBQWMsR0FDZixNQUFNLHNDQUFzQyxDQUFDO0FBRzlDLE1BQU0sV0FBWSxTQUFRLFdBQVc7SUFDbkMsS0FBSyxDQUFDLEtBQUs7UUFDVCxRQUFRO0lBQ1YsQ0FBQztJQUVNLHFCQUFxQixDQUMxQixNQUFnQixFQUNoQixNQUFjLEVBQ2QsWUFBcUI7UUFFckIsT0FBTyxJQUFJLENBQUMsZUFBZSxDQUFDLE1BQU0sRUFBRSxNQUFNLEVBQUUsWUFBWSxDQUFDLENBQUM7SUFDNUQsQ0FBQztJQUVNLGdDQUFnQyxDQUNyQyxJQUFZLEVBQ1osUUFBZ0I7UUFFaEIsT0FBTyxJQUFJLENBQUMsMEJBQTBCLENBQUMsSUFBSSxFQUFFLFFBQVEsQ0FBQyxDQUFDO0lBQ3pELENBQUM7Q0FDRjtBQUVELE1BQU0sVUFBVSxHQUFHLFlBQVksQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDO0FBRTFDLFNBQVMsU0FBUyxDQUFDLElBQVk7SUFDN0IsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSxHQUFHLENB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QUFXO2FBQ3RCO1NBQ0YsQ0FBQyxDQUNILENBQUM7UUFDRixTQUFTLENBQUMsaUJBQWlCLEVBQUUsNkJBQTZCLENBQUMsQ0FBQztRQUM1RCxTQUFTLENBQ1AsSUFBSSxDQUNGLFFBQVEsRUFDUixjQUFjLEVBQ2QsWUFBWSxFQUNaLGNBQWMsRUFDZCxZQUFZLEVBQ1osY0FBYyxDQUNmLEVBQ0QsSUFBSSxDQUFDLFNBQVMsQ0FBQztZQUNiLElBQUksRUFBRSxZQUFZO1lBQ2xCLE9BQU8sRUFBRSxPQUFPO1lBQ2hCLE9BQU8sRUFBRTtnQkFDUCxRQUFRLEVBQUUsV0FBVzthQUN0QjtTQUNGLENBQUMsQ0FDSCxDQUFDO1FBQ0YsU0FBUyxDQUFDLGlCQUFpQixFQUFFLDZCQUE2QixDQUFDLENBQUM7UUFFNUQsTUFBTSxPQUFPLEdBQUcsYUFBYSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQ3hDLE1BQU0sQ0FDSixPQUFPLENBQUMsZ0NBQWdDLENBQUMsaUJBQWlCLEVBQUUsUUFBUSxDQUFDLENBQ3RFLENBQUMsSUFBSSxDQUFDLGlCQUFpQixDQUFDLENBQUM7UUFDMUIsTUFBTSxDQUNKLE9BQU8sQ0FBQyxnQ0FBZ0MsQ0FBQyxpQkFBaUIsRUFBRSxRQUFRLENBQUMsQ0FDdEUsQ0FBQyxJQUFJLENBQ0oscUVBQXFFLENBQ3RFLENBQUM7SUFDSixDQUFDLENBQUMsQ0FBQztBQUNMLENBQUMsQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgbWtkaXJTeW5jLFxuICBta2R0ZW1wU3luYyxcbiAgcmVhbHBhdGhTeW5jLFxuICBybVN5bmMsXG4gIHdyaXRlRmlsZVN5bmMsXG59IGZyb20gJ25vZGU6ZnMnO1xuaW1wb3J0IHsgdG1wZGlyIH0gZnJvbSAnbm9kZTpvcyc7XG5pbXBvcnQgeyBkaXJuYW1lLCBqb2luIH0gZnJvbSAnbm9kZTpwYXRoJztcbmltcG9ydCB7IGFmdGVyRWFjaCwgYmVmb3JlRWFjaCwgZGVzY3JpYmUsIGV4cGVjdCwgaXQgfSBmcm9tICd2aXRlc3QnO1xuaW1wb3J0IHsgQmFzZUJ1aWxkZXIsIHR5cGUgRGlzY292ZXJlZEVudHJpZXMgfSBmcm9tICcuL2Jhc2UtYnVpbGRlci5qcyc7XG5pbXBvcnQge1xuICBpbXBvcnRQYXJlbnRzLFxuICBwYXJlbnRIYXNDaGlsZCxcbn0gZnJvbSAnLi9kaXNjb3Zlci1lbnRyaWVzLWVzYnVpbGQtcGx1Z2luLmpzJztcbmltcG9ydCB0eXBlIHsgU3RhbmRhbG9uZUNvbmZpZyB9IGZyb20gJy4vdHlwZXMuanMnO1xuXG5jbGFzcyBUZXN0QnVpbGRlciBleHRlbmRzIEJhc2VCdWlsZGVyIHtcbiAgYXN5bmMgYnVpbGQoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgLy8gbm8tb3BcbiAgfVxuXG4gIHB1YmxpYyBkaXNjb3ZlckVudHJpZXNQdWJsaWMoXG4gICAgaW5wdXRzOiBzdHJpbmdbXSxcbiAgICBvdXRkaXI6IHN0cmluZyxcbiAgICB0c2NvbmZpZ1BhdGg/OiBzdHJpbmdcbiAgKTogUHJvbWlzZTxEaXNjb3ZlcmVkRW50cmllcz4ge1xuICAgIHJldHVybiB0aGlzLmRpc2NvdmVyRW50cmllcyhpbnB1dHMsIG91dGRpciwgdHNjb25maWdQYXRoKTtcbiAgfVxuXG4gIHB1YmxpYyBjcmVhdGVSb3V0ZUltcG9ydFNwZWNpZmllclB1YmxpYyhcbiAgICBmaWxlOiBzdHJpbmcsXG4gICAgcm91dGVEaXI6IHN0cmluZ1xuICApOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLmNyZWF0ZVJvdXRlSW1wb3J0U3BlY2lmaWVyKGZpbGUsIHJvdXRlRGlyKTtcbiAgfVxufVxuXG5jb25zdCByZWFsVG1wZGlyID0gcmVhbHBhdGhTeW5jKHRtcGRpcigpKTtcblxuZnVuY3Rpb24gbm9ybWFsaXplKHBhdGg6IHN0cmluZyk6IHN0cmluZyB7XG4gIHJldHVybiBwYXRoLnJlcGxhY2UoL1xcXFwvZywgJy8nKTtcbn1cblxuZnVuY3Rpb24gd3JpdGVGaWxlKHBhdGg6IHN0cmluZywgY29udGVudHM6IHN0cmluZyk6IHZvaWQge1xuICBta2RpclN5bmMoZGlybmFtZShwYXRoKSwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gIHdyaXRlRmlsZVN5bmMocGF0aCwgY29udGVudHMsICd1dGYtOCcpO1xufVxuXG5mdW5jdGlvbiBjcmVhdGVCdWlsZGVyKFxuICB3b3JraW5nRGlyOiBzdHJpbmcsXG4gIG92ZXJyaWRlcz86IFBhcnRpYWw8U3RhbmRhbG9uZUNvbmZpZz5cbik6IFRlc3RCdWlsZGVyIHtcbiAgY29uc3QgY29uZmlnOiBTdGFuZGFsb25lQ29uZmlnID0ge1xuICAgIGJ1aWxkVGFyZ2V0OiAnc3RhbmRhbG9uZScsXG4gICAgd29ya2luZ0RpcixcbiAgICBkaXJzOiBbJy4nXSxcbiAgICBzdGVwc0J1bmRsZVBhdGg6IGpvaW4od29ya2luZ0RpciwgJ3N0ZXBzLmpzJyksXG4gICAgd29ya2Zsb3dzQnVuZGxlUGF0aDogam9pbih3b3JraW5nRGlyLCAnd29ya2Zsb3dzLmpzJyksXG4gICAgd2ViaG9va0J1bmRsZVBhdGg6IGpvaW4od29ya2luZ0RpciwgJ3dlYmhvb2suanMnKSxcbiAgICAuLi5vdmVycmlkZXMsXG4gIH07XG4gIHJldHVybiBuZXcgVGVzdEJ1aWxkZXIoY29uZmlnKTtcbn1cblxuZGVzY3JpYmUoJ2Zhc3Qgd29ya2Zsb3cgZGlzY292ZXJ5JywgKCkgPT4ge1xuICBsZXQgdGVzdFJvb3Q6IHN0cmluZztcblxuICBiZWZvcmVFYWNoKCgpID0+IHtcbiAgICB0ZXN0Um9vdCA9IG1rZHRlbXBTeW5jKGpvaW4ocmVhbFRtcGRpciwgJ3dvcmtmbG93LWZhc3QtZGlzY292ZXJ5LScpKTtcbiAgICBpbXBvcnRQYXJlbnRzLmNsZWFyKCk7XG4gIH0pO1xuXG4gIGFmdGVyRWFjaCgoKSA9PiB7XG4gICAgaW1wb3J0UGFyZW50cy5jbGVhcigpO1xuICAgIHJtU3luYyh0ZXN0Um9vdCwgeyByZWN1cnNpdmU6IHRydWUsIGZvcmNlOiB0cnVlIH0pO1xuICB9KTtcblxuICBpdCgnZGlzY292ZXJzIHRyYW5zaXRpdmUgcmVsYXRpdmUgc3RlcCBpbXBvcnRzIGFuZCB0cmFja3MgdGhlIHBhcmVudCBjaGFpbicsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBlbnRyeUZpbGUgPSBqb2luKHRlc3RSb290LCAnc3JjJywgJ2VudHJ5LnRzJyk7XG4gICAgY29uc3Qgd29ya2Zsb3dGaWxlID0gam9pbih0ZXN0Um9vdCwgJ3NyYycsICd3b3JrZmxvdy50cycpO1xuICAgIGNvbnN0IHN0ZXBGaWxlID0gam9pbih0ZXN0Um9vdCwgJ3NyYycsICdzdGVwLnRzJyk7XG5cbiAgICB3cml0ZUZpbGUoZW50cnlGaWxlLCBgaW1wb3J0ICcuL3dvcmtmbG93JztcXG5gKTtcbiAgICB3cml0ZUZpbGUod29ya2Zsb3dGaWxlLCBgaW1wb3J0IHsgZG9TdGVwIH0gZnJvbSAnLi9zdGVwJztcXG52b2lkIGRvU3RlcDtcXG5gKTtcbiAgICB3cml0ZUZpbGUoXG4gICAgICBzdGVwRmlsZSxcbiAgICAgIGBleHBvcnQgYXN5bmMgZnVuY3Rpb24gZG9TdGVwKCkge1xuICAndXNlIHN0ZXAnO1xuICByZXR1cm4gMTtcbn1cbmBcbiAgICApO1xuXG4gICAgY29uc3QgZGlzY292ZXJlZCA9IGF3YWl0IGNyZWF0ZUJ1aWxkZXIodGVzdFJvb3QpLmRpc2NvdmVyRW50cmllc1B1YmxpYyhcbiAgICAgIFtlbnRyeUZpbGVdLFxuICAgICAgam9pbih0ZXN0Um9vdCwgJ291dCcpXG4gICAgKTtcblxuICAgIGV4cGVjdChkaXNjb3ZlcmVkLmRpc2NvdmVyZWRTdGVwcykudG9FcXVhbChuZXcgU2V0KFtub3JtYWxpemUoc3RlcEZpbGUpXSkpO1xuICAgIGV4cGVjdChwYXJlbnRIYXNDaGlsZChub3JtYWxpemUoZW50cnlGaWxlKSwgbm9ybWFsaXplKHN0ZXBGaWxlKSkpLnRvQmUoXG4gICAgICB0cnVlXG4gICAgKTtcbiAgfSk7XG5cbiAgaXQoJ2Rpc2NvdmVycyByZWxhdGl2ZSBKUyBpbXBvcnRzIHdob3NlIGJhc2VuYW1lIGluY2x1ZGVzIC5zdGVwJywgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IGVudHJ5RmlsZSA9IGpvaW4odGVzdFJvb3QsICdzcmMnLCAnZW50cnkudHMnKTtcbiAgICBjb25zdCB3b3JrZmxvd0ZpbGUgPSBqb2luKHRlc3RSb290LCAnc3JjJywgJ2hlbGxvLnN0ZXAuanMnKTtcblxuICAgIHdyaXRlRmlsZShlbnRyeUZpbGUsIGBpbXBvcnQgJy4vaGVsbG8uc3RlcCc7XFxuYCk7XG4gICAgd3JpdGVGaWxlKFxuICAgICAgd29ya2Zsb3dGaWxlLFxuICAgICAgYGV4cG9ydCBhc3luYyBmdW5jdGlvbiBydW4oKSB7XG4gICd1c2Ugd29ya2Zsb3cnO1xuICByZXR1cm4gJ29rJztcbn1cbmBcbiAgICApO1xuXG4gICAgY29uc3QgZGlzY292ZXJlZCA9IGF3YWl0IGNyZWF0ZUJ1aWxkZXIodGVzdFJvb3QpLmRpc2NvdmVyRW50cmllc1B1YmxpYyhcbiAgICAgIFtlbnRyeUZpbGVdLFxuICAgICAgam9pbih0ZXN0Um9vdCwgJ291dCcpXG4gICAgKTtcblxuICAgIGV4cGVjdChkaXNjb3ZlcmVkLmRpc2NvdmVyZWRXb3JrZmxvd3MpLnRvRXF1YWwoXG4gICAgICBuZXcgU2V0KFtub3JtYWxpemUod29ya2Zsb3dGaWxlKV0pXG4gICAgKTtcbiAgICBleHBlY3QocGFyZW50SGFzQ2hpbGQobm9ybWFsaXplKGVudHJ5RmlsZSksIG5vcm1hbGl6ZSh3b3JrZmxvd0ZpbGUpKSkudG9CZShcbiAgICAgIHRydWVcbiAgICApO1xuICB9KTtcblxuICBpdCgnZGlzY292ZXJzIHdvcmtmbG93IGZpbGVzIHJlYWNoZWQgdGhyb3VnaCBhbiBpbXBvcnRlZCBwYWNrYWdlIHJlLWV4cG9ydCcsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBlbnRyeUZpbGUgPSBqb2luKHRlc3RSb290LCAnc3JjJywgJ2VudHJ5LnRzJyk7XG4gICAgY29uc3QgcGFja2FnZVJvb3QgPSBqb2luKHRlc3RSb290LCAnbm9kZV9tb2R1bGVzJywgJ3dvcmtmbG93LXBrZycpO1xuICAgIGNvbnN0IHBhY2thZ2VJbmRleCA9IGpvaW4ocGFja2FnZVJvb3QsICdpbmRleC5qcycpO1xuICAgIGNvbnN0IHBhY2thZ2VXb3JrZmxvdyA9IGpvaW4ocGFja2FnZVJvb3QsICd3b3JrZmxvdy5qcycpO1xuXG4gICAgd3JpdGVGaWxlKGVudHJ5RmlsZSwgYGltcG9ydCB7IHJ1biB9IGZyb20gJ3dvcmtmbG93LXBrZyc7XFxudm9pZCBydW47XFxuYCk7XG4gICAgd3JpdGVGaWxlKFxuICAgICAgam9pbihwYWNrYWdlUm9vdCwgJ3BhY2thZ2UuanNvbicpLFxuICAgICAgSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICBuYW1lOiAnd29ya2Zsb3ctcGtnJyxcbiAgICAgICAgdmVyc2lvbjogJzEuMC4wJyxcbiAgICAgICAgbWFpbjogJ2luZGV4LmpzJyxcbiAgICAgICAgZGVwZW5kZW5jaWVzOiB7XG4gICAgICAgICAgd29ya2Zsb3c6ICdeMS4wLjAnLFxuICAgICAgICB9LFxuICAgICAgfSlcbiAgICApO1xuICAgIHdyaXRlRmlsZShwYWNrYWdlSW5kZXgsIGBleHBvcnQgeyBydW4gfSBmcm9tICcuL3dvcmtmbG93LmpzJztcXG5gKTtcbiAgICB3cml0ZUZpbGUoXG4gICAgICBwYWNrYWdlV29ya2Zsb3csXG4gICAgICBgZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJ1bigpIHtcbiAgXCJ1c2Ugd29ya2Zsb3dcIjtcbiAgcmV0dXJuIFwib2tcIjtcbn1cbmBcbiAgICApO1xuXG4gICAgY29uc3QgZGlzY292ZXJlZCA9IGF3YWl0IGNyZWF0ZUJ1aWxkZXIodGVzdFJvb3QpLmRpc2NvdmVyRW50cmllc1B1YmxpYyhcbiAgICAgIFtlbnRyeUZpbGVdLFxuICAgICAgam9pbih0ZXN0Um9vdCwgJ291dCcpXG4gICAgKTtcblxuICAgIGV4cGVjdChkaXNjb3ZlcmVkLmRpc2NvdmVyZWRXb3JrZmxvd3MpLnRvRXF1YWwoXG4gICAgICBuZXcgU2V0KFtub3JtYWxpemUocGFja2FnZVdvcmtmbG93KV0pXG4gICAgKTtcbiAgICBleHBlY3QoXG4gICAgICBwYXJlbnRIYXNDaGlsZChub3JtYWxpemUocGFja2FnZUluZGV4KSwgbm9ybWFsaXplKHBhY2thZ2VXb3JrZmxvdykpXG4gICAgKS50b0JlKHRydWUpO1xuICB9KTtcblxuICBpdCgnZG9lcyBub3QgZGVzY2VuZCBpbnRvIG5vZGVfbW9kdWxlcyB3aGVuIGRpc2NvdmVyV29ya2Zsb3dzSW5Ob2RlTW9kdWxlcyBpcyBmYWxzZScsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBlbnRyeUZpbGUgPSBqb2luKHRlc3RSb290LCAnc3JjJywgJ2VudHJ5LnRzJyk7XG4gICAgY29uc3QgbG9jYWxXb3JrZmxvdyA9IGpvaW4odGVzdFJvb3QsICdzcmMnLCAnbG9jYWwtd29ya2Zsb3cudHMnKTtcbiAgICBjb25zdCBwYWNrYWdlUm9vdCA9IGpvaW4odGVzdFJvb3QsICdub2RlX21vZHVsZXMnLCAnd29ya2Zsb3ctcGtnJyk7XG4gICAgY29uc3QgcGFja2FnZUluZGV4ID0gam9pbihwYWNrYWdlUm9vdCwgJ2luZGV4LmpzJyk7XG4gICAgY29uc3QgcGFja2FnZVdvcmtmbG93ID0gam9pbihwYWNrYWdlUm9vdCwgJ3dvcmtmbG93LmpzJyk7XG4gICAgY29uc3QgcGFja2FnZVN0ZXAgPSBqb2luKHBhY2thZ2VSb290LCAnc3RlcC5qcycpO1xuXG4gICAgd3JpdGVGaWxlKFxuICAgICAgZW50cnlGaWxlLFxuICAgICAgYGltcG9ydCAnLi9sb2NhbC13b3JrZmxvdyc7XFxuaW1wb3J0IHsgcnVuIH0gZnJvbSAnd29ya2Zsb3ctcGtnJztcXG52b2lkIHJ1bjtcXG5gXG4gICAgKTtcbiAgICB3cml0ZUZpbGUoXG4gICAgICBsb2NhbFdvcmtmbG93LFxuICAgICAgYGV4cG9ydCBhc3luYyBmdW5jdGlvbiBsb2NhbFJ1bigpIHtcbiAgJ3VzZSB3b3JrZmxvdyc7XG4gIHJldHVybiAnb2snO1xufVxuYFxuICAgICk7XG4gICAgd3JpdGVGaWxlKFxuICAgICAgam9pbihwYWNrYWdlUm9vdCwgJ3BhY2thZ2UuanNvbicpLFxuICAgICAgSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICBuYW1lOiAnd29ya2Zsb3ctcGtnJyxcbiAgICAgICAgdmVyc2lvbjogJzEuMC4wJyxcbiAgICAgICAgbWFpbjogJ2luZGV4LmpzJyxcbiAgICAgICAgZGVwZW5kZW5jaWVzOiB7XG4gICAgICAgICAgd29ya2Zsb3c6ICdeMS4wLjAnLFxuICAgICAgICB9LFxuICAgICAgfSlcbiAgICApO1xuICAgIHdyaXRlRmlsZShcbiAgICAgIHBhY2thZ2VJbmRleCxcbiAgICAgIGBleHBvcnQgeyBydW4gfSBmcm9tICcuL3dvcmtmbG93LmpzJztcXG5leHBvcnQgeyBkb1dvcmsgfSBmcm9tICcuL3N0ZXAuanMnO1xcbmBcbiAgICApO1xuICAgIHdyaXRlRmlsZShcbiAgICAgIHBhY2thZ2VXb3JrZmxvdyxcbiAgICAgIGBleHBvcnQgYXN5bmMgZnVuY3Rpb24gcnVuKCkge1xuICBcInVzZSB3b3JrZmxvd1wiO1xuICByZXR1cm4gXCJva1wiO1xufVxuYFxuICAgICk7XG4gICAgd3JpdGVGaWxlKFxuICAgICAgcGFja2FnZVN0ZXAsXG4gICAgICBgZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGRvV29yaygpIHtcbiAgXCJ1c2Ugc3RlcFwiO1xuICByZXR1cm4gXCJkb25lXCI7XG59XG5gXG4gICAgKTtcblxuICAgIGNvbnN0IGRpc2NvdmVyZWQgPSBhd2FpdCBjcmVhdGVCdWlsZGVyKHRlc3RSb290LCB7XG4gICAgICBkaXNjb3ZlcldvcmtmbG93c0luTm9kZU1vZHVsZXM6IGZhbHNlLFxuICAgIH0pLmRpc2NvdmVyRW50cmllc1B1YmxpYyhbZW50cnlGaWxlXSwgam9pbih0ZXN0Um9vdCwgJ291dCcpKTtcblxuICAgIC8vIExvY2FsIChub24tbm9kZV9tb2R1bGVzKSB3b3JrZmxvdyBpcyBzdGlsbCBkaXNjb3ZlcmVkLlxuICAgIGV4cGVjdChkaXNjb3ZlcmVkLmRpc2NvdmVyZWRXb3JrZmxvd3MpLnRvRXF1YWwoXG4gICAgICBuZXcgU2V0KFtub3JtYWxpemUobG9jYWxXb3JrZmxvdyldKVxuICAgICk7XG4gICAgLy8gVGhlIG5vZGVfbW9kdWxlcyB3b3JrZmxvdyBhbmQgc3RlcCBhcmUgbm90IHJlZ2lzdGVyZWQuXG4gICAgZXhwZWN0KGRpc2NvdmVyZWQuZGlzY292ZXJlZFdvcmtmbG93cy5oYXMobm9ybWFsaXplKHBhY2thZ2VXb3JrZmxvdykpKS50b0JlKFxuICAgICAgZmFsc2VcbiAgICApO1xuICAgIGV4cGVjdChkaXNjb3ZlcmVkLmRpc2NvdmVyZWRTdGVwcy5oYXMobm9ybWFsaXplKHBhY2thZ2VTdGVwKSkpLnRvQmUoZmFsc2UpO1xuICAgIC8vIFRoZSBkZXBlbmRlbmN5J3MgZmlsZXMgYXJlIG5ldmVyIHJlYWQvc2Nhbm5lZDogdGhlIGltcG9ydCBncmFwaCBpcyBub3RcbiAgICAvLyBkZXNjZW5kZWQgaW50byBhdCBhbGwsIHNvIG5vbmUgb2YgdGhlbSBzaG93IHVwIGFzIGRpc2NvdmVyZWQgZmlsZXMgYW5kXG4gICAgLy8gdGhlIHBhcmVudCBlZGdlIGludG8gdGhlIHBhY2thZ2UgaXMgbm90IHJlY29yZGVkLlxuICAgIGZvciAoY29uc3QgZmlsZSBvZiBbcGFja2FnZUluZGV4LCBwYWNrYWdlV29ya2Zsb3csIHBhY2thZ2VTdGVwXSkge1xuICAgICAgZXhwZWN0KGRpc2NvdmVyZWQuZGlzY292ZXJlZEZpbGVzPy5oYXMobm9ybWFsaXplKGZpbGUpKSkudG9CZShmYWxzZSk7XG4gICAgfVxuICAgIGV4cGVjdChwYXJlbnRIYXNDaGlsZChub3JtYWxpemUoZW50cnlGaWxlKSwgbm9ybWFsaXplKHBhY2thZ2VJbmRleCkpKS50b0JlKFxuICAgICAgZmFsc2VcbiAgICApO1xuICB9KTtcblxuICBpdCgnc3RpbGwgZm9sbG93cyBpbXBvcnRzIHdpdGhpbiBub2RlX21vZHVsZXMgc28gc2VlZGVkIHBhY2thZ2UgZW50cmllcyByZXNvbHZlIHRoZWlyIHN1YnRyZWUnLCBhc3luYyAoKSA9PiB7XG4gICAgLy8gTWlycm9ycyBob3cgdGhlIFNESyBzZWVkcyBgQHdvcmtmbG93L2NvcmUvcnVudGltZS9ydW5gIChhIG5vZGVfbW9kdWxlc1xuICAgIC8vIGZpbGUpIGFzIGFuIGVudHJ5IHBvaW50OiBkZXNjZW50IGlzIGJsb2NrZWQgZnJvbSBhcHBsaWNhdGlvbiBjb2RlLCBidXQgYVxuICAgIC8vIG5vZGVfbW9kdWxlcyBmaWxlIG1heSBzdGlsbCByZWFjaCBpdHMgb3duIHRyYW5zaXRpdmUgZmlsZXMuXG4gICAgY29uc3QgZW50cnlGaWxlID0gam9pbih0ZXN0Um9vdCwgJ3NyYycsICdlbnRyeS50cycpO1xuICAgIGNvbnN0IHBhY2thZ2VSb290ID0gam9pbih0ZXN0Um9vdCwgJ25vZGVfbW9kdWxlcycsICdzZWVkZWQtcGtnJyk7XG4gICAgY29uc3QgcGFja2FnZUluZGV4ID0gam9pbihwYWNrYWdlUm9vdCwgJ2luZGV4LmpzJyk7XG4gICAgY29uc3QgcGFja2FnZVdvcmtmbG93ID0gam9pbihwYWNrYWdlUm9vdCwgJ3dvcmtmbG93LmpzJyk7XG5cbiAgICB3cml0ZUZpbGUoZW50cnlGaWxlLCBgZXhwb3J0IGNvbnN0IG5vb3AgPSAxO1xcbmApO1xuICAgIHdyaXRlRmlsZShcbiAgICAgIGpvaW4ocGFja2FnZVJvb3QsICdwYWNrYWdlLmpzb24nKSxcbiAgICAgIEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgbmFtZTogJ3NlZWRlZC1wa2cnLFxuICAgICAgICB2ZXJzaW9uOiAnMS4wLjAnLFxuICAgICAgICBtYWluOiAnaW5kZXguanMnLFxuICAgICAgICBkZXBlbmRlbmNpZXM6IHsgd29ya2Zsb3c6ICdeMS4wLjAnIH0sXG4gICAgICB9KVxuICAgICk7XG4gICAgd3JpdGVGaWxlKHBhY2thZ2VJbmRleCwgYGV4cG9ydCB7IHJ1biB9IGZyb20gJy4vd29ya2Zsb3cuanMnO1xcbmApO1xuICAgIHdyaXRlRmlsZShcbiAgICAgIHBhY2thZ2VXb3JrZmxvdyxcbiAgICAgIGBleHBvcnQgYXN5bmMgZnVuY3Rpb24gcnVuKCkge1xuICBcInVzZSB3b3JrZmxvd1wiO1xuICByZXR1cm4gXCJva1wiO1xufVxuYFxuICAgICk7XG5cbiAgICAvLyBTZWVkIHRoZSBub2RlX21vZHVsZXMgaW5kZXggZGlyZWN0bHkgYXMgYW4gZW50cnkgcG9pbnQgKGFzIHRoZSBidWlsZGVyXG4gICAgLy8gZG9lcyBmb3IgdGhlIFNESyBydW50aW1lIHNlcmRlIGVudHJ5KS5cbiAgICBjb25zdCBkaXNjb3ZlcmVkID0gYXdhaXQgY3JlYXRlQnVpbGRlcih0ZXN0Um9vdCwge1xuICAgICAgZGlzY292ZXJXb3JrZmxvd3NJbk5vZGVNb2R1bGVzOiBmYWxzZSxcbiAgICB9KS5kaXNjb3ZlckVudHJpZXNQdWJsaWMoW2VudHJ5RmlsZSwgcGFja2FnZUluZGV4XSwgam9pbih0ZXN0Um9vdCwgJ291dCcpKTtcblxuICAgIGV4cGVjdChkaXNjb3ZlcmVkLmRpc2NvdmVyZWRXb3JrZmxvd3MuaGFzKG5vcm1hbGl6ZShwYWNrYWdlV29ya2Zsb3cpKSkudG9CZShcbiAgICAgIHRydWVcbiAgICApO1xuICAgIGV4cGVjdChcbiAgICAgIHBhcmVudEhhc0NoaWxkKG5vcm1hbGl6ZShwYWNrYWdlSW5kZXgpLCBub3JtYWxpemUocGFja2FnZVdvcmtmbG93KSlcbiAgICApLnRvQmUodHJ1ZSk7XG4gIH0pO1xuXG4gIGl0KCdkaXNjb3ZlcnMgZmlsZXMgcmVhY2hlZCB0aHJvdWdoIHRzY29uZmlnIHBhdGggYWxpYXNlcycsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBlbnRyeUZpbGUgPSBqb2luKHRlc3RSb290LCAnc3JjJywgJ2VudHJ5LnRzJyk7XG4gICAgY29uc3QgcmVnaXN0cnlGaWxlID0gam9pbih0ZXN0Um9vdCwgJ3NyYycsICdfd29ya2Zsb3dzLnRzJyk7XG4gICAgY29uc3Qgd29ya2Zsb3dGaWxlID0gam9pbih0ZXN0Um9vdCwgJ3NyYycsICd3b3JrZmxvd3MnLCAnd29ya2Zsb3cudHMnKTtcbiAgICBjb25zdCB0c2NvbmZpZ0ZpbGUgPSBqb2luKHRlc3RSb290LCAndHNjb25maWcuanNvbicpO1xuXG4gICAgd3JpdGVGaWxlKFxuICAgICAgdHNjb25maWdGaWxlLFxuICAgICAgSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICBjb21waWxlck9wdGlvbnM6IHtcbiAgICAgICAgICBwYXRoczoge1xuICAgICAgICAgICAgJ0AvKic6IFsnLi9zcmMvKiddLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICB9KVxuICAgICk7XG4gICAgd3JpdGVGaWxlKGVudHJ5RmlsZSwgYGltcG9ydCB7IGFsbFdvcmtmbG93cyB9IGZyb20gJ0AvX3dvcmtmbG93cyc7XFxuYCk7XG4gICAgd3JpdGVGaWxlKFxuICAgICAgcmVnaXN0cnlGaWxlLFxuICAgICAgYGltcG9ydCAqIGFzIHdvcmtmbG93IGZyb20gJy4vd29ya2Zsb3dzL3dvcmtmbG93JztcbmV4cG9ydCBjb25zdCBhbGxXb3JrZmxvd3MgPSB7IHdvcmtmbG93IH07XG5gXG4gICAgKTtcbiAgICB3cml0ZUZpbGUoXG4gICAgICB3b3JrZmxvd0ZpbGUsXG4gICAgICBgZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJ1bigpIHtcbiAgJ3VzZSB3b3JrZmxvdyc7XG4gIHJldHVybiAnb2snO1xufVxuYFxuICAgICk7XG5cbiAgICBjb25zdCBkaXNjb3ZlcmVkID0gYXdhaXQgY3JlYXRlQnVpbGRlcih0ZXN0Um9vdCkuZGlzY292ZXJFbnRyaWVzUHVibGljKFxuICAgICAgW2VudHJ5RmlsZV0sXG4gICAgICBqb2luKHRlc3RSb290LCAnb3V0JyksXG4gICAgICB0c2NvbmZpZ0ZpbGVcbiAgICApO1xuXG4gICAgZXhwZWN0KGRpc2NvdmVyZWQuZGlzY292ZXJlZFdvcmtmbG93cykudG9FcXVhbChcbiAgICAgIG5ldyBTZXQoW25vcm1hbGl6ZSh3b3JrZmxvd0ZpbGUpXSlcbiAgICApO1xuICAgIGV4cGVjdChwYXJlbnRIYXNDaGlsZChub3JtYWxpemUoZW50cnlGaWxlKSwgbm9ybWFsaXplKHdvcmtmbG93RmlsZSkpKS50b0JlKFxuICAgICAgdHJ1ZVxuICAgICk7XG4gIH0pO1xuXG4gIGl0KCdkaXNjb3ZlcnMgZG90dGVkIGZpbGVzIHJlYWNoZWQgdGhyb3VnaCB0c2NvbmZpZyBwYXRoIGFsaWFzZXMnLCBhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgZW50cnlGaWxlID0gam9pbih0ZXN0Um9vdCwgJ3NyYycsICdlbnRyeS50cycpO1xuICAgIGNvbnN0IHJlZ2lzdHJ5RmlsZSA9IGpvaW4odGVzdFJvb3QsICdzcmMnLCAnd29ya2Zsb3dzJywgJ2hlbGxvLmluZGV4LnRzJyk7XG4gICAgY29uc3Qgd29ya2Zsb3dGaWxlID0gam9pbih0ZXN0Um9vdCwgJ3NyYycsICd3b3JrZmxvd3MnLCAnaGVsbG8udHMnKTtcbiAgICBjb25zdCB0c2NvbmZpZ0ZpbGUgPSBqb2luKHRlc3RSb290LCAndHNjb25maWcuanNvbicpO1xuXG4gICAgd3JpdGVGaWxlKFxuICAgICAgdHNjb25maWdGaWxlLFxuICAgICAgSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICBjb21waWxlck9wdGlvbnM6IHtcbiAgICAgICAgICBwYXRoczoge1xuICAgICAgICAgICAgJ0AvKic6IFsnLi9zcmMvKiddLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICB9KVxuICAgICk7XG4gICAgd3JpdGVGaWxlKFxuICAgICAgZW50cnlGaWxlLFxuICAgICAgYGltcG9ydCB7IGhlbGxvV29ya2Zsb3cgfSBmcm9tICdAL3dvcmtmbG93cy9oZWxsby5pbmRleCc7XFxuYFxuICAgICk7XG4gICAgd3JpdGVGaWxlKHJlZ2lzdHJ5RmlsZSwgYGV4cG9ydCB7IGhlbGxvV29ya2Zsb3cgfSBmcm9tICcuL2hlbGxvJztcXG5gKTtcbiAgICB3cml0ZUZpbGUoXG4gICAgICB3b3JrZmxvd0ZpbGUsXG4gICAgICBgZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGhlbGxvV29ya2Zsb3coKSB7XG4gICd1c2Ugd29ya2Zsb3cnO1xuICByZXR1cm4gJ29rJztcbn1cbmBcbiAgICApO1xuXG4gICAgY29uc3QgZGlzY292ZXJlZCA9IGF3YWl0IGNyZWF0ZUJ1aWxkZXIodGVzdFJvb3QpLmRpc2NvdmVyRW50cmllc1B1YmxpYyhcbiAgICAgIFtlbnRyeUZpbGVdLFxuICAgICAgam9pbih0ZXN0Um9vdCwgJ291dCcpLFxuICAgICAgdHNjb25maWdGaWxlXG4gICAgKTtcblxuICAgIGV4cGVjdChkaXNjb3ZlcmVkLmRpc2NvdmVyZWRXb3JrZmxvd3MpLnRvRXF1YWwoXG4gICAgICBuZXcgU2V0KFtub3JtYWxpemUod29ya2Zsb3dGaWxlKV0pXG4gICAgKTtcbiAgfSk7XG5cbiAgaXQoJ2lnbm9yZXMgbm9uLXNvdXJjZSBmaWxlcyByZWFjaGVkIHRocm91Z2ggdHNjb25maWcgcGF0aCBhbGlhc2VzJywgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IGVudHJ5RmlsZSA9IGpvaW4odGVzdFJvb3QsICdzcmMnLCAnZW50cnkudHMnKTtcbiAgICBjb25zdCBhc3NldEZpbGUgPSBqb2luKHRlc3RSb290LCAnc3JjJywgJ3N0eWxlcycsICdhcHAuY3NzJyk7XG4gICAgY29uc3QgdHNjb25maWdGaWxlID0gam9pbih0ZXN0Um9vdCwgJ3RzY29uZmlnLmpzb24nKTtcblxuICAgIHdyaXRlRmlsZShcbiAgICAgIHRzY29uZmlnRmlsZSxcbiAgICAgIEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgY29tcGlsZXJPcHRpb25zOiB7XG4gICAgICAgICAgcGF0aHM6IHtcbiAgICAgICAgICAgICdALyonOiBbJy4vc3JjLyonXSxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgfSlcbiAgICApO1xuICAgIHdyaXRlRmlsZShlbnRyeUZpbGUsIGBpbXBvcnQgJ0Avc3R5bGVzL2FwcC5jc3MnO1xcbmApO1xuICAgIHdyaXRlRmlsZShhc3NldEZpbGUsIGAndXNlIHdvcmtmbG93JztcXG5gKTtcblxuICAgIGNvbnN0IGRpc2NvdmVyZWQgPSBhd2FpdCBjcmVhdGVCdWlsZGVyKHRlc3RSb290KS5kaXNjb3ZlckVudHJpZXNQdWJsaWMoXG4gICAgICBbZW50cnlGaWxlXSxcbiAgICAgIGpvaW4odGVzdFJvb3QsICdvdXQnKSxcbiAgICAgIHRzY29uZmlnRmlsZVxuICAgICk7XG5cbiAgICBleHBlY3QoZGlzY292ZXJlZC5kaXNjb3ZlcmVkV29ya2Zsb3dzKS50b0VxdWFsKG5ldyBTZXQoKSk7XG4gICAgZXhwZWN0KGRpc2NvdmVyZWQuZGlzY292ZXJlZEZpbGVzKS50b0VxdWFsKG5ldyBTZXQoW25vcm1hbGl6ZShlbnRyeUZpbGUpXSkpO1xuICB9KTtcblxuICBpdCgnZGlzY292ZXJzIHBhdGggYWxpYXNlcyBpbmhlcml0ZWQgdGhyb3VnaCB0c2NvbmZpZyBleHRlbmRzJywgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IGVudHJ5RmlsZSA9IGpvaW4odGVzdFJvb3QsICdzcmMnLCAnZW50cnkudHMnKTtcbiAgICBjb25zdCB3b3JrZmxvd0ZpbGUgPSBqb2luKHRlc3RSb290LCAnc3JjJywgJ3dvcmtmbG93cycsICd3b3JrZmxvdy50cycpO1xuICAgIGNvbnN0IGJhc2VUc2NvbmZpZ0ZpbGUgPSBqb2luKHRlc3RSb290LCAndHNjb25maWcuYmFzZS5qc29uJyk7XG4gICAgY29uc3QgdHNjb25maWdGaWxlID0gam9pbih0ZXN0Um9vdCwgJ3RzY29uZmlnLmpzb24nKTtcblxuICAgIHdyaXRlRmlsZShcbiAgICAgIGJhc2VUc2NvbmZpZ0ZpbGUsXG4gICAgICBKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgIGNvbXBpbGVyT3B0aW9uczoge1xuICAgICAgICAgIGJhc2VVcmw6ICcuJyxcbiAgICAgICAgICBwYXRoczoge1xuICAgICAgICAgICAgJ0BiYXNlLyonOiBbJy4vc3JjLyonXSxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgfSlcbiAgICApO1xuICAgIHdyaXRlRmlsZShcbiAgICAgIHRzY29uZmlnRmlsZSxcbiAgICAgIEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgZXh0ZW5kczogJy4vdHNjb25maWcuYmFzZS5qc29uJyxcbiAgICAgIH0pXG4gICAgKTtcbiAgICB3cml0ZUZpbGUoZW50cnlGaWxlLCBgaW1wb3J0IHsgcnVuIH0gZnJvbSAnQGJhc2Uvd29ya2Zsb3dzL3dvcmtmbG93JztcXG5gKTtcbiAgICB3cml0ZUZpbGUoXG4gICAgICB3b3JrZmxvd0ZpbGUsXG4gICAgICBgZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJ1bigpIHtcbiAgJ3VzZSB3b3JrZmxvdyc7XG4gIHJldHVybiAnb2snO1xufVxuYFxuICAgICk7XG5cbiAgICBjb25zdCBkaXNjb3ZlcmVkID0gYXdhaXQgY3JlYXRlQnVpbGRlcih0ZXN0Um9vdCkuZGlzY292ZXJFbnRyaWVzUHVibGljKFxuICAgICAgW2VudHJ5RmlsZV0sXG4gICAgICBqb2luKHRlc3RSb290LCAnb3V0JyksXG4gICAgICB0c2NvbmZpZ0ZpbGVcbiAgICApO1xuXG4gICAgZXhwZWN0KGRpc2NvdmVyZWQuZGlzY292ZXJlZFdvcmtmbG93cykudG9FcXVhbChcbiAgICAgIG5ldyBTZXQoW25vcm1hbGl6ZSh3b3JrZmxvd0ZpbGUpXSlcbiAgICApO1xuICB9KTtcblxuICBpdCgnZGlzY292ZXJzIHBhdGggYWxpYXNlcyB3aXRoIG11bHRpcGxlIHdpbGRjYXJkcycsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBlbnRyeUZpbGUgPSBqb2luKHRlc3RSb290LCAnc3JjJywgJ2VudHJ5LnRzJyk7XG4gICAgY29uc3Qgd29ya2Zsb3dGaWxlID0gam9pbihcbiAgICAgIHRlc3RSb290LFxuICAgICAgJ3NyYycsXG4gICAgICAnZmVhdHVyZXMnLFxuICAgICAgJ2JpbGxpbmcnLFxuICAgICAgJ2Zsb3dzJyxcbiAgICAgICdjaGFyZ2UudHMnXG4gICAgKTtcbiAgICBjb25zdCB0c2NvbmZpZ0ZpbGUgPSBqb2luKHRlc3RSb290LCAndHNjb25maWcuanNvbicpO1xuXG4gICAgd3JpdGVGaWxlKFxuICAgICAgdHNjb25maWdGaWxlLFxuICAgICAgSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICBjb21waWxlck9wdGlvbnM6IHtcbiAgICAgICAgICBwYXRoczoge1xuICAgICAgICAgICAgJ0BmZWF0dXJlLyovd29ya2Zsb3cvKic6IFsnLi9zcmMvZmVhdHVyZXMvKi9mbG93cy8qJ10sXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgIH0pXG4gICAgKTtcbiAgICB3cml0ZUZpbGUoXG4gICAgICBlbnRyeUZpbGUsXG4gICAgICBgaW1wb3J0IHsgY2hhcmdlIH0gZnJvbSAnQGZlYXR1cmUvYmlsbGluZy93b3JrZmxvdy9jaGFyZ2UnO1xcbmBcbiAgICApO1xuICAgIHdyaXRlRmlsZShcbiAgICAgIHdvcmtmbG93RmlsZSxcbiAgICAgIGBleHBvcnQgYXN5bmMgZnVuY3Rpb24gY2hhcmdlKCkge1xuICAndXNlIHdvcmtmbG93JztcbiAgcmV0dXJuICdvayc7XG59XG5gXG4gICAgKTtcblxuICAgIGNvbnN0IGRpc2NvdmVyZWQgPSBhd2FpdCBjcmVhdGVCdWlsZGVyKHRlc3RSb290KS5kaXNjb3ZlckVudHJpZXNQdWJsaWMoXG4gICAgICBbZW50cnlGaWxlXSxcbiAgICAgIGpvaW4odGVzdFJvb3QsICdvdXQnKSxcbiAgICAgIHRzY29uZmlnRmlsZVxuICAgICk7XG5cbiAgICBleHBlY3QoZGlzY292ZXJlZC5kaXNjb3ZlcmVkV29ya2Zsb3dzKS50b0VxdWFsKFxuICAgICAgbmV3IFNldChbbm9ybWFsaXplKHdvcmtmbG93RmlsZSldKVxuICAgICk7XG4gIH0pO1xuXG4gIGl0KCdpZ25vcmVzIGltcG9ydHMgdGhhdCBvbmx5IGFwcGVhciBpbnNpZGUgY29tbWVudHMnLCBhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgZW50cnlGaWxlID0gam9pbih0ZXN0Um9vdCwgJ3NyYycsICdlbnRyeS50cycpO1xuICAgIGNvbnN0IHJlZ2lzdHJ5RmlsZSA9IGpvaW4odGVzdFJvb3QsICdzcmMnLCAnX3dvcmtmbG93cy50cycpO1xuICAgIGNvbnN0IHdvcmtmbG93RmlsZSA9IGpvaW4odGVzdFJvb3QsICdzcmMnLCAnd29ya2Zsb3dzJywgJ3NpbXBsZS50cycpO1xuXG4gICAgd3JpdGVGaWxlKGVudHJ5RmlsZSwgYGltcG9ydCAnLi9fd29ya2Zsb3dzJztcXG5gKTtcbiAgICB3cml0ZUZpbGUoXG4gICAgICByZWdpc3RyeUZpbGUsXG4gICAgICBgLy8gaW1wb3J0ICogYXMgc2ltcGxlIGZyb20gJy4vd29ya2Zsb3dzL3NpbXBsZSc7XG5cbmV4cG9ydCBjb25zdCBhbGxXb3JrZmxvd3MgPSB7XG4gICd3b3JrZmxvd3Mvc2ltcGxlLnRzJzogc2ltcGxlLFxufSBhcyBjb25zdDtcbmBcbiAgICApO1xuICAgIHdyaXRlRmlsZShcbiAgICAgIHdvcmtmbG93RmlsZSxcbiAgICAgIGBleHBvcnQgYXN5bmMgZnVuY3Rpb24gc2ltcGxlKCkge1xuICAndXNlIHdvcmtmbG93Jztcbn1cbmBcbiAgICApO1xuXG4gICAgY29uc3QgZGlzY292ZXJlZCA9IGF3YWl0IGNyZWF0ZUJ1aWxkZXIodGVzdFJvb3QpLmRpc2NvdmVyRW50cmllc1B1YmxpYyhcbiAgICAgIFtlbnRyeUZpbGVdLFxuICAgICAgam9pbih0ZXN0Um9vdCwgJ291dCcpXG4gICAgKTtcblxuICAgIGV4cGVjdChkaXNjb3ZlcmVkLmRpc2NvdmVyZWRXb3JrZmxvd3MpLnRvRXF1YWwobmV3IFNldCgpKTtcbiAgICBleHBlY3QoZGlzY292ZXJlZC5kaXNjb3ZlcmVkRmlsZXMpLnRvRXF1YWwoXG4gICAgICBuZXcgU2V0KFtub3JtYWxpemUoZW50cnlGaWxlKSwgbm9ybWFsaXplKHJlZ2lzdHJ5RmlsZSldKVxuICAgICk7XG4gIH0pO1xuXG4gIGl0KCdkb2VzIG5vdCB0cmVhdCByZWdleCBsaXRlcmFscyBhcyBjb21tZW50cycsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBlbnRyeUZpbGUgPSBqb2luKHRlc3RSb290LCAnc3JjJywgJ2VudHJ5LnRzJyk7XG4gICAgY29uc3QgcmVnaXN0cnlGaWxlID0gam9pbih0ZXN0Um9vdCwgJ3NyYycsICdfd29ya2Zsb3dzLnRzJyk7XG4gICAgY29uc3Qgd29ya2Zsb3dGaWxlID0gam9pbih0ZXN0Um9vdCwgJ3NyYycsICd3b3JrZmxvd3MnLCAnc2ltcGxlLnRzJyk7XG5cbiAgICB3cml0ZUZpbGUoZW50cnlGaWxlLCBgaW1wb3J0ICcuL193b3JrZmxvd3MnO1xcbmApO1xuICAgIHdyaXRlRmlsZShcbiAgICAgIHJlZ2lzdHJ5RmlsZSxcbiAgICAgIGBjb25zdCBjb21tZW50U3RhcnRDaGFycyA9IC9bLypdLztcbmNvbnN0IHByb3RvY29sID0gL2h0dHBzPzpcXFxcL1xcXFwvLztcbmltcG9ydCAnLi93b3JrZmxvd3Mvc2ltcGxlJztcbmBcbiAgICApO1xuICAgIHdyaXRlRmlsZShcbiAgICAgIHdvcmtmbG93RmlsZSxcbiAgICAgIGBleHBvcnQgYXN5bmMgZnVuY3Rpb24gc2ltcGxlKCkge1xuICAndXNlIHdvcmtmbG93Jztcbn1cbmBcbiAgICApO1xuXG4gICAgY29uc3QgZGlzY292ZXJlZCA9IGF3YWl0IGNyZWF0ZUJ1aWxkZXIodGVzdFJvb3QpLmRpc2NvdmVyRW50cmllc1B1YmxpYyhcbiAgICAgIFtlbnRyeUZpbGVdLFxuICAgICAgam9pbih0ZXN0Um9vdCwgJ291dCcpXG4gICAgKTtcblxuICAgIGV4cGVjdChkaXNjb3ZlcmVkLmRpc2NvdmVyZWRXb3JrZmxvd3MpLnRvRXF1YWwoXG4gICAgICBuZXcgU2V0KFtub3JtYWxpemUod29ya2Zsb3dGaWxlKV0pXG4gICAgKTtcbiAgfSk7XG5cbiAgaXQoJ3VzZXMgbmVhcmVzdCBuZXN0ZWQganNjb25maWcgYWxpYXNlcyBpbiBtb25vcmVwbyBwYWNrYWdlcycsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCByb290VHNjb25maWdGaWxlID0gam9pbih0ZXN0Um9vdCwgJ3RzY29uZmlnLmpzb24nKTtcbiAgICBjb25zdCBwYWNrYWdlUm9vdCA9IGpvaW4odGVzdFJvb3QsICdwYWNrYWdlcycsICdhcHAnKTtcbiAgICBjb25zdCBlbnRyeUZpbGUgPSBqb2luKHBhY2thZ2VSb290LCAnc3JjJywgJ2VudHJ5LmpzJyk7XG4gICAgY29uc3Qgd29ya2Zsb3dGaWxlID0gam9pbihwYWNrYWdlUm9vdCwgJ3NyYycsICd3b3JrZmxvdy5qcycpO1xuXG4gICAgd3JpdGVGaWxlKFxuICAgICAgcm9vdFRzY29uZmlnRmlsZSxcbiAgICAgIEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgY29tcGlsZXJPcHRpb25zOiB7XG4gICAgICAgICAgcGF0aHM6IHtcbiAgICAgICAgICAgICdAcm9vdC8qJzogWycuL3Jvb3QvKiddLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICB9KVxuICAgICk7XG4gICAgd3JpdGVGaWxlKFxuICAgICAgam9pbihwYWNrYWdlUm9vdCwgJ2pzY29uZmlnLmpzb24nKSxcbiAgICAgIEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgY29tcGlsZXJPcHRpb25zOiB7XG4gICAgICAgICAgcGF0aHM6IHtcbiAgICAgICAgICAgICcjLyonOiBbJy4vc3JjLyonXSxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgfSlcbiAgICApO1xuICAgIHdyaXRlRmlsZShlbnRyeUZpbGUsIGBpbXBvcnQgeyBydW4gfSBmcm9tICcjL3dvcmtmbG93JztcXG5gKTtcbiAgICB3cml0ZUZpbGUoXG4gICAgICB3b3JrZmxvd0ZpbGUsXG4gICAgICBgZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJ1bigpIHtcbiAgXCJ1c2Ugd29ya2Zsb3dcIjtcbiAgcmV0dXJuIFwib2tcIjtcbn1cbmBcbiAgICApO1xuXG4gICAgY29uc3QgZGlzY292ZXJlZCA9IGF3YWl0IGNyZWF0ZUJ1aWxkZXIodGVzdFJvb3QpLmRpc2NvdmVyRW50cmllc1B1YmxpYyhcbiAgICAgIFtlbnRyeUZpbGVdLFxuICAgICAgam9pbih0ZXN0Um9vdCwgJ291dCcpXG4gICAgKTtcblxuICAgIGV4cGVjdChkaXNjb3ZlcmVkLmRpc2NvdmVyZWRXb3JrZmxvd3MpLnRvRXF1YWwoXG4gICAgICBuZXcgU2V0KFtub3JtYWxpemUod29ya2Zsb3dGaWxlKV0pXG4gICAgKTtcbiAgfSk7XG5cbiAgaXQoJ29ubHkgdHJlYXRzIHNlcmRlIGZpbGVzIGFzIHJlZ2lzdHJhdGlvbiBjYW5kaWRhdGVzIHdoZW4gdGhleSBkZWZpbmUgc3RhdGljIHNlcmRlIG1ldGhvZHMnLCBhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgZW50cnlGaWxlID0gam9pbih0ZXN0Um9vdCwgJ3NyYycsICdlbnRyeS50cycpO1xuICAgIGNvbnN0IHJlZHVjZXJGaWxlID0gam9pbih0ZXN0Um9vdCwgJ3NyYycsICdyZWR1Y2VyLnRzJyk7XG4gICAgY29uc3Qgc2VyZGVGaWxlID0gam9pbih0ZXN0Um9vdCwgJ3NyYycsICdzZXJkZS50cycpO1xuXG4gICAgd3JpdGVGaWxlKFxuICAgICAgZW50cnlGaWxlLFxuICAgICAgYGltcG9ydCAnLi9yZWR1Y2VyJztcbmltcG9ydCAnLi9zZXJkZSc7XG5gXG4gICAgKTtcbiAgICB3cml0ZUZpbGUoXG4gICAgICByZWR1Y2VyRmlsZSxcbiAgICAgIGBpbXBvcnQgeyBXT1JLRkxPV19TRVJJQUxJWkUgfSBmcm9tICdAd29ya2Zsb3cvc2VyZGUnO1xuXG5leHBvcnQgZnVuY3Rpb24gcmVkdWNlcih2YWx1ZTogdW5rbm93bikge1xuICByZXR1cm4gdmFsdWU/LmNvbnN0cnVjdG9yPy5bV09SS0ZMT1dfU0VSSUFMSVpFXTtcbn1cbmBcbiAgICApO1xuICAgIHdyaXRlRmlsZShcbiAgICAgIHNlcmRlRmlsZSxcbiAgICAgIGBpbXBvcnQgeyBXT1JLRkxPV19TRVJJQUxJWkUgYXMgV1MgfSBmcm9tICdAd29ya2Zsb3cvc2VyZGUnO1xuXG5leHBvcnQgY2xhc3MgVmFsdWUge1xuICBzdGF0aWMgY2xhc3NJZCA9ICdWYWx1ZSc7XG4gIHN0YXRpYyBbV1NdKHZhbHVlOiBWYWx1ZSkge1xuICAgIHJldHVybiB2YWx1ZTtcbiAgfVxufVxuYFxuICAgICk7XG5cbiAgICBjb25zdCBkaXNjb3ZlcmVkID0gYXdhaXQgY3JlYXRlQnVpbGRlcih0ZXN0Um9vdCkuZGlzY292ZXJFbnRyaWVzUHVibGljKFxuICAgICAgW2VudHJ5RmlsZV0sXG4gICAgICBqb2luKHRlc3RSb290LCAnb3V0JylcbiAgICApO1xuXG4gICAgZXhwZWN0KGRpc2NvdmVyZWQuZGlzY292ZXJlZFNlcmRlRmlsZXMpLnRvRXF1YWwoXG4gICAgICBuZXcgU2V0KFtub3JtYWxpemUoc2VyZGVGaWxlKV0pXG4gICAgKTtcbiAgfSk7XG5cbiAgaXQoJ2NhdGVnb3JpemVzIHN0ZXAsIHdvcmtmbG93LCBhbmQgc2VyZGUgdXNhZ2UgaW5kZXBlbmRlbnRseScsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBlbnRyeUZpbGUgPSBqb2luKHRlc3RSb290LCAnc3JjJywgJ2VudHJ5LnRzJyk7XG4gICAgY29uc3Qgc3RlcEZpbGUgPSBqb2luKHRlc3RSb290LCAnc3JjJywgJ3N0ZXAudHMnKTtcbiAgICBjb25zdCB3b3JrZmxvd0ZpbGUgPSBqb2luKHRlc3RSb290LCAnc3JjJywgJ3dvcmtmbG93LnRzJyk7XG4gICAgY29uc3Qgc2VyZGVGaWxlID0gam9pbih0ZXN0Um9vdCwgJ3NyYycsICdzZXJkZS50cycpO1xuXG4gICAgd3JpdGVGaWxlKFxuICAgICAgZW50cnlGaWxlLFxuICAgICAgYGltcG9ydCAnLi9zdGVwJztcbmltcG9ydCAnLi93b3JrZmxvdyc7XG5pbXBvcnQgJy4vc2VyZGUnO1xuYFxuICAgICk7XG4gICAgd3JpdGVGaWxlKFxuICAgICAgc3RlcEZpbGUsXG4gICAgICBgZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJ1blN0ZXAoKSB7XG4gICd1c2Ugc3RlcCc7XG4gIHJldHVybiAnb2snO1xufVxuYFxuICAgICk7XG4gICAgd3JpdGVGaWxlKFxuICAgICAgd29ya2Zsb3dGaWxlLFxuICAgICAgYGV4cG9ydCBhc3luYyBmdW5jdGlvbiBydW5Xb3JrZmxvdygpIHtcbiAgJ3VzZSB3b3JrZmxvdyc7XG4gIHJldHVybiAnb2snO1xufVxuYFxuICAgICk7XG4gICAgd3JpdGVGaWxlKFxuICAgICAgc2VyZGVGaWxlLFxuICAgICAgYGV4cG9ydCBjbGFzcyBWYWx1ZSB7XG4gIHN0YXRpYyBjbGFzc0lkID0gJ1ZhbHVlJztcbiAgc3RhdGljIFtTeW1ib2wuZm9yKCd3b3JrZmxvdy1zZXJpYWxpemUnKV0odmFsdWU6IFZhbHVlKSB7XG4gICAgcmV0dXJuIHZhbHVlO1xuICB9XG59XG5gXG4gICAgKTtcblxuICAgIGNvbnN0IGRpc2NvdmVyZWQgPSBhd2FpdCBjcmVhdGVCdWlsZGVyKHRlc3RSb290KS5kaXNjb3ZlckVudHJpZXNQdWJsaWMoXG4gICAgICBbZW50cnlGaWxlXSxcbiAgICAgIGpvaW4odGVzdFJvb3QsICdvdXQnKVxuICAgICk7XG5cbiAgICBleHBlY3QoZGlzY292ZXJlZC5kaXNjb3ZlcmVkU3RlcHMpLnRvRXF1YWwobmV3IFNldChbbm9ybWFsaXplKHN0ZXBGaWxlKV0pKTtcbiAgICBleHBlY3QoZGlzY292ZXJlZC5kaXNjb3ZlcmVkV29ya2Zsb3dzKS50b0VxdWFsKFxuICAgICAgbmV3IFNldChbbm9ybWFsaXplKHdvcmtmbG93RmlsZSldKVxuICAgICk7XG4gICAgZXhwZWN0KGRpc2NvdmVyZWQuZGlzY292ZXJlZFNlcmRlRmlsZXMpLnRvRXF1YWwoXG4gICAgICBuZXcgU2V0KFtub3JtYWxpemUoc2VyZGVGaWxlKV0pXG4gICAgKTtcbiAgfSk7XG5cbiAgaXQoJ2lnbm9yZXMgc2VyZGUgZXhhbXBsZXMgdGhhdCBvbmx5IGFwcGVhciBpbnNpZGUgY29tbWVudHMnLCBhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgZW50cnlGaWxlID0gam9pbih0ZXN0Um9vdCwgJ3NyYycsICdlbnRyeS50cycpO1xuICAgIGNvbnN0IGRvY3NGaWxlID0gam9pbih0ZXN0Um9vdCwgJ3NyYycsICdkb2NzLnRzJyk7XG5cbiAgICB3cml0ZUZpbGUoZW50cnlGaWxlLCBgaW1wb3J0ICcuL2RvY3MnO1xcbmApO1xuICAgIHdyaXRlRmlsZShcbiAgICAgIGRvY3NGaWxlLFxuICAgICAgYC8qKlxuICogaW1wb3J0IHsgV09SS0ZMT1dfU0VSSUFMSVpFIH0gZnJvbSAnQHdvcmtmbG93L3NlcmRlJztcbiAqXG4gKiBjbGFzcyBFeGFtcGxlIHtcbiAqICAgc3RhdGljIFtXT1JLRkxPV19TRVJJQUxJWkVdKHZhbHVlKSB7XG4gKiAgICAgcmV0dXJuIHZhbHVlO1xuICogICB9XG4gKiB9XG4gKi9cbmV4cG9ydCBjb25zdCBXT1JLRkxPV19TRVJJQUxJWkUgPSBTeW1ib2wuZm9yKCd3b3JrZmxvdy1zZXJpYWxpemUnKTtcbmBcbiAgICApO1xuXG4gICAgY29uc3QgZGlzY292ZXJlZCA9IGF3YWl0IGNyZWF0ZUJ1aWxkZXIodGVzdFJvb3QpLmRpc2NvdmVyRW50cmllc1B1YmxpYyhcbiAgICAgIFtlbnRyeUZpbGVdLFxuICAgICAgam9pbih0ZXN0Um9vdCwgJ291dCcpXG4gICAgKTtcblxuICAgIGV4cGVjdChkaXNjb3ZlcmVkLmRpc2NvdmVyZWRTZXJkZUZpbGVzKS50b0VxdWFsKG5ldyBTZXQoKSk7XG4gIH0pO1xuXG4gIGl0KCdyZWxhdGl2aXplcyBuZXN0ZWQgcGFja2FnZSBzdGVwIHJlZ2lzdHJhdGlvbiBpbXBvcnRzJywgKCkgPT4ge1xuICAgIGNvbnN0IHJvdXRlRGlyID0gam9pbih0ZXN0Um9vdCwgJ2FwcCcsICcud2VsbC1rbm93bicsICd3b3JrZmxvdycsICd2MScpO1xuICAgIGNvbnN0IGRpcmVjdFBhY2thZ2VGaWxlID0gam9pbihcbiAgICAgIHRlc3RSb290LFxuICAgICAgJ25vZGVfbW9kdWxlcycsXG4gICAgICAnZGlyZWN0LXBrZycsXG4gICAgICAnc3RlcC5qcydcbiAgICApO1xuICAgIGNvbnN0IG5lc3RlZFBhY2thZ2VGaWxlID0gam9pbihcbiAgICAgIHRlc3RSb290LFxuICAgICAgJ25vZGVfbW9kdWxlcycsXG4gICAgICAncGFyZW50LXBrZycsXG4gICAgICAnbm9kZV9tb2R1bGVzJyxcbiAgICAgICduZXN0ZWQtcGtnJyxcbiAgICAgICdzdGVwLmpzJ1xuICAgICk7XG5cbiAgICB3cml0ZUZpbGUoXG4gICAgICBqb2luKHRlc3RSb290LCAncGFja2FnZS5qc29uJyksXG4gICAgICBKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgIGRlcGVuZGVuY2llczoge1xuICAgICAgICAgICdkaXJlY3QtcGtnJzogJzEuMC4wJyxcbiAgICAgICAgfSxcbiAgICAgIH0pXG4gICAgKTtcbiAgICB3cml0ZUZpbGUoXG4gICAgICBqb2luKHRlc3RSb290LCAnbm9kZV9tb2R1bGVzJywgJ2RpcmVjdC1wa2cnLCAncGFja2FnZS5qc29uJyksXG4gICAgICBKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgIG5hbWU6ICdkaXJlY3QtcGtnJyxcbiAgICAgICAgdmVyc2lvbjogJzEuMC4wJyxcbiAgICAgICAgZXhwb3J0czoge1xuICAgICAgICAgICcuL3N0ZXAnOiAnLi9zdGVwLmpzJyxcbiAgICAgICAgfSxcbiAgICAgIH0pXG4gICAgKTtcbiAgICB3cml0ZUZpbGUoZGlyZWN0UGFja2FnZUZpbGUsIGBleHBvcnQgY29uc3Qgc3RlcCA9IHRydWU7XFxuYCk7XG4gICAgd3JpdGVGaWxlKFxuICAgICAgam9pbihcbiAgICAgICAgdGVzdFJvb3QsXG4gICAgICAgICdub2RlX21vZHVsZXMnLFxuICAgICAgICAncGFyZW50LXBrZycsXG4gICAgICAgICdub2RlX21vZHVsZXMnLFxuICAgICAgICAnbmVzdGVkLXBrZycsXG4gICAgICAgICdwYWNrYWdlLmpzb24nXG4gICAgICApLFxuICAgICAgSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICBuYW1lOiAnbmVzdGVkLXBrZycsXG4gICAgICAgIHZlcnNpb246ICcxLjAuMCcsXG4gICAgICAgIGV4cG9ydHM6IHtcbiAgICAgICAgICAnLi9zdGVwJzogJy4vc3RlcC5qcycsXG4gICAgICAgIH0sXG4gICAgICB9KVxuICAgICk7XG4gICAgd3JpdGVGaWxlKG5lc3RlZFBhY2thZ2VGaWxlLCBgZXhwb3J0IGNvbnN0IHN0ZXAgPSB0cnVlO1xcbmApO1xuXG4gICAgY29uc3QgYnVpbGRlciA9IGNyZWF0ZUJ1aWxkZXIodGVzdFJvb3QpO1xuICAgIGV4cGVjdChcbiAgICAgIGJ1aWxkZXIuY3JlYXRlUm91dGVJbXBvcnRTcGVjaWZpZXJQdWJsaWMoZGlyZWN0UGFja2FnZUZpbGUsIHJvdXRlRGlyKVxuICAgICkudG9CZSgnZGlyZWN0LXBrZy9zdGVwJyk7XG4gICAgZXhwZWN0KFxuICAgICAgYnVpbGRlci5jcmVhdGVSb3V0ZUltcG9ydFNwZWNpZmllclB1YmxpYyhuZXN0ZWRQYWNrYWdlRmlsZSwgcm91dGVEaXIpXG4gICAgKS50b0JlKFxuICAgICAgJy4uLy4uLy4uLy4uL25vZGVfbW9kdWxlcy9wYXJlbnQtcGtnL25vZGVfbW9kdWxlcy9uZXN0ZWQtcGtnL3N0ZXAuanMnXG4gICAgKTtcbiAgfSk7XG59KTtcbiJdfQ==