dbctx 1.4.6 → 2.0.1

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 (164) hide show
  1. package/dist/app/assemble.d.mts +2 -2
  2. package/dist/app/assemble.d.mts.map +1 -1
  3. package/dist/app/assemble.mjs +37 -16
  4. package/dist/app/db.d.mts.map +1 -1
  5. package/dist/app/db.mjs +3 -2
  6. package/dist/app/detect.d.mts +1 -0
  7. package/dist/app/detect.d.mts.map +1 -1
  8. package/dist/app/detect.mjs +3 -2
  9. package/dist/app/list.d.mts +4 -0
  10. package/dist/app/list.d.mts.map +1 -0
  11. package/dist/app/list.mjs +93 -0
  12. package/dist/app/load-introspection.d.mts +26 -0
  13. package/dist/app/load-introspection.d.mts.map +1 -0
  14. package/dist/app/load-introspection.mjs +89 -0
  15. package/dist/app/login.d.mts +2 -0
  16. package/dist/app/login.d.mts.map +1 -0
  17. package/dist/app/login.mjs +69 -0
  18. package/dist/app/open-url.d.mts +2 -0
  19. package/dist/app/open-url.d.mts.map +1 -1
  20. package/dist/app/open-url.mjs +8 -3
  21. package/dist/app/sample.d.mts +24 -0
  22. package/dist/app/sample.d.mts.map +1 -0
  23. package/dist/app/sample.mjs +257 -0
  24. package/dist/app/session.d.mts +3 -2
  25. package/dist/app/session.d.mts.map +1 -1
  26. package/dist/app/session.mjs +46 -6
  27. package/dist/app/ssh.d.mts.map +1 -1
  28. package/dist/app/ssh.mjs +12 -1
  29. package/dist/app/tail.d.mts +13 -0
  30. package/dist/app/tail.d.mts.map +1 -0
  31. package/dist/app/tail.mjs +168 -0
  32. package/dist/db/check-constraints.d.mts +9 -0
  33. package/dist/db/check-constraints.d.mts.map +1 -0
  34. package/dist/db/check-constraints.mjs +17 -0
  35. package/dist/db/custom-types.d.mts +26 -0
  36. package/dist/db/custom-types.d.mts.map +1 -0
  37. package/dist/db/custom-types.mjs +61 -0
  38. package/dist/db/extensions.d.mts +8 -0
  39. package/dist/db/extensions.d.mts.map +1 -0
  40. package/dist/db/extensions.mjs +14 -0
  41. package/dist/db/foreign-keys.mjs +3 -3
  42. package/dist/db/functions.d.mts +11 -0
  43. package/dist/db/functions.d.mts.map +1 -0
  44. package/dist/db/functions.mjs +23 -0
  45. package/dist/db/index.d.mts +10 -1
  46. package/dist/db/index.d.mts.map +1 -1
  47. package/dist/db/index.mjs +11 -2
  48. package/dist/db/planner-stats.d.mts +33 -0
  49. package/dist/db/planner-stats.d.mts.map +1 -0
  50. package/dist/db/planner-stats.mjs +103 -0
  51. package/dist/db/relations.d.mts +1 -0
  52. package/dist/db/relations.d.mts.map +1 -1
  53. package/dist/db/relations.mjs +10 -1
  54. package/dist/db/rls.d.mts +21 -0
  55. package/dist/db/rls.d.mts.map +1 -0
  56. package/dist/db/rls.mjs +48 -0
  57. package/dist/db/sample.d.mts +16 -0
  58. package/dist/db/sample.d.mts.map +1 -0
  59. package/dist/db/sample.mjs +73 -0
  60. package/dist/db/sequences.d.mts +15 -0
  61. package/dist/db/sequences.d.mts.map +1 -0
  62. package/dist/db/sequences.mjs +31 -0
  63. package/dist/db/stats.mjs +3 -3
  64. package/dist/db/triggers.d.mts +11 -0
  65. package/dist/db/triggers.d.mts.map +1 -0
  66. package/dist/db/triggers.mjs +21 -0
  67. package/dist/flow/events.d.mts +115 -0
  68. package/dist/flow/events.d.mts.map +1 -0
  69. package/dist/flow/events.mjs +2 -0
  70. package/dist/flow/interpreter.d.mts +21 -0
  71. package/dist/flow/interpreter.d.mts.map +1 -0
  72. package/dist/flow/interpreter.mjs +605 -0
  73. package/dist/flow/projection.d.mts +17 -0
  74. package/dist/flow/projection.d.mts.map +1 -0
  75. package/dist/flow/projection.mjs +83 -0
  76. package/dist/flow/projection.test.d.mts +2 -0
  77. package/dist/flow/projection.test.d.mts.map +1 -0
  78. package/dist/flow/projection.test.mjs +162 -0
  79. package/dist/flow/reducer.d.mts +5 -0
  80. package/dist/flow/reducer.d.mts.map +1 -0
  81. package/dist/flow/reducer.mjs +306 -0
  82. package/dist/flow/reducer.test.d.mts +2 -0
  83. package/dist/flow/reducer.test.d.mts.map +1 -0
  84. package/dist/flow/reducer.test.mjs +479 -0
  85. package/dist/flow/run.d.mts +3 -0
  86. package/dist/flow/run.d.mts.map +1 -0
  87. package/dist/flow/run.mjs +89 -0
  88. package/dist/flow/states.d.mts +54 -0
  89. package/dist/flow/states.d.mts.map +1 -0
  90. package/dist/flow/states.mjs +39 -0
  91. package/dist/index.d.mts +11 -0
  92. package/dist/index.d.mts.map +1 -1
  93. package/dist/index.mjs +135 -12
  94. package/dist/lib/atomic-write.d.mts +4 -0
  95. package/dist/lib/atomic-write.d.mts.map +1 -0
  96. package/dist/lib/atomic-write.mjs +75 -0
  97. package/dist/lib/stream-job.d.mts +19 -0
  98. package/dist/lib/stream-job.d.mts.map +1 -0
  99. package/dist/lib/stream-job.mjs +55 -0
  100. package/dist/lib/trpc-url.mjs +2 -2
  101. package/dist/lib/trpc.mjs +2 -2
  102. package/dist/logger.d.mts.map +1 -1
  103. package/dist/logger.mjs +6 -3
  104. package/dist/providers/TrpcProvider.js +3 -3
  105. package/dist/store.d.mts +113 -1
  106. package/dist/store.d.mts.map +1 -1
  107. package/dist/store.mjs +81 -2
  108. package/dist/ui/App.d.ts +1 -1
  109. package/dist/ui/App.d.ts.map +1 -1
  110. package/dist/ui/App.js +32 -4
  111. package/dist/ui/components/Analyze.d.ts +10 -0
  112. package/dist/ui/components/Analyze.d.ts.map +1 -0
  113. package/dist/ui/components/Analyze.js +54 -0
  114. package/dist/ui/components/Billing.d.ts +10 -0
  115. package/dist/ui/components/Billing.d.ts.map +1 -0
  116. package/dist/ui/components/Billing.js +40 -0
  117. package/dist/ui/components/DB.d.ts.map +1 -1
  118. package/dist/ui/components/DB.js +2 -2
  119. package/dist/ui/components/DatabasePicker.d.ts +13 -0
  120. package/dist/ui/components/DatabasePicker.d.ts.map +1 -0
  121. package/dist/ui/components/DatabasePicker.js +79 -0
  122. package/dist/ui/components/Enrich.d.ts +10 -0
  123. package/dist/ui/components/Enrich.d.ts.map +1 -0
  124. package/dist/ui/components/Enrich.js +41 -0
  125. package/dist/ui/components/Gate.js +2 -2
  126. package/dist/ui/components/Introspect.d.ts.map +1 -1
  127. package/dist/ui/components/Introspect.js +2 -2
  128. package/dist/ui/components/IntrospectionUpload.d.ts +10 -0
  129. package/dist/ui/components/IntrospectionUpload.d.ts.map +1 -0
  130. package/dist/ui/components/IntrospectionUpload.js +30 -0
  131. package/dist/ui/components/Login.d.ts +19 -0
  132. package/dist/ui/components/Login.d.ts.map +1 -0
  133. package/dist/ui/components/Login.js +38 -0
  134. package/dist/ui/components/OutputJson.d.ts +10 -0
  135. package/dist/ui/components/OutputJson.d.ts.map +1 -0
  136. package/dist/ui/components/OutputJson.js +18 -0
  137. package/dist/ui/components/SSH.d.ts.map +1 -1
  138. package/dist/ui/components/SSH.js +2 -2
  139. package/dist/ui/components/SamplesUpload.d.ts +10 -0
  140. package/dist/ui/components/SamplesUpload.d.ts.map +1 -0
  141. package/dist/ui/components/SamplesUpload.js +24 -0
  142. package/dist/ui/components/Sampling.d.ts +10 -0
  143. package/dist/ui/components/Sampling.d.ts.map +1 -0
  144. package/dist/ui/components/Sampling.js +58 -0
  145. package/dist/ui/components/Session.d.ts.map +1 -1
  146. package/dist/ui/components/Session.js +4 -4
  147. package/dist/ui/components/Spinner.d.ts.map +1 -1
  148. package/dist/ui/components/Spinner.js +17 -5
  149. package/dist/ui/components/TextInput.d.ts +11 -0
  150. package/dist/ui/components/TextInput.d.ts.map +1 -0
  151. package/dist/ui/components/TextInput.js +286 -0
  152. package/dist/ui/components/UserExplanation.d.ts +10 -0
  153. package/dist/ui/components/UserExplanation.d.ts.map +1 -0
  154. package/dist/ui/components/UserExplanation.js +34 -0
  155. package/dist/validatePaths.d.mts +2 -1
  156. package/dist/validatePaths.d.mts.map +1 -1
  157. package/dist/validatePaths.mjs +6 -2
  158. package/package.json +7 -7
  159. package/dist/app/index.d.mts +0 -3
  160. package/dist/app/index.d.mts.map +0 -1
  161. package/dist/app/index.mjs +0 -82
  162. package/dist/schemas/index.d.mts +0 -107
  163. package/dist/schemas/index.d.mts.map +0 -1
  164. package/dist/schemas/index.mjs +0 -116
