vite-plugin-react-server 1.4.2 → 1.4.3

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 (73) hide show
  1. package/README.md +48 -313
  2. package/dist/package.json +123 -13
  3. package/dist/plugin/bundle/deferredStaticGeneration.js +14 -39
  4. package/dist/plugin/bundle/manifests.js +30 -48
  5. package/dist/plugin/config/autoDiscover/resolveAutoDiscover.d.ts.map +1 -1
  6. package/dist/plugin/config/autoDiscover/resolveAutoDiscover.js +4 -1
  7. package/dist/plugin/config/envPrefixFromConfig.js +12 -7
  8. package/dist/plugin/config/getCondition.d.ts.map +1 -1
  9. package/dist/plugin/config/getCondition.js +7 -5
  10. package/dist/plugin/dev-server/virtualRscHmrPlugin.js +23 -23
  11. package/dist/plugin/environments/createBuildEventPlugin.js +88 -98
  12. package/dist/plugin/environments/createEnvironmentPlugin.js +222 -250
  13. package/dist/plugin/helpers/createRscRenderHelpers.js +33 -34
  14. package/dist/plugin/helpers/createSharedLoader.d.ts.map +1 -1
  15. package/dist/plugin/helpers/createSharedLoader.js +4 -2
  16. package/dist/plugin/helpers/headlessStreamReuseHandler.js +30 -22
  17. package/dist/plugin/helpers/headlessStreamState.js +15 -28
  18. package/dist/plugin/helpers/resolveComponent.d.ts.map +1 -1
  19. package/dist/plugin/helpers/resolveComponent.js +4 -2
  20. package/dist/plugin/index.client.d.ts +5 -0
  21. package/dist/plugin/index.client.d.ts.map +1 -0
  22. package/dist/plugin/index.client.js +4 -0
  23. package/dist/plugin/index.d.ts +4 -3
  24. package/dist/plugin/index.d.ts.map +1 -1
  25. package/dist/plugin/index.js +10 -5
  26. package/dist/plugin/index.server.d.ts +5 -0
  27. package/dist/plugin/index.server.d.ts.map +1 -0
  28. package/dist/plugin/index.server.js +4 -0
  29. package/dist/plugin/metrics/createWorkerStartupMetrics.js +31 -13
  30. package/dist/plugin/orchestrator/createPluginOrchestrator.client.js +41 -38
  31. package/dist/plugin/orchestrator/createPluginOrchestrator.server.js +43 -46
  32. package/dist/plugin/plugin.client.js +2 -2
  33. package/dist/plugin/plugin.server.js +2 -2
  34. package/dist/plugin/react-static/createBuildLoader.client.js +12 -6
  35. package/dist/plugin/react-static/createBuildLoader.server.js +255 -235
  36. package/dist/plugin/react-static/plugin.client.js +684 -770
  37. package/dist/plugin/react-static/plugin.server.js +517 -603
  38. package/dist/plugin/react-static/processCssFilesForPages.js +103 -88
  39. package/dist/plugin/react-static/renderPage.client.js +455 -529
  40. package/dist/plugin/react-static/renderPage.server.js +485 -508
  41. package/dist/plugin/react-static/renderPagesBatched.js +277 -275
  42. package/dist/plugin/react-static/rscToHtmlStream.client.js +48 -29
  43. package/dist/plugin/react-static/rscToHtmlStream.server.js +62 -37
  44. package/dist/plugin/react-static/temporaryReferences.server.js +11 -2
  45. package/dist/plugin/stream/createMainThreadHandlers.js +40 -31
  46. package/dist/plugin/stream/renderRscStream.server.d.ts.map +1 -1
  47. package/dist/plugin/stream/renderRscStream.server.js +127 -144
  48. package/dist/plugin/transformer/createTransformerPlugin.js +226 -265
  49. package/dist/plugin/utils/checkReactVersion.d.ts +7 -0
  50. package/dist/plugin/utils/checkReactVersion.d.ts.map +1 -0
  51. package/dist/plugin/utils/checkReactVersion.js +23 -0
  52. package/dist/plugin/utils/envUrls.node.js +12 -11
  53. package/dist/plugin/vendor/vendor-alias.js +84 -114
  54. package/dist/plugin/vendor/vendor.client.d.ts.map +1 -1
  55. package/dist/plugin/vendor/vendor.client.js +1 -3
  56. package/dist/plugin/worker/rsc/handleRscRender.d.ts.map +1 -1
  57. package/dist/plugin/worker/rsc/handleRscRender.js +3 -1
  58. package/dist/tsconfig.tsbuildinfo +1 -1
  59. package/package.json +123 -13
  60. package/plugin/config/autoDiscover/resolveAutoDiscover.ts +4 -0
  61. package/plugin/config/getCondition.ts +6 -4
  62. package/plugin/helpers/createSharedLoader.ts +6 -1
  63. package/plugin/helpers/resolveComponent.ts +6 -1
  64. package/plugin/index.client.ts +4 -0
  65. package/plugin/index.server.ts +4 -0
  66. package/plugin/index.ts +12 -5
  67. package/plugin/plugin.client.ts +1 -1
  68. package/plugin/plugin.server.ts +1 -1
  69. package/plugin/stream/renderRscStream.server.ts +3 -0
  70. package/plugin/utils/checkReactVersion.ts +28 -0
  71. package/plugin/vendor/vendor.client.ts +0 -2
  72. package/plugin/worker/rsc/handleRscRender.ts +2 -0
  73. package/scripts/generate-toc.mjs +27 -294
@@ -1,801 +1,715 @@
1
1
  /**
2
- * plugin.client.ts
3
- *
4
- * PURPOSE: Client-side static plugin for React Server Components
5
- *
6
- * This module:
7
- * 1. Handles static site generation in the client environment
8
- * 2. Uses RSC worker for RSC rendering and main-thread for HTML rendering
9
- * 3. Generates both RSC and HTML files for static pages
10
- * 4. Integrates with Vite's build process
11
- *
12
- * Feature parity with main react-static plugin, but in reverse. Uses rsc-worker to render rsc, and main thread for html.
13
- * This is not the default behavior, but is supported for testing and custom app development purposes.
14
- * Additionally, this can make it easier to use the --app flag to build all the modules + static generation at once.
2
+ * vite-plugin-react-server
3
+ * Copyright (c) Nico Brinkkemper
4
+ * MIT License
15
5
  */
16
- import { createLogger, } from "vite";
17
- import { resolveOptions } from "../config/resolveOptions.js";
18
- import { renderPagesBatched } from "./renderPagesBatched.js";
19
- import { performance } from "node:perf_hooks";
20
- import { renderPage } from "./renderPage.client.js";
21
- import { createWorker } from "../worker/createWorker.js";
22
- import { serializedOptions, serializeResolvedConfig, } from "../helpers/serializeUserOptions.js";
23
- import { getBundleManifest } from "../helpers/getBundleManifest.js";
24
- import { handleError } from "../error/handleError.js";
25
- import { shouldCausePanic } from "../error/panicThresholdHandler.js";
26
- import { configurePreviewServer } from "./configurePreviewServer.js";
27
- import { assertNonReactServer } from "../config/getCondition.js";
28
- import { envPrefixFromConfig } from "../config/envPrefixFromConfig.js";
29
- import { createWorkerStartupMetrics } from "../metrics/createWorkerStartupMetrics.js";
30
- import { processCssFilesForPages } from "./processCssFilesForPages.js";
31
- import { createBuildLoader } from "./createBuildLoader.client.js";
32
- import { getNodeEnv } from "../config/getNodeEnv.js";
33
- import { toError } from "../error/toError.js";
34
- import { addStaticManifest, manifests, getSharedManifestStore, } from "../bundle/manifests.js";
35
- import { deferStaticGeneration } from "../bundle/deferredStaticGeneration.js";
36
- import { resolveAutoDiscover } from "../config/index.js";
37
- import { join } from "node:path";
38
- import { baseURL } from "../utils/envUrls.node.js";
39
- import { tryManifest } from "../helpers/tryManifest.js";
40
- // cssCollector removed - using filesystem-based CSS processing
6
+ import { createLogger } from 'vite';
7
+ import { resolveOptions } from '../config/resolveOptions.js';
8
+ import { renderPagesBatched } from './renderPagesBatched.js';
9
+ import { performance } from 'node:perf_hooks';
10
+ import { renderPage } from './renderPage.client.js';
11
+ import { createWorker } from '../worker/createWorker.js';
12
+ import { serializeResolvedConfig, serializedOptions } from '../helpers/serializeUserOptions.js';
13
+ import { getBundleManifest } from '../helpers/getBundleManifest.js';
14
+ import { handleError } from '../error/handleError.js';
15
+ import { shouldCausePanic } from '../error/panicThresholdHandler.js';
16
+ import { configurePreviewServer } from './configurePreviewServer.js';
17
+ import { assertNonReactServer } from '../config/getCondition.js';
18
+ import { envPrefixFromConfig } from '../config/envPrefixFromConfig.js';
19
+ import { createWorkerStartupMetrics } from '../metrics/createWorkerStartupMetrics.js';
20
+ import { processCssFilesForPages } from './processCssFilesForPages.js';
21
+ import { createBuildLoader } from './createBuildLoader.client.js';
22
+ import { getNodeEnv } from '../config/getNodeEnv.js';
23
+ import { toError } from '../error/toError.js';
24
+ import { addStaticManifest, manifests, getSharedManifestStore } from '../bundle/manifests.js';
25
+ import { deferStaticGeneration } from '../bundle/deferredStaticGeneration.js';
26
+ import { resolveAutoDiscover } from '../config/autoDiscover/resolveAutoDiscover.js';
27
+ import { join } from 'node:path';
28
+ import { baseURL } from '../utils/envUrls.node.js';
29
+ import { tryManifest } from '../helpers/tryManifest.js';
30
+
41
31
  assertNonReactServer();
42
- /**
43
- * plugin.client.ts
44
- *
45
- * PURPOSE: Client-side static plugin for React Server Components
46
- *
47
- * This module:
48
- * 1. Handles static site generation in the client environment
49
- * 2. Uses RSC worker for RSC rendering and main-thread for HTML rendering
50
- * 3. Generates both RSC and HTML files for static pages
51
- * 4. Integrates with Vite's build process
52
- *
53
- * @param options
54
- * @returns
55
- */
56
- export const reactStaticPlugin = function _reactStaticPlugin(options) {
57
- let logger;
58
- let autoDiscoveredFiles = null;
59
- let rscWorker = undefined;
60
- let resolvedConfig = null;
61
- let serverManifest = undefined;
62
- let staticBundle = undefined;
63
- let serverBundle = undefined;
64
- let configEnv;
65
- const timing = {
66
- start: performance.now(),
67
- configResolved: 0,
68
- buildStart: 0,
69
- renderStart: 0,
70
- };
71
- const resolvedOptions = resolveOptions(options);
72
- if (resolvedOptions.type === "error") {
73
- throw resolvedOptions.error;
74
- }
75
- const userOptions = resolvedOptions.userOptions;
76
- return {
77
- name: "vite:plugin-react-server/client-static",
78
- enforce: "post",
79
- apply: "build", // Apply to build mode
80
- api: {
81
- meta: { timing },
82
- },
83
- async config(_config, viteConfigEnv) {
84
- configEnv = viteConfigEnv;
85
- },
86
- applyToEnvironment(partialEnvironment) {
87
- // Client static plugin should apply to static environment (browser/ESM builds)
88
- // This is where we want to bundle everything and filter out _virtual files
89
- // Apply to both "static" and "client" environments - we'll handle which one runs static generation in closeBundle
90
- const envName = partialEnvironment.name;
91
- if (["static", "client"].includes(envName)) {
92
- return true;
32
+ const reactStaticPlugin = function _reactStaticPlugin(options) {
33
+ let logger;
34
+ let autoDiscoveredFiles = null;
35
+ let rscWorker = void 0;
36
+ let resolvedConfig = null;
37
+ let serverManifest = void 0;
38
+ let staticBundle = void 0;
39
+ let serverBundle = void 0;
40
+ let configEnv;
41
+ const timing = {
42
+ start: performance.now(),
43
+ configResolved: 0,
44
+ buildStart: 0,
45
+ renderStart: 0
46
+ };
47
+ const resolvedOptions = resolveOptions(options);
48
+ if (resolvedOptions.type === "error") {
49
+ throw resolvedOptions.error;
50
+ }
51
+ const userOptions = resolvedOptions.userOptions;
52
+ return {
53
+ name: "vite:plugin-react-server/client-static",
54
+ enforce: "post",
55
+ apply: "build",
56
+ // Apply to build mode
57
+ api: {
58
+ meta: { timing }
59
+ },
60
+ async config(_config, viteConfigEnv) {
61
+ configEnv = viteConfigEnv;
62
+ },
63
+ applyToEnvironment(partialEnvironment) {
64
+ const envName = partialEnvironment.name;
65
+ if (["static", "client"].includes(envName)) {
66
+ return true;
67
+ }
68
+ return false;
69
+ },
70
+ async configResolved(config) {
71
+ timing.configResolved = performance.now();
72
+ logger = config.customLogger || createLogger();
73
+ resolvedConfig = config;
74
+ const autoDiscoverResult = await resolveAutoDiscover({
75
+ config,
76
+ configEnv: configEnv || {
77
+ mode: config.mode,
78
+ command: config.command},
79
+ userOptions,
80
+ logger
81
+ });
82
+ if (autoDiscoverResult.type === "error") {
83
+ throw autoDiscoverResult.error;
84
+ }
85
+ autoDiscoveredFiles = autoDiscoverResult.autoDiscoveredFiles;
86
+ if (userOptions.verbose) {
87
+ logger?.info(`Auto-discovery ${autoDiscoverResult.type === "success" ? "completed" : "skipped"}`);
88
+ }
89
+ },
90
+ async buildStart() {
91
+ timing.buildStart = performance.now();
92
+ if (userOptions.verbose) {
93
+ logger?.info("[react-static-client] Build started");
94
+ }
95
+ if (userOptions.onEvent && autoDiscoveredFiles) {
96
+ try {
97
+ userOptions.onEvent({
98
+ type: "build.start",
99
+ data: {
100
+ pages: Array.from(autoDiscoveredFiles.urlMap.keys()),
101
+ files: autoDiscoveredFiles
102
+ }
103
+ });
104
+ } catch (error) {
105
+ const panicError = handleError({
106
+ error,
107
+ logger,
108
+ panicThreshold: userOptions.panicThreshold});
109
+ if (panicError != null) {
110
+ rscWorker?.terminate();
111
+ throw panicError;
112
+ }
113
+ }
114
+ }
115
+ },
116
+ async renderStart() {
117
+ timing.renderStart = performance.now();
118
+ if (userOptions.verbose) {
119
+ logger?.info("[react-static-client] Render started");
120
+ }
121
+ },
122
+ // the preview server helps to view the generated static folder, but only when the static plugin is enabled
123
+ // if no build.pages, then the preview server will instead use default vite preview server
124
+ // it works the same under both conditions
125
+ async configurePreviewServer(server) {
126
+ logger = server.config.customLogger || server.config.logger;
127
+ configurePreviewServer({
128
+ server,
129
+ userOptions
130
+ });
131
+ },
132
+ async writeBundle(_options, bundle) {
133
+ try {
134
+ if (!autoDiscoveredFiles?.urlMap) {
135
+ return;
136
+ }
137
+ const bundleManifest = getBundleManifest({
138
+ bundle,
139
+ normalizer: userOptions.normalizer
140
+ });
141
+ if (this.environment.name === "static") {
142
+ addStaticManifest(bundleManifest);
143
+ staticBundle = bundle;
144
+ } else if (this.environment.name === "client") {
145
+ if (manifests.static) {
146
+ const staticManifest = manifests.static;
147
+ for (const [, chunk] of Object.entries(bundle)) {
148
+ if (chunk.type === "chunk" && chunk.fileName) {
149
+ const normalized = userOptions.normalizer(chunk.fileName);
150
+ let value = normalized[1];
151
+ if (value.startsWith(userOptions.moduleBasePath)) {
152
+ value = value.slice(userOptions.moduleBasePath.length);
153
+ }
154
+ const entry = staticManifest[value];
155
+ if (entry && entry.file !== chunk.fileName) {
156
+ chunk.fileName = entry.file;
157
+ }
158
+ }
93
159
  }
94
- return false;
95
- },
96
- async configResolved(config) {
97
- timing.configResolved = performance.now();
98
- logger = config.customLogger || createLogger();
99
- resolvedConfig = config;
100
- // Perform auto-discovery to populate autoDiscoveredFiles
101
- const autoDiscoverResult = await resolveAutoDiscover({
102
- config: config,
160
+ }
161
+ } else if (this.environment.name === "server") {
162
+ serverBundle = bundle;
163
+ }
164
+ return;
165
+ } catch (error) {
166
+ const panicError = handleError({
167
+ error,
168
+ logger,
169
+ panicThreshold: userOptions.panicThreshold});
170
+ if (panicError != null) {
171
+ throw panicError;
172
+ }
173
+ }
174
+ },
175
+ async closeBundle() {
176
+ const envName = this.environment.name;
177
+ const isSsr = this.environment.config.build?.ssr === true;
178
+ if (userOptions.verbose) {
179
+ logger?.info(`[react-static-client] closeBundle called for environment: ${envName}, ssr: ${isSsr}`);
180
+ }
181
+ if (envName === "ssr" || envName === "server" || isSsr) {
182
+ if (userOptions.verbose) {
183
+ logger?.info(`[react-static-client] Skipping static generation for environment: ${envName} (ssr: ${isSsr})`);
184
+ }
185
+ return;
186
+ }
187
+ if (envName === "static" || envName === "client" && !isSsr) {
188
+ try {
189
+ const { rmSync, existsSync } = await import('node:fs');
190
+ const { join: join2, resolve } = await import('node:path');
191
+ const resolvedOutDir = this.environment.config.build?.outDir ? resolve(this.environment.config.root || userOptions.projectRoot, this.environment.config.build.outDir) : resolve(userOptions.projectRoot, userOptions.build.outDir);
192
+ const outputDirs = [
193
+ join2(resolvedOutDir, userOptions.build.static || "static"),
194
+ join2(resolvedOutDir, userOptions.build.client || "client")
195
+ ];
196
+ for (const outDir of outputDirs) {
197
+ const virtualDir = join2(outDir, "_virtual");
198
+ if (existsSync(virtualDir)) {
199
+ rmSync(virtualDir, { recursive: true, force: true });
200
+ if (userOptions.verbose) {
201
+ logger?.info(`[react-static-client] Cleaned up _virtual directory: ${virtualDir}`);
202
+ }
203
+ }
204
+ }
205
+ } catch (error) {
206
+ if (userOptions.verbose) {
207
+ logger?.warn(`[react-static-client] Failed to clean up _virtual directory: ${error}`);
208
+ }
209
+ }
210
+ }
211
+ if (envName === "ssr" || envName === "server" || isSsr) {
212
+ if (userOptions.verbose) {
213
+ logger?.info(`[react-static-client] Skipping static generation - not in static environment (${envName}, ssr: ${isSsr})`);
214
+ }
215
+ return;
216
+ }
217
+ const closeBundleContext = this;
218
+ deferStaticGeneration(async () => {
219
+ try {
220
+ if (!autoDiscoveredFiles) {
221
+ if (userOptions.verbose) {
222
+ logger?.warn("[react-static-client] autoDiscoveredFiles not set, attempting to re-discover");
223
+ }
224
+ const { getStashedUserOptions, getEnvironmentId } = await import('../config/stashedOptionsState.js');
225
+ const { getCondition } = await import('../config/getCondition.js');
226
+ const envId = getEnvironmentId(getCondition(), resolvedConfig?.mode || "production");
227
+ const stashedOptions = getStashedUserOptions(envId);
228
+ if (stashedOptions && resolvedConfig) {
229
+ const autoDiscoverResult = await resolveAutoDiscover({
230
+ config: resolvedConfig,
103
231
  configEnv: configEnv || {
104
- mode: config.mode,
105
- command: config.command,
106
- isSsrBuild: false,
107
- isPreview: false,
232
+ mode: resolvedConfig.mode || "production",
233
+ command: resolvedConfig.command || "build",
234
+ isSsrBuild: false,
235
+ isPreview: false
108
236
  },
109
237
  userOptions,
110
- logger,
111
- });
112
- if (autoDiscoverResult.type === "error") {
113
- throw autoDiscoverResult.error;
238
+ logger
239
+ });
240
+ if (autoDiscoverResult.type === "success") {
241
+ autoDiscoveredFiles = autoDiscoverResult.autoDiscoveredFiles;
242
+ if (userOptions.verbose) {
243
+ logger?.info(`[react-static-client] Re-discovered ${autoDiscoveredFiles.urlMap.size} pages`);
244
+ }
245
+ } else {
246
+ if (userOptions.verbose) {
247
+ logger?.warn(`[react-static-client] Failed to re-discover pages: ${autoDiscoverResult.error}`);
248
+ }
249
+ }
114
250
  }
115
- autoDiscoveredFiles = autoDiscoverResult.autoDiscoveredFiles;
251
+ }
252
+ if (!autoDiscoveredFiles?.urlMap || autoDiscoveredFiles?.urlMap.size === 0) {
116
253
  if (userOptions.verbose) {
117
- logger?.info(`Auto-discovery ${autoDiscoverResult.type === "success" ? "completed" : "skipped"}`);
254
+ logger?.warn(`[react-static-client] No pages to generate - urlMap is empty (size: ${autoDiscoveredFiles?.urlMap?.size || 0})`);
255
+ logger?.warn(`[react-static-client] autoDiscoveredFiles exists: ${!!autoDiscoveredFiles}, urlMap exists: ${!!autoDiscoveredFiles?.urlMap}`);
118
256
  }
119
- },
120
- async buildStart() {
121
- timing.buildStart = performance.now();
257
+ return;
258
+ }
259
+ if (userOptions.verbose) {
260
+ logger?.info(`[react-static-client] Starting static generation with ${autoDiscoveredFiles.urlMap.size} pages`);
261
+ }
262
+ try {
122
263
  if (userOptions.verbose) {
123
- logger?.info("[react-static-client] Build started");
264
+ logger?.info(`[react-static-client] Attempting to get server manifest from shared state`);
124
265
  }
125
- if (userOptions.onEvent && autoDiscoveredFiles) {
126
- try {
127
- userOptions.onEvent({
128
- type: "build.start",
129
- data: {
130
- pages: Array.from(autoDiscoveredFiles.urlMap.keys()),
131
- files: autoDiscoveredFiles,
132
- },
133
- });
134
- }
135
- catch (error) {
136
- const panicError = handleError({
137
- error,
138
- logger: logger,
139
- panicThreshold: userOptions.panicThreshold,
140
- context: "buildStart",
141
- });
142
- if (panicError != null) {
143
- rscWorker?.terminate();
144
- throw panicError;
145
- }
146
- }
266
+ const sharedState = getSharedManifestStore(closeBundleContext);
267
+ if (sharedState.server) {
268
+ serverManifest = sharedState.server;
269
+ if (userOptions.verbose) {
270
+ logger?.info(`[react-static-client] Got server manifest from shared state`);
271
+ }
272
+ } else {
273
+ throw new Error("No server manifest in shared state");
147
274
  }
148
- },
149
- async renderStart() {
150
- timing.renderStart = performance.now();
275
+ } catch (error) {
151
276
  if (userOptions.verbose) {
152
- logger?.info("[react-static-client] Render started");
277
+ logger?.info(`[react-static-client] Failed to get server manifest from shared state, trying filesystem: ${error}`);
153
278
  }
154
- },
155
- // the preview server helps to view the generated static folder, but only when the static plugin is enabled
156
- // if no build.pages, then the preview server will instead use default vite preview server
157
- // it works the same under both conditions
158
- async configurePreviewServer(server) {
159
- logger = server.config.customLogger || server.config.logger;
160
- configurePreviewServer({
161
- server,
162
- userOptions,
279
+ const serverManifestPath = join(
280
+ userOptions.build.outDir,
281
+ userOptions.build.server
282
+ );
283
+ const manifestPath = typeof resolvedConfig?.build.manifest === "string" ? resolvedConfig.build.manifest : ".vite/manifest.json";
284
+ if (userOptions.verbose) {
285
+ logger?.info(`[react-static-client] Loading server manifest from: ${join(serverManifestPath, manifestPath)}`);
286
+ }
287
+ const serverManifestResult = await tryManifest({
288
+ root: userOptions.projectRoot,
289
+ outDir: serverManifestPath,
290
+ manifestPath,
291
+ ssrManifest: false
292
+ });
293
+ if (serverManifestResult.type === "error") {
294
+ if (userOptions.verbose) {
295
+ logger?.warn(`[react-static-client] Failed to load server manifest: ${serverManifestResult.error}`);
296
+ }
297
+ serverManifest = {};
298
+ if (userOptions.verbose) {
299
+ logger?.warn(`[react-static-client] Using empty server manifest as fallback`);
300
+ }
301
+ } else if (serverManifestResult.type === "skip") {
302
+ if (userOptions.verbose) {
303
+ logger?.warn(`[react-static-client] Server manifest not found, using empty manifest as fallback`);
304
+ }
305
+ serverManifest = {};
306
+ } else {
307
+ serverManifest = serverManifestResult.manifest;
308
+ if (userOptions.verbose) {
309
+ logger?.info(`[react-static-client] Loaded server manifest from filesystem`);
310
+ }
311
+ }
312
+ }
313
+ const staticManifestResult = await tryManifest({
314
+ root: userOptions.projectRoot,
315
+ outDir: join(userOptions.build.outDir, userOptions.build.static),
316
+ manifestPath: resolvedConfig?.build.manifest ?? ".vite/manifest.json",
317
+ ssrManifest: false
318
+ });
319
+ if (staticManifestResult.type === "error") {
320
+ throw staticManifestResult.error;
321
+ }
322
+ const staticManifest = staticManifestResult.manifest;
323
+ const indexHtml = staticManifest?.["index.html"]?.file;
324
+ const serverPipeableStreamOptions = {
325
+ ...userOptions.serverPipeableStreamOptions,
326
+ bootstrapModules: [
327
+ ...indexHtml ? [baseURL(indexHtml)] : [],
328
+ ...userOptions.serverPipeableStreamOptions?.bootstrapModules ?? []
329
+ ]
330
+ };
331
+ userOptions.serverPipeableStreamOptions = serverPipeableStreamOptions;
332
+ const clientPipeableStreamOptions = {
333
+ ...userOptions.clientPipeableStreamOptions,
334
+ bootstrapModules: [
335
+ ...indexHtml ? [baseURL(indexHtml)] : [],
336
+ ...userOptions.clientPipeableStreamOptions?.bootstrapModules ?? []
337
+ ]
338
+ };
339
+ const { cssFilesByPage, globalCss } = processCssFilesForPages({
340
+ userOptions,
341
+ autoDiscoveredFiles,
342
+ serverManifest,
343
+ staticManifest,
344
+ bundle: staticBundle || {},
345
+ logger
346
+ });
347
+ if (userOptions.verbose) {
348
+ for (const [route, cssMap] of cssFilesByPage.entries()) {
349
+ logger.info(
350
+ `[react-static-client] Route ${route}: ${cssMap.size} CSS files`
351
+ );
352
+ for (const [key, value] of cssMap.entries()) {
353
+ logger.info(
354
+ `[react-static-client] CSS file: ${key} -> ${value.as} (${value.children ? "inline" : "link"})`
355
+ );
356
+ }
357
+ }
358
+ }
359
+ const routes = Array.from(
360
+ autoDiscoveredFiles.urlMap.keys()
361
+ );
362
+ if (routes.length === 0) {
363
+ if (userOptions.verbose) {
364
+ logger?.info(
365
+ "[react-static-client] No pages to generate, skipping static generation"
366
+ );
367
+ }
368
+ return;
369
+ }
370
+ if (userOptions.verbose) {
371
+ logger?.info(`[react-static-client] Creating build loader`);
372
+ }
373
+ const buildLoader = createBuildLoader();
374
+ if (userOptions.verbose) {
375
+ logger?.info(`[react-static-client] Build loader created`);
376
+ }
377
+ if (userOptions.verbose) {
378
+ logger?.info(
379
+ `[react-static-client] Creating RSC worker with path: ${userOptions.rscWorkerPath}`
380
+ );
381
+ }
382
+ const workerStartTime = performance.now();
383
+ let rscWorkerResult;
384
+ try {
385
+ rscWorkerResult = await createWorker({
386
+ projectRoot: userOptions.projectRoot,
387
+ workerPath: userOptions.rscWorkerPath,
388
+ currentCondition: "react-client",
389
+ reverseCondition: "react-server",
390
+ maxListeners: Math.max(routes.length * 3, 10),
391
+ // Account for multiple listeners per route
392
+ envPrefix: envPrefixFromConfig(resolvedConfig),
393
+ logger,
394
+ verbose: userOptions.verbose,
395
+ mode: getNodeEnv(),
396
+ workerData: {
397
+ userOptions: serializedOptions(userOptions, autoDiscoveredFiles),
398
+ resolvedConfig: serializeResolvedConfig(resolvedConfig),
399
+ configEnv: (() => {
400
+ const fallback = resolvedConfig ? {
401
+ command: resolvedConfig.command,
402
+ mode: resolvedConfig.mode,
403
+ isSsrBuild: false,
404
+ isPreview: false
405
+ } : void 0;
406
+ const finalConfigEnv = configEnv || fallback;
407
+ return finalConfigEnv;
408
+ })(),
409
+ serverManifest: serverManifest || {},
410
+ // Use server manifest for page component resolution
411
+ bundle: staticBundle || {},
412
+ // Use static bundle (client build) for page component resolution
413
+ staticBundle: staticBundle || {},
414
+ // Pass static bundle separately for path resolution
415
+ id: "static-client-rsc-worker"
416
+ }
417
+ });
418
+ } catch (workerError) {
419
+ if (userOptions.verbose) {
420
+ logger?.error(`[react-static-client] Error creating RSC worker: ${workerError}`);
421
+ }
422
+ throw workerError;
423
+ }
424
+ if (rscWorkerResult.type !== "success") {
425
+ const err = rscWorkerResult.error ?? new Error(`Failed to create RSC worker`);
426
+ if (userOptions.verbose) {
427
+ logger?.error(
428
+ `[react-static-client] RSC worker creation failed, throwing error`,
429
+ { error: err }
430
+ );
431
+ }
432
+ throw err;
433
+ }
434
+ rscWorker = rscWorkerResult.worker;
435
+ if (userOptions.verbose) {
436
+ logger?.info(`[react-static-client] RSC worker created successfully`);
437
+ }
438
+ const workerStartupTime = performance.now() - workerStartTime;
439
+ if (userOptions.onMetrics) {
440
+ const workerStartupMetric = createWorkerStartupMetrics({
441
+ route: "/",
442
+ // Worker startup is global, not route-specific
443
+ workerType: "rsc",
444
+ // This is the RSC worker for client-side static generation
445
+ startupTime: workerStartupTime,
446
+ fromMainThread: true,
447
+ fromRscWorker: false,
448
+ fromHtmlWorker: false,
449
+ description: `RSC worker startup for client-side static generation`
163
450
  });
164
- },
165
- async writeBundle(_options, bundle) {
166
- // Capture manifests from all environments
451
+ userOptions.onMetrics(workerStartupMetric);
452
+ }
453
+ const { onEvent, onMetrics, ...handlerOptions } = userOptions;
454
+ if (userOptions.verbose) {
455
+ logger?.info(`[react-static-client] Extracted onEvent: ${typeof onEvent}, userOptions.onEvent: ${typeof userOptions.onEvent}`);
456
+ }
457
+ if (!serverBundle && onEvent) {
458
+ const originalOnEvent = onEvent;
459
+ const tempOnEvent = (event) => {
460
+ if (event.type === "build.writeBundle.server") {
461
+ serverBundle = event.data.bundle;
462
+ logger?.info(
463
+ "[react-static-client] Captured server bundle from build event"
464
+ );
465
+ }
466
+ originalOnEvent(event);
467
+ };
468
+ userOptions.onEvent = tempOnEvent;
469
+ }
470
+ const eventHandler = onEvent || userOptions.onEvent;
471
+ if (typeof eventHandler === "function") {
167
472
  try {
168
- if (!autoDiscoveredFiles?.urlMap) {
169
- return;
473
+ if (userOptions.verbose) {
474
+ logger?.info(`[react-static-client] Emitting build.ssg.start event`);
475
+ }
476
+ const r = eventHandler({
477
+ type: "build.ssg.start",
478
+ data: {
479
+ pages: Array.from(autoDiscoveredFiles?.urlMap.keys() ?? []),
480
+ options: null,
481
+ // No specific rollup output options for static generation
482
+ bundle: staticBundle || {}
170
483
  }
171
- const bundleManifest = getBundleManifest({
172
- bundle,
173
- normalizer: userOptions.normalizer,
174
- });
175
- // Store manifest based on environment
176
- if (this.environment.name === "static") {
177
- // Store in global manifest store for environment plugin access
178
- addStaticManifest(bundleManifest);
179
- staticBundle = bundle;
484
+ });
485
+ if (r != null && typeof r === "object" && "then" in r) {
486
+ await r;
487
+ }
488
+ } catch (error) {
489
+ const eventPanicError = handleError({
490
+ error,
491
+ logger,
492
+ panicThreshold: userOptions.panicThreshold,
493
+ context: "onEvent(build.ssg.start)"
494
+ });
495
+ if (eventPanicError != null) {
496
+ throw eventPanicError;
497
+ }
498
+ }
499
+ } else if (userOptions.verbose) {
500
+ logger?.warn(`[react-static-client] No onEvent handler available to emit build.ssg.start`);
501
+ }
502
+ const renderPagesGenerator = renderPagesBatched(
503
+ routes,
504
+ {
505
+ ...handlerOptions,
506
+ // Use the clean options instead of the original handlerOptions
507
+ worker: rscWorker,
508
+ // Pass the RSC worker for RSC rendering only
509
+ rscWorker,
510
+ // Pass the RSC worker for RSC rendering only
511
+ loader: buildLoader,
512
+ // Use proper build loader instead of no-op
513
+ logger,
514
+ autoDiscoveredFiles,
515
+ cssFilesByPage,
516
+ // Pass CSS files by page
517
+ serverPipeableStreamOptions,
518
+ // Pass server options to RSC worker
519
+ clientPipeableStreamOptions,
520
+ // Pass client options to RSC worker
521
+ globalCss,
522
+ // Pass global CSS
523
+ manifest: serverManifest || {},
524
+ // Server manifest for RSC worker
525
+ staticManifest,
526
+ // Static manifest for consistent module IDs
527
+ onEvent,
528
+ onMetrics
529
+ // Pass through the onMetrics callback (metric watcher)
530
+ },
531
+ renderPage
532
+ );
533
+ let finalResult = void 0;
534
+ try {
535
+ for await (const result of renderPagesGenerator) {
536
+ if (result.type === "error") {
537
+ if (userOptions.verbose) {
538
+ logger?.error(`[react-static-client] Render error: ${result.error}`);
180
539
  }
181
- else if (this.environment.name === "client") {
182
- // Client build manifest (SSR modules) - stored globally now
183
- if (manifests.static) {
184
- const staticManifest = manifests.static;
185
- // Update bundle filenames to match static manifest
186
- for (const [, chunk] of Object.entries(bundle)) {
187
- if (chunk.type === "chunk" && chunk.fileName) {
188
- const normalized = userOptions.normalizer(chunk.fileName);
189
- let value = normalized[1];
190
- if (value.startsWith(userOptions.moduleBasePath)) {
191
- value = value.slice(userOptions.moduleBasePath.length);
192
- }
193
- const entry = staticManifest[value];
194
- if (entry && entry.file !== chunk.fileName) {
195
- // Update the filename to match static manifest
196
- chunk.fileName = entry.file;
197
- }
198
- }
199
- }
200
- }
540
+ throw result.error;
541
+ }
542
+ if (result.type === "success" && result.failedRoutes && result.failedRoutes.size > 0) {
543
+ const firstError = result.failedRoutes.values().next().value;
544
+ if (firstError != null && shouldCausePanic(firstError, {
545
+ panicThreshold: userOptions.panicThreshold
546
+ })) {
547
+ throw firstError;
201
548
  }
202
- else if (this.environment.name === "server") {
203
- // Server build manifest (server components) - stored globally now
204
- serverBundle = bundle;
549
+ for (const [route, error] of result.failedRoutes) {
550
+ const err = error instanceof Error ? error : toError(error);
551
+ closeBundleContext.warn(
552
+ new Error(
553
+ "Failed to render route: " + route + "\n" + err.message + "\n" + err.stack,
554
+ { cause: err }
555
+ )
556
+ );
205
557
  }
206
- // Skip the static generation here - it will happen in closeBundle
207
- return;
558
+ }
559
+ finalResult = result;
208
560
  }
209
- catch (error) {
210
- const panicError = handleError({
211
- error,
212
- logger: logger,
213
- panicThreshold: userOptions.panicThreshold,
214
- context: "writeBundle",
215
- });
216
- if (panicError != null) {
217
- throw panicError;
218
- }
219
- }
220
- },
221
- async closeBundle() {
222
- const envName = this.environment.name;
223
- const isSsr = this.environment.config.build?.ssr === true;
561
+ } catch (renderError) {
224
562
  if (userOptions.verbose) {
225
- logger?.info(`[react-static-client] closeBundle called for environment: ${envName}, ssr: ${isSsr}`);
563
+ logger?.error(`[react-static-client] Error during renderPages: ${renderError}`);
226
564
  }
227
- // Only run static generation in the non-SSR client environment (static builds)
228
- // Skip SSR client builds and server builds
229
- if (envName === "ssr" || envName === "server" || isSsr) {
230
- if (userOptions.verbose) {
231
- logger?.info(`[react-static-client] Skipping static generation for environment: ${envName} (ssr: ${isSsr})`);
232
- }
233
- return;
565
+ throw renderError;
566
+ }
567
+ if (!finalResult) {
568
+ const errorMsg = "No render result produced";
569
+ if (userOptions.verbose) {
570
+ logger?.error(`[react-static-client] ${errorMsg}`);
234
571
  }
235
- // Clean up _virtual files after build completes
236
- // These are Vite's internal virtual modules and aren't needed in the final output
237
- if (envName === "static" || (envName === "client" && !isSsr)) {
238
- try {
239
- const { rmSync, existsSync } = await import("node:fs");
240
- const { join, resolve } = await import("node:path");
241
- // Use the resolved output directory from the environment config
242
- const resolvedOutDir = this.environment.config.build?.outDir
243
- ? resolve(this.environment.config.root || userOptions.projectRoot, this.environment.config.build.outDir)
244
- : resolve(userOptions.projectRoot, userOptions.build.outDir);
245
- // Clean up _virtual from client/static output directories only
246
- // Don't clean up server/_virtual since we need dynamic-import-helper.js there
247
- const outputDirs = [
248
- join(resolvedOutDir, userOptions.build.static || "static"),
249
- join(resolvedOutDir, userOptions.build.client || "client"),
250
- ];
251
- for (const outDir of outputDirs) {
252
- const virtualDir = join(outDir, "_virtual");
253
- if (existsSync(virtualDir)) {
254
- rmSync(virtualDir, { recursive: true, force: true });
255
- if (userOptions.verbose) {
256
- logger?.info(`[react-static-client] Cleaned up _virtual directory: ${virtualDir}`);
257
- }
258
- }
259
- }
260
- }
261
- catch (error) {
262
- // Non-critical - log but don't fail the build
263
- if (userOptions.verbose) {
264
- logger?.warn(`[react-static-client] Failed to clean up _virtual directory: ${error}`);
265
- }
572
+ throw new Error(errorMsg);
573
+ }
574
+ if (userOptions.verbose) {
575
+ logger?.info(`[react-static-client] Render completed: ${finalResult.completedRoutes.size} pages, ${finalResult.failedRoutes?.size || 0} failed`);
576
+ }
577
+ const duration = Math.round(
578
+ performance.now() - (timing.renderStart || timing.start)
579
+ );
580
+ closeBundleContext.info(
581
+ `Rendered ${finalResult.completedRoutes.size} pages in ${duration}ms`
582
+ );
583
+ if (process.env["NODE_ENV"] !== "production") {
584
+ closeBundleContext.warn(
585
+ `THIS BUILD IS NOT INTENDED FOR PRODUCTION (${process.env["NODE_ENV"]})`
586
+ );
587
+ }
588
+ timing.render = performance.now() - (timing.renderStart ?? timing.start);
589
+ if (userOptions.verbose) {
590
+ logger?.info("[react-static-client] Static generation completed");
591
+ }
592
+ if (typeof userOptions.onEvent === "function") {
593
+ try {
594
+ const r = userOptions.onEvent({
595
+ type: "build.ssg.end",
596
+ data: {
597
+ pages: Array.from(autoDiscoveredFiles?.urlMap.keys() ?? []),
598
+ options: null,
599
+ // No specific rollup output options for static generation
600
+ bundle: staticBundle || {}
266
601
  }
602
+ });
603
+ if (r != null && typeof r === "object" && "then" in r) {
604
+ await r;
605
+ }
606
+ } catch (error) {
607
+ const eventPanicError = handleError({
608
+ error,
609
+ logger,
610
+ panicThreshold: userOptions.panicThreshold,
611
+ context: "onEvent(build.ssg.end)"
612
+ });
613
+ if (eventPanicError != null) {
614
+ throw eventPanicError;
615
+ }
267
616
  }
268
- // This runs after all writeBundle hooks are complete
269
- // Run static generation in the non-SSR client environment (static builds)
270
- // This could be "static" or "client" depending on how environments are configured
271
- if (envName === "ssr" || envName === "server" || isSsr) {
272
- if (userOptions.verbose) {
273
- logger?.info(`[react-static-client] Skipping static generation - not in static environment (${envName}, ssr: ${isSsr})`);
274
- }
275
- return;
617
+ }
618
+ } catch (error) {
619
+ const panicError = handleError({
620
+ error,
621
+ logger,
622
+ panicThreshold: userOptions.panicThreshold
623
+ });
624
+ if (rscWorker) {
625
+ const workerToCleanup = rscWorker;
626
+ try {
627
+ await Promise.race([
628
+ new Promise((resolve) => {
629
+ const timeoutId = setTimeout(() => {
630
+ workerToCleanup.removeAllListeners();
631
+ workerToCleanup.terminate();
632
+ resolve();
633
+ }, 1e3);
634
+ const messageHandler = (message) => {
635
+ if (message.type === "SHUTDOWN_COMPLETE") {
636
+ clearTimeout(timeoutId);
637
+ workerToCleanup.removeListener("message", messageHandler);
638
+ resolve();
639
+ }
640
+ };
641
+ workerToCleanup.on("message", messageHandler);
642
+ workerToCleanup.postMessage({ type: "SHUTDOWN" });
643
+ })
644
+ ]);
645
+ rscWorker = void 0;
646
+ } catch (cleanupError) {
647
+ logger.warn(`Failed to cleanup worker on error: ${cleanupError}`);
648
+ try {
649
+ workerToCleanup.removeAllListeners();
650
+ workerToCleanup.terminate();
651
+ } catch (terminateError) {
652
+ }
653
+ rscWorker = void 0;
276
654
  }
277
- // Defer static generation to run after ALL environments complete their builds.
278
- // This is necessary because we need the server manifest (from server env's writeBundle)
279
- // to resolve function-based component paths like Root: (url) => 'src/CustomRoot.tsx'.
280
- // The buildApp hook in createEnvironmentPlugin will call runDeferredStaticGeneration().
281
- const closeBundleContext = this;
282
- deferStaticGeneration(async () => {
655
+ }
656
+ if (panicError != null) {
657
+ const errorToThrow = panicError instanceof Error ? panicError : new Error(String(panicError));
658
+ const finalError = new Error(errorToThrow.message);
659
+ finalError.stack = errorToThrow.stack;
660
+ finalError.cause = errorToThrow.cause;
661
+ if (errorToThrow.name) finalError.name = errorToThrow.name;
662
+ throw finalError;
663
+ }
664
+ } finally {
665
+ if (rscWorker) {
666
+ try {
667
+ await Promise.race([
668
+ new Promise((resolve, reject) => {
669
+ const timeout = setTimeout(() => {
670
+ reject(new Error("Worker shutdown timeout"));
671
+ }, userOptions.workerShutdownTimeout);
672
+ const backupTimeout = setTimeout(() => {
673
+ reject(new Error("Worker shutdown backup timeout"));
674
+ }, Math.floor(userOptions.workerShutdownTimeout * 0.6));
675
+ const shutdownMessageHandler = (message) => {
676
+ if (message.type === "SHUTDOWN_COMPLETE") {
677
+ clearTimeout(timeout);
678
+ clearTimeout(backupTimeout);
679
+ rscWorker?.removeListener(
680
+ "message",
681
+ shutdownMessageHandler
682
+ );
683
+ rscWorker?.removeAllListeners();
684
+ resolve();
685
+ }
686
+ };
687
+ rscWorker?.on("message", shutdownMessageHandler);
688
+ rscWorker?.postMessage({
689
+ type: "SHUTDOWN",
690
+ id: "*"
691
+ });
692
+ })
693
+ ]);
694
+ } catch {
695
+ } finally {
696
+ if (rscWorker) {
283
697
  try {
284
- // Re-check autoDiscoveredFiles - it might not be set if configResolved didn't run
285
- // or if it was cleared. Try to get it from stashed options if needed
286
- if (!autoDiscoveredFiles) {
287
- if (userOptions.verbose) {
288
- logger?.warn("[react-static-client] autoDiscoveredFiles not set, attempting to re-discover");
289
- }
290
- const { getStashedUserOptions, getEnvironmentId } = await import("../config/stashedOptionsState.js");
291
- const { getCondition } = await import("../config/getCondition.js");
292
- const envId = getEnvironmentId(getCondition(), resolvedConfig?.mode || "production");
293
- const stashedOptions = getStashedUserOptions(envId);
294
- if (stashedOptions && resolvedConfig) {
295
- // Try to re-run auto-discovery if we have the config
296
- const autoDiscoverResult = await resolveAutoDiscover({
297
- config: resolvedConfig,
298
- configEnv: configEnv || {
299
- mode: resolvedConfig.mode || "production",
300
- command: resolvedConfig.command || "build",
301
- isSsrBuild: false,
302
- isPreview: false,
303
- },
304
- userOptions,
305
- logger,
306
- });
307
- if (autoDiscoverResult.type === "success") {
308
- autoDiscoveredFiles = autoDiscoverResult.autoDiscoveredFiles;
309
- if (userOptions.verbose) {
310
- logger?.info(`[react-static-client] Re-discovered ${autoDiscoveredFiles.urlMap.size} pages`);
311
- }
312
- }
313
- else {
314
- if (userOptions.verbose) {
315
- logger?.warn(`[react-static-client] Failed to re-discover pages: ${autoDiscoverResult.error}`);
316
- }
317
- }
318
- }
319
- }
320
- if (!autoDiscoveredFiles?.urlMap ||
321
- autoDiscoveredFiles?.urlMap.size === 0) {
322
- if (userOptions.verbose) {
323
- logger?.warn(`[react-static-client] No pages to generate - urlMap is empty (size: ${autoDiscoveredFiles?.urlMap?.size || 0})`);
324
- logger?.warn(`[react-static-client] autoDiscoveredFiles exists: ${!!autoDiscoveredFiles}, urlMap exists: ${!!autoDiscoveredFiles?.urlMap}`);
325
- }
326
- return;
327
- }
328
- if (userOptions.verbose) {
329
- logger?.info(`[react-static-client] Starting static generation with ${autoDiscoveredFiles.urlMap.size} pages`);
330
- }
331
- // Check if we can access the shared manifest store
332
- try {
333
- if (userOptions.verbose) {
334
- logger?.info(`[react-static-client] Attempting to get server manifest from shared state`);
335
- }
336
- const sharedState = getSharedManifestStore(closeBundleContext);
337
- if (sharedState.server) {
338
- serverManifest = sharedState.server;
339
- if (userOptions.verbose) {
340
- logger?.info(`[react-static-client] Got server manifest from shared state`);
341
- }
342
- }
343
- else {
344
- throw new Error("No server manifest in shared state");
345
- }
346
- }
347
- catch (error) {
348
- if (userOptions.verbose) {
349
- logger?.info(`[react-static-client] Failed to get server manifest from shared state, trying filesystem: ${error}`);
350
- }
351
- const serverManifestPath = join(userOptions.build.outDir, userOptions.build.server);
352
- const manifestPath = (typeof resolvedConfig?.build.manifest === "string"
353
- ? resolvedConfig.build.manifest
354
- : ".vite/manifest.json");
355
- if (userOptions.verbose) {
356
- logger?.info(`[react-static-client] Loading server manifest from: ${join(serverManifestPath, manifestPath)}`);
357
- }
358
- const serverManifestResult = await tryManifest({
359
- root: userOptions.projectRoot,
360
- outDir: serverManifestPath,
361
- manifestPath: manifestPath,
362
- ssrManifest: false,
363
- });
364
- if (serverManifestResult.type === "error") {
365
- if (userOptions.verbose) {
366
- logger?.warn(`[react-static-client] Failed to load server manifest: ${serverManifestResult.error}`);
367
- }
368
- // Use empty manifest as fallback - static generation can proceed without it
369
- serverManifest = {};
370
- if (userOptions.verbose) {
371
- logger?.warn(`[react-static-client] Using empty server manifest as fallback`);
372
- }
373
- }
374
- else if (serverManifestResult.type === "skip") {
375
- if (userOptions.verbose) {
376
- logger?.warn(`[react-static-client] Server manifest not found, using empty manifest as fallback`);
377
- }
378
- // Use empty manifest as fallback - static generation can proceed without it
379
- serverManifest = {};
380
- }
381
- else {
382
- serverManifest = serverManifestResult.manifest;
383
- if (userOptions.verbose) {
384
- logger?.info(`[react-static-client] Loaded server manifest from filesystem`);
385
- }
386
- }
387
- }
388
- // Load static manifest from filesystem for CSS path mapping
389
- const staticManifestResult = await tryManifest({
390
- root: userOptions.projectRoot,
391
- outDir: join(userOptions.build.outDir, userOptions.build.static),
392
- manifestPath: resolvedConfig?.build.manifest ?? ".vite/manifest.json",
393
- ssrManifest: false,
394
- });
395
- if (staticManifestResult.type === "error") {
396
- throw staticManifestResult.error;
397
- }
398
- const staticManifest = staticManifestResult.manifest;
399
- // Construct bootstrapModules like the server plugin does
400
- const indexHtml = staticManifest?.["index.html"]?.file;
401
- const serverPipeableStreamOptions = {
402
- ...userOptions.serverPipeableStreamOptions,
403
- bootstrapModules: [
404
- ...(indexHtml ? [baseURL(indexHtml)] : []),
405
- ...(userOptions.serverPipeableStreamOptions?.bootstrapModules ??
406
- []),
407
- ],
408
- };
409
- userOptions.serverPipeableStreamOptions = serverPipeableStreamOptions;
410
- const clientPipeableStreamOptions = {
411
- ...userOptions.clientPipeableStreamOptions,
412
- bootstrapModules: [
413
- ...(indexHtml ? [baseURL(indexHtml)] : []),
414
- ...(userOptions.clientPipeableStreamOptions?.bootstrapModules ??
415
- []),
416
- ],
417
- };
418
- // Create CSS props for each CSS file (same as server-static)
419
- const { cssFilesByPage, globalCss } = processCssFilesForPages({
420
- userOptions,
421
- autoDiscoveredFiles,
422
- serverManifest,
423
- staticManifest,
424
- bundle: staticBundle || {},
425
- logger,
426
- });
427
- if (userOptions.verbose) {
428
- for (const [route, cssMap] of cssFilesByPage.entries()) {
429
- logger.info(`[react-static-client] Route ${route}: ${cssMap.size} CSS files`);
430
- for (const [key, value] of cssMap.entries()) {
431
- logger.info(`[react-static-client] CSS file: ${key} -> ${value.as} (${value.children ? "inline" : "link"})`);
432
- }
433
- }
434
- }
435
- const routes = Array.from(autoDiscoveredFiles.urlMap.keys());
436
- // If no pages to generate, skip static generation
437
- if (routes.length === 0) {
438
- if (userOptions.verbose) {
439
- logger?.info("[react-static-client] No pages to generate, skipping static generation");
440
- }
441
- return;
442
- }
443
- // Use the static manifest to ensure consistent module IDs between RSC stream and client build
444
- // The static manifest contains the correct hashes that should be used for both builds
445
- // (staticManifest already loaded above)
446
- // Create a build loader for client mode (reuse server's sophisticated loader)
447
- if (userOptions.verbose) {
448
- logger?.info(`[react-static-client] Creating build loader`);
449
- }
450
- const buildLoader = createBuildLoader();
451
- if (userOptions.verbose) {
452
- logger?.info(`[react-static-client] Build loader created`);
453
- }
454
- // Create an RSC worker for generating RSC content
455
- if (userOptions.verbose) {
456
- logger?.info(`[react-static-client] Creating RSC worker with path: ${userOptions.rscWorkerPath}`);
457
- }
458
- const workerStartTime = performance.now();
459
- let rscWorkerResult;
460
- try {
461
- rscWorkerResult = await createWorker({
462
- projectRoot: userOptions.projectRoot,
463
- workerPath: userOptions.rscWorkerPath,
464
- currentCondition: "react-client",
465
- reverseCondition: "react-server",
466
- maxListeners: Math.max(routes.length * 3, 10), // Account for multiple listeners per route
467
- envPrefix: envPrefixFromConfig(resolvedConfig),
468
- logger: logger,
469
- verbose: userOptions.verbose,
470
- mode: getNodeEnv(),
471
- workerData: {
472
- userOptions: serializedOptions(userOptions, autoDiscoveredFiles),
473
- resolvedConfig: serializeResolvedConfig(resolvedConfig),
474
- configEnv: (() => {
475
- const fallback = resolvedConfig
476
- ? {
477
- command: resolvedConfig.command,
478
- mode: resolvedConfig.mode,
479
- isSsrBuild: false,
480
- isPreview: false,
481
- }
482
- : undefined;
483
- const finalConfigEnv = configEnv || fallback;
484
- return finalConfigEnv;
485
- })(),
486
- serverManifest: serverManifest || {}, // Use server manifest for page component resolution
487
- bundle: staticBundle || {}, // Use static bundle (client build) for page component resolution
488
- staticBundle: staticBundle || {}, // Pass static bundle separately for path resolution
489
- id: "static-client-rsc-worker",
490
- },
491
- });
492
- }
493
- catch (workerError) {
494
- if (userOptions.verbose) {
495
- logger?.error(`[react-static-client] Error creating RSC worker: ${workerError}`);
496
- }
497
- throw workerError;
498
- }
499
- if (rscWorkerResult.type !== "success") {
500
- const err = rscWorkerResult.error ?? new Error(`Failed to create RSC worker`);
501
- if (userOptions.verbose) {
502
- logger?.error(`[react-static-client] RSC worker creation failed, throwing error`, { error: err });
503
- }
504
- throw err;
505
- }
506
- rscWorker = rscWorkerResult.worker;
507
- if (userOptions.verbose) {
508
- logger?.info(`[react-static-client] RSC worker created successfully`);
509
- }
510
- // Emit worker startup metric after worker is created
511
- const workerStartupTime = performance.now() - workerStartTime;
512
- if (userOptions.onMetrics) {
513
- const workerStartupMetric = createWorkerStartupMetrics({
514
- route: "/", // Worker startup is global, not route-specific
515
- workerType: "rsc", // This is the RSC worker for client-side static generation
516
- startupTime: workerStartupTime,
517
- fromMainThread: true,
518
- fromRscWorker: false,
519
- fromHtmlWorker: false,
520
- description: `RSC worker startup for client-side static generation`,
521
- });
522
- userOptions.onMetrics(workerStartupMetric);
523
- }
524
- // Render pages using client-side renderer with RSC worker only
525
- const { onEvent, onMetrics, ...handlerOptions } = userOptions;
526
- if (userOptions.verbose) {
527
- logger?.info(`[react-static-client] Extracted onEvent: ${typeof onEvent}, userOptions.onEvent: ${typeof userOptions.onEvent}`);
528
- }
529
- // Capture server bundle from onEvent if not already captured
530
- if (!serverBundle && onEvent) {
531
- // Create a temporary event handler to capture the server bundle
532
- const originalOnEvent = onEvent;
533
- const tempOnEvent = (event) => {
534
- if (event.type === "build.writeBundle.server") {
535
- serverBundle = event.data.bundle;
536
- logger?.info("[react-static-client] Captured server bundle from build event");
537
- }
538
- // Call the original event handler
539
- originalOnEvent(event);
540
- };
541
- // Replace the onEvent temporarily to capture the server bundle
542
- userOptions.onEvent = tempOnEvent;
543
- }
544
- // Emit the static site generation start event
545
- // Use the extracted onEvent if available, otherwise fall back to userOptions.onEvent
546
- const eventHandler = onEvent || userOptions.onEvent;
547
- if (typeof eventHandler === "function") {
548
- try {
549
- if (userOptions.verbose) {
550
- logger?.info(`[react-static-client] Emitting build.ssg.start event`);
551
- }
552
- const r = eventHandler({
553
- type: "build.ssg.start",
554
- data: {
555
- pages: Array.from(autoDiscoveredFiles?.urlMap.keys() ?? []),
556
- options: null, // No specific rollup output options for static generation
557
- bundle: staticBundle || {},
558
- },
559
- });
560
- if (r != null && typeof r === "object" && "then" in r) {
561
- await r;
562
- }
563
- }
564
- catch (error) {
565
- const eventPanicError = handleError({
566
- error,
567
- logger: logger,
568
- panicThreshold: userOptions.panicThreshold,
569
- context: "onEvent(build.ssg.start)",
570
- });
571
- if (eventPanicError != null) {
572
- throw eventPanicError; // Re-throw to abort the build
573
- }
574
- }
575
- }
576
- else if (userOptions.verbose) {
577
- logger?.warn(`[react-static-client] No onEvent handler available to emit build.ssg.start`);
578
- }
579
- const renderPagesGenerator = renderPagesBatched(routes, {
580
- ...handlerOptions, // Use the clean options instead of the original handlerOptions
581
- worker: rscWorker, // Pass the RSC worker for RSC rendering only
582
- rscWorker: rscWorker, // Pass the RSC worker for RSC rendering only
583
- loader: buildLoader, // Use proper build loader instead of no-op
584
- logger: logger,
585
- autoDiscoveredFiles: autoDiscoveredFiles,
586
- cssFilesByPage: cssFilesByPage, // Pass CSS files by page
587
- serverPipeableStreamOptions: serverPipeableStreamOptions, // Pass server options to RSC worker
588
- clientPipeableStreamOptions: clientPipeableStreamOptions, // Pass client options to RSC worker
589
- globalCss: globalCss, // Pass global CSS
590
- manifest: serverManifest || {}, // Server manifest for RSC worker
591
- staticManifest: staticManifest, // Static manifest for consistent module IDs
592
- onEvent: onEvent,
593
- onMetrics: onMetrics, // Pass through the onMetrics callback (metric watcher)
594
- }, renderPage);
595
- // Process the rendered pages
596
- let finalResult = undefined;
597
- try {
598
- for await (const result of renderPagesGenerator) {
599
- if (result.type === "error") {
600
- if (userOptions.verbose) {
601
- logger?.error(`[react-static-client] Render error: ${result.error}`);
602
- }
603
- throw result.error;
604
- }
605
- // Handle failed routes based on panic threshold
606
- if (result.type === "success" &&
607
- result.failedRoutes &&
608
- result.failedRoutes.size > 0) {
609
- // Use centralized panic threshold logic (same as server plugin)
610
- const firstError = result.failedRoutes.values().next().value;
611
- if (firstError != null &&
612
- shouldCausePanic(firstError, {
613
- panicThreshold: userOptions.panicThreshold,
614
- })) {
615
- // This should cause a panic, throw the error
616
- throw firstError;
617
- }
618
- // For other panic thresholds, log warnings but continue
619
- for (const [route, error] of result.failedRoutes) {
620
- const err = error instanceof Error ? error : toError(error);
621
- closeBundleContext.warn(new Error("Failed to render route: " +
622
- route +
623
- "\n" +
624
- err.message +
625
- "\n" +
626
- err.stack, { cause: err }));
627
- }
628
- }
629
- finalResult = result;
630
- }
631
- }
632
- catch (renderError) {
633
- if (userOptions.verbose) {
634
- logger?.error(`[react-static-client] Error during renderPages: ${renderError}`);
635
- }
636
- throw renderError;
637
- }
638
- if (!finalResult) {
639
- const errorMsg = "No render result produced";
640
- if (userOptions.verbose) {
641
- logger?.error(`[react-static-client] ${errorMsg}`);
642
- }
643
- throw new Error(errorMsg);
644
- }
645
- if (userOptions.verbose) {
646
- logger?.info(`[react-static-client] Render completed: ${finalResult.completedRoutes.size} pages, ${finalResult.failedRoutes?.size || 0} failed`);
647
- }
648
- // File writes are handled by renderPages, no need to do them here
649
- // Calculate duration from timing
650
- const duration = Math.round(performance.now() - (timing.renderStart || timing.start));
651
- closeBundleContext.info(`Rendered ${finalResult.completedRoutes.size} pages in ${duration}ms`);
652
- if (process.env["NODE_ENV"] !== "production") {
653
- closeBundleContext.warn(`THIS BUILD IS NOT INTENDED FOR PRODUCTION (${process.env["NODE_ENV"]})`);
654
- }
655
- // Update timing
656
- timing.render =
657
- performance.now() - (timing.renderStart ?? timing.start);
658
- if (userOptions.verbose) {
659
- logger?.info("[react-static-client] Static generation completed");
660
- }
661
- // Emit the static site generation completion event once
662
- if (typeof userOptions.onEvent === "function") {
663
- try {
664
- const r = userOptions.onEvent({
665
- type: "build.ssg.end",
666
- data: {
667
- pages: Array.from(autoDiscoveredFiles?.urlMap.keys() ?? []),
668
- options: null, // No specific rollup output options for static generation
669
- bundle: staticBundle || {},
670
- },
671
- });
672
- if (r != null && typeof r === "object" && "then" in r) {
673
- await r;
674
- }
675
- }
676
- catch (error) {
677
- const eventPanicError = handleError({
678
- error,
679
- logger: logger,
680
- panicThreshold: userOptions.panicThreshold,
681
- context: "onEvent(build.ssg.end)",
682
- });
683
- if (eventPanicError != null) {
684
- throw eventPanicError; // Re-throw to abort the build
685
- }
686
- }
687
- }
688
- }
689
- catch (error) {
690
- const panicError = handleError({
691
- error,
692
- context: "react-static-client",
693
- logger,
694
- panicThreshold: userOptions.panicThreshold,
695
- });
696
- // Ensure graceful shutdown on error
697
- if (rscWorker) {
698
- const workerToCleanup = rscWorker;
699
- try {
700
- // Use graceful shutdown protocol even on error
701
- await Promise.race([
702
- new Promise((resolve) => {
703
- const timeoutId = setTimeout(() => {
704
- workerToCleanup.removeAllListeners();
705
- workerToCleanup.terminate();
706
- resolve();
707
- }, 1000); // 1 second timeout for graceful shutdown
708
- const messageHandler = (message) => {
709
- if (message.type === "SHUTDOWN_COMPLETE") {
710
- clearTimeout(timeoutId);
711
- workerToCleanup.removeListener("message", messageHandler);
712
- resolve();
713
- }
714
- };
715
- workerToCleanup.on("message", messageHandler);
716
- workerToCleanup.postMessage({ type: "SHUTDOWN" });
717
- }),
718
- ]);
719
- rscWorker = undefined;
720
- }
721
- catch (cleanupError) {
722
- logger.warn(`Failed to cleanup worker on error: ${cleanupError}`);
723
- // Force terminate if graceful shutdown fails
724
- try {
725
- workerToCleanup.removeAllListeners();
726
- workerToCleanup.terminate();
727
- }
728
- catch (terminateError) {
729
- // Ignore termination errors
730
- }
731
- rscWorker = undefined;
732
- }
733
- }
734
- if (panicError != null) {
735
- // Ensure we have a proper Error object that can have properties set on it
736
- const errorToThrow = panicError instanceof Error
737
- ? panicError
738
- : new Error(String(panicError));
739
- // Create a new Error object to avoid the "code" property issue
740
- const finalError = new Error(errorToThrow.message);
741
- finalError.stack = errorToThrow.stack;
742
- finalError.cause = errorToThrow.cause;
743
- // Copy any additional properties that might be needed
744
- if (errorToThrow.name)
745
- finalError.name = errorToThrow.name;
746
- throw finalError;
747
- }
748
- }
749
- finally {
750
- // Graceful worker shutdown — runs on both success and error paths
751
- if (rscWorker) {
752
- try {
753
- await Promise.race([
754
- new Promise((resolve, reject) => {
755
- const timeout = setTimeout(() => {
756
- reject(new Error("Worker shutdown timeout"));
757
- }, userOptions.workerShutdownTimeout);
758
- const backupTimeout = setTimeout(() => {
759
- reject(new Error("Worker shutdown backup timeout"));
760
- }, Math.floor(userOptions.workerShutdownTimeout * 0.6));
761
- const shutdownMessageHandler = (message) => {
762
- if (message.type === "SHUTDOWN_COMPLETE") {
763
- clearTimeout(timeout);
764
- clearTimeout(backupTimeout);
765
- rscWorker?.removeListener("message", shutdownMessageHandler);
766
- rscWorker?.removeAllListeners();
767
- resolve();
768
- }
769
- };
770
- rscWorker?.on("message", shutdownMessageHandler);
771
- rscWorker?.postMessage({
772
- type: "SHUTDOWN",
773
- id: "*",
774
- });
775
- }),
776
- ]);
777
- }
778
- catch {
779
- // Shutdown protocol failed — force terminate below
780
- }
781
- finally {
782
- if (rscWorker) {
783
- try {
784
- rscWorker.removeAllListeners();
785
- rscWorker.terminate();
786
- }
787
- catch {
788
- // Ignore termination errors
789
- }
790
- rscWorker = undefined;
791
- }
792
- }
793
- }
794
- // Reset any cached state to prevent issues in subsequent builds
795
- autoDiscoveredFiles = null;
796
- serverManifest = undefined;
698
+ rscWorker.removeAllListeners();
699
+ rscWorker.terminate();
700
+ } catch {
797
701
  }
798
- }); // end deferStaticGeneration
799
- },
800
- };
702
+ rscWorker = void 0;
703
+ }
704
+ }
705
+ }
706
+ autoDiscoveredFiles = null;
707
+ serverManifest = void 0;
708
+ }
709
+ });
710
+ }
711
+ };
801
712
  };
713
+
714
+ export { reactStaticPlugin };
715
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2luLmNsaWVudC5qcyIsInNvdXJjZXMiOlsiLi4vLi4vLi4vcGx1Z2luL3JlYWN0LXN0YXRpYy9wbHVnaW4uY2xpZW50LnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogcGx1Z2luLmNsaWVudC50c1xuICpcbiAqIFBVUlBPU0U6IENsaWVudC1zaWRlIHN0YXRpYyBwbHVnaW4gZm9yIFJlYWN0IFNlcnZlciBDb21wb25lbnRzXG4gKlxuICogVGhpcyBtb2R1bGU6XG4gKiAxLiBIYW5kbGVzIHN0YXRpYyBzaXRlIGdlbmVyYXRpb24gaW4gdGhlIGNsaWVudCBlbnZpcm9ubWVudFxuICogMi4gVXNlcyBSU0Mgd29ya2VyIGZvciBSU0MgcmVuZGVyaW5nIGFuZCBtYWluLXRocmVhZCBmb3IgSFRNTCByZW5kZXJpbmdcbiAqIDMuIEdlbmVyYXRlcyBib3RoIFJTQyBhbmQgSFRNTCBmaWxlcyBmb3Igc3RhdGljIHBhZ2VzXG4gKiA0LiBJbnRlZ3JhdGVzIHdpdGggVml0ZSdzIGJ1aWxkIHByb2Nlc3NcbiAqXG4gKiBGZWF0dXJlIHBhcml0eSB3aXRoIG1haW4gcmVhY3Qtc3RhdGljIHBsdWdpbiwgYnV0IGluIHJldmVyc2UuIFVzZXMgcnNjLXdvcmtlciB0byByZW5kZXIgcnNjLCBhbmQgbWFpbiB0aHJlYWQgZm9yIGh0bWwuXG4gKiBUaGlzIGlzIG5vdCB0aGUgZGVmYXVsdCBiZWhhdmlvciwgYnV0IGlzIHN1cHBvcnRlZCBmb3IgdGVzdGluZyBhbmQgY3VzdG9tIGFwcCBkZXZlbG9wbWVudCBwdXJwb3Nlcy5cbiAqIEFkZGl0aW9uYWxseSwgdGhpcyBjYW4gbWFrZSBpdCBlYXNpZXIgdG8gdXNlIHRoZSAtLWFwcCBmbGFnIHRvIGJ1aWxkIGFsbCB0aGUgbW9kdWxlcyArIHN0YXRpYyBnZW5lcmF0aW9uIGF0IG9uY2UuXG4gKi9cblxuaW1wb3J0IHtcbiAgY3JlYXRlTG9nZ2VyLFxuICB0eXBlIFJlc29sdmVkQ29uZmlnLFxuICB0eXBlIE1hbmlmZXN0LFxuICB0eXBlIENvbmZpZ0Vudixcbn0gZnJvbSBcInZpdGVcIjtcbmltcG9ydCB7IHJlc29sdmVPcHRpb25zIH0gZnJvbSBcIi4uL2NvbmZpZy9yZXNvbHZlT3B0aW9ucy5qc1wiO1xuaW1wb3J0IHR5cGUge1xuICBCdWlsZFRpbWluZyxcbiAgVml0ZVBsdWdpbkZuLFxuICBBdXRvRGlzY292ZXJlZEZpbGVzLFxufSBmcm9tIFwiLi4vdHlwZXMuanNcIjtcbmltcG9ydCB0eXBlIHsgT3V0cHV0QnVuZGxlIH0gZnJvbSBcInJvbGx1cFwiO1xuaW1wb3J0IHsgcmVuZGVyUGFnZXNCYXRjaGVkIH0gZnJvbSBcIi4vcmVuZGVyUGFnZXNCYXRjaGVkLmpzXCI7XG5pbXBvcnQgeyBwZXJmb3JtYW5jZSB9IGZyb20gXCJub2RlOnBlcmZfaG9va3NcIjtcbmltcG9ydCB7IHJlbmRlclBhZ2UgfSBmcm9tIFwiLi9yZW5kZXJQYWdlLmNsaWVudC5qc1wiO1xuXG5pbXBvcnQgeyBjcmVhdGVXb3JrZXIgfSBmcm9tIFwiLi4vd29ya2VyL2NyZWF0ZVdvcmtlci5qc1wiO1xuaW1wb3J0IHtcbiAgc2VyaWFsaXplZE9wdGlvbnMsXG4gIHNlcmlhbGl6ZVJlc29sdmVkQ29uZmlnLFxufSBmcm9tIFwiLi4vaGVscGVycy9zZXJpYWxpemVVc2VyT3B0aW9ucy5qc1wiO1xuaW1wb3J0IHsgZ2V0QnVuZGxlTWFuaWZlc3QgfSBmcm9tIFwiLi4vaGVscGVycy9nZXRCdW5kbGVNYW5pZmVzdC5qc1wiO1xuXG5pbXBvcnQgeyBoYW5kbGVFcnJvciB9IGZyb20gXCIuLi9lcnJvci9oYW5kbGVFcnJvci5qc1wiO1xuaW1wb3J0IHsgc2hvdWxkQ2F1c2VQYW5pYyB9IGZyb20gXCIuLi9lcnJvci9wYW5pY1RocmVzaG9sZEhhbmRsZXIuanNcIjtcbmltcG9ydCB7IGNvbmZpZ3VyZVByZXZpZXdTZXJ2ZXIgfSBmcm9tIFwiLi9jb25maWd1cmVQcmV2aWV3U2VydmVyLmpzXCI7XG5pbXBvcnQgeyBhc3NlcnROb25SZWFjdFNlcnZlciB9IGZyb20gXCIuLi9jb25maWcvZ2V0Q29uZGl0aW9uLmpzXCI7XG5pbXBvcnQgeyBlbnZQcmVmaXhGcm9tQ29uZmlnIH0gZnJvbSBcIi4uL2NvbmZpZy9lbnZQcmVmaXhGcm9tQ29uZmlnLmpzXCI7XG5pbXBvcnQgeyBjcmVhdGVXb3JrZXJTdGFydHVwTWV0cmljcyB9IGZyb20gXCIuLi9tZXRyaWNzL2NyZWF0ZVdvcmtlclN0YXJ0dXBNZXRyaWNzLmpzXCI7XG5pbXBvcnQgeyBwcm9jZXNzQ3NzRmlsZXNGb3JQYWdlcyB9IGZyb20gXCIuL3Byb2Nlc3NDc3NGaWxlc0ZvclBhZ2VzLmpzXCI7XG5pbXBvcnQgeyBjcmVhdGVCdWlsZExvYWRlciB9IGZyb20gXCIuL2NyZWF0ZUJ1aWxkTG9hZGVyLmNsaWVudC5qc1wiO1xuaW1wb3J0IHsgZ2V0Tm9kZUVudiB9IGZyb20gXCIuLi9jb25maWcvZ2V0Tm9kZUVudi5qc1wiO1xuaW1wb3J0IHsgdG9FcnJvciB9IGZyb20gXCIuLi9lcnJvci90b0Vycm9yLmpzXCI7XG5pbXBvcnQge1xuICBhZGRTdGF0aWNNYW5pZmVzdCxcbiAgbWFuaWZlc3RzLFxuICBnZXRTaGFyZWRNYW5pZmVzdFN0b3JlLFxufSBmcm9tIFwiLi4vYnVuZGxlL21hbmlmZXN0cy5qc1wiO1xuaW1wb3J0IHsgZGVmZXJTdGF0aWNHZW5lcmF0aW9uIH0gZnJvbSBcIi4uL2J1bmRsZS9kZWZlcnJlZFN0YXRpY0dlbmVyYXRpb24uanNcIjtcbmltcG9ydCB0eXBlIHsgV29ya2VyIH0gZnJvbSBcIm5vZGU6d29ya2VyX3RocmVhZHNcIjtcbmltcG9ydCB7IHJlc29sdmVBdXRvRGlzY292ZXIgfSBmcm9tIFwiLi4vY29uZmlnL2luZGV4LmpzXCI7XG5pbXBvcnQgeyBqb2luIH0gZnJvbSBcIm5vZGU6cGF0aFwiO1xuXG5pbXBvcnQgeyBiYXNlVVJMIH0gZnJvbSBcIi4uL3V0aWxzL2VudlVybHMubm9kZS5qc1wiO1xuaW1wb3J0IHsgdHJ5TWFuaWZlc3QgfSBmcm9tIFwiLi4vaGVscGVycy90cnlNYW5pZmVzdC5qc1wiO1xuLy8gY3NzQ29sbGVjdG9yIHJlbW92ZWQgLSB1c2luZyBmaWxlc3lzdGVtLWJhc2VkIENTUyBwcm9jZXNzaW5nXG5cbmFzc2VydE5vblJlYWN0U2VydmVyKCk7XG5cbi8qKlxuICogcGx1Z2luLmNsaWVudC50c1xuICpcbiAqIFBVUlBPU0U6IENsaWVudC1zaWRlIHN0YXRpYyBwbHVnaW4gZm9yIFJlYWN0IFNlcnZlciBDb21wb25lbnRzXG4gKlxuICogVGhpcyBtb2R1bGU6XG4gKiAxLiBIYW5kbGVzIHN0YXRpYyBzaXRlIGdlbmVyYXRpb24gaW4gdGhlIGNsaWVudCBlbnZpcm9ubWVudFxuICogMi4gVXNlcyBSU0Mgd29ya2VyIGZvciBSU0MgcmVuZGVyaW5nIGFuZCBtYWluLXRocmVhZCBmb3IgSFRNTCByZW5kZXJpbmdcbiAqIDMuIEdlbmVyYXRlcyBib3RoIFJTQyBhbmQgSFRNTCBmaWxlcyBmb3Igc3RhdGljIHBhZ2VzXG4gKiA0LiBJbnRlZ3JhdGVzIHdpdGggVml0ZSdzIGJ1aWxkIHByb2Nlc3NcbiAqXG4gKiBAcGFyYW0gb3B0aW9uc1xuICogQHJldHVybnNcbiAqL1xuZXhwb3J0IGNvbnN0IHJlYWN0U3RhdGljUGx1Z2luOiBWaXRlUGx1Z2luRm4gPSBmdW5jdGlvbiBfcmVhY3RTdGF0aWNQbHVnaW4oXG4gIG9wdGlvbnNcbikge1xuICBsZXQgbG9nZ2VyOiBSZXR1cm5UeXBlPHR5cGVvZiBjcmVhdGVMb2dnZXI+O1xuICBsZXQgYXV0b0Rpc2NvdmVyZWRGaWxlczogQXV0b0Rpc2NvdmVyZWRGaWxlcyB8IG51bGwgPSBudWxsO1xuICBsZXQgcnNjV29ya2VyOiBXb3JrZXIgfCB1bmRlZmluZWQgPSB1bmRlZmluZWQ7XG4gIGxldCByZXNvbHZlZENvbmZpZzogUmVzb2x2ZWRDb25maWcgfCBudWxsID0gbnVsbDtcbiAgbGV0IHNlcnZlck1hbmlmZXN0OiBNYW5pZmVzdCB8IHVuZGVmaW5lZCA9IHVuZGVmaW5lZDtcbiAgbGV0IHN0YXRpY0J1bmRsZTogT3V0cHV0QnVuZGxlIHwgdW5kZWZpbmVkID0gdW5kZWZpbmVkO1xuICBsZXQgc2VydmVyQnVuZGxlOiBPdXRwdXRCdW5kbGUgfCB1bmRlZmluZWQgPSB1bmRlZmluZWQ7XG5cbiAgbGV0IGNvbmZpZ0VudjogQ29uZmlnRW52IHwgdW5kZWZpbmVkO1xuICBjb25zdCB0aW1pbmc6IEJ1aWxkVGltaW5nID0ge1xuICAgIHN0YXJ0OiBwZXJmb3JtYW5jZS5ub3coKSxcbiAgICBjb25maWdSZXNvbHZlZDogMCxcbiAgICBidWlsZFN0YXJ0OiAwLFxuICAgIHJlbmRlclN0YXJ0OiAwLFxuICB9O1xuXG4gIGNvbnN0IHJlc29sdmVkT3B0aW9ucyA9IHJlc29sdmVPcHRpb25zKG9wdGlvbnMpO1xuICBpZiAocmVzb2x2ZWRPcHRpb25zLnR5cGUgPT09IFwiZXJyb3JcIikge1xuICAgIHRocm93IHJlc29sdmVkT3B0aW9ucy5lcnJvcjtcbiAgfVxuICBjb25zdCB1c2VyT3B0aW9ucyA9IHJlc29sdmVkT3B0aW9ucy51c2VyT3B0aW9ucztcblxuICByZXR1cm4ge1xuICAgIG5hbWU6IFwidml0ZTpwbHVnaW4tcmVhY3Qtc2VydmVyL2NsaWVudC1zdGF0aWNcIixcbiAgICBlbmZvcmNlOiBcInBvc3RcIixcbiAgICBhcHBseTogXCJidWlsZFwiLCAvLyBBcHBseSB0byBidWlsZCBtb2RlXG4gICAgYXBpOiB7XG4gICAgICBtZXRhOiB7IHRpbWluZyB9LFxuICAgIH0sXG4gICAgYXN5bmMgY29uZmlnKF9jb25maWcsIHZpdGVDb25maWdFbnYpIHtcbiAgICAgIGNvbmZpZ0VudiA9IHZpdGVDb25maWdFbnY7XG4gICAgfSxcbiAgICBhcHBseVRvRW52aXJvbm1lbnQocGFydGlhbEVudmlyb25tZW50KSB7XG4gICAgICAvLyBDbGllbnQgc3RhdGljIHBsdWdpbiBzaG91bGQgYXBwbHkgdG8gc3RhdGljIGVudmlyb25tZW50IChicm93c2VyL0VTTSBidWlsZHMpXG4gICAgICAvLyBUaGlzIGlzIHdoZXJlIHdlIHdhbnQgdG8gYnVuZGxlIGV2ZXJ5dGhpbmcgYW5kIGZpbHRlciBvdXQgX3ZpcnR1YWwgZmlsZXNcbiAgICAgIC8vIEFwcGx5IHRvIGJvdGggXCJzdGF0aWNcIiBhbmQgXCJjbGllbnRcIiBlbnZpcm9ubWVudHMgLSB3ZSdsbCBoYW5kbGUgd2hpY2ggb25lIHJ1bnMgc3RhdGljIGdlbmVyYXRpb24gaW4gY2xvc2VCdW5kbGVcbiAgICAgIGNvbnN0IGVudk5hbWUgPSBwYXJ0aWFsRW52aXJvbm1lbnQubmFtZSBhcyBcImNsaWVudFwiIHwgXCJzZXJ2ZXJcIiB8IFwic3NyXCIgfCBcInN0YXRpY1wiO1xuICAgICAgaWYgKFxuICAgICAgICBbXCJzdGF0aWNcIiwgXCJjbGllbnRcIl0uaW5jbHVkZXMoZW52TmFtZSlcbiAgICAgICkge1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9LFxuXG4gICAgYXN5bmMgY29uZmlnUmVzb2x2ZWQoY29uZmlnKSB7XG4gICAgICB0aW1pbmcuY29uZmlnUmVzb2x2ZWQgPSBwZXJmb3JtYW5jZS5ub3coKTtcbiAgICAgIGxvZ2dlciA9IGNvbmZpZy5jdXN0b21Mb2dnZXIgfHwgY3JlYXRlTG9nZ2VyKCk7XG4gICAgICByZXNvbHZlZENvbmZpZyA9IGNvbmZpZztcblxuICAgICAgLy8gUGVyZm9ybSBhdXRvLWRpc2NvdmVyeSB0byBwb3B1bGF0ZSBhdXRvRGlzY292ZXJlZEZpbGVzXG4gICAgICBjb25zdCBhdXRvRGlzY292ZXJSZXN1bHQgPSBhd2FpdCByZXNvbHZlQXV0b0Rpc2NvdmVyKHtcbiAgICAgICAgY29uZmlnOiBjb25maWcsXG4gICAgICAgIGNvbmZpZ0VudjogY29uZmlnRW52IHx8IHtcbiAgICAgICAgICBtb2RlOiBjb25maWcubW9kZSxcbiAgICAgICAgICBjb21tYW5kOiBjb25maWcuY29tbWFuZCxcbiAgICAgICAgICBpc1NzckJ1aWxkOiBmYWxzZSxcbiAgICAgICAgICBpc1ByZXZpZXc6IGZhbHNlLFxuICAgICAgICB9LFxuICAgICAgICB1c2VyT3B0aW9ucyxcbiAgICAgICAgbG9nZ2VyLFxuICAgICAgfSk7XG4gICAgICBpZiAoYXV0b0Rpc2NvdmVyUmVzdWx0LnR5cGUgPT09IFwiZXJyb3JcIikge1xuICAgICAgICB0aHJvdyBhdXRvRGlzY292ZXJSZXN1bHQuZXJyb3I7XG4gICAgICB9XG4gICAgICBhdXRvRGlzY292ZXJlZEZpbGVzID0gYXV0b0Rpc2NvdmVyUmVzdWx0LmF1dG9EaXNjb3ZlcmVkRmlsZXM7XG4gICAgICBpZih1c2VyT3B0aW9ucy52ZXJib3NlKSB7XG4gICAgICAgIGxvZ2dlcj8uaW5mbyhgQXV0by1kaXNjb3ZlcnkgJHthdXRvRGlzY292ZXJSZXN1bHQudHlwZSA9PT0gXCJzdWNjZXNzXCIgPyBcImNvbXBsZXRlZFwiIDogXCJza2lwcGVkXCJ9YCk7XG4gICAgICB9XG4gICAgfSxcblxuICAgIGFzeW5jIGJ1aWxkU3RhcnQoKSB7XG4gICAgICB0aW1pbmcuYnVpbGRTdGFydCA9IHBlcmZvcm1hbmNlLm5vdygpO1xuICAgICAgaWYodXNlck9wdGlvbnMudmVyYm9zZSkge1xuICAgICAgICBsb2dnZXI/LmluZm8oXCJbcmVhY3Qtc3RhdGljLWNsaWVudF0gQnVpbGQgc3RhcnRlZFwiKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHVzZXJPcHRpb25zLm9uRXZlbnQgJiYgYXV0b0Rpc2NvdmVyZWRGaWxlcykge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIHVzZXJPcHRpb25zLm9uRXZlbnQoe1xuICAgICAgICAgICAgdHlwZTogXCJidWlsZC5zdGFydFwiLFxuICAgICAgICAgICAgZGF0YToge1xuICAgICAgICAgICAgICBwYWdlczogQXJyYXkuZnJvbShhdXRvRGlzY292ZXJlZEZpbGVzLnVybE1hcC5rZXlzKCkpLFxuICAgICAgICAgICAgICBmaWxlczogYXV0b0Rpc2NvdmVyZWRGaWxlcyxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgY29uc3QgcGFuaWNFcnJvciA9IGhhbmRsZUVycm9yKHtcbiAgICAgICAgICAgIGVycm9yLFxuICAgICAgICAgICAgbG9nZ2VyOiBsb2dnZXIsXG4gICAgICAgICAgICBwYW5pY1RocmVzaG9sZDogdXNlck9wdGlvbnMucGFuaWNUaHJlc2hvbGQsXG4gICAgICAgICAgICBjb250ZXh0OiBcImJ1aWxkU3RhcnRcIixcbiAgICAgICAgICB9KTtcbiAgICAgICAgICBpZiAocGFuaWNFcnJvciAhPSBudWxsKSB7XG4gICAgICAgICAgICByc2NXb3JrZXI/LnRlcm1pbmF0ZSgpO1xuICAgICAgICAgIHRocm93IHBhbmljRXJyb3I7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfSxcblxuICAgIGFzeW5jIHJlbmRlclN0YXJ0KCkge1xuICAgICAgdGltaW5nLnJlbmRlclN0YXJ0ID0gcGVyZm9ybWFuY2Uubm93KCk7XG4gICAgICBpZih1c2VyT3B0aW9ucy52ZXJib3NlKSB7IFxuICAgICAgICBsb2dnZXI/LmluZm8oXCJbcmVhY3Qtc3RhdGljLWNsaWVudF0gUmVuZGVyIHN0YXJ0ZWRcIik7XG4gICAgICB9XG4gICAgfSxcblxuICAgIC8vIHRoZSBwcmV2aWV3IHNlcnZlciBoZWxwcyB0byB2aWV3IHRoZSBnZW5lcmF0ZWQgc3RhdGljIGZvbGRlciwgYnV0IG9ubHkgd2hlbiB0aGUgc3RhdGljIHBsdWdpbiBpcyBlbmFibGVkXG4gICAgLy8gaWYgbm8gYnVpbGQucGFnZXMsIHRoZW4gdGhlIHByZXZpZXcgc2VydmVyIHdpbGwgaW5zdGVhZCB1c2UgZGVmYXVsdCB2aXRlIHByZXZpZXcgc2VydmVyXG4gICAgLy8gaXQgd29ya3MgdGhlIHNhbWUgdW5kZXIgYm90aCBjb25kaXRpb25zXG4gICAgYXN5bmMgY29uZmlndXJlUHJldmlld1NlcnZlcihzZXJ2ZXIpIHtcbiAgICAgIGxvZ2dlciA9IHNlcnZlci5jb25maWcuY3VzdG9tTG9nZ2VyIHx8IHNlcnZlci5jb25maWcubG9nZ2VyO1xuICAgICAgY29uZmlndXJlUHJldmlld1NlcnZlcih7XG4gICAgICAgIHNlcnZlcixcbiAgICAgICAgdXNlck9wdGlvbnMsXG4gICAgICB9KTtcbiAgICB9LFxuXG5cblxuICAgIGFzeW5jIHdyaXRlQnVuZGxlKF9vcHRpb25zLCBidW5kbGUpIHtcblxuICAgICAgLy8gQ2FwdHVyZSBtYW5pZmVzdHMgZnJvbSBhbGwgZW52aXJvbm1lbnRzXG4gICAgICB0cnkge1xuICAgICAgICBpZiAoIWF1dG9EaXNjb3ZlcmVkRmlsZXM/LnVybE1hcCkge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGJ1bmRsZU1hbmlmZXN0ID0gZ2V0QnVuZGxlTWFuaWZlc3Q8ZmFsc2U+KHtcbiAgICAgICAgICBidW5kbGUsXG4gICAgICAgICAgbm9ybWFsaXplcjogdXNlck9wdGlvbnMubm9ybWFsaXplcixcbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gU3RvcmUgbWFuaWZlc3QgYmFzZWQgb24gZW52aXJvbm1lbnRcbiAgICAgICAgaWYgKHRoaXMuZW52aXJvbm1lbnQubmFtZSA9PT0gXCJzdGF0aWNcIikge1xuICAgICAgICAgIC8vIFN0b3JlIGluIGdsb2JhbCBtYW5pZmVzdCBzdG9yZSBmb3IgZW52aXJvbm1lbnQgcGx1Z2luIGFjY2Vzc1xuICAgICAgICAgIGFkZFN0YXRpY01hbmlmZXN0KGJ1bmRsZU1hbmlmZXN0KTtcblxuICAgICAgICAgIHN0YXRpY0J1bmRsZSA9IGJ1bmRsZTtcbiAgICAgICAgfSBlbHNlIGlmICh0aGlzLmVudmlyb25tZW50Lm5hbWUgPT09IFwiY2xpZW50XCIpIHtcbiAgICAgICAgICAvLyBDbGllbnQgYnVpbGQgbWFuaWZlc3QgKFNTUiBtb2R1bGVzKSAtIHN0b3JlZCBnbG9iYWxseSBub3dcblxuICAgICAgICAgIGlmIChtYW5pZmVzdHMuc3RhdGljKSB7XG4gICAgICAgICAgICBjb25zdCBzdGF0aWNNYW5pZmVzdCA9IG1hbmlmZXN0cy5zdGF0aWM7XG5cbiAgICAgICAgICAgIC8vIFVwZGF0ZSBidW5kbGUgZmlsZW5hbWVzIHRvIG1hdGNoIHN0YXRpYyBtYW5pZmVzdFxuICAgICAgICAgICAgZm9yIChjb25zdCBbLCBjaHVua10gb2YgT2JqZWN0LmVudHJpZXMoYnVuZGxlKSkge1xuICAgICAgICAgICAgICBpZiAoY2h1bmsudHlwZSA9PT0gXCJjaHVua1wiICYmIGNodW5rLmZpbGVOYW1lKSB7XG4gICAgICAgICAgICAgICAgY29uc3Qgbm9ybWFsaXplZCA9IHVzZXJPcHRpb25zLm5vcm1hbGl6ZXIoY2h1bmsuZmlsZU5hbWUpO1xuICAgICAgICAgICAgICAgIGxldCB2YWx1ZSA9IG5vcm1hbGl6ZWRbMV07XG4gICAgICAgICAgICAgICAgaWYgKHZhbHVlLnN0YXJ0c1dpdGgodXNlck9wdGlvbnMubW9kdWxlQmFzZVBhdGgpKSB7XG4gICAgICAgICAgICAgICAgICB2YWx1ZSA9IHZhbHVlLnNsaWNlKHVzZXJPcHRpb25zLm1vZHVsZUJhc2VQYXRoLmxlbmd0aCk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgY29uc3QgZW50cnkgPSBzdGF0aWNNYW5pZmVzdFt2YWx1ZV07XG4gICAgICAgICAgICAgICAgaWYgKGVudHJ5ICYmIGVudHJ5LmZpbGUgIT09IGNodW5rLmZpbGVOYW1lKSB7XG4gICAgICAgICAgICAgICAgICAvLyBVcGRhdGUgdGhlIGZpbGVuYW1lIHRvIG1hdGNoIHN0YXRpYyBtYW5pZmVzdFxuICAgICAgICAgICAgICAgICAgY2h1bmsuZmlsZU5hbWUgPSBlbnRyeS5maWxlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmICh0aGlzLmVudmlyb25tZW50Lm5hbWUgPT09IFwic2VydmVyXCIpIHtcbiAgICAgICAgICAvLyBTZXJ2ZXIgYnVpbGQgbWFuaWZlc3QgKHNlcnZlciBjb21wb25lbnRzKSAtIHN0b3JlZCBnbG9iYWxseSBub3dcbiAgICAgICAgICBzZXJ2ZXJCdW5kbGUgPSBidW5kbGU7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBTa2lwIHRoZSBzdGF0aWMgZ2VuZXJhdGlvbiBoZXJlIC0gaXQgd2lsbCBoYXBwZW4gaW4gY2xvc2VCdW5kbGVcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgY29uc3QgcGFuaWNFcnJvciA9IGhhbmRsZUVycm9yKHtcbiAgICAgICAgICBlcnJvcixcbiAgICAgICAgICBsb2dnZXI6IGxvZ2dlcixcbiAgICAgICAgICBwYW5pY1RocmVzaG9sZDogdXNlck9wdGlvbnMucGFuaWNUaHJlc2hvbGQsXG4gICAgICAgICAgY29udGV4dDogXCJ3cml0ZUJ1bmRsZVwiLFxuICAgICAgICB9KTtcbiAgICAgICAgaWYgKHBhbmljRXJyb3IgIT0gbnVsbCkge1xuICAgICAgICAgIHRocm93IHBhbmljRXJyb3I7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9LFxuXG4gICAgYXN5bmMgY2xvc2VCdW5kbGUoKSB7XG4gICAgICBjb25zdCBlbnZOYW1lID0gdGhpcy5lbnZpcm9ubWVudC5uYW1lO1xuICAgICAgY29uc3QgaXNTc3IgPSB0aGlzLmVudmlyb25tZW50LmNvbmZpZy5idWlsZD8uc3NyID09PSB0cnVlO1xuICAgICAgXG4gICAgICBpZiAodXNlck9wdGlvbnMudmVyYm9zZSkge1xuICAgICAgICBsb2dnZXI/LmluZm8oYFtyZWFjdC1zdGF0aWMtY2xpZW50XSBjbG9zZUJ1bmRsZSBjYWxsZWQgZm9yIGVudmlyb25tZW50OiAke2Vudk5hbWV9LCBzc3I6ICR7aXNTc3J9YCk7XG4gICAgICB9XG4gICAgICBcbiAgICAgIC8vIE9ubHkgcnVuIHN0YXRpYyBnZW5lcmF0aW9uIGluIHRoZSBub24tU1NSIGNsaWVudCBlbnZpcm9ubWVudCAoc3RhdGljIGJ1aWxkcylcbiAgICAgIC8vIFNraXAgU1NSIGNsaWVudCBidWlsZHMgYW5kIHNlcnZlciBidWlsZHNcbiAgICAgIGlmIChlbnZOYW1lID09PSBcInNzclwiIHx8IGVudk5hbWUgPT09IFwic2VydmVyXCIgfHwgaXNTc3IpIHtcbiAgICAgICAgaWYgKHVzZXJPcHRpb25zLnZlcmJvc2UpIHtcbiAgICAgICAgICBsb2dnZXI/LmluZm8oYFtyZWFjdC1zdGF0aWMtY2xpZW50XSBTa2lwcGluZyBzdGF0aWMgZ2VuZXJhdGlvbiBmb3IgZW52aXJvbm1lbnQ6ICR7ZW52TmFtZX0gKHNzcjogJHtpc1Nzcn0pYCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICAvLyBDbGVhbiB1cCBfdmlydHVhbCBmaWxlcyBhZnRlciBidWlsZCBjb21wbGV0ZXNcbiAgICAgIC8vIFRoZXNlIGFyZSBWaXRlJ3MgaW50ZXJuYWwgdmlydHVhbCBtb2R1bGVzIGFuZCBhcmVuJ3QgbmVlZGVkIGluIHRoZSBmaW5hbCBvdXRwdXRcbiAgICAgIGlmIChlbnZOYW1lID09PSBcInN0YXRpY1wiIHx8IChlbnZOYW1lID09PSBcImNsaWVudFwiICYmICFpc1NzcikpIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBjb25zdCB7IHJtU3luYywgZXhpc3RzU3luYyB9ID0gYXdhaXQgaW1wb3J0KFwibm9kZTpmc1wiKTtcbiAgICAgICAgICBjb25zdCB7IGpvaW4sIHJlc29sdmUgfSA9IGF3YWl0IGltcG9ydChcIm5vZGU6cGF0aFwiKTtcbiAgICAgICAgICBcbiAgICAgICAgICAvLyBVc2UgdGhlIHJlc29sdmVkIG91dHB1dCBkaXJlY3RvcnkgZnJvbSB0aGUgZW52aXJvbm1lbnQgY29uZmlnXG4gICAgICAgICAgY29uc3QgcmVzb2x2ZWRPdXREaXIgPSB0aGlzLmVudmlyb25tZW50LmNvbmZpZy5idWlsZD8ub3V0RGlyIFxuICAgICAgICAgICAgPyByZXNvbHZlKHRoaXMuZW52aXJvbm1lbnQuY29uZmlnLnJvb3QgfHwgdXNlck9wdGlvbnMucHJvamVjdFJvb3QsIHRoaXMuZW52aXJvbm1lbnQuY29uZmlnLmJ1aWxkLm91dERpcilcbiAgICAgICAgICAgIDogcmVzb2x2ZSh1c2VyT3B0aW9ucy5wcm9qZWN0Um9vdCwgdXNlck9wdGlvbnMuYnVpbGQub3V0RGlyKTtcbiAgICAgICAgICBcbiAgICAgICAgICAvLyBDbGVhbiB1cCBfdmlydHVhbCBmcm9tIGNsaWVudC9zdGF0aWMgb3V0cHV0IGRpcmVjdG9yaWVzIG9ubHlcbiAgICAgICAgICAvLyBEb24ndCBjbGVhbiB1cCBzZXJ2ZXIvX3ZpcnR1YWwgc2luY2Ugd2UgbmVlZCBkeW5hbWljLWltcG9ydC1oZWxwZXIuanMgdGhlcmVcbiAgICAgICAgICBjb25zdCBvdXRwdXREaXJzID0gW1xuICAgICAgICAgICAgam9pbihyZXNvbHZlZE91dERpciwgdXNlck9wdGlvbnMuYnVpbGQuc3RhdGljIHx8IFwic3RhdGljXCIpLFxuICAgICAgICAgICAgam9pbihyZXNvbHZlZE91dERpciwgdXNlck9wdGlvbnMuYnVpbGQuY2xpZW50IHx8IFwiY2xpZW50XCIpLFxuICAgICAgICAgIF07XG4gICAgICAgICAgXG4gICAgICAgICAgZm9yIChjb25zdCBvdXREaXIgb2Ygb3V0cHV0RGlycykge1xuICAgICAgICAgICAgY29uc3QgdmlydHVhbERpciA9IGpvaW4ob3V0RGlyLCBcIl92aXJ0dWFsXCIpO1xuICAgICAgICAgICAgaWYgKGV4aXN0c1N5bmModmlydHVhbERpcikpIHtcbiAgICAgICAgICAgICAgcm1TeW5jKHZpcnR1YWxEaXIsIHsgcmVjdXJzaXZlOiB0cnVlLCBmb3JjZTogdHJ1ZSB9KTtcbiAgICAgICAgICAgICAgaWYgKHVzZXJPcHRpb25zLnZlcmJvc2UpIHtcbiAgICAgICAgICAgICAgICBsb2dnZXI/LmluZm8oYFtyZWFjdC1zdGF0aWMtY2xpZW50XSBDbGVhbmVkIHVwIF92aXJ0dWFsIGRpcmVjdG9yeTogJHt2aXJ0dWFsRGlyfWApO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgIC8vIE5vbi1jcml0aWNhbCAtIGxvZyBidXQgZG9uJ3QgZmFpbCB0aGUgYnVpbGRcbiAgICAgICAgICBpZiAodXNlck9wdGlvbnMudmVyYm9zZSkge1xuICAgICAgICAgICAgbG9nZ2VyPy53YXJuKGBbcmVhY3Qtc3RhdGljLWNsaWVudF0gRmFpbGVkIHRvIGNsZWFuIHVwIF92aXJ0dWFsIGRpcmVjdG9yeTogJHtlcnJvcn1gKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgLy8gVGhpcyBydW5zIGFmdGVyIGFsbCB3cml0ZUJ1bmRsZSBob29rcyBhcmUgY29tcGxldGVcbiAgICAgIC8vIFJ1biBzdGF0aWMgZ2VuZXJhdGlvbiBpbiB0aGUgbm9uLVNTUiBjbGllbnQgZW52aXJvbm1lbnQgKHN0YXRpYyBidWlsZHMpXG4gICAgICAvLyBUaGlzIGNvdWxkIGJlIFwic3RhdGljXCIgb3IgXCJjbGllbnRcIiBkZXBlbmRpbmcgb24gaG93IGVudmlyb25tZW50cyBhcmUgY29uZmlndXJlZFxuICAgICAgaWYgKGVudk5hbWUgPT09IFwic3NyXCIgfHwgZW52TmFtZSA9PT0gXCJzZXJ2ZXJcIiB8fCBpc1Nzcikge1xuICAgICAgICBpZiAodXNlck9wdGlvbnMudmVyYm9zZSkge1xuICAgICAgICAgIGxvZ2dlcj8uaW5mbyhgW3JlYWN0LXN0YXRpYy1jbGllbnRdIFNraXBwaW5nIHN0YXRpYyBnZW5lcmF0aW9uIC0gbm90IGluIHN0YXRpYyBlbnZpcm9ubWVudCAoJHtlbnZOYW1lfSwgc3NyOiAke2lzU3NyfSlgKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIC8vIERlZmVyIHN0YXRpYyBnZW5lcmF0aW9uIHRvIHJ1biBhZnRlciBBTEwgZW52aXJvbm1lbnRzIGNvbXBsZXRlIHRoZWlyIGJ1aWxkcy5cbiAgICAgIC8vIFRoaXMgaXMgbmVjZXNzYXJ5IGJlY2F1c2Ugd2UgbmVlZCB0aGUgc2VydmVyIG1hbmlmZXN0IChmcm9tIHNlcnZlciBlbnYncyB3cml0ZUJ1bmRsZSlcbiAgICAgIC8vIHRvIHJlc29sdmUgZnVuY3Rpb24tYmFzZWQgY29tcG9uZW50IHBhdGhzIGxpa2UgUm9vdDogKHVybCkgPT4gJ3NyYy9DdXN0b21Sb290LnRzeCcuXG4gICAgICAvLyBUaGUgYnVpbGRBcHAgaG9vayBpbiBjcmVhdGVFbnZpcm9ubWVudFBsdWdpbiB3aWxsIGNhbGwgcnVuRGVmZXJyZWRTdGF0aWNHZW5lcmF0aW9uKCkuXG4gICAgICBjb25zdCBjbG9zZUJ1bmRsZUNvbnRleHQgPSB0aGlzO1xuICAgICAgZGVmZXJTdGF0aWNHZW5lcmF0aW9uKGFzeW5jICgpID0+IHtcblxuICAgICAgdHJ5IHtcbiAgICAgICAgLy8gUmUtY2hlY2sgYXV0b0Rpc2NvdmVyZWRGaWxlcyAtIGl0IG1pZ2h0IG5vdCBiZSBzZXQgaWYgY29uZmlnUmVzb2x2ZWQgZGlkbid0IHJ1blxuICAgICAgICAvLyBvciBpZiBpdCB3YXMgY2xlYXJlZC4gVHJ5IHRvIGdldCBpdCBmcm9tIHN0YXNoZWQgb3B0aW9ucyBpZiBuZWVkZWRcbiAgICAgICAgaWYgKCFhdXRvRGlzY292ZXJlZEZpbGVzKSB7XG4gICAgICAgICAgaWYgKHVzZXJPcHRpb25zLnZlcmJvc2UpIHtcbiAgICAgICAgICAgIGxvZ2dlcj8ud2FybihcIltyZWFjdC1zdGF0aWMtY2xpZW50XSBhdXRvRGlzY292ZXJlZEZpbGVzIG5vdCBzZXQsIGF0dGVtcHRpbmcgdG8gcmUtZGlzY292ZXJcIik7XG4gICAgICAgICAgfVxuICAgICAgICAgIGNvbnN0IHsgZ2V0U3Rhc2hlZFVzZXJPcHRpb25zLCBnZXRFbnZpcm9ubWVudElkIH0gPSBhd2FpdCBpbXBvcnQoXCIuLi9jb25maWcvc3Rhc2hlZE9wdGlvbnNTdGF0ZS5qc1wiKTtcbiAgICAgICAgICBjb25zdCB7IGdldENvbmRpdGlvbiB9ID0gYXdhaXQgaW1wb3J0KFwiLi4vY29uZmlnL2dldENvbmRpdGlvbi5qc1wiKTtcbiAgICAgICAgICBjb25zdCBlbnZJZCA9IGdldEVudmlyb25tZW50SWQoZ2V0Q29uZGl0aW9uKCksIHJlc29sdmVkQ29uZmlnPy5tb2RlIHx8IFwicHJvZHVjdGlvblwiKTtcbiAgICAgICAgICBjb25zdCBzdGFzaGVkT3B0aW9ucyA9IGdldFN0YXNoZWRVc2VyT3B0aW9ucyhlbnZJZCk7XG4gICAgICAgICAgaWYgKHN0YXNoZWRPcHRpb25zICYmIHJlc29sdmVkQ29uZmlnKSB7XG4gICAgICAgICAgICAvLyBUcnkgdG8gcmUtcnVuIGF1dG8tZGlzY292ZXJ5IGlmIHdlIGhhdmUgdGhlIGNvbmZpZ1xuICAgICAgICAgICAgY29uc3QgYXV0b0Rpc2NvdmVyUmVzdWx0ID0gYXdhaXQgcmVzb2x2ZUF1dG9EaXNjb3Zlcih7XG4gICAgICAgICAgICAgIGNvbmZpZzogcmVzb2x2ZWRDb25maWcsXG4gICAgICAgICAgICAgIGNvbmZpZ0VudjogY29uZmlnRW52IHx8IHtcbiAgICAgICAgICAgICAgICBtb2RlOiByZXNvbHZlZENvbmZpZy5tb2RlIHx8IFwicHJvZHVjdGlvblwiLFxuICAgICAgICAgICAgICAgIGNvbW1hbmQ6IHJlc29sdmVkQ29uZmlnLmNvbW1hbmQgfHwgXCJidWlsZFwiLFxuICAgICAgICAgICAgICAgIGlzU3NyQnVpbGQ6IGZhbHNlLFxuICAgICAgICAgICAgICAgIGlzUHJldmlldzogZmFsc2UsXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIHVzZXJPcHRpb25zLFxuICAgICAgICAgICAgICBsb2dnZXIsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIGlmIChhdXRvRGlzY292ZXJSZXN1bHQudHlwZSA9PT0gXCJzdWNjZXNzXCIpIHtcbiAgICAgICAgICAgICAgYXV0b0Rpc2NvdmVyZWRGaWxlcyA9IGF1dG9EaXNjb3ZlclJlc3VsdC5hdXRvRGlzY292ZXJlZEZpbGVzO1xuICAgICAgICAgICAgICBpZiAodXNlck9wdGlvbnMudmVyYm9zZSkge1xuICAgICAgICAgICAgICAgIGxvZ2dlcj8uaW5mbyhgW3JlYWN0LXN0YXRpYy1jbGllbnRdIFJlLWRpc2NvdmVyZWQgJHthdXRvRGlzY292ZXJlZEZpbGVzLnVybE1hcC5zaXplfSBwYWdlc2ApO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICBpZiAodXNlck9wdGlvbnMudmVyYm9zZSkge1xuICAgICAgICAgICAgICAgIGxvZ2dlcj8ud2FybihgW3JlYWN0LXN0YXRpYy1jbGllbnRdIEZhaWxlZCB0byByZS1kaXNjb3ZlciBwYWdlczogJHthdXRvRGlzY292ZXJSZXN1bHQuZXJyb3J9YCk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoXG4gICAgICAgICAgIWF1dG9EaXNjb3ZlcmVkRmlsZXM/LnVybE1hcCB8fFxuICAgICAgICAgIGF1dG9EaXNjb3ZlcmVkRmlsZXM/LnVybE1hcC5zaXplID09PSAwXG4gICAgICAgICkge1xuICAgICAgICAgIGlmICh1c2VyT3B0aW9ucy52ZXJib3NlKSB7XG4gICAgICAgICAgICBsb2dnZXI/Lndhcm4oYFtyZWFjdC1zdGF0aWMtY2xpZW50XSBObyBwYWdlcyB0byBnZW5lcmF0ZSAtIHVybE1hcCBpcyBlbXB0eSAoc2l6ZTogJHthdXRvRGlzY292ZXJlZEZpbGVzPy51cmxNYXA/LnNpemUgfHwgMH0pYCk7XG4gICAgICAgICAgICBsb2dnZXI/Lndhcm4oYFtyZWFjdC1zdGF0aWMtY2xpZW50XSBhdXRvRGlzY292ZXJlZEZpbGVzIGV4aXN0czogJHshIWF1dG9EaXNjb3ZlcmVkRmlsZXN9LCB1cmxNYXAgZXhpc3RzOiAkeyEhYXV0b0Rpc2NvdmVyZWRGaWxlcz8udXJsTWFwfWApO1xuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodXNlck9wdGlvbnMudmVyYm9zZSkge1xuICAgICAgICAgIGxvZ2dlcj8uaW5mbyhgW3JlYWN0LXN0YXRpYy1jbGllbnRdIFN0YXJ0aW5nIHN0YXRpYyBnZW5lcmF0aW9uIHdpdGggJHthdXRvRGlzY292ZXJlZEZpbGVzLnVybE1hcC5zaXplfSBwYWdlc2ApO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gQ2hlY2sgaWYgd2UgY2FuIGFjY2VzcyB0aGUgc2hhcmVkIG1hbmlmZXN0IHN0b3JlXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgaWYgKHVzZXJPcHRpb25zLnZlcmJvc2UpIHtcbiAgICAgICAgICAgIGxvZ2dlcj8uaW5mbyhgW3JlYWN0LXN0YXRpYy1jbGllbnRdIEF0dGVtcHRpbmcgdG8gZ2V0IHNlcnZlciBtYW5pZmVzdCBmcm9tIHNoYXJlZCBzdGF0ZWApO1xuICAgICAgICAgIH1cbiAgICAgICAgICBjb25zdCBzaGFyZWRTdGF0ZSA9IGdldFNoYXJlZE1hbmlmZXN0U3RvcmUoY2xvc2VCdW5kbGVDb250ZXh0KTtcbiAgICAgICAgICBpZiAoc2hhcmVkU3RhdGUuc2VydmVyKSB7XG4gICAgICAgICAgICBzZXJ2ZXJNYW5pZmVzdCA9IHNoYXJlZFN0YXRlLnNlcnZlcjtcbiAgICAgICAgICAgIGlmICh1c2VyT3B0aW9ucy52ZXJib3NlKSB7XG4gICAgICAgICAgICAgIGxvZ2dlcj8uaW5mbyhgW3JlYWN0LXN0YXRpYy1jbGllbnRdIEdvdCBzZXJ2ZXIgbWFuaWZlc3QgZnJvbSBzaGFyZWQgc3RhdGVgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiTm8gc2VydmVyIG1hbmlmZXN0IGluIHNoYXJlZCBzdGF0ZVwiKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgaWYgKHVzZXJPcHRpb25zLnZlcmJvc2UpIHtcbiAgICAgICAgICAgIGxvZ2dlcj8uaW5mbyhgW3JlYWN0LXN0YXRpYy1jbGllbnRdIEZhaWxlZCB0byBnZXQgc2VydmVyIG1hbmlmZXN0IGZyb20gc2hhcmVkIHN0YXRlLCB0cnlpbmcgZmlsZXN5c3RlbTogJHtlcnJvcn1gKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgY29uc3Qgc2VydmVyTWFuaWZlc3RQYXRoID0gam9pbihcbiAgICAgICAgICAgIHVzZXJPcHRpb25zLmJ1aWxkLm91dERpcixcbiAgICAgICAgICAgIHVzZXJPcHRpb25zLmJ1aWxkLnNlcnZlclxuICAgICAgICAgICk7XG4gICAgICAgICAgY29uc3QgbWFuaWZlc3RQYXRoID1cbiAgICAgICAgICAgICh0eXBlb2YgcmVzb2x2ZWRDb25maWc/LmJ1aWxkLm1hbmlmZXN0ID09PSBcInN0cmluZ1wiIFxuICAgICAgICAgICAgICA/IHJlc29sdmVkQ29uZmlnLmJ1aWxkLm1hbmlmZXN0IFxuICAgICAgICAgICAgICA6IFwiLnZpdGUvbWFuaWZlc3QuanNvblwiKTtcblxuICAgICAgICAgIGlmICh1c2VyT3B0aW9ucy52ZXJib3NlKSB7XG4gICAgICAgICAgICBsb2dnZXI/LmluZm8oYFtyZWFjdC1zdGF0aWMtY2xpZW50XSBMb2FkaW5nIHNlcnZlciBtYW5pZmVzdCBmcm9tOiAke2pvaW4oc2VydmVyTWFuaWZlc3RQYXRoLCBtYW5pZmVzdFBhdGgpfWApO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGNvbnN0IHNlcnZlck1hbmlmZXN0UmVzdWx0ID0gYXdhaXQgdHJ5TWFuaWZlc3Qoe1xuICAgICAgICAgICAgcm9vdDogdXNlck9wdGlvbnMucHJvamVjdFJvb3QsXG4gICAgICAgICAgICBvdXREaXI6IHNlcnZlck1hbmlmZXN0UGF0aCxcbiAgICAgICAgICAgIG1hbmlmZXN0UGF0aDogbWFuaWZlc3RQYXRoLFxuICAgICAgICAgICAgc3NyTWFuaWZlc3Q6IGZhbHNlLFxuICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgaWYgKHNlcnZlck1hbmlmZXN0UmVzdWx0LnR5cGUgPT09IFwiZXJyb3JcIikge1xuICAgICAgICAgICAgaWYgKHVzZXJPcHRpb25zLnZlcmJvc2UpIHtcbiAgICAgICAgICAgICAgbG9nZ2VyPy53YXJuKGBbcmVhY3Qtc3RhdGljLWNsaWVudF0gRmFpbGVkIHRvIGxvYWQgc2VydmVyIG1hbmlmZXN0OiAke3NlcnZlck1hbmlmZXN0UmVzdWx0LmVycm9yfWApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gVXNlIGVtcHR5IG1hbmlmZXN0IGFzIGZhbGxiYWNrIC0gc3RhdGljIGdlbmVyYXRpb24gY2FuIHByb2NlZWQgd2l0aG91dCBpdFxuICAgICAgICAgICAgc2VydmVyTWFuaWZlc3QgPSB7fTtcbiAgICAgICAgICAgIGlmICh1c2VyT3B0aW9ucy52ZXJib3NlKSB7XG4gICAgICAgICAgICAgIGxvZ2dlcj8ud2FybihgW3JlYWN0LXN0YXRpYy1jbGllbnRdIFVzaW5nIGVtcHR5IHNlcnZlciBtYW5pZmVzdCBhcyBmYWxsYmFja2ApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gZWxzZSBpZiAoc2VydmVyTWFuaWZlc3RSZXN1bHQudHlwZSA9PT0gXCJza2lwXCIpIHtcbiAgICAgICAgICAgIGlmICh1c2VyT3B0aW9ucy52ZXJib3NlKSB7XG4gICAgICAgICAgICAgIGxvZ2dlcj8ud2FybihgW3JlYWN0LXN0YXRpYy1jbGllbnRdIFNlcnZlciBtYW5pZmVzdCBub3QgZm91bmQsIHVzaW5nIGVtcHR5IG1hbmlmZXN0IGFzIGZhbGxiYWNrYCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBVc2UgZW1wdHkgbWFuaWZlc3QgYXMgZmFsbGJhY2sgLSBzdGF0aWMgZ2VuZXJhdGlvbiBjYW4gcHJvY2VlZCB3aXRob3V0IGl0XG4gICAgICAgICAgICBzZXJ2ZXJNYW5pZmVzdCA9IHt9O1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBzZXJ2ZXJNYW5pZmVzdCA9IHNlcnZlck1hbmlmZXN0UmVzdWx0Lm1hbmlmZXN0O1xuICAgICAgICAgICAgaWYgKHVzZXJPcHRpb25zLnZlcmJvc2UpIHtcbiAgICAgICAgICAgICAgbG9nZ2VyPy5pbmZvKGBbcmVhY3Qtc3RhdGljLWNsaWVudF0gTG9hZGVkIHNlcnZlciBtYW5pZmVzdCBmcm9tIGZpbGVzeXN0ZW1gKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvLyBMb2FkIHN0YXRpYyBtYW5pZmVzdCBmcm9tIGZpbGVzeXN0ZW0gZm9yIENTUyBwYXRoIG1hcHBpbmdcblxuICAgICAgICBjb25zdCBzdGF0aWNNYW5pZmVzdFJlc3VsdCA9IGF3YWl0IHRyeU1hbmlmZXN0KHtcbiAgICAgICAgICByb290OiB1c2VyT3B0aW9ucy5wcm9qZWN0Um9vdCxcbiAgICAgICAgICBvdXREaXI6IGpvaW4odXNlck9wdGlvbnMuYnVpbGQub3V0RGlyLCB1c2VyT3B0aW9ucy5idWlsZC5zdGF0aWMpLFxuICAgICAgICAgIG1hbmlmZXN0UGF0aDogcmVzb2x2ZWRDb25maWc/LmJ1aWxkLm1hbmlmZXN0ID8/IFwiLnZpdGUvbWFuaWZlc3QuanNvblwiLFxuICAgICAgICAgIHNzck1hbmlmZXN0OiBmYWxzZSxcbiAgICAgICAgfSk7XG4gICAgICAgIGlmIChzdGF0aWNNYW5pZmVzdFJlc3VsdC50eXBlID09PSBcImVycm9yXCIpIHtcbiAgICAgICAgICB0aHJvdyBzdGF0aWNNYW5pZmVzdFJlc3VsdC5lcnJvcjtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBzdGF0aWNNYW5pZmVzdCA9IHN0YXRpY01hbmlmZXN0UmVzdWx0Lm1hbmlmZXN0O1xuXG4gICAgICAgIC8vIENvbnN0cnVjdCBib290c3RyYXBNb2R1bGVzIGxpa2UgdGhlIHNlcnZlciBwbHVnaW4gZG9lc1xuICAgICAgICBjb25zdCBpbmRleEh0bWwgPSBzdGF0aWNNYW5pZmVzdD8uW1wiaW5kZXguaHRtbFwiXT8uZmlsZTtcbiAgICAgICAgY29uc3Qgc2VydmVyUGlwZWFibGVTdHJlYW1PcHRpb25zID0ge1xuICAgICAgICAgIC4uLnVzZXJPcHRpb25zLnNlcnZlclBpcGVhYmxlU3RyZWFtT3B0aW9ucyxcbiAgICAgICAgICBib290c3RyYXBNb2R1bGVzOiBbXG4gICAgICAgICAgICAuLi4oaW5kZXhIdG1sID8gW2Jhc2VVUkwoaW5kZXhIdG1sKV0gOiBbXSksXG4gICAgICAgICAgICAuLi4odXNlck9wdGlvbnMuc2VydmVyUGlwZWFibGVTdHJlYW1PcHRpb25zPy5ib290c3RyYXBNb2R1bGVzID8/XG4gICAgICAgICAgICAgIFtdKSxcbiAgICAgICAgICBdLFxuICAgICAgICB9O1xuICAgICAgICB1c2VyT3B0aW9ucy5zZXJ2ZXJQaXBlYWJsZVN0cmVhbU9wdGlvbnMgPSBzZXJ2ZXJQaXBlYWJsZVN0cmVhbU9wdGlvbnM7XG4gICAgICAgIGNvbnN0IGNsaWVudFBpcGVhYmxlU3RyZWFtT3B0aW9ucyA9IHtcbiAgICAgICAgICAuLi51c2VyT3B0aW9ucy5jbGllbnRQaXBlYWJsZVN0cmVhbU9wdGlvbnMsXG4gICAgICAgICAgYm9vdHN0cmFwTW9kdWxlczogW1xuICAgICAgICAgICAgLi4uKGluZGV4SHRtbCA/IFtiYXNlVVJMKGluZGV4SHRtbCldIDogW10pLFxuICAgICAgICAgICAgLi4uKHVzZXJPcHRpb25zLmNsaWVudFBpcGVhYmxlU3RyZWFtT3B0aW9ucz8uYm9vdHN0cmFwTW9kdWxlcyA/P1xuICAgICAgICAgICAgICBbXSksXG4gICAgICAgICAgXSxcbiAgICAgICAgfTtcbiAgICAgICAgLy8gQ3JlYXRlIENTUyBwcm9wcyBmb3IgZWFjaCBDU1MgZmlsZSAoc2FtZSBhcyBzZXJ2ZXItc3RhdGljKVxuICAgICAgICBjb25zdCB7IGNzc0ZpbGVzQnlQYWdlLCBnbG9iYWxDc3MgfSA9IHByb2Nlc3NDc3NGaWxlc0ZvclBhZ2VzKHtcbiAgICAgICAgICB1c2VyT3B0aW9ucyxcbiAgICAgICAgICBhdXRvRGlzY292ZXJlZEZpbGVzLFxuICAgICAgICAgIHNlcnZlck1hbmlmZXN0LFxuICAgICAgICAgIHN0YXRpY01hbmlmZXN0LFxuICAgICAgICAgIGJ1bmRsZTogc3RhdGljQnVuZGxlIHx8IHt9LFxuICAgICAgICAgIGxvZ2dlcixcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaWYgKHVzZXJPcHRpb25zLnZlcmJvc2UpIHtcbiAgICAgICAgICBmb3IgKGNvbnN0IFtyb3V0ZSwgY3NzTWFwXSBvZiBjc3NGaWxlc0J5UGFnZS5lbnRyaWVzKCkpIHtcbiAgICAgICAgICAgIGxvZ2dlci5pbmZvKFxuICAgICAgICAgICAgICBgW3JlYWN0LXN0YXRpYy1jbGllbnRdIFJvdXRlICR7cm91dGV9OiAke2Nzc01hcC5zaXplfSBDU1MgZmlsZXNgXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgY3NzTWFwLmVudHJpZXMoKSkge1xuICAgICAgICAgICAgICBsb2dnZXIuaW5mbyhcbiAgICAgICAgICAgICAgICBgW3JlYWN0LXN0YXRpYy1jbGllbnRdICAgQ1NTIGZpbGU6ICR7a2V5fSAtPiAke3ZhbHVlLmFzfSAoJHtcbiAgICAgICAgICAgICAgICAgIHZhbHVlLmNoaWxkcmVuID8gXCJpbmxpbmVcIiA6IFwibGlua1wiXG4gICAgICAgICAgICAgICAgfSlgXG4gICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgY29uc3Qgcm91dGVzID0gQXJyYXkuZnJvbShcbiAgICAgICAgICBhdXRvRGlzY292ZXJlZEZpbGVzLnVybE1hcC5rZXlzKClcbiAgICAgICAgKSBhcyBzdHJpbmdbXTtcblxuICAgICAgICAvLyBJZiBubyBwYWdlcyB0byBnZW5lcmF0ZSwgc2tpcCBzdGF0aWMgZ2VuZXJhdGlvblxuICAgICAgICBpZiAocm91dGVzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgIGlmICh1c2VyT3B0aW9ucy52ZXJib3NlKSB7XG4gICAgICAgICAgICBsb2dnZXI/LmluZm8oXG4gICAgICAgICAgICAgIFwiW3JlYWN0LXN0YXRpYy1jbGllbnRdIE5vIHBhZ2VzIHRvIGdlbmVyYXRlLCBza2lwcGluZyBzdGF0aWMgZ2VuZXJhdGlvblwiXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICAvLyBVc2UgdGhlIHN0YXRpYyBtYW5pZmVzdCB0byBlbnN1cmUgY29uc2lzdGVudCBtb2R1bGUgSURzIGJldHdlZW4gUlNDIHN0cmVhbSBhbmQgY2xpZW50IGJ1aWxkXG4gICAgICAgIC8vIFRoZSBzdGF0aWMgbWFuaWZlc3QgY29udGFpbnMgdGhlIGNvcnJlY3QgaGFzaGVzIHRoYXQgc2hvdWxkIGJlIHVzZWQgZm9yIGJvdGggYnVpbGRzXG4gICAgICAgIC8vIChzdGF0aWNNYW5pZmVzdCBhbHJlYWR5IGxvYWRlZCBhYm92ZSlcblxuICAgICAgICAvLyBDcmVhdGUgYSBidWlsZCBsb2FkZXIgZm9yIGNsaWVudCBtb2RlIChyZXVzZSBzZXJ2ZXIncyBzb3BoaXN0aWNhdGVkIGxvYWRlcilcbiAgICAgICAgaWYgKHVzZXJPcHRpb25zLnZlcmJvc2UpIHtcbiAgICAgICAgICBsb2dnZXI/LmluZm8oYFtyZWFjdC1zdGF0aWMtY2xpZW50XSBDcmVhdGluZyBidWlsZCBsb2FkZXJgKTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBidWlsZExvYWRlciA9IGNyZWF0ZUJ1aWxkTG9hZGVyKCk7XG4gICAgICAgIGlmICh1c2VyT3B0aW9ucy52ZXJib3NlKSB7XG4gICAgICAgICAgbG9nZ2VyPy5pbmZvKGBbcmVhY3Qtc3RhdGljLWNsaWVudF0gQnVpbGQgbG9hZGVyIGNyZWF0ZWRgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIENyZWF0ZSBhbiBSU0Mgd29ya2VyIGZvciBnZW5lcmF0aW5nIFJTQyBjb250ZW50XG4gICAgICAgIGlmICh1c2VyT3B0aW9ucy52ZXJib3NlKSB7XG4gICAgICAgICAgbG9nZ2VyPy5pbmZvKFxuICAgICAgICAgICAgYFtyZWFjdC1zdGF0aWMtY2xpZW50XSBDcmVhdGluZyBSU0Mgd29ya2VyIHdpdGggcGF0aDogJHt1c2VyT3B0aW9ucy5yc2NXb3JrZXJQYXRofWBcbiAgICAgICAgICApO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3Qgd29ya2VyU3RhcnRUaW1lID0gcGVyZm9ybWFuY2Uubm93KCk7XG4gICAgICAgIGxldCByc2NXb3JrZXJSZXN1bHQ7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgcnNjV29ya2VyUmVzdWx0ID0gYXdhaXQgY3JlYXRlV29ya2VyKHtcbiAgICAgICAgICAgIHByb2plY3RSb290OiB1c2VyT3B0aW9ucy5wcm9qZWN0Um9vdCxcbiAgICAgICAgICAgIHdvcmtlclBhdGg6IHVzZXJPcHRpb25zLnJzY1dvcmtlclBhdGgsXG4gICAgICAgICAgICBjdXJyZW50Q29uZGl0aW9uOiBcInJlYWN0LWNsaWVudFwiLFxuICAgICAgICAgICAgcmV2ZXJzZUNvbmRpdGlvbjogXCJyZWFjdC1zZXJ2ZXJcIixcbiAgICAgICAgICAgIG1heExpc3RlbmVyczogTWF0aC5tYXgocm91dGVzLmxlbmd0aCAqIDMsIDEwKSwgLy8gQWNjb3VudCBmb3IgbXVsdGlwbGUgbGlzdGVuZXJzIHBlciByb3V0ZVxuICAgICAgICAgICAgZW52UHJlZml4OiBlbnZQcmVmaXhGcm9tQ29uZmlnKHJlc29sdmVkQ29uZmlnIGFzIGFueSksXG4gICAgICAgICAgICBsb2dnZXI6IGxvZ2dlcixcbiAgICAgICAgICAgIHZlcmJvc2U6IHVzZXJPcHRpb25zLnZlcmJvc2UsXG4gICAgICAgICAgICBtb2RlOiBnZXROb2RlRW52KCksXG4gICAgICAgICAgICB3b3JrZXJEYXRhOiB7XG4gICAgICAgICAgICAgIHVzZXJPcHRpb25zOiBzZXJpYWxpemVkT3B0aW9ucyh1c2VyT3B0aW9ucywgYXV0b0Rpc2NvdmVyZWRGaWxlcyksXG4gICAgICAgICAgICAgIHJlc29sdmVkQ29uZmlnOiBzZXJpYWxpemVSZXNvbHZlZENvbmZpZyhyZXNvbHZlZENvbmZpZyBhcyBhbnkpLFxuICAgICAgICAgICAgICBjb25maWdFbnY6ICgoKSA9PiB7XG4gICAgICAgICAgICAgICAgY29uc3QgZmFsbGJhY2sgPSByZXNvbHZlZENvbmZpZ1xuICAgICAgICAgICAgICAgICAgPyB7XG4gICAgICAgICAgICAgICAgICAgICAgY29tbWFuZDogcmVzb2x2ZWRDb25maWcuY29tbWFuZCxcbiAgICAgICAgICAgICAgICAgICAgICBtb2RlOiByZXNvbHZlZENvbmZpZy5tb2RlLFxuICAgICAgICAgICAgICAgICAgICAgIGlzU3NyQnVpbGQ6IGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICAgIGlzUHJldmlldzogZmFsc2UsXG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgIDogdW5kZWZpbmVkO1xuICAgICAgICAgICAgICAgIGNvbnN0IGZpbmFsQ29uZmlnRW52ID0gY29uZmlnRW52IHx8IGZhbGxiYWNrO1xuXG4gICAgICAgICAgICAgICAgcmV0dXJuIGZpbmFsQ29uZmlnRW52O1xuICAgICAgICAgICAgICB9KSgpLFxuICAgICAgICAgICAgICBzZXJ2ZXJNYW5pZmVzdDogc2VydmVyTWFuaWZlc3QgfHwge30sIC8vIFVzZSBzZXJ2ZXIgbWFuaWZlc3QgZm9yIHBhZ2UgY29tcG9uZW50IHJlc29sdXRpb25cbiAgICAgICAgICAgICAgYnVuZGxlOiBzdGF0aWNCdW5kbGUgfHwge30sIC8vIFVzZSBzdGF0aWMgYnVuZGxlIChjbGllbnQgYnVpbGQpIGZvciBwYWdlIGNvbXBvbmVudCByZXNvbHV0aW9uXG4gICAgICAgICAgICAgIHN0YXRpY0J1bmRsZTogc3RhdGljQnVuZGxlIHx8IHt9LCAvLyBQYXNzIHN0YXRpYyBidW5kbGUgc2VwYXJhdGVseSBmb3IgcGF0aCByZXNvbHV0aW9uXG5cbiAgICAgICAgICAgICAgaWQ6IFwic3RhdGljLWNsaWVudC1yc2Mtd29ya2VyXCIsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIH0pO1xuICAgICAgICB9IGNhdGNoICh3b3JrZXJFcnJvcikge1xuICAgICAgICAgIGlmICh1c2VyT3B0aW9ucy52ZXJib3NlKSB7XG4gICAgICAgICAgICBsb2dnZXI/LmVycm9yKGBbcmVhY3Qtc3RhdGljLWNsaWVudF0gRXJyb3IgY3JlYXRpbmcgUlNDIHdvcmtlcjogJHt3b3JrZXJFcnJvcn1gKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgdGhyb3cgd29ya2VyRXJyb3I7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAocnNjV29ya2VyUmVzdWx0LnR5cGUgIT09IFwic3VjY2Vzc1wiKSB7XG4gICAgICAgICAgY29uc3QgZXJyID0gcnNjV29ya2VyUmVzdWx0LmVycm9yID8/IG5ldyBFcnJvcihgRmFpbGVkIHRvIGNyZWF0ZSBSU0Mgd29ya2VyYCk7XG4gICAgICAgICAgaWYgKHVzZXJPcHRpb25zLnZlcmJvc2UpIHtcbiAgICAgICAgICAgIGxvZ2dlcj8uZXJyb3IoXG4gICAgICAgICAgICAgIGBbcmVhY3Qtc3RhdGljLWNsaWVudF0gUlNDIHdvcmtlciBjcmVhdGlvbiBmYWlsZWQsIHRocm93aW5nIGVycm9yYCwgeyBlcnJvcjogZXJyIH1cbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHRocm93IGVycjtcbiAgICAgICAgfVxuXG4gICAgICAgIHJzY1dvcmtlciA9IHJzY1dvcmtlclJlc3VsdC53b3JrZXI7XG4gICAgICAgIGlmICh1c2VyT3B0aW9ucy52ZXJib3NlKSB7XG4gICAgICAgICAgbG9nZ2VyPy5pbmZvKGBbcmVhY3Qtc3RhdGljLWNsaWVudF0gUlNDIHdvcmtlciBjcmVhdGVkIHN1Y2Nlc3NmdWxseWApO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gRW1pdCB3b3JrZXIgc3RhcnR1cCBtZXRyaWMgYWZ0ZXIgd29ya2VyIGlzIGNyZWF0ZWRcbiAgICAgICAgY29uc3Qgd29ya2VyU3RhcnR1cFRpbWUgPSBwZXJmb3JtYW5jZS5ub3coKSAtIHdvcmtlclN0YXJ0VGltZTtcbiAgICAgICAgaWYgKHVzZXJPcHRpb25zLm9uTWV0cmljcykge1xuICAgICAgICAgIGNvbnN0IHdvcmtlclN0YXJ0dXBNZXRyaWMgPSBjcmVhdGVXb3JrZXJTdGFydHVwTWV0cmljcyh7XG4gICAgICAgICAgICByb3V0ZTogXCIvXCIsIC8vIFdvcmtlciBzdGFydHVwIGlzIGdsb2JhbCwgbm90IHJvdXRlLXNwZWNpZmljXG4gICAgICAgICAgICB3b3JrZXJUeXBlOiBcInJzY1wiLCAvLyBUaGlzIGlzIHRoZSBSU0Mgd29ya2VyIGZvciBjbGllbnQtc2lkZSBzdGF0aWMgZ2VuZXJhdGlvblxuICAgICAgICAgICAgc3RhcnR1cFRpbWU6IHdvcmtlclN0YXJ0dXBUaW1lLFxuICAgICAgICAgICAgZnJvbU1haW5UaHJlYWQ6IHRydWUsXG4gICAgICAgICAgICBmcm9tUnNjV29ya2VyOiBmYWxzZSxcbiAgICAgICAgICAgIGZyb21IdG1sV29ya2VyOiBmYWxzZSxcbiAgICAgICAgICAgIGRlc2NyaXB0aW9uOiBgUlNDIHdvcmtlciBzdGFydHVwIGZvciBjbGllbnQtc2lkZSBzdGF0aWMgZ2VuZXJhdGlvbmAsXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgdXNlck9wdGlvbnMub25NZXRyaWNzKHdvcmtlclN0YXJ0dXBNZXRyaWMpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gUmVuZGVyIHBhZ2VzIHVzaW5nIGNsaWVudC1zaWRlIHJlbmRlcmVyIHdpdGggUlNDIHdvcmtlciBvbmx5XG4gICAgICAgIGNvbnN0IHsgb25FdmVudCwgb25NZXRyaWNzLCAuLi5oYW5kbGVyT3B0aW9ucyB9ID0gdXNlck9wdGlvbnM7XG5cbiAgICAgICAgaWYgKHVzZXJPcHRpb25zLnZlcmJvc2UpIHtcbiAgICAgICAgICBsb2dnZXI/LmluZm8oYFtyZWFjdC1zdGF0aWMtY2xpZW50XSBFeHRyYWN0ZWQgb25FdmVudDogJHt0eXBlb2Ygb25FdmVudH0sIHVzZXJPcHRpb25zLm9uRXZlbnQ6ICR7dHlwZW9mIHVzZXJPcHRpb25zLm9uRXZlbnR9YCk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBDYXB0dXJlIHNlcnZlciBidW5kbGUgZnJvbSBvbkV2ZW50IGlmIG5vdCBhbHJlYWR5IGNhcHR1cmVkXG4gICAgICAgIGlmICghc2VydmVyQnVuZGxlICYmIG9uRXZlbnQpIHtcbiAgICAgICAgICAvLyBDcmVhdGUgYSB0ZW1wb3JhcnkgZXZlbnQgaGFuZGxlciB0byBjYXB0dXJlIHRoZSBzZXJ2ZXIgYnVuZGxlXG4gICAgICAgICAgY29uc3Qgb3JpZ2luYWxPbkV2ZW50ID0gb25FdmVudDtcbiAgICAgICAgICBjb25zdCB0ZW1wT25FdmVudCA9IChldmVudDogYW55KSA9PiB7XG4gICAgICAgICAgICBpZiAoZXZlbnQudHlwZSA9PT0gXCJidWlsZC53cml0ZUJ1bmRsZS5zZXJ2ZXJcIikge1xuICAgICAgICAgICAgICBzZXJ2ZXJCdW5kbGUgPSBldmVudC5kYXRhLmJ1bmRsZTtcbiAgICAgICAgICAgICAgbG9nZ2VyPy5pbmZvKFxuICAgICAgICAgICAgICAgIFwiW3JlYWN0LXN0YXRpYy1jbGllbnRdIENhcHR1cmVkIHNlcnZlciBidW5kbGUgZnJvbSBidWlsZCBldmVudFwiXG4gICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBDYWxsIHRoZSBvcmlnaW5hbCBldmVudCBoYW5kbGVyXG4gICAgICAgICAgICBvcmlnaW5hbE9uRXZlbnQoZXZlbnQpO1xuICAgICAgICAgIH07XG5cbiAgICAgICAgICAvLyBSZXBsYWNlIHRoZSBvbkV2ZW50IHRlbXBvcmFyaWx5IHRvIGNhcHR1cmUgdGhlIHNlcnZlciBidW5kbGVcbiAgICAgICAgICB1c2VyT3B0aW9ucy5vbkV2ZW50ID0gdGVtcE9uRXZlbnQ7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBFbWl0IHRoZSBzdGF0aWMgc2l0ZSBnZW5lcmF0aW9uIHN0YXJ0IGV2ZW50XG4gICAgICAgIC8vIFVzZSB0aGUgZXh0cmFjdGVkIG9uRXZlbnQgaWYgYXZhaWxhYmxlLCBvdGhlcndpc2UgZmFsbCBiYWNrIHRvIHVzZXJPcHRpb25zLm9uRXZlbnRcbiAgICAgICAgY29uc3QgZXZlbnRIYW5kbGVyID0gb25FdmVudCB8fCB1c2VyT3B0aW9ucy5vbkV2ZW50O1xuICAgICAgICBpZiAodHlwZW9mIGV2ZW50SGFuZGxlciA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGlmICh1c2VyT3B0aW9ucy52ZXJib3NlKSB7XG4gICAgICAgICAgICAgIGxvZ2dlcj8uaW5mbyhgW3JlYWN0LXN0YXRpYy1jbGllbnRdIEVtaXR0aW5nIGJ1aWxkLnNzZy5zdGFydCBldmVudGApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY29uc3QgciA9IGV2ZW50SGFuZGxlcih7XG4gICAgICAgICAgICAgIHR5cGU6IFwiYnVpbGQuc3NnLnN0YXJ0XCIsXG4gICAgICAgICAgICAgIGRhdGE6IHtcbiAgICAgICAgICAgICAgICBwYWdlczogQXJyYXkuZnJvbShhdXRvRGlzY292ZXJlZEZpbGVzPy51cmxNYXAua2V5cygpID8/IFtdKSxcbiAgICAgICAgICAgICAgICBvcHRpb25zOiBudWxsIGFzIGFueSwgLy8gTm8gc3BlY2lmaWMgcm9sbHVwIG91dHB1dCBvcHRpb25zIGZvciBzdGF0aWMgZ2VuZXJhdGlvblxuICAgICAgICAgICAgICAgIGJ1bmRsZTogc3RhdGljQnVuZGxlIHx8IHt9LFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBpZiAociAhPSBudWxsICYmIHR5cGVvZiByID09PSBcIm9iamVjdFwiICYmIFwidGhlblwiIGluIHIpIHtcbiAgICAgICAgICAgICAgYXdhaXQgKHIgYXMgUHJvbWlzZTxhbnk+KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgICAgY29uc3QgZXZlbnRQYW5pY0Vycm9yID0gaGFuZGxlRXJyb3Ioe1xuICAgICAgICAgICAgICBlcnJvcixcbiAgICAgICAgICAgICAgbG9nZ2VyOiBsb2dnZXIsXG4gICAgICAgICAgICAgIHBhbmljVGhyZXNob2xkOiB1c2VyT3B0aW9ucy5wYW5pY1RocmVzaG9sZCxcbiAgICAgICAgICAgICAgY29udGV4dDogXCJvbkV2ZW50KGJ1aWxkLnNzZy5zdGFydClcIixcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgaWYgKGV2ZW50UGFuaWNFcnJvciAhPSBudWxsKSB7XG4gICAgICAgICAgICAgIHRocm93IGV2ZW50UGFuaWNFcnJvcjsgLy8gUmUtdGhyb3cgdG8gYWJvcnQgdGhlIGJ1aWxkXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2UgaWYgKHVzZXJPcHRpb25zLnZlcmJvc2UpIHtcbiAgICAgICAgICBsb2dnZXI/Lndhcm4oYFtyZWFjdC1zdGF0aWMtY2xpZW50XSBObyBvbkV2ZW50IGhhbmRsZXIgYXZhaWxhYmxlIHRvIGVtaXQgYnVpbGQuc3NnLnN0YXJ0YCk7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCByZW5kZXJQYWdlc0dlbmVyYXRvciA9IHJlbmRlclBhZ2VzQmF0Y2hlZChcbiAgICAgICAgICByb3V0ZXMsXG4gICAgICAgICAge1xuICAgICAgICAgICAgLi4uaGFuZGxlck9wdGlvbnMsIC8vIFVzZSB0aGUgY2xlYW4gb3B0aW9ucyBpbnN0ZWFkIG9mIHRoZSBvcmlnaW5hbCBoYW5kbGVyT3B0aW9uc1xuICAgICAgICAgICAgd29ya2VyOiByc2NXb3JrZXIsIC8vIFBhc3MgdGhlIFJTQyB3b3JrZXIgZm9yIFJTQyByZW5kZXJpbmcgb25seVxuICAgICAgICAgICAgcnNjV29ya2VyOiByc2NXb3JrZXIsIC8vIFBhc3MgdGhlIFJTQyB3b3JrZXIgZm9yIFJTQyByZW5kZXJpbmcgb25seVxuICAgICAgICAgICAgbG9hZGVyOiBidWlsZExvYWRlciwgLy8gVXNlIHByb3BlciBidWlsZCBsb2FkZXIgaW5zdGVhZCBvZiBuby1vcFxuICAgICAgICAgICAgbG9nZ2VyOiBsb2dnZXIsXG4gICAgICAgICAgICBhdXRvRGlzY292ZXJlZEZpbGVzOiBhdXRvRGlzY292ZXJlZEZpbGVzLFxuICAgICAgICAgICAgY3NzRmlsZXNCeVBhZ2U6IGNzc0ZpbGVzQnlQYWdlLCAvLyBQYXNzIENTUyBmaWxlcyBieSBwYWdlXG4gICAgICAgICAgICBzZXJ2ZXJQaXBlYWJsZVN0cmVhbU9wdGlvbnM6IHNlcnZlclBpcGVhYmxlU3RyZWFtT3B0aW9ucywgLy8gUGFzcyBzZXJ2ZXIgb3B0aW9ucyB0byBSU0Mgd29ya2VyXG4gICAgICAgICAgICBjbGllbnRQaXBlYWJsZVN0cmVhbU9wdGlvbnM6IGNsaWVudFBpcGVhYmxlU3RyZWFtT3B0aW9ucywgLy8gUGFzcyBjbGllbnQgb3B0aW9ucyB0byBSU0Mgd29ya2VyXG4gICAgICAgICAgICBnbG9iYWxDc3M6IGdsb2JhbENzcywgLy8gUGFzcyBnbG9iYWwgQ1NTXG4gICAgICAgICAgICBtYW5pZmVzdDogc2VydmVyTWFuaWZlc3QgfHwge30sIC8vIFNlcnZlciBtYW5pZmVzdCBmb3IgUlNDIHdvcmtlclxuICAgICAgICAgICAgc3RhdGljTWFuaWZlc3Q6IHN0YXRpY01hbmlmZXN0LCAvLyBTdGF0aWMgbWFuaWZlc3QgZm9yIGNvbnNpc3RlbnQgbW9kdWxlIElEc1xuICAgICAgICAgICAgb25FdmVudDogb25FdmVudCxcbiAgICAgICAgICAgIG9uTWV0cmljczogb25NZXRyaWNzLCAvLyBQYXNzIHRocm91Z2ggdGhlIG9uTWV0cmljcyBjYWxsYmFjayAobWV0cmljIHdhdGNoZXIpXG4gICAgICAgICAgfSxcbiAgICAgICAgICByZW5kZXJQYWdlXG4gICAgICAgICk7XG5cbiAgICAgICAgLy8gUHJvY2VzcyB0aGUgcmVuZGVyZWQgcGFnZXNcbiAgICAgICAgbGV0IGZpbmFsUmVzdWx0OiBhbnkgPSB1bmRlZmluZWQ7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgZm9yIGF3YWl0IChjb25zdCByZXN1bHQgb2YgcmVuZGVyUGFnZXNHZW5lcmF0b3IpIHtcbiAgICAgICAgICAgIGlmIChyZXN1bHQudHlwZSA9PT0gXCJlcnJvclwiKSB7XG4gICAgICAgICAgICAgIGlmICh1c2VyT3B0aW9ucy52ZXJib3NlKSB7XG4gICAgICAgICAgICAgICAgbG9nZ2VyPy5lcnJvcihgW3JlYWN0LXN0YXRpYy1jbGllbnRdIFJlbmRlciBlcnJvcjogJHtyZXN1bHQuZXJyb3J9YCk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgdGhyb3cgcmVzdWx0LmVycm9yO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gSGFuZGxlIGZhaWxlZCByb3V0ZXMgYmFzZWQgb24gcGFuaWMgdGhyZXNob2xkXG4gICAgICAgICAgaWYgKFxuICAgICAgICAgICAgcmVzdWx0LnR5cGUgPT09IFwic3VjY2Vzc1wiICYmXG4gICAgICAgICAgICByZXN1bHQuZmFpbGVkUm91dGVzICYmXG4gICAgICAgICAgICByZXN1bHQuZmFpbGVkUm91dGVzLnNpemUgPiAwXG4gICAgICAgICAgKSB7XG4gICAgICAgICAgICAvLyBVc2UgY2VudHJhbGl6ZWQgcGFuaWMgdGhyZXNob2xkIGxvZ2ljIChzYW1lIGFzIHNlcnZlciBwbHVnaW4pXG4gICAgICAgICAgICBjb25zdCBmaXJzdEVycm9yID0gcmVzdWx0LmZhaWxlZFJvdXRlcy52YWx1ZXMoKS5uZXh0KCkudmFsdWU7XG4gICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgIGZpcnN0RXJyb3IgIT0gbnVsbCAmJlxuICAgICAgICAgICAgICBzaG91bGRDYXVzZVBhbmljKGZpcnN0RXJyb3IsIHtcbiAgICAgICAgICAgICAgICBwYW5pY1RocmVzaG9sZDogdXNlck9wdGlvbnMucGFuaWNUaHJlc2hvbGQsXG4gICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgLy8gVGhpcyBzaG91bGQgY2F1c2UgYSBwYW5pYywgdGhyb3cgdGhlIGVycm9yXG4gICAgICAgICAgICAgIHRocm93IGZpcnN0RXJyb3I7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBGb3Igb3RoZXIgcGFuaWMgdGhyZXNob2xkcywgbG9nIHdhcm5pbmdzIGJ1dCBjb250aW51ZVxuICAgICAgICAgICAgZm9yIChjb25zdCBbcm91dGUsIGVycm9yXSBvZiByZXN1bHQuZmFpbGVkUm91dGVzKSB7XG4gICAgICAgICAgICAgIGNvbnN0IGVyciA9IGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvciA6IHRvRXJyb3IoZXJyb3IpO1xuICAgICAgICAgICAgICBjbG9zZUJ1bmRsZUNvbnRleHQud2FybihcbiAgICAgICAgICAgICAgICBuZXcgRXJyb3IoXG4gICAgICAgICAgICAgICAgICBcIkZhaWxlZCB0byByZW5kZXIgcm91dGU6IFwiICtcbiAgICAgICAgICAgICAgICAgICAgcm91dGUgK1xuICAgICAgICAgICAgICAgICAgICBcIlxcblwiICtcbiAgICAgICAgICAgICAgICAgICAgZXJyLm1lc3NhZ2UgK1xuICAgICAgICAgICAgICAgICAgICBcIlxcblwiICtcbiAgICAgICAgICAgICAgICAgICAgZXJyLnN0YWNrLFxuICAgICAgICAgICAgICAgICAgeyBjYXVzZTogZXJyIH1cbiAgICAgICAgICAgICAgICApXG4gICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgICBmaW5hbFJlc3VsdCA9IHJlc3VsdDtcbiAgICAgICAgICB9XG4gICAgICAgIH0gY2F0Y2ggKHJlbmRlckVycm9yKSB7XG4gICAgICAgICAgaWYgKHVzZXJPcHRpb25zLnZlcmJvc2UpIHtcbiAgICAgICAgICAgIGxvZ2dlcj8uZXJyb3IoYFtyZWFjdC1zdGF0aWMtY2xpZW50XSBFcnJvciBkdXJpbmcgcmVuZGVyUGFnZXM6ICR7cmVuZGVyRXJyb3J9YCk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHRocm93IHJlbmRlckVycm9yO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCFmaW5hbFJlc3VsdCkge1xuICAgICAgICAgIGNvbnN0IGVycm9yTXNnID0gXCJObyByZW5kZXIgcmVzdWx0IHByb2R1Y2VkXCI7XG4gICAgICAgICAgaWYgKHVzZXJPcHRpb25zLnZlcmJvc2UpIHtcbiAgICAgICAgICAgIGxvZ2dlcj8uZXJyb3IoYFtyZWFjdC1zdGF0aWMtY2xpZW50XSAke2Vycm9yTXNnfWApO1xuICAgICAgICAgIH1cbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoZXJyb3JNc2cpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHVzZXJPcHRpb25zLnZlcmJvc2UpIHtcbiAgICAgICAgICBsb2dnZXI/LmluZm8oYFtyZWFjdC1zdGF0aWMtY2xpZW50XSBSZW5kZXIgY29tcGxldGVkOiAke2ZpbmFsUmVzdWx0LmNvbXBsZXRlZFJvdXRlcy5zaXplfSBwYWdlcywgJHtmaW5hbFJlc3VsdC5mYWlsZWRSb3V0ZXM/LnNpemUgfHwgMH0gZmFpbGVkYCk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBGaWxlIHdyaXRlcyBhcmUgaGFuZGxlZCBieSByZW5kZXJQYWdlcywgbm8gbmVlZCB0byBkbyB0aGVtIGhlcmVcblxuICAgICAgICAvLyBDYWxjdWxhdGUgZHVyYXRpb24gZnJvbSB0aW1pbmdcbiAgICAgICAgY29uc3QgZHVyYXRpb24gPSBNYXRoLnJvdW5kKFxuICAgICAgICAgIHBlcmZvcm1hbmNlLm5vdygpIC0gKHRpbWluZy5yZW5kZXJTdGFydCB8fCB0aW1pbmcuc3RhcnQpXG4gICAgICAgICk7XG5cbiAgICAgICAgY2xvc2VCdW5kbGVDb250ZXh0LmluZm8oXG4gICAgICAgICAgYFJlbmRlcmVkICR7ZmluYWxSZXN1bHQuY29tcGxldGVkUm91dGVzLnNpemV9IHBhZ2VzIGluICR7ZHVyYXRpb259bXNgXG4gICAgICAgICk7XG5cbiAgICAgICAgaWYgKHByb2Nlc3MuZW52W1wiTk9ERV9FTlZcIl0gIT09IFwicHJvZHVjdGlvblwiKSB7XG4gICAgICAgICAgY2xvc2VCdW5kbGVDb250ZXh0Lndhcm4oXG4gICAgICAgICAgICBgVEhJUyBCVUlMRCBJUyBOT1QgSU5URU5ERUQgRk9SIFBST0RVQ1RJT04gKCR7cHJvY2Vzcy5lbnZbXCJOT0RFX0VOVlwiXX0pYFxuICAgICAgICAgICk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBVcGRhdGUgdGltaW5nXG4gICAgICAgIHRpbWluZy5yZW5kZXIgPVxuICAgICAgICAgIHBlcmZvcm1hbmNlLm5vdygpIC0gKHRpbWluZy5yZW5kZXJTdGFydCA/PyB0aW1pbmcuc3RhcnQpO1xuXG4gICAgICAgIGlmICh1c2VyT3B0aW9ucy52ZXJib3NlKSB7XG4gICAgICAgICAgbG9nZ2VyPy5pbmZvKFwiW3JlYWN0LXN0YXRpYy1jbGllbnRdIFN0YXRpYyBnZW5lcmF0aW9uIGNvbXBsZXRlZFwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEVtaXQgdGhlIHN0YXRpYyBzaXRlIGdlbmVyYXRpb24gY29tcGxldGlvbiBldmVudCBvbmNlXG4gICAgICAgIGlmICh0eXBlb2YgdXNlck9wdGlvbnMub25FdmVudCA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGNvbnN0IHIgPSB1c2VyT3B0aW9ucy5vbkV2ZW50KHtcbiAgICAgICAgICAgICAgdHlwZTogXCJidWlsZC5zc2cuZW5kXCIsXG4gICAgICAgICAgICAgIGRhdGE6IHtcbiAgICAgICAgICAgICAgICBwYWdlczogQXJyYXkuZnJvbShhdXRvRGlzY292ZXJlZEZpbGVzPy51cmxNYXAua2V5cygpID8/IFtdKSxcbiAgICAgICAgICAgICAgICBvcHRpb25zOiBudWxsIGFzIGFueSwgLy8gTm8gc3BlY2lmaWMgcm9sbHVwIG91dHB1dCBvcHRpb25zIGZvciBzdGF0aWMgZ2VuZXJhdGlvblxuICAgICAgICAgICAgICAgIGJ1bmRsZTogc3RhdGljQnVuZGxlIHx8IHt9LFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBpZiAociAhPSBudWxsICYmIHR5cGVvZiByID09PSBcIm9iamVjdFwiICYmIFwidGhlblwiIGluIHIpIHtcbiAgICAgICAgICAgICAgYXdhaXQgKHIgYXMgUHJvbWlzZTxhbnk+KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgICAgY29uc3QgZXZlbnRQYW5pY0Vycm9yID0gaGFuZGxlRXJyb3Ioe1xuICAgICAgICAgICAgICBlcnJvcixcbiAgICAgICAgICAgICAgbG9nZ2VyOiBsb2dnZXIsXG4gICAgICAgICAgICAgIHBhbmljVGhyZXNob2xkOiB1c2VyT3B0aW9ucy5wYW5pY1RocmVzaG9sZCxcbiAgICAgICAgICAgICAgY29udGV4dDogXCJvbkV2ZW50KGJ1aWxkLnNzZy5lbmQpXCIsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIGlmIChldmVudFBhbmljRXJyb3IgIT0gbnVsbCkge1xuICAgICAgICAgICAgICB0aHJvdyBldmVudFBhbmljRXJyb3I7IC8vIFJlLXRocm93IHRvIGFib3J0IHRoZSBidWlsZFxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgY29uc3QgcGFuaWNFcnJvciA9IGhhbmRsZUVycm9yKHtcbiAgICAgICAgICBlcnJvcixcbiAgICAgICAgICBjb250ZXh0OiBcInJlYWN0LXN0YXRpYy1jbGllbnRcIixcbiAgICAgICAgICBsb2dnZXIsXG4gICAgICAgICAgcGFuaWNUaHJlc2hvbGQ6IHVzZXJPcHRpb25zLnBhbmljVGhyZXNob2xkLFxuICAgICAgICB9KTtcblxuICAgICAgICAvLyBFbnN1cmUgZ3JhY2VmdWwgc2h1dGRvd24gb24gZXJyb3JcbiAgICAgICAgaWYgKHJzY1dvcmtlcikge1xuICAgICAgICAgIGNvbnN0IHdvcmtlclRvQ2xlYW51cCA9IHJzY1dvcmtlcjtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgLy8gVXNlIGdyYWNlZnVsIHNodXRkb3duIHByb3RvY29sIGV2ZW4gb24gZXJyb3JcbiAgICAgICAgICAgIGF3YWl0IFByb21pc2UucmFjZShbXG4gICAgICAgICAgICAgIG5ldyBQcm9taXNlPHZvaWQ+KChyZXNvbHZlKSA9PiB7XG4gICAgICAgICAgICAgICAgY29uc3QgdGltZW91dElkID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgICAgICAgICB3b3JrZXJUb0NsZWFudXAucmVtb3ZlQWxsTGlzdGVuZXJzKCk7XG4gICAgICAgICAgICAgICAgICB3b3JrZXJUb0NsZWFudXAudGVybWluYXRlKCk7XG4gICAgICAgICAgICAgICAgICByZXNvbHZlKCk7XG4gICAgICAgICAgICAgICAgfSwgMTAwMCk7IC8vIDEgc2Vjb25kIHRpbWVvdXQgZm9yIGdyYWNlZnVsIHNodXRkb3duXG5cbiAgICAgICAgICAgICAgICBjb25zdCBtZXNzYWdlSGFuZGxlciA9IChtZXNzYWdlOiBhbnkpID0+IHtcbiAgICAgICAgICAgICAgICAgIGlmIChtZXNzYWdlLnR5cGUgPT09IFwiU0hVVERPV05fQ09NUExFVEVcIikge1xuICAgICAgICAgICAgICAgICAgICBjbGVhclRpbWVvdXQodGltZW91dElkKTtcbiAgICAgICAgICAgICAgICAgICAgd29ya2VyVG9DbGVhbnVwLnJlbW92ZUxpc3RlbmVyKFwibWVzc2FnZVwiLCBtZXNzYWdlSGFuZGxlcik7XG4gICAgICAgICAgICAgICAgICAgIHJlc29sdmUoKTtcbiAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIHdvcmtlclRvQ2xlYW51cC5vbihcIm1lc3NhZ2VcIiwgbWVzc2FnZUhhbmRsZXIpO1xuICAgICAgICAgICAgICAgIHdvcmtlclRvQ2xlYW51cC5wb3N0TWVzc2FnZSh7IHR5cGU6IFwiU0hVVERPV05cIiB9KTtcbiAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICBdKTtcbiAgICAgICAgICAgIHJzY1dvcmtlciA9IHVuZGVmaW5lZDtcbiAgICAgICAgICB9IGNhdGNoIChjbGVhbnVwRXJyb3IpIHtcbiAgICAgICAgICAgIGxvZ2dlci53YXJuKGBGYWlsZWQgdG8gY2xlYW51cCB3b3JrZXIgb24gZXJyb3I6ICR7Y2xlYW51cEVycm9yfWApO1xuICAgICAgICAgICAgLy8gRm9yY2UgdGVybWluYXRlIGlmIGdyYWNlZnVsIHNodXRkb3duIGZhaWxzXG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICB3b3JrZXJUb0NsZWFudXAucmVtb3ZlQWxsTGlzdGVuZXJzKCk7XG4gICAgICAgICAgICAgIHdvcmtlclRvQ2xlYW51cC50ZXJtaW5hdGUoKTtcbiAgICAgICAgICAgIH0gY2F0Y2ggKHRlcm1pbmF0ZUVycm9yKSB7XG4gICAgICAgICAgICAgIC8vIElnbm9yZSB0ZXJtaW5hdGlvbiBlcnJvcnNcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJzY1dvcmtlciA9IHVuZGVmaW5lZDtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZiAocGFuaWNFcnJvciAhPSBudWxsKSB7XG4gICAgICAgICAgLy8gRW5zdXJlIHdlIGhhdmUgYSBwcm9wZXIgRXJyb3Igb2JqZWN0IHRoYXQgY2FuIGhhdmUgcHJvcGVydGllcyBzZXQgb24gaXRcbiAgICAgICAgICBjb25zdCBlcnJvclRvVGhyb3cgPVxuICAgICAgICAgICAgcGFuaWNFcnJvciBpbnN0YW5jZW9mIEVycm9yXG4gICAgICAgICAgICAgID8gcGFuaWNFcnJvclxuICAgICAgICAgICAgICA6IG5ldyBFcnJvcihTdHJpbmcocGFuaWNFcnJvcikpO1xuXG4gICAgICAgICAgLy8gQ3JlYXRlIGEgbmV3IEVycm9yIG9iamVjdCB0byBhdm9pZCB0aGUgXCJjb2RlXCIgcHJvcGVydHkgaXNzdWVcbiAgICAgICAgICBjb25zdCBmaW5hbEVycm9yID0gbmV3IEVycm9yKGVycm9yVG9UaHJvdy5tZXNzYWdlKTtcbiAgICAgICAgICBmaW5hbEVycm9yLnN0YWNrID0gZXJyb3JUb1Rocm93LnN0YWNrO1xuICAgICAgICAgIGZpbmFsRXJyb3IuY2F1c2UgPSBlcnJvclRvVGhyb3cuY2F1c2U7XG5cbiAgICAgICAgICAvLyBDb3B5IGFueSBhZGRpdGlvbmFsIHByb3BlcnRpZXMgdGhhdCBtaWdodCBiZSBuZWVkZWRcbiAgICAgICAgICBpZiAoZXJyb3JUb1Rocm93Lm5hbWUpIGZpbmFsRXJyb3IubmFtZSA9IGVycm9yVG9UaHJvdy5uYW1lO1xuXG4gICAgICAgIHRocm93IGZpbmFsRXJyb3I7XG4gICAgICAgIH1cbiAgICAgIH0gZmluYWxseSB7XG4gICAgICAgIC8vIEdyYWNlZnVsIHdvcmtlciBzaHV0ZG93biDigJQgcnVucyBvbiBib3RoIHN1Y2Nlc3MgYW5kIGVycm9yIHBhdGhzXG4gICAgICAgIGlmIChyc2NXb3JrZXIpIHtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgYXdhaXQgUHJvbWlzZS5yYWNlKFtcbiAgICAgICAgICAgICAgbmV3IFByb21pc2U8dm9pZD4oKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICAgICAgICAgIGNvbnN0IHRpbWVvdXQgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICAgICAgICAgIHJlamVjdChuZXcgRXJyb3IoXCJXb3JrZXIgc2h1dGRvd24gdGltZW91dFwiKSk7XG4gICAgICAgICAgICAgICAgfSwgdXNlck9wdGlvbnMud29ya2VyU2h1dGRvd25UaW1lb3V0KTtcblxuICAgICAgICAgICAgICAgIGNvbnN0IGJhY2t1cFRpbWVvdXQgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICAgICAgICAgIHJlamVjdChuZXcgRXJyb3IoXCJXb3JrZXIgc2h1dGRvd24gYmFja3VwIHRpbWVvdXRcIikpO1xuICAgICAgICAgICAgICAgIH0sIE1hdGguZmxvb3IodXNlck9wdGlvbnMud29ya2VyU2h1dGRvd25UaW1lb3V0ICogMC42KSk7XG5cbiAgICAgICAgICAgICAgICBjb25zdCBzaHV0ZG93bk1lc3NhZ2VIYW5kbGVyID0gKG1lc3NhZ2U6IGFueSkgPT4ge1xuICAgICAgICAgICAgICAgICAgaWYgKG1lc3NhZ2UudHlwZSA9PT0gXCJTSFVURE9XTl9DT01QTEVURVwiKSB7XG4gICAgICAgICAgICAgICAgICAgIGNsZWFyVGltZW91dCh0aW1lb3V0KTtcbiAgICAgICAgICAgICAgICAgICAgY2xlYXJUaW1lb3V0KGJhY2t1cFRpbWVvdXQpO1xuICAgICAgICAgICAgICAgICAgICByc2NXb3JrZXI/LnJlbW92ZUxpc3RlbmVyKFxuICAgICAgICAgICAgICAgICAgICAgIFwibWVzc2FnZVwiLFxuICAgICAgICAgICAgICAgICAgICAgIHNodXRkb3duTWVzc2FnZUhhbmRsZXJcbiAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgcnNjV29ya2VyPy5yZW1vdmVBbGxMaXN0ZW5lcnMoKTtcbiAgICAgICAgICAgICAgICAgICAgcmVzb2x2ZSgpO1xuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgICAgICByc2NXb3JrZXI/Lm9uKFwibWVzc2FnZVwiLCBzaHV0ZG93bk1lc3NhZ2VIYW5kbGVyKTtcbiAgICAgICAgICAgICAgICByc2NXb3JrZXI/LnBvc3RNZXNzYWdlKHtcbiAgICAgICAgICAgICAgICAgIHR5cGU6IFwiU0hVVERPV05cIixcbiAgICAgICAgICAgICAgICAgIGlkOiBcIipcIixcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICBdKTtcbiAgICAgICAgICB9IGNhdGNoIHtcbiAgICAgICAgICAgIC8vIFNodXRkb3duIHByb3RvY29sIGZhaWxlZCDigJQgZm9yY2UgdGVybWluYXRlIGJlbG93XG4gICAgICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgICAgIGlmIChyc2NXb3JrZXIpIHtcbiAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAocnNjV29ya2VyIGFzIFdvcmtlcikucmVtb3ZlQWxsTGlzdGVuZXJzKCk7XG4gICAgICAgICAgICAgICAgKHJzY1dvcmtlciBhcyBXb3JrZXIpLnRlcm1pbmF0ZSgpO1xuICAgICAgICAgICAgICB9IGNhdGNoIHtcbiAgICAgICAgICAgICAgICAvLyBJZ25vcmUgdGVybWluYXRpb24gZXJyb3JzXG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgcnNjV29ya2VyID0gdW5kZWZpbmVkO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFJlc2V0IGFueSBjYWNoZWQgc3RhdGUgdG8gcHJldmVudCBpc3N1ZXMgaW4gc3Vic2VxdWVudCBidWlsZHNcbiAgICAgICAgYXV0b0Rpc2NvdmVyZWRGaWxlcyA9IG51bGw7XG4gICAgICAgIHNlcnZlck1hbmlmZXN0ID0gdW5kZWZpbmVkO1xuICAgICAgfVxuXG4gICAgICB9KTsgLy8gZW5kIGRlZmVyU3RhdGljR2VuZXJhdGlvblxuICAgIH0sXG4gIH07XG59O1xuIl0sIm5hbWVzIjpbImpvaW4iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQWdFQSxvQkFBcUIsRUFBQTtBQWdCUixNQUFBLGlCQUFBLEdBQWtDLFNBQVMsa0JBQUEsQ0FDdEQsT0FDQSxFQUFBO0FBQ0EsRUFBSSxJQUFBLE1BQUE7QUFDSixFQUFBLElBQUksbUJBQWtELEdBQUEsSUFBQTtBQUN0RCxFQUFBLElBQUksU0FBZ0MsR0FBQSxNQUFBO0FBQ3BDLEVBQUEsSUFBSSxjQUF3QyxHQUFBLElBQUE7QUFDNUMsRUFBQSxJQUFJLGNBQXVDLEdBQUEsTUFBQTtBQUMzQyxFQUFBLElBQUksWUFBeUMsR0FBQSxNQUFBO0FBQzdDLEVBQUEsSUFBSSxZQUF5QyxHQUFBLE1BQUE7QUFFN0MsRUFBSSxJQUFBLFNBQUE7QUFDSixFQUFBLE1BQU0sTUFBc0IsR0FBQTtBQUFBLElBQzFCLEtBQUEsRUFBTyxZQUFZLEdBQUks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