@@ -0,0 +1,605 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { TRPCClientError } from '@trpc/client';
3
+ import { computeSchemaHash } from '@dbctx/common/schema-hash';
4
+ import { runInAction } from 'mobx';
5
+ import { connectSSH } from '../app/ssh.mjs';
6
+ import { connectDB } from '../app/db.mjs';
7
+ import { assembleDatabase } from '../app/assemble.mjs';
8
+ import { loadIntrospectionFromFile, populateIntrospectionCounts, } from '../app/load-introspection.mjs';
9
+ import { createSession, waitForAuthorization, connectAccount, checkGate, checkBilling, } from '../app/session.mjs';
10
+ import { buildSessionURL } from '../app/open-url.mjs';
11
+ import { readConfig, flushConfig } from '../app/config.mjs';
12
+ import { runSampling, prepareOutputDir, persistTableSamplesToDir, loadSensitiveMask, } from '../app/sample.mjs';
13
+ import { fetchPublicPlannerStatistics } from '../db/index.mjs';
14
+ import { createAuthenticatedTRPCClient } from '../lib/trpc.mjs';
15
+ import { streamPostIntrospection, dispatchAndStreamPostSampling, } from '../app/tail.mjs';
16
+ import { atomicWriteFile, recoverAtomicWrite } from '../lib/atomic-write.mjs';
17
+ import { DBCTX_DEV } from '../lib/env.mjs';
18
+ import { logger } from '../logger.mjs';
19
+ import { when } from 'mobx';
20
+ export const initialContext = () => ({
21
+ cleanupSSH: null,
22
+ db: null,
23
+ introspection: null,
24
+ authed: null,
25
+ postIntrospectionPoll: null,
26
+ explanation: null,
27
+ });
28
+ const errMsg = (e) => e instanceof Error ? e.message : String(e);
29
+ // Pulls the structured `dbctx` payload tRPC's errorFormatter promotes onto
30
+ // shape.data. Returns null for non-tRPC errors or non-gate errors so callers
31
+ // can fall back to the prose `message`.
32
+ const extractGateError = (e) => {
33
+ if (!(e instanceof TRPCClientError)) {
34
+ return null;
35
+ }
36
+ const data = e.data;
37
+ return data?.dbctx ?? null;
38
+ };
39
+ // Dispatches an ingest-failed event and, if the error carries structured
40
+ // gate data, parks it on the store so the UI can render a tailored layout
41
+ // instead of the prose `message`. The gate field sits outside the flow
42
+ // projection on purpose — projection only owns `state`/`error`.
43
+ const dispatchIngestFailed = (err, dispatch, store) => {
44
+ const gate = extractGateError(err);
45
+ if (gate !== null) {
46
+ runInAction(() => {
47
+ store.steps.ingestion.introspection.gate = gate;
48
+ });
49
+ }
50
+ dispatch({ kind: 'ingest-failed', error: errMsg(err) });
51
+ };
52
+ // Single phase transition handler. Called once per (prev → curr) phase
53
+ // change with prev !== curr. Each branch fires the side effects for the
54
+ // new phase and dispatches event(s) back when async work resolves.
55
+ export const driveSide = async (prev, curr, store, ctx, dispatch) => {
56
+ if (prev !== null && prev.phase === curr.phase) {
57
+ // Side-channel sub-status updates don't trigger effects.
58
+ return;
59
+ }
60
+ if (curr.phase === 'connecting-ssh') {
61
+ try {
62
+ ctx.cleanupSSH = (await connectSSH(store)) ?? null;
63
+ // connectSSH may set enabled=false when no ssh flag was passed.
64
+ if (!store.steps.sshConnection.enabled) {
65
+ dispatch({ kind: 'ssh-not-needed' });
66
+ return;
67
+ }
68
+ await when(() => {
69
+ const s = store.steps.sshConnection.state;
70
+ return s === 'connected' || s === 'error';
71
+ });
72
+ const finalState = store.steps.sshConnection.state;
73
+ if (finalState === 'error') {
74
+ dispatch({
75
+ kind: 'ssh-failed',
76
+ error: store.steps.sshConnection.error ?? 'ssh failed',
77
+ });
78
+ return;
79
+ }
80
+ dispatch({ kind: 'ssh-connected' });
81
+ }
82
+ catch (err) {
83
+ dispatch({ kind: 'ssh-failed', error: errMsg(err) });
84
+ }
85
+ return;
86
+ }
87
+ if (curr.phase === 'connecting-db') {
88
+ try {
89
+ ctx.db = (await connectDB(store)) ?? null;
90
+ await when(() => {
91
+ const s = store.steps.databaseConnection.state;
92
+ return s === 'connected' || s === 'error';
93
+ });
94
+ const dbState = store.steps.databaseConnection.state;
95
+ if (dbState === 'error' || ctx.db === null) {
96
+ dispatch({
97
+ kind: 'db-failed',
98
+ error: store.steps.databaseConnection.error ?? 'db failed',
99
+ });
100
+ return;
101
+ }
102
+ dispatch({ kind: 'db-connected' });
103
+ }
104
+ catch (err) {
105
+ dispatch({ kind: 'db-failed', error: errMsg(err) });
106
+ }
107
+ return;
108
+ }
109
+ if (curr.phase === 'introspecting') {
110
+ if (ctx.db === null) {
111
+ dispatch({
112
+ kind: 'introspection-failed',
113
+ error: 'no db connection',
114
+ });
115
+ return;
116
+ }
117
+ try {
118
+ const useJsonPath = store.outputOptions.useIntrospectionJsonPath;
119
+ if (useJsonPath !== null) {
120
+ runInAction(() => {
121
+ store.steps.introspection.state = 'fetching';
122
+ });
123
+ const loaded = await loadIntrospectionFromFile(useJsonPath, ctx.db.pool);
124
+ if (!loaded.ok) {
125
+ runInAction(() => {
126
+ store.steps.introspection.state = 'error';
127
+ store.steps.introspection.error = loaded.error.message;
128
+ });
129
+ dispatch({
130
+ kind: 'introspection-failed',
131
+ error: loaded.error.message,
132
+ });
133
+ return;
134
+ }
135
+ populateIntrospectionCounts(store, loaded.result);
136
+ runInAction(() => {
137
+ store.steps.introspection.state = 'done';
138
+ });
139
+ ctx.introspection = loaded.result;
140
+ }
141
+ else {
142
+ ctx.introspection = await assembleDatabase(ctx.db.pool, store);
143
+ }
144
+ if (DBCTX_DEV) {
145
+ const { databaseIntrospectionSchema } = await import('@dbctx/core/schemas/introspection');
146
+ databaseIntrospectionSchema.parse(ctx.introspection);
147
+ }
148
+ dispatch({ kind: 'introspection-loaded' });
149
+ }
150
+ catch (err) {
151
+ dispatch({ kind: 'introspection-failed', error: errMsg(err) });
152
+ }
153
+ return;
154
+ }
155
+ if (curr.phase === 'output-json') {
156
+ const outputPath = curr.outputJSONPath;
157
+ if (outputPath === null || ctx.introspection === null) {
158
+ dispatch({ kind: 'output-json-not-requested' });
159
+ return;
160
+ }
161
+ try {
162
+ await recoverAtomicWrite(outputPath);
163
+ if (existsSync(outputPath) &&
164
+ !store.outputOptions.allowIntrospectionJsonOverwrite) {
165
+ runInAction(() => {
166
+ store.steps.outputJson.state = 'prompting-overwrite';
167
+ store.steps.outputJson.path = outputPath;
168
+ });
169
+ await when(() => store.steps.outputJson.confirmed !== null);
170
+ if (!store.steps.outputJson.confirmed) {
171
+ dispatch({ kind: 'output-json-skipped' });
172
+ return;
173
+ }
174
+ }
175
+ runInAction(() => {
176
+ store.steps.outputJson.state = 'writing';
177
+ store.steps.outputJson.path = outputPath;
178
+ });
179
+ await atomicWriteFile(outputPath, JSON.stringify(ctx.introspection, null, 2));
180
+ runInAction(() => {
181
+ store.steps.outputJson.state = 'done';
182
+ });
183
+ dispatch({ kind: 'output-json-written' });
184
+ }
185
+ catch (err) {
186
+ runInAction(() => {
187
+ store.steps.outputJson.state = 'error';
188
+ store.steps.outputJson.error = errMsg(err);
189
+ });
190
+ dispatch({ kind: 'output-json-failed', error: errMsg(err) });
191
+ }
192
+ return;
193
+ }
194
+ if (curr.phase === 'creating-session') {
195
+ if (ctx.db === null || ctx.introspection === null) {
196
+ dispatch({
197
+ kind: 'session-failed',
198
+ error: 'no db or introspection in context',
199
+ });
200
+ return;
201
+ }
202
+ try {
203
+ const config = await readConfig();
204
+ const sessionId = await createSession(ctx.db.pool, ctx.introspection, store, config.token ?? null, config.device_id);
205
+ // Re-auth fast-path: if existing config token is still valid,
206
+ // skip the browser-auth handshake entirely.
207
+ if (config.token) {
208
+ try {
209
+ await connectAccount(config.token, store);
210
+ await checkBilling(config.token, buildSessionURL(sessionId), store);
211
+ const canContinue = await checkGate(config.token, store);
212
+ if (!canContinue) {
213
+ dispatch({ kind: 'auth-not-needed' });
214
+ return;
215
+ }
216
+ // Single dispatch carrying both sessionId and token.
217
+ // Avoids transitioning through awaiting-authorization,
218
+ // which would race-fire waitForAuthorization and stomp
219
+ // the already-'connected' account state back to 'waiting'.
220
+ dispatch({
221
+ kind: 'fast-path-completed',
222
+ sessionId,
223
+ token: config.token,
224
+ });
225
+ return;
226
+ }
227
+ catch (err) {
228
+ if (err instanceof TRPCClientError &&
229
+ (err.data?.code === 'UNAUTHORIZED' ||
230
+ err.data?.code === 'NOT_FOUND')) {
231
+ await flushConfig();
232
+ }
233
+ else {
234
+ throw err;
235
+ }
236
+ }
237
+ }
238
+ dispatch({ kind: 'session-created', sessionId });
239
+ }
240
+ catch (err) {
241
+ dispatch({ kind: 'session-failed', error: errMsg(err) });
242
+ }
243
+ return;
244
+ }
245
+ if (curr.phase === 'awaiting-authorization') {
246
+ if (curr.sessionId === null) {
247
+ dispatch({ kind: 'auth-failed', error: 'no sessionId in state' });
248
+ return;
249
+ }
250
+ try {
251
+ await waitForAuthorization(curr.sessionId, store);
252
+ const freshToken = (await readConfig()).token;
253
+ if (!freshToken) {
254
+ dispatch({ kind: 'auth-failed', error: 'no token after auth' });
255
+ return;
256
+ }
257
+ await checkBilling(freshToken, buildSessionURL(curr.sessionId), store);
258
+ const canContinue = await checkGate(freshToken, store);
259
+ if (!canContinue) {
260
+ dispatch({ kind: 'auth-failed', error: 'gate blocked' });
261
+ return;
262
+ }
263
+ dispatch({ kind: 'auth-confirmed', token: freshToken });
264
+ }
265
+ catch (err) {
266
+ dispatch({ kind: 'auth-failed', error: errMsg(err) });
267
+ }
268
+ return;
269
+ }
270
+ if (curr.phase === 'awaiting-explanation') {
271
+ if (curr.explanation !== null) {
272
+ ctx.explanation = curr.explanation;
273
+ runInAction(() => {
274
+ store.steps.userExplanation.state = 'done';
275
+ store.steps.userExplanation.value = curr.explanation;
276
+ });
277
+ dispatch({
278
+ kind: 'explanation-given',
279
+ value: curr.explanation,
280
+ });
281
+ return;
282
+ }
283
+ runInAction(() => {
284
+ store.steps.userExplanation.state = 'prompting';
285
+ });
286
+ await when(() => store.steps.userExplanation.state === 'done');
287
+ const v = store.steps.userExplanation.value ?? '';
288
+ ctx.explanation = v;
289
+ dispatch({ kind: 'explanation-given', value: v });
290
+ return;
291
+ }
292
+ if (curr.phase === 'preflight-checking') {
293
+ if (ctx.db === null ||
294
+ ctx.introspection === null ||
295
+ curr.authToken === null ||
296
+ curr.sessionId === null) {
297
+ dispatch({
298
+ kind: 'ingest-failed',
299
+ error: 'context not ready for preflight',
300
+ });
301
+ return;
302
+ }
303
+ try {
304
+ ctx.authed = createAuthenticatedTRPCClient(() => Promise.resolve(curr.authToken));
305
+ const explanation = ctx.explanation ?? curr.explanation;
306
+ if (explanation !== null) {
307
+ ctx.introspection.userExplanation = explanation;
308
+ }
309
+ const plannerStats = await fetchPublicPlannerStatistics(ctx.db.pool);
310
+ const introspectionHash = computeSchemaHash(ctx.introspection);
311
+ const checkHit = await ctx.authed.revisions.checkIntrospection.mutate({
312
+ sessionId: curr.sessionId,
313
+ introspectionHash,
314
+ systemIdentifier: ctx.introspection.identifier.system_identifier,
315
+ databaseOID: String(ctx.introspection.identifier.database_oid),
316
+ plannerStatistics: { relations: plannerStats },
317
+ });
318
+ if (checkHit !== null) {
319
+ runInAction(() => {
320
+ store.landingURL = checkHit.landingURL;
321
+ });
322
+ kickPostIntrospectionPoll(ctx, checkHit.postIntrospectionJobId, store);
323
+ dispatch({
324
+ kind: 'check-introspection-hit',
325
+ revisionId: checkHit.revisionId,
326
+ samplesExist: checkHit.samplesExist,
327
+ tablesNeedingSamples: checkHit.tablesNeedingSamples,
328
+ postIntrospectionJobId: checkHit.postIntrospectionJobId,
329
+ });
330
+ return;
331
+ }
332
+ dispatch({ kind: 'check-introspection-miss' });
333
+ }
334
+ catch (err) {
335
+ dispatchIngestFailed(err, dispatch, store);
336
+ }
337
+ return;
338
+ }
339
+ if (curr.phase === 'ingesting-introspection') {
340
+ if (ctx.authed === null ||
341
+ ctx.introspection === null ||
342
+ curr.sessionId === null ||
343
+ ctx.db === null) {
344
+ dispatch({
345
+ kind: 'ingest-failed',
346
+ error: 'context not ready for ingest',
347
+ });
348
+ return;
349
+ }
350
+ try {
351
+ runInAction(() => {
352
+ store.steps.ingestion.introspection.state = 'uploading';
353
+ });
354
+ const plannerStats = await fetchPublicPlannerStatistics(ctx.db.pool);
355
+ const ingest = await ctx.authed.revisions.ingestIntrospection.mutate({
356
+ sessionId: curr.sessionId,
357
+ introspection: ctx.introspection,
358
+ plannerStatistics: { relations: plannerStats },
359
+ });
360
+ runInAction(() => {
361
+ store.landingURL = ingest.landingURL;
362
+ });
363
+ kickPostIntrospectionPoll(ctx, ingest.postIntrospectionJobId, store);
364
+ dispatch({
365
+ kind: 'introspection-ingested',
366
+ revisionId: ingest.revisionId,
367
+ samplesExist: ingest.samplesExist,
368
+ tablesNeedingSamples: ingest.tablesNeedingSamples,
369
+ postIntrospectionJobId: ingest.postIntrospectionJobId,
370
+ });
371
+ }
372
+ catch (err) {
373
+ dispatchIngestFailed(err, dispatch, store);
374
+ }
375
+ return;
376
+ }
377
+ if (curr.phase === 'sampling-mask-resolving') {
378
+ if (ctx.authed === null ||
379
+ curr.revisionId === null ||
380
+ ctx.introspection === null) {
381
+ dispatch({
382
+ kind: 'mask-fetch-failed',
383
+ error: 'context not ready for mask resolution',
384
+ });
385
+ return;
386
+ }
387
+ try {
388
+ const fileMaskPath = curr.fileMaskPath;
389
+ if (fileMaskPath !== null) {
390
+ const mask = await loadSensitiveMask(fileMaskPath);
391
+ dispatch({ kind: 'mask-loaded', mask });
392
+ return;
393
+ }
394
+ // Server-managed mask: wait for post-introspection to finish.
395
+ if (ctx.postIntrospectionPoll !== null) {
396
+ await ctx.postIntrospectionPoll;
397
+ ctx.postIntrospectionPoll = null;
398
+ }
399
+ // After the await, sub-status reflects post-introspection state.
400
+ // The reducer's projection won't have re-fired driveSide on its own
401
+ // (sub-status only). Inspect store directly.
402
+ if (store.steps.ingestion.postIntrospection.state === 'error') {
403
+ dispatch({
404
+ kind: 'mask-fetch-failed',
405
+ error: 'post-introspection enrichment failed — sensitive mask unavailable; refusing to sample',
406
+ });
407
+ return;
408
+ }
409
+ const res = await ctx.authed.revisions.getSensitiveMask.query({
410
+ revisionId: curr.revisionId,
411
+ });
412
+ if (!res.ready) {
413
+ dispatch({
414
+ kind: 'mask-fetch-failed',
415
+ error: 'server reported sensitive mask not ready after post-introspection completion; refusing to sample',
416
+ });
417
+ return;
418
+ }
419
+ dispatch({ kind: 'mask-loaded', mask: res.mask });
420
+ }
421
+ catch (err) {
422
+ dispatch({ kind: 'mask-fetch-failed', error: errMsg(err) });
423
+ }
424
+ return;
425
+ }
426
+ if (curr.phase === 'sampling') {
427
+ if (ctx.db === null ||
428
+ ctx.introspection === null ||
429
+ curr.sampling.mask === null) {
430
+ dispatch({
431
+ kind: 'sampling-failed',
432
+ error: 'context not ready for sampling',
433
+ });
434
+ return;
435
+ }
436
+ try {
437
+ const mask = curr.sampling.mask;
438
+ const sampleFileIndex = {};
439
+ const outputDir = curr.outputSamplesDir;
440
+ if (outputDir !== null) {
441
+ const ready = await prepareOutputDir(outputDir, store.outputOptions.allowSampleOverwrite, store);
442
+ if (!ready) {
443
+ dispatch({
444
+ kind: 'sampling-failed',
445
+ error: 'output dir not ready',
446
+ });
447
+ return;
448
+ }
449
+ }
450
+ // Filter the per-table sampling loop to only the tables the
451
+ // server flagged as needing fresh samples. Null = pre-handshake
452
+ // sentinel; treat as "all tables" for safety.
453
+ const tableFilter = curr.tablesNeedingSamples === null
454
+ ? undefined
455
+ : new Set(curr.tablesNeedingSamples);
456
+ for await (const event of runSampling(ctx.db.pool, ctx.introspection, store, mask, tableFilter)) {
457
+ if (outputDir !== null) {
458
+ await persistTableSamplesToDir(outputDir, event, sampleFileIndex);
459
+ }
460
+ dispatch({ kind: 'sample-table-yielded', event });
461
+ }
462
+ dispatch({ kind: 'sampling-completed' });
463
+ }
464
+ catch (err) {
465
+ dispatch({ kind: 'sampling-failed', error: errMsg(err) });
466
+ }
467
+ return;
468
+ }
469
+ if (curr.phase === 'uploading-samples') {
470
+ if (ctx.authed === null || curr.revisionId === null) {
471
+ dispatch({
472
+ kind: 'samples-upload-failed',
473
+ error: 'context not ready for upload',
474
+ });
475
+ return;
476
+ }
477
+ try {
478
+ const samples = curr.sampling.collected;
479
+ if (samples.length === 0) {
480
+ runInAction(() => {
481
+ store.steps.ingestion.samples.state = 'done';
482
+ });
483
+ dispatch({ kind: 'samples-upload-not-needed' });
484
+ return;
485
+ }
486
+ const sampleInputs = samples.map((event) => ({
487
+ tableName: event.tableName,
488
+ columns: Object.fromEntries(Object.entries(event.samples.columns).map(([col, s]) => [
489
+ col,
490
+ [...s.values],
491
+ ])),
492
+ }));
493
+ const CHUNK_SIZE = 25;
494
+ runInAction(() => {
495
+ store.steps.ingestion.samples.state = 'uploading';
496
+ store.steps.ingestion.samples.totalTables = sampleInputs.length;
497
+ store.steps.ingestion.samples.uploadedTables = 0;
498
+ });
499
+ const chunks = Array.from({ length: Math.ceil(sampleInputs.length / CHUNK_SIZE) }, (_, i) => sampleInputs.slice(i * CHUNK_SIZE, (i + 1) * CHUNK_SIZE));
500
+ for (let i = 0; i < chunks.length; i++) {
501
+ const chunk = chunks[i];
502
+ await ctx.authed.revisions.ingestSamples.mutate({
503
+ revisionId: curr.revisionId,
504
+ samples: chunk,
505
+ chunkIndex: i,
506
+ chunkTotal: chunks.length,
507
+ });
508
+ runInAction(() => {
509
+ store.steps.ingestion.samples.uploadedTables +=
510
+ chunk.length;
511
+ });
512
+ dispatch({
513
+ kind: 'sample-chunk-uploaded',
514
+ chunkSize: chunk.length,
515
+ });
516
+ }
517
+ runInAction(() => {
518
+ store.steps.ingestion.samples.state = 'done';
519
+ });
520
+ logger.info(`ingested ${sampleInputs.length} sample tables in ${chunks.length} chunk(s)`);
521
+ dispatch({ kind: 'samples-upload-completed' });
522
+ }
523
+ catch (err) {
524
+ dispatch({ kind: 'samples-upload-failed', error: errMsg(err) });
525
+ }
526
+ return;
527
+ }
528
+ if (curr.phase === 'awaiting-post-sampling') {
529
+ if (ctx.authed === null || curr.revisionId === null) {
530
+ dispatch({
531
+ kind: 'post-sampling-failed',
532
+ error: 'context not ready',
533
+ });
534
+ return;
535
+ }
536
+ try {
537
+ // First ensure post-introspection finished (file-mask fast path may
538
+ // have skipped the explicit await earlier).
539
+ if (ctx.postIntrospectionPoll !== null) {
540
+ await ctx.postIntrospectionPoll;
541
+ ctx.postIntrospectionPoll = null;
542
+ }
543
+ if (store.steps.ingestion.postIntrospection.state === 'error') {
544
+ runInAction(() => {
545
+ store.steps.ingestion.postSampling.state = 'error';
546
+ store.steps.ingestion.postSampling.error =
547
+ 'skipped — post-introspection enrichment failed';
548
+ });
549
+ dispatch({
550
+ kind: 'post-sampling-failed',
551
+ error: 'post-introspection enrichment failed',
552
+ });
553
+ return;
554
+ }
555
+ await dispatchAndStreamPostSampling(ctx.authed, curr.revisionId, store);
556
+ if (store.steps.ingestion.postSampling.state === 'error') {
557
+ dispatch({
558
+ kind: 'post-sampling-failed',
559
+ error: store.steps.ingestion.postSampling.error ??
560
+ 'post-sampling failed',
561
+ });
562
+ return;
563
+ }
564
+ dispatch({ kind: 'post-sampling-completed' });
565
+ }
566
+ catch (err) {
567
+ dispatch({ kind: 'post-sampling-failed', error: errMsg(err) });
568
+ }
569
+ return;
570
+ }
571
+ if (curr.phase === 'done' || curr.phase === 'error') {
572
+ cleanup(ctx);
573
+ return;
574
+ }
575
+ };
576
+ const kickPostIntrospectionPoll = (ctx, jobId, store) => {
577
+ runInAction(() => {
578
+ if (jobId === null) {
579
+ store.steps.ingestion.postIntrospection.state = 'done';
580
+ store.steps.ingestion.postIntrospection.reused = true;
581
+ }
582
+ else {
583
+ store.steps.ingestion.postIntrospection.jobId = jobId;
584
+ if (store.steps.ingestion.postIntrospection.state === 'idle') {
585
+ store.steps.ingestion.postIntrospection.state = 'queued';
586
+ }
587
+ }
588
+ });
589
+ if (jobId === null || ctx.authed === null) {
590
+ ctx.postIntrospectionPoll = Promise.resolve();
591
+ return;
592
+ }
593
+ ctx.postIntrospectionPoll = streamPostIntrospection(ctx.authed, jobId, store).then(() => { }, () => { });
594
+ };
595
+ export const cleanup = (ctx) => {
596
+ if (ctx.db !== null) {
597
+ ctx.db.cleanup();
598
+ ctx.db = null;
599
+ }
600
+ if (ctx.cleanupSSH !== null) {
601
+ ctx.cleanupSSH();
602
+ ctx.cleanupSSH = null;
603
+ }
604
+ };
605
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW50ZXJwcmV0ZXIubWpzIiwic291cmNlUm9vdCI6Ii4vc3JjLyIsInNvdXJjZXMiOlsiZmxvdy9pbnRlcnByZXRlci5tdHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFDLFVBQVUsRUFBQyxNQUFNLFNBQVMsQ0FBQztBQUduQyxPQUFPLEVBQUMsZUFBZSxFQUFDLE1BQU0sY0FBYyxDQUFDO0FBQzdDLE9BQU8sRUFBQyxpQkFBaUIsRUFBQyxNQUFNLDJCQUEyQixDQUFDO0FBQzVELE9BQU8sRUFBQyxXQUFXLEVBQUMsTUFBTSxNQUFNLENBQUM7QUFDakMsT0FBTyxFQUFDLFVBQVUsRUFBQyxNQUFNLGdCQUFnQixDQUFDO0FBQzFDLE9BQU8sRUFBQyxTQUFTLEVBQXFCLE1BQU0sZUFBZSxDQUFDO0FBQzVELE9BQU8sRUFBQyxnQkFBZ0IsRUFBQyxNQUFNLHFCQUFxQixDQUFDO0FBQ3JELE9BQU8sRUFDSCx5QkFBeUIsRUFDekIsMkJBQTJCLEdBQzlCLE1BQU0sK0JBQStCLENBQUM7QUFDdkMsT0FBTyxFQUNILGFBQWEsRUFDYixvQkFBb0IsRUFDcEIsY0FBYyxFQUNkLFNBQVMsRUFDVCxZQUFZLEdBQ2YsTUFBTSxvQkFBb0IsQ0FBQztBQUM1QixPQUFPLEVBQUMsZUFBZSxFQUFDLE1BQU0scUJBQXFCLENBQUM7QUFDcEQsT0FBTyxFQUFDLFVBQVUsRUFBRSxXQUFXLEVBQUMsTUFBTSxtQkFBbUIsQ0FBQztBQUMxRCxPQUFPLEVBQ0gsV0FBVyxFQUNYLGdCQUFnQixFQUNoQix3QkFBd0IsRUFDeEIsaUJBQWlCLEdBRXBCLE1BQU0sbUJBQW1CLENBQUM7QUFDM0IsT0FBTyxFQUFDLDRCQUE0QixFQUFDLE1BQU0saUJBQWlCLENBQUM7QUFDN0QsT0FBTyxFQUFDLDZCQUE2QixFQUFDLE1BQU0saUJBQWlCLENBQUM7QUFDOUQsT0FBTyxFQUNILHVCQUF1QixFQUN2Qiw2QkFBNkIsR0FDaEMsTUFBTSxpQkFBaUIsQ0FBQztBQUN6QixPQUFPLEVB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QUMsaUJBQWlCLENBQUMsS0FBSyxLQUFLLE1BQU0sRUFBRSxDQUFDO2dCQUMzRCxLQUFLLENBQUMsS0FBSyxDQUFDLFNBQVMsQ0FBQyxpQkFBaUIsQ0FBQyxLQUFLLEdBQUcsUUFBUSxDQUFDO1lBQzdELENBQUM7UUFDTCxDQUFDO0lBQ0wsQ0FBQyxDQUFDLENBQUM7SUFDSCxJQUFJLEtBQUssS0FBSyxJQUFJLElBQUksR0FBRyxDQUFDLE1BQU0sS0FBSyxJQUFJLEVBQUUsQ0FBQztRQUN4QyxHQUFHLENBQUMscUJBQXFCLEdBQUcsT0FBTyxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQzlDLE9BQU87SUFDWCxDQUFDO0lBQ0QsR0FBRyxDQUFDLHFCQUFxQixHQUFHLHVCQUF1QixDQUMvQyxHQUFHLENBQUMsTUFBTSxFQUNWLEtBQUssRUFDTCxLQUFLLENBQ1IsQ0FBQyxJQUFJLENBQ0YsR0FBRyxFQUFFLEdBQUUsQ0FBQyxFQUNSLEdBQUcsRUFBRSxHQUFFLENBQUMsQ0FDWCxDQUFDO0FBQ04sQ0FBQyxDQUFDO0FBRUYsTUFBTSxDQUFDLE1BQU0sT0FBTyxHQUFHLENBQUMsR0FBd0IsRUFBUSxFQUFFO0lBQ3RELElBQUksR0FBRyxDQUFDLEVBQUUsS0FBSyxJQUFJLEVBQUUsQ0FBQztRQUNsQixHQUFHLENBQUMsRUFBRSxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ2pCLEdBQUcsQ0FBQyxFQUFFLEdBQUcsSUFBSSxDQUFDO0lBQ2xCLENBQUM7SUFDRCxJQUFJLEdBQUcsQ0FBQyxVQUFVLEtBQUssSUFBSSxFQUFFLENBQUM7UUFDMUIsR0FBRyxDQUFDLFVBQVUsRUFBRSxDQUFDO1FBQ2pCLEdBQUcsQ0FBQyxVQUFVLEdBQUcsSUFBSSxDQUFDO0lBQzFCLENBQUM7QUFDTCxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge2V4aXN0c1N5bmN9IGZyb20gJ25vZGU6ZnMnO1xuaW1wb3J0IHR5cGUge1RSUENDbGllbnR9IGZyb20gJ0B0cnBjL2NsaWVudCc7XG5pbXBvcnQgdHlwZSB7VEFwcFJvdXRlciwgVEdhdGVFcnJvckRhdGF9IGZyb20gJ0BkYmN0eC9jb3JlJztcbmltcG9ydCB7VFJQQ0NsaWVudEVycm9yfSBmcm9tICdAdHJwYy9jbGllbnQnO1xuaW1wb3J0IHtjb21wdXRlU2NoZW1hSGFzaH0gZnJvbSAnQGRiY3R4L2NvbW1vbi9zY2hlbWEtaGFzaCc7XG5pbXBvcnQge3J1bkluQWN0aW9ufSBmcm9tICdtb2J4JztcbmltcG9ydCB7Y29ubmVjdFNTSH0gZnJvbSAnLi4vYXBwL3NzaC5tanMnO1xuaW1wb3J0IHtjb25uZWN0REIsIHR5cGUgVERCQ29ubmVjdGlvbn0gZnJvbSAnLi4vYXBwL2RiLm1qcyc7XG5pbXBvcnQge2Fzc2VtYmxlRGF0YWJhc2V9IGZyb20gJy4uL2FwcC9hc3NlbWJsZS5tanMnO1xuaW1wb3J0IHtcbiAgICBsb2FkSW50cm9zcGVjdGlvbkZyb21GaWxlLFxuICAgIHBvcHVsYXRlSW50cm9zcGVjdGlvbkNvdW50cyxcbn0gZnJvbSAnLi4vYXBwL2xvYWQtaW50cm9zcGVjdGlvbi5tanMnO1xuaW1wb3J0IHtcbiAgICBjcmVhdGVTZXNzaW9uLFxuICAgIHdhaXRGb3JBdXRob3JpemF0aW9uLFxuICAgIGNvbm5lY3RBY2NvdW50LFxuICAgIGNoZWNrR2F0ZSxcbiAgICBjaGVja0JpbGxpbmcsXG59IGZyb20gJy4uL2FwcC9zZXNzaW9uLm1qcyc7XG5pbXBvcnQge2J1aWxkU2Vzc2lvblVSTH0gZnJvbSAnLi4vYXBwL29wZW4tdXJsLm1qcyc7XG5pbXBvcnQge3JlYWRDb25maWcsIGZsdXNoQ29uZmlnfSBmcm9tICcuLi9hcHAvY29uZmlnLm1qcyc7XG5pbXBvcnQge1xuICAgIHJ1blNhbXBsaW5nLFxuICAgIHByZXBhcmVPdXRwdXREaXIsXG4gICAgcGVyc2lzdFRhYmxlU2FtcGxlc1RvRGlyLFxuICAgIGxvYWRTZW5zaXRpdmVNYXNrLFxuICAgIHR5cGUgVFNlbnNpdGl2ZU1hc2ssXG59IGZyb20gJy4uL2FwcC9zYW1wbGUubWpzJztcbmltcG9ydCB7ZmV0Y2hQdWJsaWNQbGFubmVyU3RhdGlzdGljc30gZnJvbSAnLi4vZGIvaW5kZXgubWpzJztcbmltcG9ydCB7Y3JlYXRlQXV0aGVudGljYXRlZFRSUENDbGllbnR9IGZyb20gJy4uL2xpYi90cnBjLm1qcyc7XG5pbXBvcnQge1xuICAgIHN0cmVhbVBvc3RJbnRyb3NwZWN0aW9uLFxuICAgIGRpc3BhdGNoQW5kU3RyZWFtUG9zdFNhbXBsaW5nLFxufSBmcm9tICcuLi9hcHAvdGFpbC5tanMnO1xuaW1wb3J0IHthdG9taWNXcml0ZUZpbGUsIHJlY292ZXJBdG9taWNXcml0ZX0gZnJvbSAnLi4vbGliL2F0b21pYy13cml0ZS5tanMnO1xuaW1wb3J0IHtEQkNUWF9ERVZ9IGZyb20gJy4uL2xpYi9lbnYubWpzJztcbmltcG9ydCB7bG9nZ2VyfSBmcm9tICcuLi9sb2dnZXIubWpzJztcbmltcG9ydCB0eXBlIHtUU3RvcmV9IGZyb20gJy4uL3N0b3JlLm1qcyc7XG5pbXBvcnQgdHlwZSB7VEZsb3dFdmVudH0gZnJvbSAnLi9ldmVudHMubWpzJztcbmltcG9ydCB0eXBlIHtURmxvd1N0YXRlfSBmcm9tICcuL3N0YXRlcy5tanMnO1xuaW1wb3J0IHt3aGVufSBmcm9tICdtb2J4JztcblxuLy8gRWZmZWN0IGhhbmRsZXMgdGhlIGludGVycHJldGVyIGFjY3VtdWxhdGVzIGFzIHRoZSBmbG93IGFkdmFuY2VzLiBOb3Rcbi8vIHBhcnQgb2YgVEZsb3dTdGF0ZSBiZWNhdXNlIHRoZXkgYXJlbid0IHB1cmUgZGF0YSDigJQgUHJvbWlzZSBoYW5kbGVzLCBEQlxuLy8gcG9vbHMsIGNsZWFudXAgY2FsbGJhY2tzLiBUaGUgZGlzcGF0Y2hlciBjbG9zZXMgb3ZlciB0aGlzIGNvbnRleHQuXG5leHBvcnQgdHlwZSBUSW50ZXJwcmV0ZXJDb250ZXh0ID0ge1xuICAgIGNsZWFudXBTU0g6ICgoKSA9PiB2b2lkKSB8IG51bGw7XG4gICAgZGI6IFREQkNvbm5lY3Rpb24gfCBudWxsO1xuICAgIGludHJvc3BlY3Rpb246IEF3YWl0ZWQ8UmV0dXJuVHlwZTx0eXBlb2YgYXNzZW1ibGVEYXRhYmFzZT4+IHwgbnVsbDtcbiAgICBhdXRoZWQ6IFRSUENDbGllbnQ8VEFwcFJvdXRlcj4gfCBudWxsO1xuICAgIHBvc3RJbnRyb3NwZWN0aW9uUG9sbDogUHJvbWlzZTx2b2lkPiB8IG51bGw7XG4gICAgZXhwbGFuYXRpb246IHN0cmluZyB8IG51bGw7XG59O1xuXG5leHBvcnQgY29uc3QgaW5pdGlhbENvbnRleHQgPSAoKTogVEludGVycHJldGVyQ29udGV4dCA9PiAoe1xuICAgIGNsZWFudXBTU0g6IG51bGwsXG4gICAgZGI6IG51bGwsXG4gICAgaW50cm9zcGVjdGlvbjogbnVsbCxcbiAgICBhdXRoZWQ6IG51bGwsXG4gICAgcG9zdEludHJvc3BlY3Rpb25Qb2xsOiBudWxsLFxuICAgIGV4cGxhbmF0aW9uOiBudWxsLFxufSk7XG5cbnR5cGUgVERpc3BhdGNoID0gKGV2ZW50OiBURmxvd0V2ZW50KSA9PiB2b2lkO1xuXG5jb25zdCBlcnJNc2cgPSAoZTogdW5rbm93bik6IHN0cmluZyA9PlxuICAgIGUgaW5zdGFuY2VvZiBFcnJvciA/IGUubWVzc2FnZSA6IFN0cmluZyhlKTtcblxuLy8gUHVsbHMgdGhlIHN0cnVjdHVyZWQgYGRiY3R4YCBwYXlsb2FkIHRSUEMncyBlcnJvckZvcm1hdHRlciBwcm9tb3RlcyBvbnRvXG4vLyBzaGFwZS5kYXRhLiBSZXR1cm5zIG51bGwgZm9yIG5vbi10UlBDIGVycm9ycyBvciBub24tZ2F0ZSBlcnJvcnMgc28gY2FsbGVyc1xuLy8gY2FuIGZhbGwgYmFjayB0byB0aGUgcHJvc2UgYG1lc3NhZ2VgLlxuY29uc3QgZXh0cmFjdEdhdGVFcnJvciA9IChlOiB1bmtub3duKTogVEdhdGVFcnJvckRhdGEgfCBudWxsID0+IHtcbiAgICBpZiAoIShlIGluc3RhbmNlb2YgVFJQQ0NsaWVudEVycm9yKSkge1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG4gICAgY29uc3QgZGF0YSA9IGUuZGF0YSBhcyB7ZGJjdHg/OiBUR2F0ZUVycm9yRGF0YSB8IG51bGx9IHwgdW5kZWZpbmVkO1xuICAgIHJldHVybiBkYXRhPy5kYmN0eCA/PyBudWxsO1xufTtcblxuLy8gRGlzcGF0Y2hlcyBhbiBpbmdlc3QtZmFpbGVkIGV2ZW50IGFuZCwgaWYgdGhlIGVycm9yIGNhcnJpZXMgc3RydWN0dXJlZFxuLy8gZ2F0ZSBkYXRhLCBwYXJrcyBpdCBvbiB0aGUgc3RvcmUgc28gdGhlIFVJIGNhbiByZW5kZXIgYSB0YWlsb3JlZCBsYXlvdXRcbi8vIGluc3RlYWQgb2YgdGhlIHByb3NlIGBtZXNzYWdlYC4gVGhlIGdhdGUgZmllbGQgc2l0cyBvdXRzaWRlIHRoZSBmbG93XG4vLyBwcm9qZWN0aW9uIG9uIHB1cnBvc2Ug4oCUIHByb2plY3Rpb24gb25seSBvd25zIGBzdGF0ZWAvYGVycm9yYC5cbmNvbnN0IGRpc3BhdGNoSW5nZXN0RmFpbGVkID0gKFxuICAgIGVycjogdW5rbm93bixcbiAgICBkaXNwYXRjaDogVERpc3BhdGNoLFxuICAgIHN0b3JlOiBUU3RvcmUsXG4pOiB2b2lkID0+IHtcbiAgICBjb25zdCBnYXRlID0gZXh0cmFjdEdhdGVFcnJvcihlcnIpO1xuICAgIGlmIChnYXRlICE9PSBudWxsKSB7XG4gICAgICAgIHJ1bkluQWN0aW9uKCgpID0+IHtcbiAgICAgICAgICAgIHN0b3JlLnN0ZXBzLmluZ2VzdGlvbi5pbnRyb3NwZWN0aW9uLmdhdGUgPSBnYXRlO1xuICAgICAgICB9KTtcbiAgICB9XG4gICAgZGlzcGF0Y2goe2tpbmQ6ICdpbmdlc3QtZmFpbGVkJywgZXJyb3I6IGVyck1zZyhlcnIpfSk7XG59O1xuXG4vLyBTaW5nbGUgcGhhc2UgdHJhbnNpdGlvbiBoYW5kbGVyLiBDYWxsZWQgb25jZSBwZXIgKHByZXYg4oaSIGN1cnIpIHBoYXNlXG4vLyBjaGFuZ2Ugd2l0aCBwcmV2ICE9PSBjdXJyLiBFYWNoIGJyYW5jaCBmaXJlcyB0aGUgc2lkZSBlZmZlY3RzIGZvciB0aGVcbi8vIG5ldyBwaGFzZSBhbmQgZGlzcGF0Y2hlcyBldmVudChzKSBiYWNrIHdoZW4gYXN5bmMgd29yayByZXNvbHZlcy5cbmV4cG9ydCBjb25zdCBkcml2ZVNpZGUgPSBhc3luYyAoXG4gICAgcHJldjogVEZsb3dTdGF0ZSB8IG51bGwsXG4gICAgY3VycjogVEZsb3dTdGF0ZSxcbiAgICBzdG9yZTogVFN0b3JlLFxuICAgIGN0eDogVEludGVycHJldGVyQ29udGV4dCxcbiAgICBkaXNwYXRjaDogVERpc3BhdGNoLFxuKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gICAgaWYgKHByZXYgIT09IG51bGwgJiYgcHJldi5waGFzZSA9PT0gY3Vyci5waGFzZSkge1xuICAgICAgICAvLyBTaWRlLWNoYW5uZWwgc3ViLXN0YXR1cyB1cGRhdGVzIGRvbid0IHRyaWdnZXIgZWZmZWN0cy5cbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmIChjdXJyLnBoYXNlID09PSAnY29ubmVjdGluZy1zc2gnKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjdHguY2xlYW51cFNTSCA9IChhd2FpdCBjb25uZWN0U1NIKHN0b3JlKSkgPz8gbnVsbDtcbiAgICAgICAgICAgIC8vIGNvbm5lY3RTU0ggbWF5IHNldCBlbmFibGVkPWZhbHNlIHdoZW4gbm8gc3NoIGZsYWcgd2FzIHBhc3NlZC5cbiAgICAgICAgICAgIGlmICghc3RvcmUuc3RlcHMuc3NoQ29ubmVjdGlvbi5lbmFibGVkKSB7XG4gICAgICAgICAgICAgICAgZGlzcGF0Y2goe2tpbmQ6ICdzc2gtbm90LW5lZWRlZCd9KTtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBhd2FpdCB3aGVuKCgpID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCBzOiBzdHJpbmcgPSBzdG9yZS5zdGVwcy5zc2hDb25uZWN0aW9uLnN0YXRlO1xuICAgICAgICAgICAgICAgIHJldHVybiBzID09PSAnY29ubmVjdGVkJyB8fCBzID09PSAnZXJyb3InO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBjb25zdCBmaW5hbFN0YXRlOiBzdHJpbmcgPSBzdG9yZS5zdGVwcy5zc2hDb25uZWN0aW9uLnN0YXRlO1xuICAgICAgICAgICAgaWYgKGZpbmFsU3RhdGUgPT09ICdlcnJvcicpIHtcbiAgICAgICAgICAgICAgICBkaXNwYXRjaCh7XG4gICAgICAgICAgICAgICAgICAgIGtpbmQ6ICdzc2gtZmFpbGVkJyxcbiAgICAgICAgICAgICAgICAgICAgZXJyb3I6IHN0b3JlLnN0ZXBzLnNzaENvbm5lY3Rpb24uZXJyb3IgPz8gJ3NzaCBmYWlsZWQnLFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGRpc3BhdGNoKHtraW5kOiAnc3NoLWNvbm5lY3RlZCd9KTtcbiAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICBkaXNwYXRjaCh7a2luZDogJ3NzaC1mYWlsZWQnLCBlcnJvcjogZXJyTXNnKGVycil9KTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKGN1cnIucGhhc2UgPT09ICdjb25uZWN0aW5nLWRiJykge1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgY3R4LmRiID0gKGF3YWl0IGNvbm5lY3REQihzdG9yZSkpID8/IG51bGw7XG4gICAgICAgICAgICBhd2FpdCB3aGVuKCgpID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCBzOiBzdHJpbmcgPSBzdG9yZS5zdGVwcy5kYXRhYmFzZUNvbm5lY3Rpb24uc3RhdGU7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHMgPT09ICdjb25uZWN0ZWQnIHx8IHMgPT09ICdlcnJvcic7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIGNvbnN0IGRiU3RhdGU6IHN0cmluZyA9IHN0b3JlLnN0ZXBzLmRhdGFiYXNlQ29ubmVjdGlvbi5zdGF0ZTtcbiAgICAgICAgICAgIGlmIChkYlN0YXRlID09PSAnZXJyb3InIHx8IGN0eC5kYiA9PT0gbnVsbCkge1xuICAgICAgICAgICAgICAgIGRpc3BhdGNoKHtcbiAgICAgICAgICAgICAgICAgICAga2luZDogJ2RiLWZhaWxlZCcsXG4gICAgICAgICAgICAgICAgICAgIGVycm9yOiBzdG9yZS5zdGVwcy5kYXRhYmFzZUNvbm5lY3Rpb24uZXJyb3IgPz8gJ2RiIGZhaWxlZCcsXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZGlzcGF0Y2goe2tpbmQ6ICdkYi1jb25uZWN0ZWQnfSk7XG4gICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgZGlzcGF0Y2goe2tpbmQ6ICdkYi1mYWlsZWQnLCBlcnJvcjogZXJyTXNnKGVycil9KTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKGN1cnIucGhhc2UgPT09ICdpbnRyb3NwZWN0aW5nJykge1xuICAgICAgICBpZiAoY3R4LmRiID09PSBudWxsKSB7XG4gICAgICAgICAgICBkaXNwYXRjaCh7XG4gICAgICAgICAgICAgICAga2luZDogJ2ludHJvc3BlY3Rpb24tZmFpbGVkJyxcbiAgICAgICAgICAgICAgICBlcnJvcjogJ25vIGRiIGNvbm5lY3Rpb24nLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGNvbnN0IHVzZUpzb25QYXRoID0gc3RvcmUub3V0cHV0T3B0aW9ucy51c2VJbnRyb3NwZWN0aW9uSnNvblBhdGg7XG4gICAgICAgICAgICBpZiAodXNlSnNvblBhdGggIT09IG51bGwpIHtcbiAgICAgICAgICAgICAgICBydW5JbkFjdGlvbigoKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIHN0b3JlLnN0ZXBzLmludHJvc3BlY3Rpb24uc3RhdGUgPSAnZmV0Y2hpbmcnO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIGNvbnN0IGxvYWRlZCA9IGF3YWl0IGxvYWRJbnRyb3NwZWN0aW9uRnJvbUZpbGUoXG4gICAgICAgICAgICAgICAgICAgIHVzZUpzb25QYXRoLFxuICAgICAgICAgICAgICAgICAgICBjdHguZGIucG9vbCxcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIGlmICghbG9hZGVkLm9rKSB7XG4gICAgICAgICAgICAgICAgICAgIHJ1bkluQWN0aW9uKCgpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHN0b3JlLnN0ZXBzLmludHJvc3BlY3Rpb24uc3RhdGUgPSAnZXJyb3InO1xuICAgICAgICAgICAgICAgICAgICAgICAgc3RvcmUuc3RlcHMuaW50cm9zcGVjdGlvbi5lcnJvciA9IGxvYWRlZC5lcnJvci5tZXNzYWdlO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgZGlzcGF0Y2goe1xuICAgICAgICAgICAgICAgICAgICAgICAga2luZDogJ2ludHJvc3BlY3Rpb24tZmFpbGVkJyxcbiAgICAgICAgICAgICAgICAgICAgICAgIGVycm9yOiBsb2FkZWQuZXJyb3IubWVzc2FnZSxcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcG9wdWxhdGVJbnRyb3NwZWN0aW9uQ291bnRzKHN0b3JlLCBsb2FkZWQucmVzdWx0KTtcbiAgICAgICAgICAgICAgICBydW5JbkFjdGlvbigoKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIHN0b3JlLnN0ZXBzLmludHJvc3BlY3Rpb24uc3RhdGUgPSAnZG9uZSc7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgY3R4LmludHJvc3BlY3Rpb24gPSBsb2FkZWQucmVzdWx0O1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBjdHguaW50cm9zcGVjdGlvbiA9IGF3YWl0IGFzc2VtYmxlRGF0YWJhc2UoY3R4LmRiLnBvb2wsIHN0b3JlKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKERCQ1RYX0RFVikge1xuICAgICAgICAgICAgICAgIGNvbnN0IHtkYXRhYmFzZUludHJvc3BlY3Rpb25TY2hlbWF9ID1cbiAgICAgICAgICAgICAgICAgICAgYXdhaXQgaW1wb3J0KCdAZGJjdHgvY29yZS9zY2hlbWFzL2ludHJvc3BlY3Rpb24nKTtcbiAgICAgICAgICAgICAgICBkYXRhYmFzZUludHJvc3BlY3Rpb25TY2hlbWEucGFyc2UoY3R4LmludHJvc3BlY3Rpb24pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZGlzcGF0Y2goe2tpbmQ6ICdpbnRyb3NwZWN0aW9uLWxvYWRlZCd9KTtcbiAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICBkaXNwYXRjaCh7a2luZDogJ2ludHJvc3BlY3Rpb24tZmFpbGVkJywgZXJyb3I6IGVyck1zZyhlcnIpfSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmIChjdXJyLnBoYXNlID09PSAnb3V0cHV0LWpzb24nKSB7XG4gICAgICAgIGNvbnN0IG91dHB1dFBhdGggPSBjdXJyLm91dHB1dEpTT05QYXRoO1xuICAgICAgICBpZiAob3V0cHV0UGF0aCA9PT0gbnVsbCB8fCBjdHguaW50cm9zcGVjdGlvbiA9PT0gbnVsbCkge1xuICAgICAgICAgICAgZGlzcGF0Y2goe2tpbmQ6ICdvdXRwdXQtanNvbi1ub3QtcmVxdWVzdGVkJ30pO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBhd2FpdCByZWNvdmVyQXRvbWljV3JpdGUob3V0cHV0UGF0aCk7XG4gICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgZXhpc3RzU3luYyhvdXRwdXRQYXRoKSAmJlxuICAgICAgICAgICAgICAgICFzdG9yZS5vdXRwdXRPcHRpb25zLmFsbG93SW50cm9zcGVjdGlvbkpzb25PdmVyd3JpdGVcbiAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAgIHJ1bkluQWN0aW9uKCgpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgc3RvcmUuc3RlcHMub3V0cHV0SnNvbi5zdGF0ZSA9ICdwcm9tcHRpbmctb3ZlcndyaXRlJztcbiAgICAgICAgICAgICAgICAgICAgc3RvcmUuc3RlcHMub3V0cHV0SnNvbi5wYXRoID0gb3V0cHV0UGF0aDtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICBhd2FpdCB3aGVuKCgpID0+IHN0b3JlLnN0ZXBzLm91dHB1dEpzb24uY29uZmlybWVkICE9PSBudWxsKTtcbiAgICAgICAgICAgICAgICBpZiAoIXN0b3JlLnN0ZXBzLm91dHB1dEpzb24uY29uZmlybWVkKSB7XG4gICAgICAgICAgICAgICAgICAgIGRpc3BhdGNoKHtraW5kOiAnb3V0cHV0LWpzb24tc2tpcHBlZCd9KTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJ1bkluQWN0aW9uKCgpID0+IHtcbiAgICAgICAgICAgICAgICBzdG9yZS5zdGVwcy5vdXRwdXRKc29uLnN0YXRlID0gJ3dyaXRpbmcnO1xuICAgICAgICAgICAgICAgIHN0b3JlLnN0ZXBzLm91dHB1dEpzb24ucGF0aCA9IG91dHB1dFBhdGg7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIGF3YWl0IGF0b21pY1dyaXRlRmlsZShcbiAgICAgICAgICAgICAgICBvdXRwdXRQYXRoLFxuICAgICAgICAgICAgICAgIEpTT04uc3RyaW5naWZ5KGN0eC5pbnRyb3NwZWN0aW9uLCBudWxsLCAyKSxcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBydW5JbkFjdGlvbigoKSA9PiB7XG4gICAgICAgICAgICAgICAgc3RvcmUuc3RlcHMub3V0cHV0SnNvbi5zdGF0ZSA9ICdkb25lJztcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgZGlzcGF0Y2goe2tpbmQ6ICdvdXRwdXQtanNvbi13cml0dGVuJ30pO1xuICAgICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICAgIHJ1bkluQWN0aW9uKCgpID0+IHtcbiAgICAgICAgICAgICAgICBzdG9yZS5zdGVwcy5vdXRwdXRKc29uLnN0YXRlID0gJ2Vycm9yJztcbiAgICAgICAgICAgICAgICBzdG9yZS5zdGVwcy5vdXRwdXRKc29uLmVycm9yID0gZXJyTXNnKGVycik7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIGRpc3BhdGNoKHtraW5kOiAnb3V0cHV0LWpzb24tZmFpbGVkJywgZXJyb3I6IGVyck1zZyhlcnIpfSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmIChjdXJyLnBoYXNlID09PSAnY3JlYXRpbmctc2Vzc2lvbicpIHtcbiAgICAgICAgaWYgKGN0eC5kYiA9PT0gbnVsbCB8fCBjdHguaW50cm9zcGVjdGlvbiA9PT0gbnVsbCkge1xuICAgICAgICAgICAgZGlzcGF0Y2goe1xuICAgICAgICAgICAgICAgIGtpbmQ6ICdzZXNzaW9uLWZhaWxlZCcsXG4gICAgICAgICAgICAgICAgZXJyb3I6ICdubyBkYiBvciBpbnRyb3NwZWN0aW9uIGluIGNvbnRleHQnLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGNvbnN0IGNvbmZpZyA9IGF3YWl0IHJlYWRDb25maWcoKTtcbiAgICAgICAgICAgIGNvbnN0IHNlc3Npb25JZCA9IGF3YWl0IGNyZWF0ZVNlc3Npb24oXG4gICAgICAgICAgICAgICAgY3R4LmRiLnBvb2wsXG4gICAgICAgICAgICAgICAgY3R4LmludHJvc3BlY3Rpb24sXG4gICAgICAgICAgICAgICAgc3RvcmUsXG4gICAgICAgICAgICAgICAgY29uZmlnLnRva2VuID8/IG51bGwsXG4gICAgICAgICAgICAgICAgY29uZmlnLmRldmljZV9pZCxcbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIC8vIFJlLWF1dGggZmFzdC1wYXRoOiBpZiBleGlzdGluZyBjb25maWcgdG9rZW4gaXMgc3RpbGwgdmFsaWQsXG4gICAgICAgICAgICAvLyBza2lwIHRoZSBicm93c2VyLWF1dGggaGFuZHNoYWtlIGVudGlyZWx5LlxuICAgICAgICAgICAgaWYgKGNvbmZpZy50b2tlbikge1xuICAgICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IGNvbm5lY3RBY2NvdW50KGNvbmZpZy50b2tlbiwgc3RvcmUpO1xuICAgICAgICAgICAgICAgICAgICBhd2FpdCBjaGVja0JpbGxpbmcoXG4gICAgICAgICAgICAgICAgICAgICAgICBjb25maWcudG9rZW4sXG4gICAgICAgICAgICAgICAgICAgICAgICBidWlsZFNlc3Npb25VUkwoc2Vzc2lvbklkKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHN0b3JlLFxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBjYW5Db250aW51ZSA9IGF3YWl0IGNoZWNrR2F0ZShjb25maWcudG9rZW4sIHN0b3JlKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCFjYW5Db250aW51ZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgZGlzcGF0Y2goe2tpbmQ6ICdhdXRoLW5vdC1uZWVkZWQnfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgLy8gU2luZ2xlIGRpc3BhdGNoIGNhcnJ5aW5nIGJvdGggc2Vzc2lvbklkIGFuZCB0b2tlbi5cbiAgICAgICAgICAgICAgICAgICAgLy8gQXZvaWRzIHRyYW5zaXRpb25pbmcgdGhyb3VnaCBhd2FpdGluZy1hdXRob3JpemF0aW9uLFxuICAgICAgICAgICAgICAgICAgICAvLyB3aGljaCB3b3VsZCByYWNlLWZpcmUgd2FpdEZvckF1dGhvcml6YXRpb24gYW5kIHN0b21wXG4gICAgICAgICAgICAgICAgICAgIC8vIHRoZSBhbHJlYWR5LSdjb25uZWN0ZWQnIGFjY291bnQgc3RhdGUgYmFjayB0byAnd2FpdGluZycuXG4gICAgICAgICAgICAgICAgICAgIGRpc3BhdGNoKHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGtpbmQ6ICdmYXN0LXBhdGgtY29tcGxldGVkJyxcbiAgICAgICAgICAgICAgICAgICAgICAgIHNlc3Npb25JZCxcbiAgICAgICAgICAgICAgICAgICAgICAgIHRva2VuOiBjb25maWcudG9rZW4sXG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgICAgICAgICAgIGVyciBpbnN0YW5jZW9mIFRSUENDbGllbnRFcnJvciAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgKGVyci5kYXRhPy5jb2RlID09PSAnVU5BVVRIT1JJWkVEJyB8fFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVyci5kYXRhPy5jb2RlID09PSAnTk9UX0ZPVU5EJylcbiAgICAgICAgICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBhd2FpdCBmbHVzaENvbmZpZygpO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhyb3cgZXJyO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBkaXNwYXRjaCh7a2luZDogJ3Nlc3Npb24tY3JlYXRlZCcsIHNlc3Npb25JZH0pO1xuICAgICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICAgIGRpc3BhdGNoKHtraW5kOiAnc2Vzc2lvbi1mYWlsZWQnLCBlcnJvcjogZXJyTXNnKGVycil9KTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKGN1cnIucGhhc2UgPT09ICdhd2FpdGluZy1hdXRob3JpemF0aW9uJykge1xuICAgICAgICBpZiAoY3Vyci5zZXNzaW9uSWQgPT09IG51bGwpIHtcbiAgICAgICAgICAgIGRpc3BhdGNoKHtraW5kOiAnYXV0aC1mYWlsZWQnLCBlcnJvcjogJ25vIHNlc3Npb25JZCBpbiBzdGF0ZSd9KTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICB0cnkge1xuICAgICAgICAgICAgYXdhaXQgd2FpdEZvckF1dGhvcml6YXRpb24oY3Vyci5zZXNzaW9uSWQsIHN0b3JlKTtcbiAgICAgICAgICAgIGNvbnN0IGZyZXNoVG9rZW4gPSAoYXdhaXQgcmVhZENvbmZpZygpKS50b2tlbjtcbiAgICAgICAgICAgIGlmICghZnJlc2hUb2tlbikge1xuICAgICAgICAgICAgICAgIGRpc3BhdGNoKHtraW5kOiAnYXV0aC1mYWlsZWQnLCBlcnJvcjogJ25vIHRva2VuIGFmdGVyIGF1dGgnfSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgYXdhaXQgY2hlY2tCaWxsaW5nKFxuICAgICAgICAgICAgICAgIGZyZXNoVG9rZW4sXG4gICAgICAgICAgICAgICAgYnVpbGRTZXNzaW9uVVJMKGN1cnIuc2Vzc2lvbklkKSxcbiAgICAgICAgICAgICAgICBzdG9yZSxcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBjb25zdCBjYW5Db250aW51ZSA9IGF3YWl0IGNoZWNrR2F0ZShmcmVzaFRva2VuLCBzdG9yZSk7XG4gICAgICAgICAgICBpZiAoIWNhbkNvbnRpbnVlKSB7XG4gICAgICAgICAgICAgICAgZGlzcGF0Y2goe2tpbmQ6ICdhdXRoLWZhaWxlZCcsIGVycm9yOiAnZ2F0ZSBibG9ja2VkJ30pO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGRpc3BhdGNoKHtraW5kOiAnYXV0aC1jb25maXJtZWQnLCB0b2tlbjogZnJlc2hUb2tlbn0pO1xuICAgICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICAgIGRpc3BhdGNoKHtraW5kOiAnYXV0aC1mYWlsZWQnLCBlcnJvcjogZXJyTXNnKGVycil9KTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKGN1cnIucGhhc2UgPT09ICdhd2FpdGluZy1leHBsYW5hdGlvbicpIHtcbiAgICAgICAgaWYgKGN1cnIuZXhwbGFuYXRpb24gIT09IG51bGwpIHtcbiAgICAgICAgICAgIGN0eC5leHBsYW5hdGlvbiA9IGN1cnIuZXhwbGFuYXRpb247XG4gICAgICAgICAgICBydW5JbkFjdGlvbigoKSA9PiB7XG4gICAgICAgICAgICAgICAgc3RvcmUuc3RlcHMudXNlckV4cGxhbmF0aW9uLnN0YXRlID0gJ2RvbmUnO1xuICAgICAgICAgICAgICAgIHN0b3JlLnN0ZXBzLnVzZXJFeHBsYW5hdGlvbi52YWx1ZSA9IGN1cnIuZXhwbGFuYXRpb247XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIGRpc3BhdGNoKHtcbiAgICAgICAgICAgICAgICBraW5kOiAnZXhwbGFuYXRpb24tZ2l2ZW4nLFxuICAgICAgICAgICAgICAgIHZhbHVlOiBjdXJyLmV4cGxhbmF0aW9uLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgcnVuSW5BY3Rpb24oKCkgPT4ge1xuICAgICAgICAgICAgc3RvcmUuc3RlcHMudXNlckV4cGxhbmF0aW9uLnN0YXRlID0gJ3Byb21wdGluZyc7XG4gICAgICAgIH0pO1xuICAgICAgICBhd2FpdCB3aGVuKCgpID0+IHN0b3JlLnN0ZXBzLnVzZXJFeHBsYW5hdGlvbi5zdGF0ZSA9PT0gJ2RvbmUnKTtcbiAgICAgICAgY29uc3QgdiA9IHN0b3JlLnN0ZXBzLnVzZXJFeHBsYW5hdGlvbi52YWx1ZSA/PyAnJztcbiAgICAgICAgY3R4LmV4cGxhbmF0aW9uID0gdjtcbiAgICAgICAgZGlzcGF0Y2goe2tpbmQ6ICdleHBsYW5hdGlvbi1naXZlbicsIHZhbHVlOiB2fSk7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAoY3Vyci5waGFzZSA9PT0gJ3ByZWZsaWdodC1jaGVja2luZycpIHtcbiAgICAgICAgaWYgKFxuICAgICAgICAgICAgY3R4LmRiID09PSBudWxsIHx8XG4gICAgICAgICAgICBjdHguaW50cm9zcGVjdGlvbiA9PT0gbnVsbCB8fFxuICAgICAgICAgICAgY3Vyci5hdXRoVG9rZW4gPT09IG51bGwgfHxcbiAgICAgICAgICAgIGN1cnIuc2Vzc2lvbklkID09PSBudWxsXG4gICAgICAgICkge1xuICAgICAgICAgICAgZGlzcGF0Y2goe1xuICAgICAgICAgICAgICAgIGtpbmQ6ICdpbmdlc3QtZmFpbGVkJyxcbiAgICAgICAgICAgICAgICBlcnJvcjogJ2NvbnRleHQgbm90IHJlYWR5IGZvciBwcmVmbGlnaHQnLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGN0eC5hdXRoZWQgPSBjcmVhdGVBdXRoZW50aWNhdGVkVFJQQ0NsaWVudCgoKSA9PlxuICAgICAgICAgICAgICAgIFByb21pc2UucmVzb2x2ZShjdXJyLmF1dGhUb2tlbiEpLFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGNvbnN0IGV4cGxhbmF0aW9uID0gY3R4LmV4cGxhbmF0aW9uID8/IGN1cnIuZXhwbGFuYXRpb247XG4gICAgICAgICAgICBpZiAoZXhwbGFuYXRpb24gIT09IG51bGwpIHtcbiAgICAgICAgICAgICAgICBjdHguaW50cm9zcGVjdGlvbi51c2VyRXhwbGFuYXRpb24gPSBleHBsYW5hdGlvbjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IHBsYW5uZXJTdGF0cyA9IGF3YWl0IGZldGNoUHVibGljUGxhbm5lclN0YXRpc3RpY3MoXG4gICAgICAgICAgICAgICAgY3R4LmRiLnBvb2wsXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgY29uc3QgaW50cm9zcGVjdGlvbkhhc2ggPSBjb21wdXRlU2NoZW1hSGFzaChjdHguaW50cm9zcGVjdGlvbik7XG4gICAgICAgICAgICBjb25zdCBjaGVja0hpdCA9XG4gICAgICAgICAgICAgICAgYXdhaXQgY3R4LmF1dGhlZC5yZXZpc2lvbnMuY2hlY2tJbnRyb3NwZWN0aW9uLm11dGF0ZSh7XG4gICAgICAgICAgICAgICAgICAgIHNlc3Npb25JZDogY3Vyci5zZXNzaW9uSWQsXG4gICAgICAgICAgICAgICAgICAgIGludHJvc3BlY3Rpb25IYXNoLFxuICAgICAgICAgICAgICAgICAgICBzeXN0ZW1JZGVudGlmaWVyOlxuICAgICAgICAgICAgICAgICAgICAgICAgY3R4LmludHJvc3BlY3Rpb24uaWRlbnRpZmllci5zeXN0ZW1faWRlbnRpZmllcixcbiAgICAgICAgICAgICAgICAgICAgZGF0YWJhc2VPSUQ6IFN0cmluZyhcbiAgICAgICAgICAgICAgICAgICAgICAgIGN0eC5pbnRyb3NwZWN0aW9uLmlkZW50aWZpZXIuZGF0YWJhc2Vfb2lkLFxuICAgICAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICAgICAgICBwbGFubmVyU3RhdGlzdGljczoge3JlbGF0aW9uczogcGxhbm5lclN0YXRzfSxcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIGlmIChjaGVja0hpdCAhPT0gbnVsbCkge1xuICAgICAgICAgICAgICAgIHJ1bkluQWN0aW9uKCgpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgc3RvcmUubGFuZGluZ1VSTCA9IGNoZWNrSGl0LmxhbmRpbmdVUkw7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAga2lja1Bvc3RJbnRyb3NwZWN0aW9uUG9sbChcbiAgICAgICAgICAgICAgICAgICAgY3R4LFxuICAgICAgICAgICAgICAgICAgICBjaGVja0hpdC5wb3N0SW50cm9zcGVjdGlvbkpvYklkLFxuICAgICAgICAgICAgICAgICAgICBzdG9yZSxcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIGRpc3BhdGNoKHtcbiAgICAgICAgICAgICAgICAgICAga2luZDogJ2NoZWNrLWludHJvc3BlY3Rpb24taGl0JyxcbiAgICAgICAgICAgICAgICAgICAgcmV2aXNpb25JZDogY2hlY2tIaXQucmV2aXNpb25JZCxcbiAgICAgICAgICAgICAgICAgICAgc2FtcGxlc0V4aXN0OiBjaGVja0hpdC5zYW1wbGVzRXhpc3QsXG4gICAgICAgICAgICAgICAgICAgIHRhYmxlc05lZWRpbmdTYW1wbGVzOiBjaGVja0hpdC50YWJsZXNOZWVkaW5nU2FtcGxlcyxcbiAgICAgICAgICAgICAgICAgICAgcG9zdEludHJvc3BlY3Rpb25Kb2JJZDogY2hlY2tIaXQucG9zdEludHJvc3BlY3Rpb25Kb2JJZCxcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBkaXNwYXRjaCh7a2luZDogJ2NoZWNrLWludHJvc3BlY3Rpb24tbWlzcyd9KTtcbiAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICBkaXNwYXRjaEluZ2VzdEZhaWxlZChlcnIsIGRpc3BhdGNoLCBzdG9yZSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmIChjdXJyLnBoYXNlID09PSAnaW5nZXN0aW5nLWludHJvc3BlY3Rpb24nKSB7XG4gICAgICAgIGlmIChcbiAgICAgICAgICAgIGN0eC5hdXRoZWQgPT09IG51bGwgfHxcbiAgICAgICAgICAgIGN0eC5pbnRyb3NwZWN0aW9uID09PSBudWxsIHx8XG4gICAgICAgICAgICBjdXJyLnNlc3Npb25JZCA9PT0gbnVsbCB8fFxuICAgICAgICAgICAgY3R4LmRiID09PSBudWxsXG4gICAgICAgICkge1xuICAgICAgICAgICAgZGlzcGF0Y2goe1xuICAgICAgICAgICAgICAgIGtpbmQ6ICdpbmdlc3QtZmFpbGVkJyxcbiAgICAgICAgICAgICAgICBlcnJvcjogJ2NvbnRleHQgbm90IHJlYWR5IGZvciBpbmdlc3QnLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIHJ1bkluQWN0aW9uKCgpID0+IHtcbiAgICAgICAgICAgICAgICBzdG9yZS5zdGVwcy5pbmdlc3Rpb24uaW50cm9zcGVjdGlvbi5zdGF0ZSA9ICd1cGxvYWRpbmcnO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBjb25zdCBwbGFubmVyU3RhdHMgPSBhd2FpdCBmZXRjaFB1YmxpY1BsYW5uZXJTdGF0aXN0aWNzKFxuICAgICAgICAgICAgICAgIGN0eC5kYi5wb29sLFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGNvbnN0IGluZ2VzdCA9XG4gICAgICAgICAgICAgICAgYXdhaXQgY3R4LmF1dGhlZC5yZXZpc2lvbnMuaW5nZXN0SW50cm9zcGVjdGlvbi5tdXRhdGUoe1xuICAgICAgICAgICAgICAgICAgICBzZXNzaW9uSWQ6IGN1cnIuc2Vzc2lvbklkLFxuICAgICAgICAgICAgICAgICAgICBpbnRyb3NwZWN0aW9uOiBjdHguaW50cm9zcGVjdGlvbixcbiAgICAgICAgICAgICAgICAgICAgcGxhbm5lclN0YXRpc3RpY3M6IHtyZWxhdGlvbnM6IHBsYW5uZXJTdGF0c30sXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBydW5JbkFjdGlvbigoKSA9PiB7XG4gICAgICAgICAgICAgICAgc3RvcmUubGFuZGluZ1VSTCA9IGluZ2VzdC5sYW5kaW5nVVJMO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBraWNrUG9zdEludHJvc3BlY3Rpb25Qb2xsKFxuICAgICAgICAgICAgICAgIGN0eCxcbiAgICAgICAgICAgICAgICBpbmdlc3QucG9zdEludHJvc3BlY3Rpb25Kb2JJZCxcbiAgICAgICAgICAgICAgICBzdG9yZSxcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBkaXNwYXRjaCh7XG4gICAgICAgICAgICAgICAga2luZDogJ2ludHJvc3BlY3Rpb24taW5nZXN0ZWQnLFxuICAgICAgICAgICAgICAgIHJldmlzaW9uSWQ6IGluZ2VzdC5yZXZpc2lvbklkLFxuICAgICAgICAgICAgICAgIHNhbXBsZXNFeGlzdDogaW5nZXN0LnNhbXBsZXNFeGlzdCxcbiAgICAgICAgICAgICAgICB0YWJsZXNOZWVkaW5nU2FtcGxlczogaW5nZXN0LnRhYmxlc05lZWRpbmdTYW1wbGVzLFxuICAgICAgICAgICAgICAgIHBvc3RJbnRyb3NwZWN0aW9uSm9iSWQ6IGluZ2VzdC5wb3N0SW50cm9zcGVjdGlvbkpvYklkLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgZGlzcGF0Y2hJbmdlc3RGYWlsZWQoZXJyLCBkaXNwYXRjaCwgc3RvcmUpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAoY3Vyci5waGFzZSA9PT0gJ3NhbXBsaW5nLW1hc2stcmVzb2x2aW5nJykge1xuICAgICAgICBpZiAoXG4gICAgICAgICAgICBjdHguYXV0aGVkID09PSBudWxsIHx8XG4gICAgICAgICAgICBjdXJyLnJldmlzaW9uSWQgPT09IG51bGwgfHxcbiAgICAgICAgICAgIGN0eC5pbnRyb3NwZWN0aW9uID09PSBudWxsXG4gICAgICAgICkge1xuICAgICAgICAgICAgZGlzcGF0Y2goe1xuICAgICAgICAgICAgICAgIGtpbmQ6ICdtYXNrLWZldGNoLWZhaWxlZCcsXG4gICAgICAgICAgICAgICAgZXJyb3I6ICdjb250ZXh0IG5vdCByZWFkeSBmb3IgbWFzayByZXNvbHV0aW9uJyxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjb25zdCBmaWxlTWFza1BhdGggPSBjdXJyLmZpbGVNYXNrUGF0aDtcbiAgICAgICAgICAgIGlmIChmaWxlTWFza1BhdGggIT09IG51bGwpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBtYXNrID0gYXdhaXQgbG9hZFNlbnNpdGl2ZU1hc2soZmlsZU1hc2tQYXRoKTtcbiAgICAgICAgICAgICAgICBkaXNwYXRjaCh7a2luZDogJ21hc2stbG9hZGVkJywgbWFza30pO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIFNlcnZlci1tYW5hZ2VkIG1hc2s6IHdhaXQgZm9yIHBvc3QtaW50cm9zcGVjdGlvbiB0byBmaW5pc2guXG4gICAgICAgICAgICBpZiAoY3R4LnBvc3RJbnRyb3NwZWN0aW9uUG9sbCAhPT0gbnVsbCkge1xuICAgICAgICAgICAgICAgIGF3YWl0IGN0eC5wb3N0SW50cm9zcGVjdGlvblBvbGw7XG4gICAgICAgICAgICAgICAgY3R4LnBvc3RJbnRyb3NwZWN0aW9uUG9sbCA9IG51bGw7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBBZnRlciB0aGUgYXdhaXQsIHN1Yi1zdGF0dXMgcmVmbGVjdHMgcG9zdC1pbnRyb3NwZWN0aW9uIHN0YXRlLlxuICAgICAgICAgICAgLy8gVGhlIHJlZHVjZXIncyBwcm9qZWN0aW9uIHdvbid0IGhhdmUgcmUtZmlyZWQgZHJpdmVTaWRlIG9uIGl0cyBvd25cbiAgICAgICAgICAgIC8vIChzdWItc3RhdHVzIG9ubHkpLiBJbnNwZWN0IHN0b3JlIGRpcmVjdGx5LlxuICAgICAgICAgICAgaWYgKHN0b3JlLnN0ZXBzLmluZ2VzdGlvbi5wb3N0SW50cm9zcGVjdGlvbi5zdGF0ZSA9PT0gJ2Vycm9yJykge1xuICAgICAgICAgICAgICAgIGRpc3BhdGNoKHtcbiAgICAgICAgICAgICAgICAgICAga2luZDogJ21hc2stZmV0Y2gtZmFpbGVkJyxcbiAgICAgICAgICAgICAgICAgICAgZXJyb3I6ICdwb3N0LWludHJvc3BlY3Rpb24gZW5yaWNobWVudCBmYWlsZWQg4oCUIHNlbnNpdGl2ZSBtYXNrIHVuYXZhaWxhYmxlOyByZWZ1c2luZyB0byBzYW1wbGUnLFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IHJlcyA9IGF3YWl0IGN0eC5hdXRoZWQucmV2aXNpb25zLmdldFNlbnNpdGl2ZU1hc2sucXVlcnkoe1xuICAgICAgICAgICAgICAgIHJldmlzaW9uSWQ6IGN1cnIucmV2aXNpb25JZCxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgaWYgKCFyZXMucmVhZHkpIHtcbiAgICAgICAgICAgICAgICBkaXNwYXRjaCh7XG4gICAgICAgICAgICAgICAgICAgIGtpbmQ6ICdtYXNrLWZldGNoLWZhaWxlZCcsXG4gICAgICAgICAgICAgICAgICAgIGVycm9yOiAnc2VydmVyIHJlcG9ydGVkIHNlbnNpdGl2ZSBtYXNrIG5vdCByZWFkeSBhZnRlciBwb3N0LWludHJvc3BlY3Rpb24gY29tcGxldGlvbjsgcmVmdXNpbmcgdG8gc2FtcGxlJyxcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBkaXNwYXRjaCh7a2luZDogJ21hc2stbG9hZGVkJywgbWFzazogcmVzLm1hc2t9KTtcbiAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICBkaXNwYXRjaCh7a2luZDogJ21hc2stZmV0Y2gtZmFpbGVkJywgZXJyb3I6IGVyck1zZyhlcnIpfSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmIChjdXJyLnBoYXNlID09PSAnc2FtcGxpbmcnKSB7XG4gICAgICAgIGlmIChcbiAgICAgICAgICAgIGN0eC5kYiA9PT0gbnVsbCB8fFxuICAgICAgICAgICAgY3R4LmludHJvc3BlY3Rpb24gPT09IG51bGwgfHxcbiAgICAgICAgICAgIGN1cnIuc2FtcGxpbmcubWFzayA9PT0gbnVsbFxuICAgICAgICApIHtcbiAgICAgICAgICAgIGRpc3BhdGNoKHtcbiAgICAgICAgICAgICAgICBraW5kOiAnc2FtcGxpbmctZmFpbGVkJyxcbiAgICAgICAgICAgICAgICBlcnJvcjogJ2NvbnRleHQgbm90IHJlYWR5IGZvciBzYW1wbGluZycsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICB0cnkge1xuICAgICAgICAgICAgY29uc3QgbWFzazogVFNlbnNpdGl2ZU1hc2sgPSBjdXJyLnNhbXBsaW5nLm1hc2s7XG4gICAgICAgICAgICBjb25zdCBzYW1wbGVGaWxlSW5kZXg6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7fTtcbiAgICAgICAgICAgIGNvbnN0IG91dHB1dERpciA9IGN1cnIub3V0cHV0U2FtcGxlc0RpcjtcbiAgICAgICAgICAgIGlmIChvdXRwdXREaXIgIT09IG51bGwpIHtcbiAgICAgICAgICAgICAgICBjb25zdCByZWFkeSA9IGF3YWl0IHByZXBhcmVPdXRwdXREaXIoXG4gICAgICAgICAgICAgICAgICAgIG91dHB1dERpcixcbiAgICAgICAgICAgICAgICAgICAgc3RvcmUub3V0cHV0T3B0aW9ucy5hbGxvd1NhbXBsZU92ZXJ3cml0ZSxcbiAgICAgICAgICAgICAgICAgICAgc3RvcmUsXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICBpZiAoIXJlYWR5KSB7XG4gICAgICAgICAgICAgICAgICAgIGRpc3BhdGNoKHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGtpbmQ6ICdzYW1wbGluZy1mYWlsZWQnLFxuICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3I6ICdvdXRwdXQgZGlyIG5vdCByZWFkeScsXG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gRmlsdGVyIHRoZSBwZXItdGFibGUgc2FtcGxpbmcgbG9vcCB0byBvbmx5IHRoZSB0YWJsZXMgdGhlXG4gICAgICAgICAgICAvLyBzZXJ2ZXIgZmxhZ2dlZCBhcyBuZWVkaW5nIGZyZXNoIHNhbXBsZXMuIE51bGwgPSBwcmUtaGFuZHNoYWtlXG4gICAgICAgICAgICAvLyBzZW50aW5lbDsgdHJlYXQgYXMgXCJhbGwgdGFibGVzXCIgZm9yIHNhZmV0eS5cbiAgICAgICAgICAgIGNvbnN0IHRhYmxlRmlsdGVyOiBSZWFkb25seVNldDxzdHJpbmc+IHwgdW5kZWZpbmVkID1cbiAgICAgICAgICAgICAgICBjdXJyLnRhYmxlc05lZWRpbmdTYW1wbGVzID09PSBudWxsXG4gICAgICAgICAgICAgICAgICAgID8gdW5kZWZpbmVkXG4gICAgICAgICAgICAgICAgICAgIDogbmV3IFNldChjdXJyLnRhYmxlc05lZWRpbmdTYW1wbGVzKTtcbiAgICAgICAgICAgIGZvciBhd2FpdCAoY29uc3QgZXZlbnQgb2YgcnVuU2FtcGxpbmcoXG4gICAgICAgICAgICAgICAgY3R4LmRiLnBvb2wsXG4gICAgICAgICAgICAgICAgY3R4LmludHJvc3BlY3Rpb24sXG4gICAgICAgICAgICAgICAgc3RvcmUsXG4gICAgICAgICAgICAgICAgbWFzayxcbiAgICAgICAgICAgICAgICB0YWJsZUZpbHRlcixcbiAgICAgICAgICAgICkpIHtcbiAgICAgICAgICAgICAgICBpZiAob3V0cHV0RGlyICE9PSBudWxsKSB7XG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IHBlcnNpc3RUYWJsZVNhbXBsZXNUb0RpcihcbiAgICAgICAgICAgICAgICAgICAgICAgIG91dHB1dERpcixcbiAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50LFxuICAgICAgICAgICAgICAgICAgICAgICAgc2FtcGxlRmlsZUluZGV4LFxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBkaXNwYXRjaCh7a2luZDogJ3NhbXBsZS10YWJsZS15aWVsZGVkJywgZXZlbnR9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGRpc3BhdGNoKHtraW5kOiAnc2FtcGxpbmctY29tcGxldGVkJ30pO1xuICAgICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICAgIGRpc3BhdGNoKHtraW5kOiAnc2FtcGxpbmctZmFpbGVkJywgZXJyb3I6IGVyck1zZyhlcnIpfSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmIChjdXJyLnBoYXNlID09PSAndXBsb2FkaW5nLXNhbXBsZXMnKSB7XG4gICAgICAgIGlmIChjdHguYXV0aGVkID09PSBudWxsIHx8IGN1cnIucmV2aXNpb25JZCA9PT0gbnVsbCkge1xuICAgICAgICAgICAgZGlzcGF0Y2goe1xuICAgICAgICAgICAgICAgIGtpbmQ6ICdzYW1wbGVzLXVwbG9hZC1mYWlsZWQnLFxuICAgICAgICAgICAgICAgIGVycm9yOiAnY29udGV4dCBub3QgcmVhZHkgZm9yIHVwbG9hZCcsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICB0cnkge1xuICAgICAgICAgICAgY29uc3Qgc2FtcGxlcyA9IGN1cnIuc2FtcGxpbmcuY29sbGVjdGVkO1xuICAgICAgICAgICAgaWYgKHNhbXBsZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICAgICAgcnVuSW5BY3Rpb24oKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICBzdG9yZS5zdGVwcy5pbmdlc3Rpb24uc2FtcGxlcy5zdGF0ZSA9ICdkb25lJztcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICBkaXNwYXRjaCh7a2luZDogJ3NhbXBsZXMtdXBsb2FkLW5vdC1uZWVkZWQnfSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY29uc3Qgc2FtcGxlSW5wdXRzID0gc2FtcGxlcy5tYXAoKGV2ZW50KSA9PiAoe1xuICAgICAgICAgICAgICAgIHRhYmxlTmFtZTogZXZlbnQudGFibGVOYW1lLFxuICAgICAgICAgICAgICAgIGNvbHVtbnM6IE9iamVjdC5mcm9tRW50cmllcyhcbiAgICAgICAgICAgICAgICAgICAgT2JqZWN0LmVudHJpZXMoZXZlbnQuc2FtcGxlcy5jb2x1bW5zKS5tYXAoKFtjb2wsIHNdKSA9PiBbXG4gICAgICAgICAgICAgICAgICAgICAgICBjb2wsXG4gICAgICAgICAgICAgICAgICAgICAgICBbLi4ucy52YWx1ZXNdLFxuICAgICAgICAgICAgICAgICAgICBdKSxcbiAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgfSkpO1xuICAgICAgICAgICAgY29uc3QgQ0hVTktfU0laRSA9IDI1O1xuICAgICAgICAgICAgcnVuSW5BY3Rpb24oKCkgPT4ge1xuICAgICAgICAgICAgICAgIHN0b3JlLnN0ZXBzLmluZ2VzdGlvbi5zYW1wbGVzLnN0YXRlID0gJ3VwbG9hZGluZyc7XG4gICAgICAgICAgICAgICAgc3RvcmUuc3RlcHMuaW5nZXN0aW9uLnNhbXBsZXMudG90YWxUYWJsZXMgPSBzYW1wbGVJbnB1dHMubGVuZ3RoO1xuICAgICAgICAgICAgICAgIHN0b3JlLnN0ZXBzLmluZ2VzdGlvbi5zYW1wbGVzLnVwbG9hZGVkVGFibGVzID0gMDtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgY29uc3QgY2h1bmtzID0gQXJyYXkuZnJvbShcbiAgICAgICAgICAgICAgICB7bGVuZ3RoOiBNYXRoLmNlaWwoc2FtcGxlSW5wdXRzLmxlbmd0aCAvIENIVU5LX1NJWkUpfSxcbiAgICAgICAgICAgICAgICAoXywgaSkgPT5cbiAgICAgICAgICAgICAgICAgICAgc2FtcGxlSW5wdXRzLnNsaWNlKGkgKiBDSFVOS19TSVpFLCAoaSArIDEpICogQ0hVTktfU0laRSksXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBjaHVua3MubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICBjb25zdCBjaHVuayA9IGNodW5rc1tpXTtcbiAgICAgICAgICAgICAgICBhd2FpdCBjdHguYXV0aGVkLnJldmlzaW9ucy5pbmdlc3RTYW1wbGVzLm11dGF0ZSh7XG4gICAgICAgICAgICAgICAgICAgIHJldmlzaW9uSWQ6IGN1cnIucmV2aXNpb25JZCxcbiAgICAgICAgICAgICAgICAgICAgc2FtcGxlczogY2h1bmssXG4gICAgICAgICAgICAgICAgICAgIGNodW5rSW5kZXg6IGksXG4gICAgICAgICAgICAgICAgICAgIGNodW5rVG90YWw6IGNodW5rcy5sZW5ndGgsXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgcnVuSW5BY3Rpb24oKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICBzdG9yZS5zdGVwcy5pbmdlc3Rpb24uc2FtcGxlcy51cGxvYWRlZFRhYmxlcyArPVxuICAgICAgICAgICAgICAgICAgICAgICAgY2h1bmsubGVuZ3RoO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIGRpc3BhdGNoKHtcbiAgICAgICAgICAgICAgICAgICAga2luZDogJ3NhbXBsZS1jaHVuay11cGxvYWRlZCcsXG4gICAgICAgICAgICAgICAgICAgIGNodW5rU2l6ZTogY2h1bmsubGVuZ3RoLFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcnVuSW5BY3Rpb24oKCkgPT4ge1xuICAgICAgICAgICAgICAgIHN0b3JlLnN0ZXBzLmluZ2VzdGlvbi5zYW1wbGVzLnN0YXRlID0gJ2RvbmUnO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBsb2dnZXIuaW5mbyhcbiAgICAgICAgICAgICAgICBgaW5nZXN0ZWQgJHtzYW1wbGVJbnB1dHMubGVuZ3RofSBzYW1wbGUgdGFibGVzIGluICR7Y2h1bmtzLmxlbmd0aH0gY2h1bmsocylgLFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGRpc3BhdGNoKHtraW5kOiAnc2FtcGxlcy11cGxvYWQtY29tcGxldGVkJ30pO1xuICAgICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICAgIGRpc3BhdGNoKHtraW5kOiAnc2FtcGxlcy11cGxvYWQtZmFpbGVkJywgZXJyb3I6IGVyck1zZyhlcnIpfSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmIChjdXJyLnBoYXNlID09PSAnYXdhaXRpbmctcG9zdC1zYW1wbGluZycpIHtcbiAgICAgICAgaWYgKGN0eC5hdXRoZWQgPT09IG51bGwgfHwgY3Vyci5yZXZpc2lvbklkID09PSBudWxsKSB7XG4gICAgICAgICAgICBkaXNwYXRjaCh7XG4gICAgICAgICAgICAgICAga2luZDogJ3Bvc3Qtc2FtcGxpbmctZmFpbGVkJyxcbiAgICAgICAgICAgICAgICBlcnJvcjogJ2NvbnRleHQgbm90IHJlYWR5JyxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICAvLyBGaXJzdCBlbnN1cmUgcG9zdC1pbnRyb3NwZWN0aW9uIGZpbmlzaGVkIChmaWxlLW1hc2sgZmFzdCBwYXRoIG1heVxuICAgICAgICAgICAgLy8gaGF2ZSBza2lwcGVkIHRoZSBleHBsaWNpdCBhd2FpdCBlYXJsaWVyKS5cbiAgICAgICAgICAgIGlmIChjdHgucG9zdEludHJvc3BlY3Rpb25Qb2xsICE9PSBudWxsKSB7XG4gICAgICAgICAgICAgICAgYXdhaXQgY3R4LnBvc3RJbnRyb3NwZWN0aW9uUG9sbDtcbiAgICAgICAgICAgICAgICBjdHgucG9zdEludHJvc3BlY3Rpb25Qb2xsID0gbnVsbDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChzdG9yZS5zdGVwcy5pbmdlc3Rpb24ucG9zdEludHJvc3BlY3Rpb24uc3RhdGUgPT09ICdlcnJvcicpIHtcbiAgICAgICAgICAgICAgICBydW5JbkFjdGlvbigoKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIHN0b3JlLnN0ZXBzLmluZ2VzdGlvbi5wb3N0U2FtcGxpbmcuc3RhdGUgPSAnZXJyb3InO1xuICAgICAgICAgICAgICAgICAgICBzdG9yZS5zdGVwcy5pbmdlc3Rpb24ucG9zdFNhbXBsaW5nLmVycm9yID1cbiAgICAgICAgICAgICAgICAgICAgICAgICdza2lwcGVkIOKAlCBwb3N0LWludHJvc3BlY3Rpb24gZW5yaWNobWVudCBmYWlsZWQnO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIGRpc3BhdGNoKHtcbiAgICAgICAgICAgICAgICAgICAga2luZDogJ3Bvc3Qtc2FtcGxpbmctZmFpbGVkJyxcbiAgICAgICAgICAgICAgICAgICAgZXJyb3I6ICdwb3N0LWludHJvc3BlY3Rpb24gZW5yaWNobWVudCBmYWlsZWQnLFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGF3YWl0IGRpc3BhdGNoQW5kU3RyZWFtUG9zdFNhbXBsaW5nKFxuICAgICAgICAgICAgICAgIGN0eC5hdXRoZWQsXG4gICAgICAgICAgICAgICAgY3Vyci5yZXZpc2lvbklkLFxuICAgICAgICAgICAgICAgIHN0b3JlLFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGlmIChzdG9yZS5zdGVwcy5pbmdlc3Rpb24ucG9zdFNhbXBsaW5nLnN0YXRlID09PSAnZXJyb3InKSB7XG4gICAgICAgICAgICAgICAgZGlzcGF0Y2goe1xuICAgICAgICAgICAgICAgICAgICBraW5kOiAncG9zdC1zYW1wbGluZy1mYWlsZWQnLFxuICAgICAgICAgICAgICAgICAgICBlcnJvcjpcbiAgICAgICAgICAgICAgICAgICAgICAgIHN0b3JlLnN0ZXBzLmluZ2VzdGlvbi5wb3N0U2FtcGxpbmcuZXJyb3IgPz9cbiAgICAgICAgICAgICAgICAgICAgICAgICdwb3N0LXNhbXBsaW5nIGZhaWxlZCcsXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZGlzcGF0Y2goe2tpbmQ6ICdwb3N0LXNhbXBsaW5nLWNvbXBsZXRlZCd9KTtcbiAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICBkaXNwYXRjaCh7a2luZDogJ3Bvc3Qtc2FtcGxpbmctZmFpbGVkJywgZXJyb3I6IGVyck1zZyhlcnIpfSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmIChjdXJyLnBoYXNlID09PSAnZG9uZScgfHwgY3Vyci5waGFzZSA9PT0gJ2Vycm9yJykge1xuICAgICAgICBjbGVhbnVwKGN0eCk7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG59O1xuXG5jb25zdCBraWNrUG9zdEludHJvc3BlY3Rpb25Qb2xsID0gKFxuICAgIGN0eDogVEludGVycHJldGVyQ29udGV4dCxcbiAgICBqb2JJZDogc3RyaW5nIHwgbnVsbCxcbiAgICBzdG9yZTogVFN0b3JlLFxuKTogdm9pZCA9PiB7XG4gICAgcnVuSW5BY3Rpb24oKCkgPT4ge1xuICAgICAgICBpZiAoam9iSWQgPT09IG51bGwpIHtcbiAgICAgICAgICAgIHN0b3JlLnN0ZXBzLmluZ2VzdGlvbi5wb3N0SW50cm9zcGVjdGlvbi5zdGF0ZSA9ICdkb25lJztcbiAgICAgICAgICAgIHN0b3JlLnN0ZXBzLmluZ2VzdGlvbi5wb3N0SW50cm9zcGVjdGlvbi5yZXVzZWQgPSB0cnVlO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgc3RvcmUuc3RlcHMuaW5nZXN0aW9uLnBvc3RJbnRyb3NwZWN0aW9uLmpvYklkID0gam9iSWQ7XG4gICAgICAgICAgICBpZiAoc3RvcmUuc3RlcHMuaW5nZXN0aW9uLnBvc3RJbnRyb3NwZWN0aW9uLnN0YXRlID09PSAnaWRsZScpIHtcbiAgICAgICAgICAgICAgICBzdG9yZS5zdGVwcy5pbmdlc3Rpb24ucG9zdEludHJvc3BlY3Rpb24uc3RhdGUgPSAncXVldWVkJztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH0pO1xuICAgIGlmIChqb2JJZCA9PT0gbnVsbCB8fCBjdHguYXV0aGVkID09PSBudWxsKSB7XG4gICAgICAgIGN0eC5wb3N0SW50cm9zcGVjdGlvblBvbGwgPSBQcm9taXNlLnJlc29sdmUoKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjdHgucG9zdEludHJvc3BlY3Rpb25Qb2xsID0gc3RyZWFtUG9zdEludHJvc3BlY3Rpb24oXG4gICAgICAgIGN0eC5hdXRoZWQsXG4gICAgICAgIGpvYklkLFxuICAgICAgICBzdG9yZSxcbiAgICApLnRoZW4oXG4gICAgICAgICgpID0+IHt9LFxuICAgICAgICAoKSA9PiB7fSxcbiAgICApO1xufTtcblxuZXhwb3J0IGNvbnN0IGNsZWFudXAgPSAoY3R4OiBUSW50ZXJwcmV0ZXJDb250ZXh0KTogdm9pZCA9PiB7XG4gICAgaWYgKGN0eC5kYiAhPT0gbnVsbCkge1xuICAgICAgICBjdHguZGIuY2xlYW51cCgpO1xuICAgICAgICBjdHguZGIgPSBudWxsO1xuICAgIH1cbiAgICBpZiAoY3R4LmNsZWFudXBTU0ggIT09IG51bGwpIHtcbiAgICAgICAgY3R4LmNsZWFudXBTU0goKTtcbiAgICAgICAgY3R4LmNsZWFudXBTU0ggPSBudWxsO1xuICAgIH1cbn07XG4iXX0=