@cdktn/provider-generator 0.24.0-pre.88 → 0.24.0-pre.89

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 (66) hide show
  1. package/build/__tests__/edge-provider-schema/builder.d.ts +9 -3
  2. package/build/__tests__/edge-provider-schema/builder.js +6 -3
  3. package/build/__tests__/edge-provider-schema/index.js +119 -1
  4. package/build/__tests__/provider.test.js +4 -1
  5. package/build/get/__tests__/generator/ephemeral-resources.test.d.ts +2 -0
  6. package/build/get/__tests__/generator/ephemeral-resources.test.js +49 -0
  7. package/build/get/__tests__/generator/provider-functions.test.d.ts +2 -0
  8. package/build/get/__tests__/generator/provider-functions.test.js +176 -0
  9. package/build/get/__tests__/generator/provider.test.js +9 -1
  10. package/build/get/__tests__/generator/write-only.test.d.ts +2 -0
  11. package/build/get/__tests__/generator/write-only.test.js +65 -0
  12. package/build/get/__tests__/target-versions.test.d.ts +2 -0
  13. package/build/get/__tests__/target-versions.test.js +171 -0
  14. package/build/get/constructs-maker.d.ts +8 -1
  15. package/build/get/constructs-maker.js +13 -4
  16. package/build/get/generator/emitter/attributes-emitter.d.ts +12 -2
  17. package/build/get/generator/emitter/attributes-emitter.js +47 -5
  18. package/build/get/generator/emitter/index.d.ts +1 -0
  19. package/build/get/generator/emitter/index.js +2 -1
  20. package/build/get/generator/emitter/provider-functions-emitter.d.ts +11 -0
  21. package/build/get/generator/emitter/provider-functions-emitter.js +94 -0
  22. package/build/get/generator/emitter/resource-emitter.d.ts +5 -1
  23. package/build/get/generator/emitter/resource-emitter.js +83 -7
  24. package/build/get/generator/models/attribute-model.d.ts +2 -0
  25. package/build/get/generator/models/attribute-model.js +2 -1
  26. package/build/get/generator/models/index.d.ts +1 -0
  27. package/build/get/generator/models/index.js +2 -1
  28. package/build/get/generator/models/provider-function-model.d.ts +102 -0
  29. package/build/get/generator/models/provider-function-model.js +667 -0
  30. package/build/get/generator/models/resource-model.d.ts +3 -0
  31. package/build/get/generator/models/resource-model.js +13 -4
  32. package/build/get/generator/models/struct.d.ts +2 -0
  33. package/build/get/generator/models/struct.js +6 -2
  34. package/build/get/generator/provider-generator.d.ts +2 -0
  35. package/build/get/generator/provider-generator.js +31 -3
  36. package/build/get/generator/resource-parser.js +3 -1
  37. package/package.json +4 -4
  38. package/src/__tests__/__snapshots__/edge-provider-schema.test.ts.snap +4 -0
  39. package/src/__tests__/edge-provider-schema/builder.ts +17 -1
  40. package/src/__tests__/edge-provider-schema/index.ts +124 -1
  41. package/src/__tests__/provider.test.ts +3 -0
  42. package/src/get/__tests__/generator/__snapshots__/ephemeral-resources.test.ts.snap +524 -0
  43. package/src/get/__tests__/generator/__snapshots__/provider-functions.test.ts.snap +444 -0
  44. package/src/get/__tests__/generator/__snapshots__/write-only.test.ts.snap +262 -0
  45. package/src/get/__tests__/generator/ephemeral-resources.test.ts +46 -0
  46. package/src/get/__tests__/generator/fixtures/ephemeral-resources.test.fixture.json +160 -0
  47. package/src/get/__tests__/generator/fixtures/provider-functions-collision.test.fixture.json +31 -0
  48. package/src/get/__tests__/generator/fixtures/provider-functions-synthetic.test.fixture.json +192 -0
  49. package/src/get/__tests__/generator/fixtures/provider-functions.test.fixture.json +170 -0
  50. package/src/get/__tests__/generator/fixtures/write-only.test.fixture.json +58 -0
  51. package/src/get/__tests__/generator/provider-functions.test.ts +262 -0
  52. package/src/get/__tests__/generator/provider.test.ts +8 -0
  53. package/src/get/__tests__/generator/write-only.test.ts +71 -0
  54. package/src/get/__tests__/target-versions.test.ts +206 -0
  55. package/src/get/constructs-maker.ts +43 -3
  56. package/src/get/generator/emitter/attributes-emitter.ts +61 -6
  57. package/src/get/generator/emitter/index.ts +1 -0
  58. package/src/get/generator/emitter/provider-functions-emitter.ts +117 -0
  59. package/src/get/generator/emitter/resource-emitter.ts +110 -6
  60. package/src/get/generator/models/attribute-model.ts +3 -0
  61. package/src/get/generator/models/index.ts +1 -0
  62. package/src/get/generator/models/provider-function-model.ts +872 -0
  63. package/src/get/generator/models/resource-model.ts +25 -3
  64. package/src/get/generator/models/struct.ts +9 -1
  65. package/src/get/generator/provider-generator.ts +70 -4
  66. package/src/get/generator/resource-parser.ts +2 -0
@@ -0,0 +1,667 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildProviderFunctionsModel = exports.assertNoFunctionsGetterCollision = void 0;
4
+ // Copyright (c) HashiCorp, Inc
5
+ // SPDX-License-Identifier: MPL-2.0
6
+ const codemaker_1 = require("codemaker");
7
+ // Parameter names that collide with a reserved word/identifier in one of the
8
+ // jsii target languages. This is the sibling table for provider-defined
9
+ // functions: tools/generate-function-bindings/scripts/generate.ts holds the
10
+ // canonical (and separately maintained) table for built-in `Fn.*` functions.
11
+ // The two are intentionally not shared - that script lives outside the
12
+ // packages/ build and generates a different artifact - but any reserved name
13
+ // added there should be considered here too.
14
+ const RESERVED_PARAMETER_NAMES = {
15
+ default: "defaultValue", // reserved word in TypeScript
16
+ string: "str", // causes issues in Go
17
+ };
18
+ function sanitizeParameterName(name) {
19
+ var _a;
20
+ const camelCased = (0, codemaker_1.toCamelCase)(name);
21
+ return (_a = RESERVED_PARAMETER_NAMES[camelCased]) !== null && _a !== void 0 ? _a : camelCased;
22
+ }
23
+ function sanitizeMethodName(name) {
24
+ if (name === "length")
25
+ return "lengthOf"; // reserved on jsii-generated classes
26
+ return (0, codemaker_1.toCamelCase)(name);
27
+ }
28
+ // Members that `ProviderFunctionsEmitter` (see `emitter/provider-functions-emitter.ts`)
29
+ // itself puts on every generated `<Provider>ProviderFunctions` wrapper class,
30
+ // regardless of which functions a provider declares:
31
+ // - "constructor": the class's own constructor, which takes the provider's
32
+ // `providerLocalName`. A provider-defined function named "constructor"
33
+ // would sanitize to a *second* `constructor` member on the class, which
34
+ // is invalid TypeScript.
35
+ // - "providerLocalName": the `private readonly providerLocalName: string`
36
+ // field the constructor assigns (see the emitter's `emitClassHeader`/
37
+ // constructor emission). A provider-defined function sanitizing to this
38
+ // name would collide with that field.
39
+ // If `ProviderFunctionsEmitter` ever grows more members on the wrapper class,
40
+ // add them here too.
41
+ const RESERVED_WRAPPER_MEMBER_NAMES = new Set([
42
+ "constructor",
43
+ "providerLocalName",
44
+ ]);
45
+ /**
46
+ * The bracket-composable ("T[]", no top-level union) TypeScript/docstring
47
+ * type for an element that can nest inside an array without ITSELF needing
48
+ * the whole-collection token union at that level: `string`, `number`, or a
49
+ * list/set of one of those, recursively (e.g. `list(list(string))` bottoms
50
+ * out at `string`). Returns `undefined` for anything else (`bool`, `map`,
51
+ * `object`, `dynamic`, or a nested collection that doesn't itself qualify),
52
+ * so the caller falls back to widening the whole parameter to
53
+ * `any[] | cdktn.IResolvable` instead.
54
+ */
55
+ function plainArrayElementType(type) {
56
+ if (type === "string")
57
+ return { tsType: "string", docstringType: "string" };
58
+ if (type === "number")
59
+ return { tsType: "number", docstringType: "number" };
60
+ if (Array.isArray(type) && (type[0] === "list" || type[0] === "set")) {
61
+ const inner = plainArrayElementType(type[1]);
62
+ if (!inner)
63
+ return undefined;
64
+ return {
65
+ tsType: `${inner.tsType}[]`,
66
+ docstringType: `${type[0] === "set" ? "Set" : "Array"}<${inner.docstringType}>`,
67
+ };
68
+ }
69
+ return undefined;
70
+ }
71
+ /**
72
+ * Maps a `list`/`set` parameter to its jsii-safe shape - mirrors
73
+ * `ListAttributeTypeModel`/`SetAttributeTypeModel.inputTypeDefinition`
74
+ * (both identical) branch for branch, since jsii parameters, like resource
75
+ * inputs, are allowed to union in a whole-collection `cdktn.IResolvable`
76
+ * token. `kind` only affects the documentation: the docstring notation
77
+ * (`Array<...>` for a Terraform list, `Set<...>` for a Terraform set,
78
+ * recursively via `plainArrayElementType`/`mapParameterType`) plus, for
79
+ * sets, a prose note - the jsii type is an array either way, so the note
80
+ * keeps a reader from literally passing a JS `Set` and flags the
81
+ * ordering/duplicate-element semantics difference. The type-level handling
82
+ * is identical for both.
83
+ */
84
+ function mapListOrSetParameterType(kind, element) {
85
+ const wrapper = kind === "set" ? "Set" : "Array";
86
+ const docstringNote = kind === "set"
87
+ ? "Terraform set; ordering is not guaranteed and duplicate values are removed."
88
+ : undefined;
89
+ if (element === "string") {
90
+ // Mirrors the final `else` branch: encoded list tokens already satisfy
91
+ // `string[]`, so no union is needed.
92
+ return {
93
+ tsType: "string[]",
94
+ docstringType: `${wrapper}<string>`,
95
+ docstringNote,
96
+ acceptsResolvableAlready: false,
97
+ };
98
+ }
99
+ if (element === "number") {
100
+ // Same reasoning as `string` above.
101
+ return {
102
+ tsType: "number[]",
103
+ docstringType: `${wrapper}<number>`,
104
+ docstringNote,
105
+ acceptsResolvableAlready: false,
106
+ };
107
+ }
108
+ if (element === "bool") {
109
+ // Mirrors the `elementType.storedClassType === "boolean"` branch: bool
110
+ // has no lossless per-element token, but the WHOLE collection is still
111
+ // tokenizable, so the union is on the outside.
112
+ return {
113
+ tsType: "Array<boolean | cdktn.IResolvable> | cdktn.IResolvable",
114
+ docstringType: `${wrapper}<boolean | IResolvable>`,
115
+ docstringNote,
116
+ acceptsResolvableAlready: true,
117
+ };
118
+ }
119
+ const plainElement = plainArrayElementType(element);
120
+ if (plainElement) {
121
+ // Mirrors the `elementType.typeModelType !== "simple"` branch: a nested
122
+ // list/set that itself bottoms out at string/number composes into a
123
+ // proper nested array type (e.g. `list(list(string))` -> `string[][]`),
124
+ // with the whole-collection token additionally accepted alongside it.
125
+ return {
126
+ tsType: `${plainElement.tsType}[] | cdktn.IResolvable`,
127
+ docstringType: `${wrapper}<${plainElement.docstringType}>`,
128
+ docstringNote,
129
+ acceptsResolvableAlready: true,
130
+ };
131
+ }
132
+ // map/object/dynamic element, or a nested collection that doesn't itself
133
+ // reduce to string/number: no jsii-safe array-of-X type exists - widen
134
+ // the whole parameter to `any[]`. Unlike a bare `any` parameter, plain
135
+ // `any[]` does NOT structurally accept a whole-collection
136
+ // `cdktn.IResolvable` token, so the union is required here (this is
137
+ // stricter than `MapAttributeTypeModel`/`ListAttributeTypeModel` have to
138
+ // be, since those only ever fall back to `any[] | cdktn.IResolvable` via
139
+ // the same "not simple" branch above, which already grants it). Keep the
140
+ // docstring honest about the real element shape rather than just saying
141
+ // `any`.
142
+ const elementDescription = mapParameterType(element).docstringType;
143
+ return {
144
+ tsType: "any[] | cdktn.IResolvable",
145
+ docstringType: `${wrapper}<${elementDescription}>`,
146
+ docstringNote,
147
+ acceptsResolvableAlready: true,
148
+ };
149
+ }
150
+ /**
151
+ * Maps a `map` parameter to its jsii-safe shape - mirrors
152
+ * `MapAttributeTypeModel.inputTypeDefinition`. Only the `bool`-element case
153
+ * is reachable from real provider schemas today (`string`/`number` element
154
+ * maps stay a plain, non-union record; nested/complex map elements aren't
155
+ * emitted for provider functions - see the `object` fallback in
156
+ * `mapParameterType`), but the shape is kept branch-for-branch aligned with
157
+ * the model it mirrors rather than collapsed.
158
+ */
159
+ function mapMapParameterType(element) {
160
+ if (element === "string") {
161
+ return {
162
+ tsType: "{ [key: string]: string }",
163
+ docstringType: "{ [key: string]: string }",
164
+ acceptsResolvableAlready: false,
165
+ };
166
+ }
167
+ if (element === "number") {
168
+ return {
169
+ tsType: "{ [key: string]: number }",
170
+ docstringType: "{ [key: string]: number }",
171
+ acceptsResolvableAlready: false,
172
+ };
173
+ }
174
+ if (element === "bool") {
175
+ // Mirrors the `elementType.storedClassType === "boolean"` branch: map
176
+ // of booleans has PER-ENTRY token support, but the whole map itself is
177
+ // not additionally unioned with `cdktn.IResolvable` (unlike the list/set
178
+ // case) - matching `MapAttributeTypeModel.inputTypeDefinition` exactly.
179
+ return {
180
+ tsType: "{ [key: string]: (boolean | cdktn.IResolvable) }",
181
+ docstringType: "{ [key: string]: (boolean | IResolvable) }",
182
+ acceptsResolvableAlready: false,
183
+ };
184
+ }
185
+ // map/object/dynamic element: no structural input helper exists here -
186
+ // stays `any`, which (being `any`) already accepts a whole-map
187
+ // `cdktn.IResolvable` token too.
188
+ return {
189
+ tsType: "any",
190
+ docstringType: "any",
191
+ acceptsResolvableAlready: true,
192
+ };
193
+ }
194
+ /**
195
+ * Maps a provider function parameter's declared Terraform type to a
196
+ * jsii-safe TypeScript parameter type, recursively for collection types.
197
+ *
198
+ * Unlike return types, jsii allows unions in *parameter* position, so
199
+ * `bool` is typed `boolean | cdktn.IResolvable` (mirroring
200
+ * `SimpleAttributeTypeModel.inputTypeDefinition`'s input-side convention) -
201
+ * this both accepts a real boolean and still accepts a token in place of
202
+ * one. `dynamic` has no structural typing and stays `any` (which already
203
+ * accepts anything, including a token); `object` (structural input helpers
204
+ * are deferred to a follow-up issue) stays `any` too.
205
+ *
206
+ * `list`/`set` and `map` delegate to `mapListOrSetParameterType`/
207
+ * `mapMapParameterType`, which mirror `ListAttributeTypeModel`/
208
+ * `SetAttributeTypeModel`/`MapAttributeTypeModel.inputTypeDefinition`
209
+ * branch for branch (see `attribute-type-model.ts`) - the same
210
+ * whole-collection-token conventions already used for resource inputs.
211
+ */
212
+ function mapParameterType(type) {
213
+ if (type === "string") {
214
+ return {
215
+ tsType: "string",
216
+ docstringType: "string",
217
+ acceptsResolvableAlready: false,
218
+ };
219
+ }
220
+ if (type === "number") {
221
+ return {
222
+ tsType: "number",
223
+ docstringType: "number",
224
+ acceptsResolvableAlready: false,
225
+ };
226
+ }
227
+ if (type === "bool") {
228
+ return {
229
+ tsType: "boolean | cdktn.IResolvable",
230
+ docstringType: "boolean | IResolvable",
231
+ acceptsResolvableAlready: true,
232
+ };
233
+ }
234
+ if (type === "dynamic") {
235
+ return {
236
+ tsType: "any",
237
+ docstringType: "any",
238
+ acceptsResolvableAlready: true,
239
+ };
240
+ }
241
+ if (Array.isArray(type) && (type[0] === "list" || type[0] === "set")) {
242
+ return mapListOrSetParameterType(type[0], type[1]);
243
+ }
244
+ if (Array.isArray(type) && type[0] === "map") {
245
+ return mapMapParameterType(type[1]);
246
+ }
247
+ // object: structural input helpers are deferred to a follow-up issue.
248
+ return {
249
+ tsType: "any",
250
+ docstringType: "object",
251
+ acceptsResolvableAlready: true,
252
+ };
253
+ }
254
+ function buildParameterModel(parameter, fallbackName) {
255
+ var _a;
256
+ const terraformName = (_a = parameter.name) !== null && _a !== void 0 ? _a : fallbackName;
257
+ const { tsType, docstringType, docstringNote, acceptsResolvableAlready } = mapParameterType(parameter.type);
258
+ return {
259
+ terraformName,
260
+ name: sanitizeParameterName(terraformName),
261
+ tsType,
262
+ docstringType,
263
+ docstringNote,
264
+ description: parameter.description,
265
+ acceptsResolvableAlready,
266
+ };
267
+ }
268
+ /**
269
+ * Widens a mapped type's `tsType`/`docstringType` to also accept an
270
+ * explicit `cdktn.Token.nullValue()` in this position - unless
271
+ * `acceptsResolvableAlready` says it already does (e.g. a `bool` parameter
272
+ * is already `boolean | cdktn.IResolvable`, so nullability adds nothing to
273
+ * the type itself, only to the docstring note appended by the caller).
274
+ */
275
+ function withNullableResolvableUnion(model) {
276
+ if (model.acceptsResolvableAlready) {
277
+ return { tsType: model.tsType, docstringType: model.docstringType };
278
+ }
279
+ return {
280
+ tsType: `${model.tsType} | cdktn.IResolvable`,
281
+ docstringType: `${model.docstringType} | IResolvable`,
282
+ };
283
+ }
284
+ /**
285
+ * Applies `is_nullable` trailing-compatibility rules across a function's
286
+ * fixed (non-variadic) parameter list. This needs the whole list in view
287
+ * (see `buildFunctionModel`), since whether a nullable parameter can become
288
+ * jsii-optional depends on every parameter *after* it too:
289
+ *
290
+ * - A nullable parameter where it and every later fixed parameter are also
291
+ * nullable becomes jsii-optional (`name?: T`): omitting it in TypeScript
292
+ * leaves `undefined` in the invoke args array, which `FunctionCall`
293
+ * already renders as the Terraform `null` keyword. It additionally gains
294
+ * the `| cdktn.IResolvable` union (see `withNullableResolvableUnion`), so
295
+ * a caller who does supply the argument can pass
296
+ * `cdktn.Token.nullValue()` for an explicit Terraform `null` without
297
+ * omitting the parameter.
298
+ * - A nullable parameter followed by a required one keeps its position
299
+ * (jsii can't express "optional but not trailing"), and instead gains the
300
+ * same `| cdktn.IResolvable` union so a caller can still pass an explicit
301
+ * `cdktn.Token.nullValue()` (an `IResolvable` resolving to `null` - see
302
+ * `Token.nullValue()`/`Token.asAny()`) in that fixed position - keeping
303
+ * the parameter's real type rather than giving up all type safety by
304
+ * widening it to `any`.
305
+ *
306
+ * Both cases document the real mechanism in the docstring note rather than
307
+ * implying the plain TypeScript `null` literal is accepted: the trailing
308
+ * case can also just be omitted, the mid-position case can't be omitted at
309
+ * all (jsii can't express "optional but not trailing").
310
+ */
311
+ function applyNullability(parameters, models) {
312
+ const trailingCompatible = new Array(parameters.length).fill(false);
313
+ let allNullableSoFar = true;
314
+ for (let i = parameters.length - 1; i >= 0; i--) {
315
+ allNullableSoFar = allNullableSoFar && parameters[i].is_nullable === true;
316
+ trailingCompatible[i] = allNullableSoFar;
317
+ }
318
+ return models.map((model, index) => {
319
+ const parameter = parameters[index];
320
+ if (!parameter.is_nullable)
321
+ return model;
322
+ const { tsType, docstringType } = withNullableResolvableUnion(model);
323
+ const nullabilityNote = trailingCompatible[index]
324
+ ? "Omit or pass cdktn.Token.nullValue() to render the Terraform null keyword."
325
+ : "Pass cdktn.Token.nullValue() for an explicit Terraform null.";
326
+ return {
327
+ ...model,
328
+ ...(trailingCompatible[index] ? { optional: true } : {}),
329
+ tsType,
330
+ docstringType,
331
+ docstringNote: [model.docstringNote, nullabilityNote]
332
+ .filter(Boolean)
333
+ .join(" "),
334
+ };
335
+ });
336
+ }
337
+ /**
338
+ * Maps a provider function's declared return type to the jsii-safe
339
+ * TypeScript return type, the `@returns` JSDoc type, and the expression
340
+ * that unwraps the `TerraformProviderFunction.invoke(...)` `IResolvable`
341
+ * into it.
342
+ *
343
+ * jsii return positions can't use the `T | cdktn.IResolvable` union that
344
+ * parameters can (see `mapParameterType`), so every shape that can't be
345
+ * losslessly unwrapped through an `asXxx` Token helper falls back to the
346
+ * plain `cdktn.IResolvable` produced by `invoke()` itself, unwrapped.
347
+ * Provider functions frequently return objects (e.g. every function in the
348
+ * `time` provider), so - unlike built-in `Fn.*` functions - the object case
349
+ * is a primary path, not an error: it is treated the same as
350
+ * `dynamic`/a `list`/`set` of anything other than `string`/`number` (no
351
+ * `asAnyList` Token helper exists), and returned as the RAW `invoke()`
352
+ * result. `map` returns, unlike those, DO have a full set of typed Token
353
+ * helpers (`asStringMap`/`asNumberMap`/`asBooleanMap`/`asAnyMap`), so every
354
+ * `map` shape gets an actual typed record return instead of falling back to
355
+ * `cdktn.IResolvable`.
356
+ *
357
+ * Whenever the declared return type IS `cdktn.IResolvable` (not `any`):
358
+ * unlike `helpers.ts` `asAny`, this must NOT go through
359
+ * `cdktn.Token.asString(...)` - `Token.asString()` produces an encoded
360
+ * string token that `Tokenization.isResolvable()` does not recognize, so
361
+ * generated struct setters (e.g. an `OutputReference` `internalValue`) treat
362
+ * it as a plain object with no known keys and the attribute silently
363
+ * vanishes from synth output. The raw `IResolvable` from `invoke()` IS
364
+ * recognized by `Tokenization.isResolvable()` and resolves correctly.
365
+ * Declaring it as `cdktn.IResolvable` instead of `any` also gives callers
366
+ * real type safety: `any` let a caller write `result.hours` on a token with
367
+ * no compile-time feedback, silently producing `undefined` at runtime;
368
+ * `IResolvable` has no such property and forces the caller through
369
+ * `cdktn.Token`/the provider's struct types instead. `invoke()` already
370
+ * returns `IResolvable`, so no cast is needed to return it as
371
+ * `cdktn.IResolvable`.
372
+ */
373
+ function mapReturnType(returnType) {
374
+ if (returnType === "string") {
375
+ return {
376
+ tsType: "string",
377
+ docstringType: "string",
378
+ wrapReturn: (expr) => `cdktn.Token.asString(${expr})`,
379
+ };
380
+ }
381
+ if (returnType === "number") {
382
+ return {
383
+ tsType: "number",
384
+ docstringType: "number",
385
+ wrapReturn: (expr) => `cdktn.Token.asNumber(${expr})`,
386
+ };
387
+ }
388
+ if (returnType === "bool") {
389
+ // Booleans can't be represented as tokens (see helpers.ts asBoolean):
390
+ // return the IResolvable produced by invoke() unwrapped. The docstring
391
+ // still documents the real conceptual shape.
392
+ return {
393
+ tsType: "cdktn.IResolvable",
394
+ docstringType: "boolean | IResolvable",
395
+ wrapReturn: (expr) => expr,
396
+ };
397
+ }
398
+ if (returnType === "dynamic") {
399
+ return {
400
+ tsType: "cdktn.IResolvable",
401
+ docstringType: "any",
402
+ wrapReturn: (expr) => expr,
403
+ };
404
+ }
405
+ if (Array.isArray(returnType) &&
406
+ (returnType[0] === "list" || returnType[0] === "set")) {
407
+ // Same documentation conventions as `mapListOrSetParameterType`: the
408
+ // notation (`Array<...>`/`Set<...>`) carries the Terraform collection
409
+ // structure recursively, and only sets get a prose note.
410
+ const wrapper = returnType[0] === "set" ? "Set" : "Array";
411
+ const docstringNote = returnType[0] === "set"
412
+ ? "Terraform set; ordering is not guaranteed and duplicate values are removed."
413
+ : undefined;
414
+ const element = returnType[1];
415
+ if (element === "string") {
416
+ return {
417
+ tsType: "string[]",
418
+ docstringType: `${wrapper}<string>`,
419
+ docstringNote,
420
+ wrapReturn: (expr) => `cdktn.Token.asList(${expr})`,
421
+ };
422
+ }
423
+ if (element === "number") {
424
+ return {
425
+ tsType: "number[]",
426
+ docstringType: `${wrapper}<number>`,
427
+ docstringNote,
428
+ wrapReturn: (expr) => `cdktn.Token.asNumberList(${expr})`,
429
+ };
430
+ }
431
+ // list/set of anything else: there is no `asAnyList` Token helper -
432
+ // fall back to the raw IResolvable, same reasoning as dynamic/object
433
+ // below, but keep the docstring honest about the real element shape
434
+ // (reusing mapParameterType purely for its descriptive docstringType -
435
+ // its tsType/acceptsResolvableAlready are irrelevant here).
436
+ return {
437
+ tsType: "cdktn.IResolvable",
438
+ docstringType: `${wrapper}<${mapParameterType(element).docstringType}>`,
439
+ docstringNote,
440
+ wrapReturn: (expr) => expr,
441
+ };
442
+ }
443
+ if (Array.isArray(returnType) && returnType[0] === "map") {
444
+ // Unlike list/set and object/dynamic, every `map` shape has a matching
445
+ // typed Token helper (see token.ts), so it gets a real typed record
446
+ // return instead of falling back to the raw IResolvable.
447
+ const element = returnType[1];
448
+ if (element === "string") {
449
+ return {
450
+ tsType: "{ [key: string]: string }",
451
+ docstringType: "{ [key: string]: string }",
452
+ wrapReturn: (expr) => `cdktn.Token.asStringMap(${expr})`,
453
+ };
454
+ }
455
+ if (element === "number") {
456
+ return {
457
+ tsType: "{ [key: string]: number }",
458
+ docstringType: "{ [key: string]: number }",
459
+ wrapReturn: (expr) => `cdktn.Token.asNumberMap(${expr})`,
460
+ };
461
+ }
462
+ if (element === "bool") {
463
+ // Token.asBooleanMap's declared return type is `{ [key: string]:
464
+ // boolean }` (see token.ts) - used verbatim, not unioned with
465
+ // IResolvable: the map's individual entries are plain booleans once
466
+ // unwrapped by the helper.
467
+ return {
468
+ tsType: "{ [key: string]: boolean }",
469
+ docstringType: "{ [key: string]: boolean }",
470
+ wrapReturn: (expr) => `cdktn.Token.asBooleanMap(${expr})`,
471
+ };
472
+ }
473
+ // map of anything else (object/dynamic/nested collection): asAnyMap
474
+ // still gives a typed (if loosely-typed) record rather than falling
475
+ // back to the raw IResolvable.
476
+ return {
477
+ tsType: "{ [key: string]: any }",
478
+ docstringType: "{ [key: string]: any }",
479
+ wrapReturn: (expr) => `cdktn.Token.asAnyMap(${expr})`,
480
+ };
481
+ }
482
+ // object: no structural typing for arbitrary provider function results -
483
+ // declared as `cdktn.IResolvable`, and returned as the raw `IResolvable`
484
+ // from invoke() (NOT wrapped in `cdktn.Token.asString(...)`, which would
485
+ // make the result unrecognizable to `Tokenization.isResolvable()`
486
+ // downstream - see the mapReturnType docstring above).
487
+ return {
488
+ tsType: "cdktn.IResolvable",
489
+ docstringType: "object",
490
+ wrapReturn: (expr) => expr,
491
+ };
492
+ }
493
+ function buildFunctionModel(terraformName, signature) {
494
+ var _a;
495
+ const { tsType: returnTsType, docstringType: returnDocstringType, docstringNote: returnDocstringNote, wrapReturn, } = mapReturnType(signature.return_type);
496
+ const rawParameters = (_a = signature.parameters) !== null && _a !== void 0 ? _a : [];
497
+ const parameters = applyNullability(rawParameters, rawParameters.map((parameter, index) => buildParameterModel(parameter, `arg${index}`)));
498
+ let variadicParameter;
499
+ if (signature.variadic_parameter) {
500
+ const elementModel = buildParameterModel(signature.variadic_parameter, "values");
501
+ if (signature.variadic_parameter.is_nullable) {
502
+ // A nullable variadic parameter: jsii can't express "each individual
503
+ // argument may independently be null" on the generated `values:
504
+ // Array<T>` array parameter (it's an ordinary array parameter, not a
505
+ // true rest/spread parameter - only the invoke() call site spreads
506
+ // it), so every element's type instead widens to also accept an
507
+ // explicit `cdktn.Token.nullValue()`, the same way a fixed nullable
508
+ // parameter does (see `withNullableResolvableUnion`); the docstring
509
+ // keeps the honest per-element type plus that guidance in its note.
510
+ const { tsType, docstringType } = withNullableResolvableUnion(elementModel);
511
+ variadicParameter = {
512
+ ...elementModel,
513
+ tsType,
514
+ docstringType: `Array<${docstringType}>`,
515
+ docstringNote: [
516
+ elementModel.docstringNote,
517
+ "Pass cdktn.Token.nullValue() for an explicit Terraform null.",
518
+ ]
519
+ .filter(Boolean)
520
+ .join(" "),
521
+ };
522
+ }
523
+ else {
524
+ // Non-nullable: the docstring wraps the element's docstring type in
525
+ // `Array<...>` here (rather than in the emitter), so every parameter
526
+ // - fixed or variadic - can share one `@param {docstringType}`
527
+ // emission path.
528
+ variadicParameter = {
529
+ ...elementModel,
530
+ docstringType: `Array<${elementModel.docstringType}>`,
531
+ };
532
+ }
533
+ }
534
+ return {
535
+ terraformName,
536
+ methodName: sanitizeMethodName(terraformName),
537
+ description: signature.description,
538
+ summary: signature.summary,
539
+ deprecationMessage: signature.deprecation_message,
540
+ returnTsType,
541
+ returnDocstringType,
542
+ returnDocstringNote,
543
+ wrapReturn,
544
+ parameters,
545
+ variadicParameter,
546
+ };
547
+ }
548
+ /**
549
+ * Throws if two functions in the same provider sanitize to the same
550
+ * generated method name. Terraform function names are unique, but
551
+ * `sanitizeMethodName` (camelCasing, `length` -> `lengthOf`) is not
552
+ * necessarily injective, so a real - if unlikely - provider schema could
553
+ * still produce a duplicate method. Generation is aborted rather than
554
+ * silently emitting one method that shadows the other.
555
+ */
556
+ function assertNoMethodNameCollisions(providerName, functions) {
557
+ const seenBy = new Map(); // methodName -> terraformName
558
+ for (const fn of functions) {
559
+ const existingTerraformName = seenBy.get(fn.methodName);
560
+ if (existingTerraformName !== undefined) {
561
+ throw new Error(`Provider "${providerName}" declares two provider-defined functions, ` +
562
+ `"${existingTerraformName}" and "${fn.terraformName}", that both ` +
563
+ `sanitize to the generated method name "${fn.methodName}". ` +
564
+ `Generation aborted to avoid silently overwriting one method with ` +
565
+ `the other - please report this as an issue.`);
566
+ }
567
+ seenBy.set(fn.methodName, fn.terraformName);
568
+ }
569
+ }
570
+ /**
571
+ * Throws if a function's sanitized `methodName` lands on a member name
572
+ * `ProviderFunctionsEmitter` already puts on every wrapper class (see
573
+ * `RESERVED_WRAPPER_MEMBER_NAMES`). Unlike `assertNoMethodNameCollisions`,
574
+ * which only catches two *functions* colliding with each other, this catches
575
+ * a single function colliding with the wrapper class itself - e.g. a
576
+ * Terraform function literally named "constructor", or "provider_local_name"
577
+ * camelCasing to "providerLocalName".
578
+ *
579
+ * This intentionally does NOT also check sanitized *parameter* names against
580
+ * "providerLocalName": parameters are declared in the generated method's own
581
+ * scope, not the class's, so a parameter named `providerLocalName` shadows
582
+ * the class field within that method body without colliding with it (valid,
583
+ * if confusing, TypeScript) - there is nothing to abort generation over.
584
+ */
585
+ function assertNoReservedWrapperMemberCollisions(providerName, functions) {
586
+ for (const fn of functions) {
587
+ if (RESERVED_WRAPPER_MEMBER_NAMES.has(fn.methodName)) {
588
+ throw new Error(`Provider "${providerName}" declares a provider-defined function ` +
589
+ `"${fn.terraformName}" that sanitizes to the generated method name ` +
590
+ `"${fn.methodName}", which collides with a member that ` +
591
+ `ProviderFunctionsEmitter already puts on every ` +
592
+ `"<Provider>ProviderFunctions" wrapper class (the class ` +
593
+ `constructor, or its "providerLocalName" field). Generation ` +
594
+ `aborted to avoid emitting invalid TypeScript or silently ` +
595
+ `shadowing that member - please report this as an issue.`);
596
+ }
597
+ }
598
+ }
599
+ /**
600
+ * Throws if two parameters of the same function (including the variadic
601
+ * parameter) sanitize to the same generated parameter name, for the same
602
+ * reason as `assertNoMethodNameCollisions` above but at the parameter level.
603
+ */
604
+ function assertNoParameterNameCollisions(providerName, fn) {
605
+ const seenBy = new Map(); // sanitized name -> terraformName
606
+ const allParameters = fn.variadicParameter
607
+ ? [...fn.parameters, fn.variadicParameter]
608
+ : fn.parameters;
609
+ for (const param of allParameters) {
610
+ const existingTerraformName = seenBy.get(param.name);
611
+ if (existingTerraformName !== undefined) {
612
+ throw new Error(`Provider "${providerName}" function "${fn.terraformName}" declares ` +
613
+ `two parameters, "${existingTerraformName}" and ` +
614
+ `"${param.terraformName}", that both sanitize to the generated ` +
615
+ `parameter name "${param.name}". Generation aborted to avoid ` +
616
+ `silently dropping one parameter - please report this as an issue.`);
617
+ }
618
+ seenBy.set(param.name, param.terraformName);
619
+ }
620
+ }
621
+ /**
622
+ * Throws if the provider's own config schema declares an attribute whose
623
+ * generated property name (see `AttributeModel.name` /
624
+ * `escapeAttributeName`) is exactly "functions", while the provider also
625
+ * declares provider-defined functions. That combination would collide with
626
+ * the memoized `functions` getter `ResourceEmitter` emits on the provider
627
+ * class (see `resource-emitter.ts`'s `emitFunctionsGetter`) - one would
628
+ * silently shadow the other. Same loud-failure convention as
629
+ * `assertNoMethodNameCollisions`/`assertNoParameterNameCollisions` above:
630
+ * generation is aborted rather than silently picking a winner.
631
+ */
632
+ function assertNoFunctionsGetterCollision(providerName, attributeNames) {
633
+ if (attributeNames.includes("functions")) {
634
+ throw new Error(`Provider "${providerName}" declares provider-defined functions and its ` +
635
+ `own config schema also has an attribute that generates the property ` +
636
+ `name "functions" on the provider class. This collides with the ` +
637
+ `generated "functions" getter used to invoke provider-defined ` +
638
+ `functions. Generation aborted to avoid silently shadowing one with ` +
639
+ `the other - please report this as an issue.`);
640
+ }
641
+ }
642
+ exports.assertNoFunctionsGetterCollision = assertNoFunctionsGetterCollision;
643
+ /**
644
+ * Builds the model for a provider's `provider-functions/index.ts` file from
645
+ * its provider schema `functions` map. Returns `undefined` when the provider
646
+ * declares no functions - callers should skip emitting the file entirely.
647
+ */
648
+ function buildProviderFunctionsModel(providerName, functions) {
649
+ const entries = Object.entries(functions !== null && functions !== void 0 ? functions : {});
650
+ if (entries.length === 0)
651
+ return undefined;
652
+ const mappedFunctions = entries
653
+ .sort(([a], [b]) => a.localeCompare(b))
654
+ .map(([name, signature]) => buildFunctionModel(name, signature));
655
+ assertNoMethodNameCollisions(providerName, mappedFunctions);
656
+ assertNoReservedWrapperMemberCollisions(providerName, mappedFunctions);
657
+ for (const fn of mappedFunctions) {
658
+ assertNoParameterNameCollisions(providerName, fn);
659
+ }
660
+ return {
661
+ providerName,
662
+ className: `${(0, codemaker_1.toPascalCase)(providerName)}ProviderFunctions`,
663
+ functions: mappedFunctions,
664
+ };
665
+ }
666
+ exports.buildProviderFunctionsModel = buildProviderFunctionsModel;
667
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvdmlkZXItZnVuY3Rpb24tbW9kZWwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvZ2V0L2dlbmVyYXRvci9tb2RlbHMvcHJvdmlkZXItZnVuY3Rpb24tbW9kZWwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsK0JBQStCO0FBQy9CLG1DQUFtQztBQUNuQyx5Q0FBc0Q7QUF5R3RELDZFQUE2RTtBQUM3RSx3RUFBd0U7QUFDeEUsNEVBQTRFO0FBQzVFLDZFQUE2RTtBQUM3RSx1RUFBdUU7QUFDdkUsNkVBQTZFO0FBQzdFLDZDQUE2QztBQUM3QyxNQUFNLHdCQUF3QixHQUErQjtJQUMzRCxPQUFPLEVBQUUsY0FBYyxFQUFFLDhCQUE4QjtJQUN2RCxNQUFNLEVBQUUsS0FBSyxFQUFFLHNCQUFzQjtDQUN0QyxDQUFDO0FBRUYsU0FBUyxxQkFBcUIsQ0FBQyxJQUFZOztJQUN6QyxNQUFNLFVBQVUsR0FBRyxJQUFBLHVCQUFXLEVBQUMsSUFBSSxDQUFDLENBQUM7SUFDckMsT0FBTyxNQUFBLHdCQUF3QixDQUFDLFVBQVUsQ0FBQyxtQ0FBSSxVQUFVLENBQUM7QUFDNUQsQ0FBQztBQUVELFNBQVMsa0JBQWtCLENBQUMsSUFBWTtJQUN0QyxJQUFJLElBQUksS0FBSyxRQUFRO1FBQUUsT0FBTyxVQUFVLENBQUMsQ0FBQyxxQ0FBcUM7SUFDL0UsT0FBTyxJQUFBLHVCQUFXLEVBQUMsSUFBSSxDQUFDLENBQUM7QUFDM0IsQ0FBQztBQUVELHdGQUF3RjtBQUN4Riw4RUFBOEU7QUFDOUUscURBQXFEO0FBQ3JELDZFQUE2RTtBQUM3RSwyRUFBMkU7QUFDM0UsNEVBQTRFO0FBQzVFLDZCQUE2QjtBQUM3Qiw0RUFBNEU7QUFDNUUsMEVBQTBFO0FBQzFFLDRFQUE0RTtBQUM1RSwwQ0FBMEM7QUFDMUMsOEVBQThFO0FBQzlFLHFCQUFxQjtBQUNyQixNQUFNLDZCQUE2QixHQUFHLElBQUksR0FBRyxDQUFDO0lBQzVDLGFBQWE7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QUFDLE1BQU0sS0FBSyxDQUFDO1FBQUUsT0FBTyxTQUFTLENBQUM7SUFFM0MsTUFBTSxlQUFlLEdBQUcsT0FBTztTQUM1QixJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxhQUFhLENBQUMsQ0FBQyxDQUFDLENBQUM7U0FDdEMsR0FBRyxDQUFDLENBQUMsQ0FBQyxJQUFJLEVBQUUsU0FBUyxDQUFDLEVBQUUsRUFBRSxDQUFDLGtCQUFrQixDQUFDLElBQUksRUFBRSxTQUFTLENBQUMsQ0FBQyxDQUFDO0lBRW5FLDRCQUE0QixDQUFDLFlBQVksRUFBRSxlQUFlLENBQUMsQ0FBQztJQUM1RCx1Q0FBdUMsQ0FBQyxZQUFZLEVBQUUsZUFBZSxDQUFDLENBQUM7SUFDdkUsS0FBSyxNQUFNLEVBQUUsSUFBSSxlQUFlLEVBQUUsQ0FBQztRQUNqQywrQkFBK0IsQ0FBQyxZQUFZLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDcEQsQ0FBQztJQUVELE9BQU87UUFDTCxZQUFZO1FBQ1osU0FBUyxFQUFFLEdBQUcsSUFBQSx3QkFBWSxFQUFDLFlBQVksQ0FBQyxtQkFBbUI7UUFDM0QsU0FBUyxFQUFFLGVBQWU7S0FDM0IsQ0FBQztBQUNKLENBQUM7QUF0QkQsa0VBc0JDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IChjKSBIYXNoaUNvcnAsIEluY1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1QTC0yLjBcbmltcG9ydCB7IHRvQ2FtZWxDYXNlLCB0b1Bhc2NhbENhc2UgfSBmcm9tIFwiY29kZW1ha2VyXCI7XG5pbXBvcnQge1xuICBBdHRyaWJ1dGVUeXBlLFxuICBGdW5jdGlvblBhcmFtZXRlcixcbiAgRnVuY3Rpb25TaWduYXR1cmUsXG59IGZyb20gXCJAY2RrdG4vY29tbW9uc1wiO1xuXG4vKipcbiAqIEEgcHJvdmlkZXItZGVmaW5lZCBmdW5jdGlvbiBwYXJhbWV0ZXIgKHBvc2l0aW9uYWwgb3IgdGhlIHRyYWlsaW5nXG4gKiB2YXJpYWRpYyBvbmUpLCBtYXBwZWQgdG8gdGhlIGpzaWktc2FmZSBUeXBlU2NyaXB0IHR5cGUgdXNlZCBpbiB0aGVcbiAqIGdlbmVyYXRlZCBtZXRob2Qgc2lnbmF0dXJlLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFByb3ZpZGVyRnVuY3Rpb25QYXJhbWV0ZXJNb2RlbCB7XG4gIHJlYWRvbmx5IHRlcnJhZm9ybU5hbWU6IHN0cmluZztcbiAgcmVhZG9ubHkgbmFtZTogc3RyaW5nO1xuICByZWFkb25seSB0c1R5cGU6IHN0cmluZztcbiAgLyoqXG4gICAqIFRoZSBKU0RvYyB0eXBlIGV4cHJlc3Npb24gZW1pdHRlZCBpbnNpZGUgdGhlIGBAcGFyYW0gey4uLn1gIGJyYWNlcy5cbiAgICogQSBwdXJlIHR5cGUgZXhwcmVzc2lvbiBvbmx5IC0gcHJvc2UgKFRlcnJhZm9ybSBsaXN0L3NldCBzZW1hbnRpY3MsXG4gICAqIGBjZGt0bi5Ub2tlbi5udWxsVmFsdWUoKWAgZ3VpZGFuY2UpIGJlbG9uZ3MgaW4gYGRvY3N0cmluZ05vdGVgLlxuICAgKi9cbiAgcmVhZG9ubHkgZG9jc3RyaW5nVHlwZTogc3RyaW5nO1xuICAvKipcbiAgICogUHJvc2UgYXBwZW5kZWQgYWZ0ZXIgdGhlIHBhcmFtZXRlciBuYW1lIChhbmQgYGRlc2NyaXB0aW9uYCwgaWYgYW55KSBpblxuICAgKiB0aGUgZW1pdHRlZCBgQHBhcmFtYCBsaW5lIC0gZS5nLiBzZXQtb3JkZXJpbmcgc2VtYW50aWNzIG9yIGhvdyB0byBwYXNzXG4gICAqIGFuIGV4cGxpY2l0IFRlcnJhZm9ybSBgbnVsbGAuIE9mZmljaWFsIEpTRG9jIHBsYWNlcyBvbmx5IHRoZSB0eXBlXG4gICAqIGV4cHJlc3Npb24gaW5zaWRlIHRoZSBicmFjZXMsIHNvIHRoaXMgbXVzdCBuZXZlciBiZSBmb2xkZWQgaW50b1xuICAgKiBgZG9jc3RyaW5nVHlwZWAuXG4gICAqL1xuICByZWFkb25seSBkb2NzdHJpbmdOb3RlPzogc3RyaW5nO1xuICByZWFkb25seSBkZXNjcmlwdGlvbj86IHN0cmluZztcbiAgLyoqXG4gICAqIFRydWUgd2hlbiB0aGlzIChmaXhlZCwgbm9uLXZhcmlhZGljKSBwYXJhbWV0ZXIgaXMgZW1pdHRlZCBhcyBhXG4gICAqIGpzaWktb3B0aW9uYWwgVHlwZVNjcmlwdCBwYXJhbWV0ZXIgKGBuYW1lPzogVGApIC0gc2VlIHRoZVxuICAgKiBpc19udWxsYWJsZS90cmFpbGluZy1jb21wYXRpYmlsaXR5IGhhbmRsaW5nIGluIGBhcHBseU51bGxhYmlsaXR5YC5cbiAgICogTmV2ZXIgc2V0IG9uIHRoZSB2YXJpYWRpYyBwYXJhbWV0ZXI6IGFuIGFycmF5IHBhcmFtZXRlciBjYW4ndCBiZSBgP2AuXG4gICAqL1xuICByZWFkb25seSBvcHRpb25hbD86IGJvb2xlYW47XG59XG5cbi8qKlxuICogYFByb3ZpZGVyRnVuY3Rpb25QYXJhbWV0ZXJNb2RlbGAgcGx1cyB0aGUgb25lIGJpdCBvZiBpbmZvcm1hdGlvbiB0aGF0J3NcbiAqIG9ubHkgbmVlZGVkIHdoaWxlIGJ1aWxkaW5nIHRoZSBtb2RlbCAoc2VlIGBtYXBQYXJhbWV0ZXJUeXBlYC9cbiAqIGBhcHBseU51bGxhYmlsaXR5YCksIG5ldmVyIGJ5IHRoZSBlbWl0dGVyOiB3aGV0aGVyIGB0c1R5cGVgIGFscmVhZHlcbiAqIGFjY2VwdHMgYW4gYXJiaXRyYXJ5IGBjZGt0bi5JUmVzb2x2YWJsZWAgaW4gdGhpcyBwb3NpdGlvbiAoYSBiYXJlXG4gKiBib29sZWFuL2NvbGxlY3Rpb24tb2YtYm9vbGVhbiB0b2tlbiwgYGFueWAsIG9yIGFuIGV4cGxpY2l0XG4gKiBgfCBjZGt0bi5JUmVzb2x2YWJsZWAgdW5pb24gYWxyZWFkeSBwcmVzZW50KS4gTnVsbGFiaWxpdHkgaGFuZGxpbmcgdXNlc1xuICogdGhpcyB0byBkZWNpZGUgd2hldGhlciBpdCBuZWVkcyB0byBhcHBlbmQgYW5vdGhlciBgfCBjZGt0bi5JUmVzb2x2YWJsZWBcbiAqIHNvIGEgY2FsbGVyIGNhbiBwYXNzIGBjZGt0bi5Ub2tlbi5udWxsVmFsdWUoKWAgLSB3aXRob3V0IHJlc29ydGluZyB0b1xuICogcmUtZGVyaXZpbmcgdGhhdCBhbnN3ZXIgd2l0aCBhIHN0cmluZyBzZWFyY2ggb3ZlciBgdHNUeXBlYC5cbiAqL1xuaW50ZXJmYWNlIEludGVybmFsUGFyYW1ldGVyTW9kZWwgZXh0ZW5kcyBQcm92aWRlckZ1bmN0aW9uUGFyYW1ldGVyTW9kZWwge1xuICByZWFkb25seSBhY2NlcHRzUmVzb2x2YWJsZUFscmVhZHk6IGJvb2xlYW47XG59XG5cbi8qKlxuICogQSBzaW5nbGUgcHJvdmlkZXItZGVmaW5lZCBmdW5jdGlvbiwgbWFwcGVkIHRvIGEgc3RhdGljIG1ldGhvZCBvbiB0aGVcbiAqIGdlbmVyYXRlZCBgPFByb3ZpZGVyPlByb3ZpZGVyRnVuY3Rpb25zYCBjbGFzcy5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBQcm92aWRlckZ1bmN0aW9uTW9kZWwge1xuICByZWFkb25seSB0ZXJyYWZvcm1OYW1lOiBzdHJpbmc7XG4gIHJlYWRvbmx5IG1ldGhvZE5hbWU6IHN0cmluZztcbiAgcmVhZG9ubHkgZGVzY3JpcHRpb24/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IHN1bW1hcnk/OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBUZXJyYWZvcm0gKD49MS44KSBkZXByZWNhdGlvbiBtZXNzYWdlIGZvciB0aGUgZnVuY3Rpb24sIHN1cmZhY2VkIGFzIGFuXG4gICAqIGBAZGVwcmVjYXRlZGAgSlNEb2MgdGFnLiBPcGVuVG9mdSBuZXZlciBlbWl0cyB0aGlzIGZpZWxkIC0gc2VlXG4gICAqIGBGdW5jdGlvblNpZ25hdHVyZS5kZXByZWNhdGlvbl9tZXNzYWdlYC5cbiAgICovXG4gIHJlYWRvbmx5IGRlcHJlY2F0aW9uTWVzc2FnZT86IHN0cmluZztcbiAgcmVhZG9ubHkgcmV0dXJuVHNUeXBlOiBzdHJpbmc7XG4gIC8qKlxuICAgKiBUaGUgYEByZXR1cm5zIHsuLi59YCBKU0RvYyB0eXBlLCBkZXNjcmliaW5nIHRoZSBjb25jZXB0dWFsL1RlcnJhZm9ybVxuICAgKiBzaGFwZSBvZiB0aGUgcmV0dXJuIHZhbHVlIC0gc2VlIGBtYXBSZXR1cm5UeXBlYC4gVGhpcyBkZWxpYmVyYXRlbHkgY2FuXG4gICAqIGRpZmZlciBmcm9tIGByZXR1cm5Uc1R5cGVgIChlLmcuIGEgYGJvb2xgIHJldHVybiBpcyBkZWNsYXJlZFxuICAgKiBgY2RrdG4uSVJlc29sdmFibGVgIGJ1dCBkb2N1bWVudGVkIGFzIGBib29sZWFuIHwgSVJlc29sdmFibGVgKSwgdGhlIHNhbWVcbiAgICogd2F5IGEgcGFyYW1ldGVyJ3MgYGRvY3N0cmluZ1R5cGVgIGNhbiBkaWZmZXIgZnJvbSBpdHMgYHRzVHlwZWAuXG4gICAqL1xuICByZWFkb25seSByZXR1cm5Eb2NzdHJpbmdUeXBlOiBzdHJpbmc7XG4gIC8qKlxuICAgKiBQcm9zZSBhcHBlbmRlZCBhZnRlciB0aGUgYEByZXR1cm5zIHsuLi59YCBicmFjZXMgKGUuZy4gVGVycmFmb3JtXG4gICAqIGxpc3Qvc2V0IHNlbWFudGljcykgLSB0aGUgcmV0dXJuLXNpZGUgY291bnRlcnBhcnQgb2YgYSBwYXJhbWV0ZXInc1xuICAgKiBgZG9jc3RyaW5nTm90ZWAuXG4gICAqL1xuICByZWFkb25seSByZXR1cm5Eb2NzdHJpbmdOb3RlPzogc3RyaW5nO1xuICAvKipcbiAgICogV3JhcHMgdGhlIGBjZGt0bi5UZXJyYWZvcm1Qcm92aWRlckZ1bmN0aW9uLmludm9rZSguLi4pYCBjYWxsIGV4cHJlc3Npb25cbiAgICogaW50byB0aGUgbWV0aG9kJ3MgYHJldHVybmAgc3RhdGVtZW50IChlLmcuIHdyYXBwaW5nIGl0IGluXG4gICAqIGBjZGt0bi5Ub2tlbi5hc1N0cmluZyguLi4pYCwgb3IgcmV0dXJuaW5nIGl0IHVud3JhcHBlZCBmb3IgYGJvb2xgKS5cbiAgICovXG4gIHJlYWRvbmx5IHdyYXBSZXR1cm46IChpbnZva2VFeHByZXNzaW9uOiBzdHJpbmcpID0+IHN0cmluZztcbiAgcmVhZG9ubHkgcGFyYW1ldGVyczogUHJvdmlkZXJGdW5jdGlvblBhcmFtZXRlck1vZGVsW107XG4gIHJlYWRvbmx5IHZhcmlhZGljUGFyYW1ldGVyPzogUHJvdmlkZXJGdW5jdGlvblBhcmFtZXRlck1vZGVsO1xufVxuXG4vKipcbiAqIEFsbCBwcm92aWRlci1kZWZpbmVkIGZ1bmN0aW9ucyBvZiBhIHNpbmdsZSBwcm92aWRlciwgbWFwcGVkIHRvIGEgc2luZ2xlXG4gKiBnZW5lcmF0ZWQgYHByb3ZpZGVycy88cHJvdmlkZXI+L3Byb3ZpZGVyLWZ1bmN0aW9ucy9pbmRleC50c2AgZmlsZS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBQcm92aWRlckZ1bmN0aW9uc01vZGVsIHtcbiAgcmVhZG9ubHkgcHJvdmlkZXJOYW1lOiBzdHJpbmc7XG4gIHJlYWRvbmx5IGNsYXNzTmFtZTogc3RyaW5nO1xuICByZWFkb25seSBmdW5jdGlvbnM6IFByb3ZpZGVyRnVuY3Rpb25Nb2RlbFtdO1xufVxuXG4vLyBQYXJhbWV0ZXIgbmFtZXMgdGhhdCBjb2xsaWRlIHdpdGggYSByZXNlcnZlZCB3b3JkL2lkZW50aWZpZXIgaW4gb25lIG9mIHRoZVxuLy8ganNpaSB0YXJnZXQgbGFuZ3VhZ2VzLiBUaGlzIGlzIHRoZSBzaWJsaW5nIHRhYmxlIGZvciBwcm92aWRlci1kZWZpbmVkXG4vLyBmdW5jdGlvbnM6IHRvb2xzL2dlbmVyYXRlLWZ1bmN0aW9uLWJpbmRpbmdzL3NjcmlwdHMvZ2VuZXJhdGUudHMgaG9sZHMgdGhlXG4vLyBjYW5vbmljYWwgKGFuZCBzZXBhcmF0ZWx5IG1haW50YWluZWQpIHRhYmxlIGZvciBidWlsdC1pbiBgRm4uKmAgZnVuY3Rpb25zLlxuLy8gVGhlIHR3byBhcmUgaW50ZW50aW9uYWxseSBub3Qgc2hhcmVkIC0gdGhhdCBzY3JpcHQgbGl2ZXMgb3V0c2lkZSB0aGVcbi8vIHBhY2thZ2VzLyBidWlsZCBhbmQgZ2VuZXJhdGVzIGEgZGlmZmVyZW50IGFydGlmYWN0IC0gYnV0IGFueSByZXNlcnZlZCBuYW1lXG4vLyBhZGRlZCB0aGVyZSBzaG91bGQgYmUgY29uc2lkZXJlZCBoZXJlIHRvby5cbmNvbnN0IFJFU0VSVkVEX1BBUkFNRVRFUl9OQU1FUzogeyBbbmFtZTogc3RyaW5nXTogc3RyaW5nIH0gPSB7XG4gIGRlZmF1bHQ6IFwiZGVmYXVsdFZhbHVlXCIsIC8vIHJlc2VydmVkIHdvcmQgaW4gVHlwZVNjcmlwdFxuICBzdHJpbmc6IFwic3RyXCIsIC8vIGNhdXNlcyBpc3N1ZXMgaW4gR29cbn07XG5cbmZ1bmN0aW9uIHNhbml0aXplUGFyYW1ldGVyTmFtZShuYW1lOiBzdHJpbmcpOiBzdHJpbmcge1xuICBjb25zdCBjYW1lbENhc2VkID0gdG9DYW1lbENhc2UobmFtZSk7XG4gIHJldHVybiBSRVNFUlZFRF9QQVJBTUVURVJfTkFNRVNbY2FtZWxDYXNlZF0gPz8gY2FtZWxDYXNlZDtcbn1cblxuZnVuY3Rpb24gc2FuaXRpemVNZXRob2ROYW1lKG5hbWU6IHN0cmluZyk6IHN0cmluZyB7XG4gIGlmIChuYW1lID09PSBcImxlbmd0aFwiKSByZXR1cm4gXCJsZW5ndGhPZlwiOyAvLyByZXNlcnZlZCBvbiBqc2lpLWdlbmVyYXRlZCBjbGFzc2VzXG4gIHJldHVybiB0b0NhbWVsQ2FzZShuYW1lKTtcbn1cblxuLy8gTWVtYmVycyB0aGF0IGBQcm92aWRlckZ1bmN0aW9uc0VtaXR0ZXJgIChzZWUgYGVtaXR0ZXIvcHJvdmlkZXItZnVuY3Rpb25zLWVtaXR0ZXIudHNgKVxuLy8gaXRzZWxmIHB1dHMgb24gZXZlcnkgZ2VuZXJhdGVkIGA8UHJvdmlkZXI+UHJvdmlkZXJGdW5jdGlvbnNgIHdyYXBwZXIgY2xhc3MsXG4vLyByZWdhcmRsZXNzIG9mIHdoaWNoIGZ1bmN0aW9ucyBhIHByb3ZpZGVyIGRlY2xhcmVzOlxuLy8gICAtIFwiY29uc3RydWN0b3JcIjogdGhlIGNsYXNzJ3Mgb3duIGNvbnN0cnVjdG9yLCB3aGljaCB0YWtlcyB0aGUgcHJvdmlkZXInc1xuLy8gICAgIGBwcm92aWRlckxvY2FsTmFtZWAuIEEgcHJvdmlkZXItZGVmaW5lZCBmdW5jdGlvbiBuYW1lZCBcImNvbnN0cnVjdG9yXCJcbi8vICAgICB3b3VsZCBzYW5pdGl6ZSB0byBhICpzZWNvbmQqIGBjb25zdHJ1Y3RvcmAgbWVtYmVyIG9uIHRoZSBjbGFzcywgd2hpY2hcbi8vICAgICBpcyBpbnZhbGlkIFR5cGVTY3JpcHQuXG4vLyAgIC0gXCJwcm92aWRlckxvY2FsTmFtZVwiOiB0aGUgYHByaXZhdGUgcmVhZG9ubHkgcHJvdmlkZXJMb2NhbE5hbWU6IHN0cmluZ2Bcbi8vICAgICBmaWVsZCB0aGUgY29uc3RydWN0b3IgYXNzaWducyAoc2VlIHRoZSBlbWl0dGVyJ3MgYGVtaXRDbGFzc0hlYWRlcmAvXG4vLyAgICAgY29uc3RydWN0b3IgZW1pc3Npb24pLiBBIHByb3ZpZGVyLWRlZmluZWQgZnVuY3Rpb24gc2FuaXRpemluZyB0byB0aGlzXG4vLyAgICAgbmFtZSB3b3VsZCBjb2xsaWRlIHdpdGggdGhhdCBmaWVsZC5cbi8vIElmIGBQcm92aWRlckZ1bmN0aW9uc0VtaXR0ZXJgIGV2ZXIgZ3Jvd3MgbW9yZSBtZW1iZXJzIG9uIHRoZSB3cmFwcGVyIGNsYXNzLFxuLy8gYWRkIHRoZW0gaGVyZSB0b28uXG5jb25zdCBSRVNFUlZFRF9XUkFQUEVSX01FTUJFUl9OQU1FUyA9IG5ldyBTZXQoW1xuICBcImNvbnN0cnVjdG9yXCIsXG4gIFwicHJvdmlkZXJMb2NhbE5hbWVcIixcbl0pO1xuXG4vKipcbiAqIFJlc3VsdCBvZiBtYXBwaW5nIGEgc2luZ2xlIFRlcnJhZm9ybSBhdHRyaWJ1dGUgdHlwZSBpbnRvIGEganNpaS1zYWZlXG4gKiBwYXJhbWV0ZXIgc2hhcGUgKHNlZSBgbWFwUGFyYW1ldGVyVHlwZWApLlxuICovXG5pbnRlcmZhY2UgTWFwcGVkUGFyYW1ldGVyVHlwZSB7XG4gIHJlYWRvbmx5IHRzVHlwZTogc3RyaW5nO1xuICByZWFkb25seSBkb2NzdHJpbmdUeXBlOiBzdHJpbmc7XG4gIC8qKiBTZWUgYFByb3ZpZGVyRnVuY3Rpb25QYXJhbWV0ZXJNb2RlbC5kb2NzdHJpbmdOb3RlYC4gKi9cbiAgcmVhZG9ubHkgZG9jc3RyaW5nTm90ZT86IHN0cmluZztcbiAgLyoqXG4gICAqIFRydWUgd2hlbiBgdHNUeXBlYCBhbHJlYWR5IGFjY2VwdHMgYW4gYXJiaXRyYXJ5IGBjZGt0bi5JUmVzb2x2YWJsZWAgaW5cbiAgICogdGhpcyBwb3NpdGlvbiB3aXRob3V0IG5lZWRpbmcgYW4gZXh0cmEgYHwgY2RrdG4uSVJlc29sdmFibGVgIHVuaW9uIC1cbiAgICogc2VlIGBJbnRlcm5hbFBhcmFtZXRlck1vZGVsYC5cbiAgICovXG4gIHJlYWRvbmx5IGFjY2VwdHNSZXNvbHZhYmxlQWxyZWFkeTogYm9vbGVhbjtcbn1cblxuLyoqXG4gKiBUaGUgYnJhY2tldC1jb21wb3NhYmxlIChcIlRbXVwiLCBubyB0b3AtbGV2ZWwgdW5pb24pIFR5cGVTY3JpcHQvZG9jc3RyaW5nXG4gKiB0eXBlIGZvciBhbiBlbGVtZW50IHRoYXQgY2FuIG5lc3QgaW5zaWRlIGFuIGFycmF5IHdpdGhvdXQgSVRTRUxGIG5lZWRpbmdcbiAqIHRoZSB3aG9sZS1jb2xsZWN0aW9uIHRva2VuIHVuaW9uIGF0IHRoYXQgbGV2ZWw6IGBzdHJpbmdgLCBgbnVtYmVyYCwgb3IgYVxuICogbGlzdC9zZXQgb2Ygb25lIG9mIHRob3NlLCByZWN1cnNpdmVseSAoZS5nLiBgbGlzdChsaXN0KHN0cmluZykpYCBib3R0b21zXG4gKiBvdXQgYXQgYHN0cmluZ2ApLiBSZXR1cm5zIGB1bmRlZmluZWRgIGZvciBhbnl0aGluZyBlbHNlIChgYm9vbGAsIGBtYXBgLFxuICogYG9iamVjdGAsIGBkeW5hbWljYCwgb3IgYSBuZXN0ZWQgY29sbGVjdGlvbiB0aGF0IGRvZXNuJ3QgaXRzZWxmIHF1YWxpZnkpLFxuICogc28gdGhlIGNhbGxlciBmYWxscyBiYWNrIHRvIHdpZGVuaW5nIHRoZSB3aG9sZSBwYXJhbWV0ZXIgdG9cbiAqIGBhbnlbXSB8IGNka3RuLklSZXNvbHZhYmxlYCBpbnN0ZWFkLlxuICovXG5mdW5jdGlvbiBwbGFpbkFycmF5RWxlbWVudFR5cGUoXG4gIHR5cGU6IEF0dHJpYnV0ZVR5cGUsXG4pOiB7IHRzVHlwZTogc3RyaW5nOyBkb2NzdHJpbmdUeXBlOiBzdHJpbmcgfSB8IHVuZGVmaW5lZCB7XG4gIGlmICh0eXBlID09PSBcInN0cmluZ1wiKSByZXR1cm4geyB0c1R5cGU6IFwic3RyaW5nXCIsIGRvY3N0cmluZ1R5cGU6IFwic3RyaW5nXCIgfTtcbiAgaWYgKHR5cGUgPT09IFwibnVtYmVyXCIpIHJldHVybiB7IHRzVHlwZTogXCJudW1iZXJcIiwgZG9jc3RyaW5nVHlwZTogXCJudW1iZXJcIiB9O1xuICBpZiAoQXJyYXkuaXNBcnJheSh0eXBlKSAmJiAodHlwZVswXSA9PT0gXCJsaXN0XCIgfHwgdHlwZVswXSA9PT0gXCJzZXRcIikpIHtcbiAgICBjb25zdCBpbm5lciA9IHBsYWluQXJyYXlFbGVtZW50VHlwZSh0eXBlWzFdKTtcbiAgICBpZiAoIWlubmVyKSByZXR1cm4gdW5kZWZpbmVkO1xuICAgIHJldHVybiB7XG4gICAgICB0c1R5cGU6IGAke2lubmVyLnRzVHlwZX1bXWAsXG4gICAgICBkb2NzdHJpbmdUeXBlOiBgJHt0eXBlWzBdID09PSBcInNldFwiID8gXCJTZXRcIiA6IFwiQXJyYXlcIn08JHtpbm5lci5kb2NzdHJpbmdUeXBlfT5gLFxuICAgIH07XG4gIH1cbiAgcmV0dXJuIHVuZGVmaW5lZDtcbn1cblxuLyoqXG4gKiBNYXBzIGEgYGxpc3RgL2BzZXRgIHBhcmFtZXRlciB0byBpdHMganNpaS1zYWZlIHNoYXBlIC0gbWlycm9yc1xuICogYExpc3RBdHRyaWJ1dGVUeXBlTW9kZWxgL2BTZXRBdHRyaWJ1dGVUeXBlTW9kZWwuaW5wdXRUeXBlRGVmaW5pdGlvbmBcbiAqIChib3RoIGlkZW50aWNhbCkgYnJhbmNoIGZvciBicmFuY2gsIHNpbmNlIGpzaWkgcGFyYW1ldGVycywgbGlrZSByZXNvdXJjZVxuICogaW5wdXRzLCBhcmUgYWxsb3dlZCB0byB1bmlvbiBpbiBhIHdob2xlLWNvbGxlY3Rpb24gYGNka3RuLklSZXNvbHZhYmxlYFxuICogdG9rZW4uIGBraW5kYCBvbmx5IGFmZmVjdHMgdGhlIGRvY3VtZW50YXRpb246IHRoZSBkb2NzdHJpbmcgbm90YXRpb25cbiAqIChgQXJyYXk8Li4uPmAgZm9yIGEgVGVycmFmb3JtIGxpc3QsIGBTZXQ8Li4uPmAgZm9yIGEgVGVycmFmb3JtIHNldCxcbiAqIHJlY3Vyc2l2ZWx5IHZpYSBgcGxhaW5BcnJheUVsZW1lbnRUeXBlYC9gbWFwUGFyYW1ldGVyVHlwZWApIHBsdXMsIGZvclxuICogc2V0cywgYSBwcm9zZSBub3RlIC0gdGhlIGpzaWkgdHlwZSBpcyBhbiBhcnJheSBlaXRoZXIgd2F5LCBzbyB0aGUgbm90ZVxuICoga2VlcHMgYSByZWFkZXIgZnJvbSBsaXRlcmFsbHkgcGFzc2luZyBhIEpTIGBTZXRgIGFuZCBmbGFncyB0aGVcbiAqIG9yZGVyaW5nL2R1cGxpY2F0ZS1lbGVtZW50IHNlbWFudGljcyBkaWZmZXJlbmNlLiBUaGUgdHlwZS1sZXZlbCBoYW5kbGluZ1xuICogaXMgaWRlbnRpY2FsIGZvciBib3RoLlxuICovXG5mdW5jdGlvbiBtYXBMaXN0T3JTZXRQYXJhbWV0ZXJUeXBlKFxuICBraW5kOiBcImxpc3RcIiB8IFwic2V0XCIsXG4gIGVsZW1lbnQ6IEF0dHJpYnV0ZVR5cGUsXG4pOiBNYXBwZWRQYXJhbWV0ZXJUeXBlIHtcbiAgY29uc3Qgd3JhcHBlciA9IGtpbmQgPT09IFwic2V0XCIgPyBcIlNldFwiIDogXCJBcnJheVwiO1xuICBjb25zdCBkb2NzdHJpbmdOb3RlID1cbiAgICBraW5kID09PSBcInNldFwiXG4gICAgICA/IFwiVGVycmFmb3JtIHNldDsgb3JkZXJpbmcgaXMgbm90IGd1YXJhbnRlZWQgYW5kIGR1cGxpY2F0ZSB2YWx1ZXMgYXJlIHJlbW92ZWQuXCJcbiAgICAgIDogdW5kZWZpbmVkO1xuXG4gIGlmIChlbGVtZW50ID09PSBcInN0cmluZ1wiKSB7XG4gICAgLy8gTWlycm9ycyB0aGUgZmluYWwgYGVsc2VgIGJyYW5jaDogZW5jb2RlZCBsaXN0IHRva2VucyBhbHJlYWR5IHNhdGlzZnlcbiAgICAvLyBgc3RyaW5nW11gLCBzbyBubyB1bmlvbiBpcyBuZWVkZWQuXG4gICAgcmV0dXJuIHtcbiAgICAgIHRzVHlwZTogXCJzdHJpbmdbXVwiLFxuICAgICAgZG9jc3RyaW5nVHlwZTogYCR7d3JhcHBlcn08c3RyaW5nPmAsXG4gICAgICBkb2NzdHJpbmdOb3RlLFxuICAgICAgYWNjZXB0c1Jlc29sdmFibGVBbHJlYWR5OiBmYWxzZSxcbiAgICB9O1xuICB9XG4gIGlmIChlbGVtZW50ID09PSBcIm51bWJlclwiKSB7XG4gICAgLy8gU2FtZSByZWFzb25pbmcgYXMgYHN0cmluZ2AgYWJvdmUuXG4gICAgcmV0dXJuIHtcbiAgICAgIHRzVHlwZTogXCJudW1iZXJbXVwiLFxuICAgICAgZG9jc3RyaW5nVHlwZTogYCR7d3JhcHBlcn08bnVtYmVyPmAsXG4gICAgICBkb2NzdHJpbmdOb3RlLFxuICAgICAgYWNjZXB0c1Jlc29sdmFibGVBbHJlYWR5OiBmYWxzZSxcbiAgICB9O1xuICB9XG4gIGlmIChlbGVtZW50ID09PSBcImJvb2xcIikge1xuICAgIC8vIE1pcnJvcnMgdGhlIGBlbGVtZW50VHlwZS5zdG9yZWRDbGFzc1R5cGUgPT09IFwiYm9vbGVhblwiYCBicmFuY2g6IGJvb2xcbiAgICAvLyBoYXMgbm8gbG9zc2xlc3MgcGVyLWVsZW1lbnQgdG9rZW4sIGJ1dCB0aGUgV0hPTEUgY29sbGVjdGlvbiBpcyBzdGlsbFxuICAgIC8vIHRva2VuaXphYmxlLCBzbyB0aGUgdW5pb24gaXMgb24gdGhlIG91dHNpZGUuXG4gICAgcmV0dXJuIHtcbiAgICAgIHRzVHlwZTogXCJBcnJheTxib29sZWFuIHwgY2RrdG4uSVJlc29sdmFibGU+IHwgY2RrdG4uSVJlc29sdmFibGVcIixcbiAgICAgIGRvY3N0cmluZ1R5cGU6IGAke3dyYXBwZXJ9PGJvb2xlYW4gfCBJUmVzb2x2YWJsZT5gLFxuICAgICAgZG9jc3RyaW5nTm90ZSxcbiAgICAgIGFjY2VwdHNSZXNvbHZhYmxlQWxyZWFkeTogdHJ1ZSxcbiAgICB9O1xuICB9XG5cbiAgY29uc3QgcGxhaW5FbGVtZW50ID0gcGxhaW5BcnJheUVsZW1lbnRUeXBlKGVsZW1lbnQpO1xuICBpZiAocGxhaW5FbGVtZW50KSB7XG4gICAgLy8gTWlycm9ycyB0aGUgYGVsZW1lbnRUeXBlLnR5cGVNb2RlbFR5cGUgIT09IFwic2ltcGxlXCJgIGJyYW5jaDogYSBuZXN0ZWRcbiAgICAvLyBsaXN0L3NldCB0aGF0IGl0c2VsZiBib3R0b21zIG91dCBhdCBzdHJpbmcvbnVtYmVyIGNvbXBvc2VzIGludG8gYVxuICAgIC8vIHByb3BlciBuZXN0ZWQgYXJyYXkgdHlwZSAoZS5nLiBgbGlzdChsaXN0KHN0cmluZykpYCAtPiBgc3RyaW5nW11bXWApLFxuICAgIC8vIHdpdGggdGhlIHdob2xlLWNvbGxlY3Rpb24gdG9rZW4gYWRkaXRpb25hbGx5IGFjY2VwdGVkIGFsb25nc2lkZSBpdC5cbiAgICByZXR1cm4ge1xuICAgICAgdHNUeXBlOiBgJHtwbGFpbkVsZW1lbnQudHNUeXBlfVtdIHwgY2RrdG4uSVJlc29sdmFibGVgLFxuICAgICAgZG9jc3RyaW5nVHlwZTogYCR7d3JhcHBlcn08JHtwbGFpbkVsZW1lbnQuZG9jc3RyaW5nVHlwZX0+YCxcbiAgICAgIGRvY3N0cmluZ05vdGUsXG4gICAgICBhY2NlcHRzUmVzb2x2YWJsZUFscmVhZHk6IHRydWUsXG4gICAgfTtcbiAgfVxuXG4gIC8vIG1hcC9vYmplY3QvZHluYW1pYyBlbGVtZW50LCBvciBhIG5lc3RlZCBjb2xsZWN0aW9uIHRoYXQgZG9lc24ndCBpdHNlbGZcbiAgLy8gcmVkdWNlIHRvIHN0cmluZy9udW1iZXI6IG5vIGpzaWktc2FmZSBhcnJheS1vZi1YIHR5cGUgZXhpc3RzIC0gd2lkZW5cbiAgLy8gdGhlIHdob2xlIHBhcmFtZXRlciB0byBgYW55W11gLiBVbmxpa2UgYSBiYXJlIGBhbnlgIHBhcmFtZXRlciwgcGxhaW5cbiAgLy8gYGFueVtdYCBkb2VzIE5PVCBzdHJ1Y3R1cmFsbHkgYWNjZXB0IGEgd2hvbGUtY29sbGVjdGlvblxuICAvLyBgY2RrdG4uSVJlc29sdmFibGVgIHRva2VuLCBzbyB0aGUgdW5pb24gaXMgcmVxdWlyZWQgaGVyZSAodGhpcyBpc1xuICAvLyBzdHJpY3RlciB0aGFuIGBNYXBBdHRyaWJ1dGVUeXBlTW9kZWxgL2BMaXN0QXR0cmlidXRlVHlwZU1vZGVsYCBoYXZlIHRvXG4gIC8vIGJlLCBzaW5jZSB0aG9zZSBvbmx5IGV2ZXIgZmFsbCBiYWNrIHRvIGBhbnlbXSB8IGNka3RuLklSZXNvbHZhYmxlYCB2aWFcbiAgLy8gdGhlIHNhbWUgXCJub3Qgc2ltcGxlXCIgYnJhbmNoIGFib3ZlLCB3aGljaCBhbHJlYWR5IGdyYW50cyBpdCkuIEtlZXAgdGhlXG4gIC8vIGRvY3N0cmluZyBob25lc3QgYWJvdXQgdGhlIHJlYWwgZWxlbWVudCBzaGFwZSByYXRoZXIgdGhhbiBqdXN0IHNheWluZ1xuICAvLyBgYW55YC5cbiAgY29uc3QgZWxlbWVudERlc2NyaXB0aW9uID0gbWFwUGFyYW1ldGVyVHlwZShlbGVtZW50KS5kb2NzdHJpbmdUeXBlO1xuICByZXR1cm4ge1xuICAgIHRzVHlwZTogXCJhbnlbXSB8IGNka3RuLklSZXNvbHZhYmxlXCIsXG4gICAgZG9jc3RyaW5nVHlwZTogYCR7d3JhcHBlcn08JHtlbGVtZW50RGVzY3JpcHRpb259PmAsXG4gICAgZG9jc3RyaW5nTm90ZSxcbiAgICBhY2NlcHRzUmVzb2x2YWJsZUFscmVhZHk6IHRydWUsXG4gIH07XG59XG5cbi8qKlxuICogTWFwcyBhIGBtYXBgIHBhcmFtZXRlciB0byBpdHMganNpaS1zYWZlIHNoYXBlIC0gbWlycm9yc1xuICogYE1hcEF0dHJpYnV0ZVR5cGVNb2RlbC5pbnB1dFR5cGVEZWZpbml0aW9uYC4gT25seSB0aGUgYGJvb2xgLWVsZW1lbnQgY2FzZVxuICogaXMgcmVhY2hhYmxlIGZyb20gcmVhbCBwcm92aWRlciBzY2hlbWFzIHRvZGF5IChgc3RyaW5nYC9gbnVtYmVyYCBlbGVtZW50XG4gKiBtYXBzIHN0YXkgYSBwbGFpbiwgbm9uLXVuaW9uIHJlY29yZDsgbmVzdGVkL2NvbXBsZXggbWFwIGVsZW1lbnRzIGFyZW4ndFxuICogZW1pdHRlZCBmb3IgcHJvdmlkZXIgZnVuY3Rpb25zIC0gc2VlIHRoZSBgb2JqZWN0YCBmYWxsYmFjayBpblxuICogYG1hcFBhcmFtZXRlclR5cGVgKSwgYnV0IHRoZSBzaGFwZSBpcyBrZXB0IGJyYW5jaC1mb3ItYnJhbmNoIGFsaWduZWQgd2l0aFxuICogdGhlIG1vZGVsIGl0IG1pcnJvcnMgcmF0aGVyIHRoYW4gY29sbGFwc2VkLlxuICovXG5mdW5jdGlvbiBtYXBNYXBQYXJhbWV0ZXJUeXBlKGVsZW1lbnQ6IEF0dHJpYnV0ZVR5cGUpOiBNYXBwZWRQYXJhbWV0ZXJUeXBlIHtcbiAgaWYgKGVsZW1lbnQgPT09IFwic3RyaW5nXCIpIHtcbiAgICByZXR1cm4ge1xuICAgICAgdHNUeXBlOiBcInsgW2tleTogc3RyaW5nXTogc3RyaW5nIH1cIixcbiAgICAgIGRvY3N0cmluZ1R5cGU6IFwieyBba2V5OiBzdHJpbmddOiBzdHJpbmcgfVwiLFxuICAgICAgYWNjZXB0c1Jlc29sdmFibGVBbHJlYWR5OiBmYWxzZSxcbiAgICB9O1xuICB9XG4gIGlmIChlbGVtZW50ID09PSBcIm51bWJlclwiKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHRzVHlwZTogXCJ7IFtrZXk6IHN0cmluZ106IG51bWJlciB9XCIsXG4gICAgICBkb2NzdHJpbmdUeXBlOiBcInsgW2tleTogc3RyaW5nXTogbnVtYmVyIH1cIixcbiAgICAgIGFjY2VwdHNSZXNvbHZhYmxlQWxyZWFkeTogZmFsc2UsXG4gICAgfTtcbiAgfVxuICBpZiAoZWxlbWVudCA9PT0gXCJib29sXCIpIHtcbiAgICAvLyBNaXJyb3JzIHRoZSBgZWxlbWVudFR5cGUuc3RvcmVkQ2xhc3NUeXBlID09PSBcImJvb2xlYW5cImAgYnJhbmNoOiBtYXBcbiAgICAvLyBvZiBib29sZWFucyBoYXMgUEVSLUVOVFJZIHRva2VuIHN1cHBvcnQsIGJ1dCB0aGUgd2hvbGUgbWFwIGl0c2VsZiBpc1xuICAgIC8vIG5vdCBhZGRpdGlvbmFsbHkgdW5pb25lZCB3aXRoIGBjZGt0bi5JUmVzb2x2YWJsZWAgKHVubGlrZSB0aGUgbGlzdC9zZXRcbiAgICAvLyBjYXNlKSAtIG1hdGNoaW5nIGBNYXBBdHRyaWJ1dGVUeXBlTW9kZWwuaW5wdXRUeXBlRGVmaW5pdGlvbmAgZXhhY3RseS5cbiAgICByZXR1cm4ge1xuICAgICAgdHNUeXBlOiBcInsgW2tleTogc3RyaW5nXTogKGJvb2xlYW4gfCBjZGt0bi5JUmVzb2x2YWJsZSkgfVwiLFxuICAgICAgZG9jc3RyaW5nVHlwZTogXCJ7IFtrZXk6IHN0cmluZ106IChib29sZWFuIHwgSVJlc29sdmFibGUpIH1cIixcbiAgICAgIGFjY2VwdHNSZXNvbHZhYmxlQWxyZWFkeTogZmFsc2UsXG4gICAgfTtcbiAgfVxuICAvLyBtYXAvb2JqZWN0L2R5bmFtaWMgZWxlbWVudDogbm8gc3RydWN0dXJhbCBpbnB1dCBoZWxwZXIgZXhpc3RzIGhlcmUgLVxuICAvLyBzdGF5cyBgYW55YCwgd2hpY2ggKGJlaW5nIGBhbnlgKSBhbHJlYWR5IGFjY2VwdHMgYSB3aG9sZS1tYXBcbiAgLy8gYGNka3RuLklSZXNvbHZhYmxlYCB0b2tlbiB0b28uXG4gIHJldHVybiB7XG4gICAgdHNUeXBlOiBcImFueVwiLFxuICAgIGRvY3N0cmluZ1R5cGU6IFwiYW55XCIsXG4gICAgYWNjZXB0c1Jlc29sdmFibGVBbHJlYWR5OiB0cnVlLFxuICB9O1xufVxuXG4vKipcbiAqIE1hcHMgYSBwcm92aWRlciBmdW5jdGlvbiBwYXJhbWV0ZXIncyBkZWNsYXJlZCBUZXJyYWZvcm0gdHlwZSB0byBhXG4gKiBqc2lpLXNhZmUgVHlwZVNjcmlwdCBwYXJhbWV0ZXIgdHlwZSwgcmVjdXJzaXZlbHkgZm9yIGNvbGxlY3Rpb24gdHlwZXMuXG4gKlxuICogVW5saWtlIHJldHVybiB0eXBlcywganNpaSBhbGxvd3MgdW5pb25zIGluICpwYXJhbWV0ZXIqIHBvc2l0aW9uLCBzb1xuICogYGJvb2xgIGlzIHR5cGVkIGBib29sZWFuIHwgY2RrdG4uSVJlc29sdmFibGVgIChtaXJyb3JpbmdcbiAqIGBTaW1wbGVBdHRyaWJ1dGVUeXBlTW9kZWwuaW5wdXRUeXBlRGVmaW5pdGlvbmAncyBpbnB1dC1zaWRlIGNvbnZlbnRpb24pIC1cbiAqIHRoaXMgYm90aCBhY2NlcHRzIGEgcmVhbCBib29sZWFuIGFuZCBzdGlsbCBhY2NlcHRzIGEgdG9rZW4gaW4gcGxhY2Ugb2ZcbiAqIG9uZS4gYGR5bmFtaWNgIGhhcyBubyBzdHJ1Y3R1cmFsIHR5cGluZyBhbmQgc3RheXMgYGFueWAgKHdoaWNoIGFscmVhZHlcbiAqIGFjY2VwdHMgYW55dGhpbmcsIGluY2x1ZGluZyBhIHRva2VuKTsgYG9iamVjdGAgKHN0cnVjdHVyYWwgaW5wdXQgaGVscGVyc1xuICogYXJlIGRlZmVycmVkIHRvIGEgZm9sbG93LXVwIGlzc3VlKSBzdGF5cyBgYW55YCB0b28uXG4gKlxuICogYGxpc3RgL2BzZXRgIGFuZCBgbWFwYCBkZWxlZ2F0ZSB0byBgbWFwTGlzdE9yU2V0UGFyYW1ldGVyVHlwZWAvXG4gKiBgbWFwTWFwUGFyYW1ldGVyVHlwZWAsIHdoaWNoIG1pcnJvciBgTGlzdEF0dHJpYnV0ZVR5cGVNb2RlbGAvXG4gKiBgU2V0QXR0cmlidXRlVHlwZU1vZGVsYC9gTWFwQXR0cmlidXRlVHlwZU1vZGVsLmlucHV0VHlwZURlZmluaXRpb25gXG4gKiBicmFuY2ggZm9yIGJyYW5jaCAoc2VlIGBhdHRyaWJ1dGUtdHlwZS1tb2RlbC50c2ApIC0gdGhlIHNhbWVcbiAqIHdob2xlLWNvbGxlY3Rpb24tdG9rZW4gY29udmVudGlvbnMgYWxyZWFkeSB1c2VkIGZvciByZXNvdXJjZSBpbnB1dHMuXG4gKi9cbmZ1bmN0aW9uIG1hcFBhcmFtZXRlclR5cGUodHlwZTogQXR0cmlidXRlVHlwZSk6IE1hcHBlZFBhcmFtZXRlclR5cGUge1xuICBpZiAodHlwZSA9PT0gXCJzdHJpbmdcIikge1xuICAgIHJldHVybiB7XG4gICAgICB0c1R5cGU6IFwic3RyaW5nXCIsXG4gICAgICBkb2NzdHJpbmdUeXBlOiBcInN0cmluZ1wiLFxuICAgICAgYWNjZXB0c1Jlc29sdmFibGVBbHJlYWR5OiBmYWxzZSxcbiAgICB9O1xuICB9XG4gIGlmICh0eXBlID09PSBcIm51bWJlclwiKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHRzVHlwZTogXCJudW1iZXJcIixcbiAgICAgIGRvY3N0cmluZ1R5cGU6IFwibnVtYmVyXCIsXG4gICAgICBhY2NlcHRzUmVzb2x2YWJsZUFscmVhZHk6IGZhbHNlLFxuICAgIH07XG4gIH1cbiAgaWYgKHR5cGUgPT09IFwiYm9vbFwiKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHRzVHlwZTogXCJib29sZWFuIHwgY2RrdG4uSVJlc29sdmFibGVcIixcbiAgICAgIGRvY3N0cmluZ1R5cGU6IFwiYm9vbGVhbiB8IElSZXNvbHZhYmxlXCIsXG4gICAgICBhY2NlcHRzUmVzb2x2YWJsZUFscmVhZHk6IHRydWUsXG4gICAgfTtcbiAgfVxuICBpZiAodHlwZSA9PT0gXCJkeW5hbWljXCIpIHtcbiAgICByZXR1cm4ge1xuICAgICAgdHNUeXBlOiBcImFueVwiLFxuICAgICAgZG9jc3RyaW5nVHlwZTogXCJhbnlcIixcbiAgICAgIGFjY2VwdHNSZXNvbHZhYmxlQWxyZWFkeTogdHJ1ZSxcbiAgICB9O1xuICB9XG5cbiAgaWYgKEFycmF5LmlzQXJyYXkodHlwZSkgJiYgKHR5cGVbMF0gPT09IFwibGlzdFwiIHx8IHR5cGVbMF0gPT09IFwic2V0XCIpKSB7XG4gICAgcmV0dXJuIG1hcExpc3RPclNldFBhcmFtZXRlclR5cGUodHlwZVswXSwgdHlwZVsxXSk7XG4gIH1cblxuICBpZiAoQXJyYXkuaXNBcnJheSh0eXBlKSAmJiB0eXBlWzBdID09PSBcIm1hcFwiKSB7XG4gICAgcmV0dXJuIG1hcE1hcFBhcmFtZXRlclR5cGUodHlwZVsxXSk7XG4gIH1cblxuICAvLyBvYmplY3Q6IHN0cnVjdHVyYWwgaW5wdXQgaGVscGVycyBhcmUgZGVmZXJyZWQgdG8gYSBmb2xsb3ctdXAgaXNzdWUuXG4gIHJldHVybiB7XG4gICAgdHNUeXBlOiBcImFueVwiLFxuICAgIGRvY3N0cmluZ1R5cGU6IFwib2JqZWN0XCIsXG4gICAgYWNjZXB0c1Jlc29sdmFibGVBbHJlYWR5OiB0cnVlLFxuICB9O1xufVxuXG5mdW5jdGlvbiBidWlsZFBhcmFtZXRlck1vZGVsKFxuICBwYXJhbWV0ZXI6IEZ1bmN0aW9uUGFyYW1ldGVyLFxuICBmYWxsYmFja05hbWU6IHN0cmluZyxcbik6IEludGVybmFsUGFyYW1ldGVyTW9kZWwge1xuICBjb25zdCB0ZXJyYWZvcm1OYW1lID0gcGFyYW1ldGVyLm5hbWUgPz8gZmFsbGJhY2tOYW1lO1xuICBjb25zdCB7IHRzVHlwZSwgZG9jc3RyaW5nVHlwZSwgZG9jc3RyaW5nTm90ZSwgYWNjZXB0c1Jlc29sdmFibGVBbHJlYWR5IH0gPVxuICAgIG1hcFBhcmFtZXRlclR5cGUocGFyYW1ldGVyLnR5cGUpO1xuICByZXR1cm4ge1xuICAgIHRlcnJhZm9ybU5hbWUsXG4gICAgbmFtZTogc2FuaXRpemVQYXJhbWV0ZXJOYW1lKHRlcnJhZm9ybU5hbWUpLFxuICAgIHRzVHlwZSxcbiAgICBkb2NzdHJpbmdUeXBlLFxuICAgIGRvY3N0cmluZ05vdGUsXG4gICAgZGVzY3JpcHRpb246IHBhcmFtZXRlci5kZXNjcmlwdGlvbixcbiAgICBhY2NlcHRzUmVzb2x2YWJsZUFscmVhZHksXG4gIH07XG59XG5cbi8qKlxuICogV2lkZW5zIGEgbWFwcGVkIHR5cGUncyBgdHNUeXBlYC9gZG9jc3RyaW5nVHlwZWAgdG8gYWxzbyBhY2NlcHQgYW5cbiAqIGV4cGxpY2l0IGBjZGt0bi5Ub2tlbi5udWxsVmFsdWUoKWAgaW4gdGhpcyBwb3NpdGlvbiAtIHVubGVzc1xuICogYGFjY2VwdHNSZXNvbHZhYmxlQWxyZWFkeWAgc2F5cyBpdCBhbHJlYWR5IGRvZXMgKGUuZy4gYSBgYm9vbGAgcGFyYW1ldGVyXG4gKiBpcyBhbHJlYWR5IGBib29sZWFuIHwgY2RrdG4uSVJlc29sdmFibGVgLCBzbyBudWxsYWJpbGl0eSBhZGRzIG5vdGhpbmcgdG9cbiAqIHRoZSB0eXBlIGl0c2VsZiwgb25seSB0byB0aGUgZG9jc3RyaW5nIG5vdGUgYXBwZW5kZWQgYnkgdGhlIGNhbGxlcikuXG4gKi9cbmZ1bmN0aW9uIHdpdGhOdWxsYWJsZVJlc29sdmFibGVVbmlvbihcbiAgbW9kZWw6IFBpY2s8XG4gICAgSW50ZXJuYWxQYXJhbWV0ZXJNb2RlbCxcbiAgICBcInRzVHlwZVwiIHwgXCJkb2NzdHJpbmdUeXBlXCIgfCBcImFjY2VwdHNSZXNvbHZhYmxlQWxyZWFkeVwiXG4gID4sXG4pOiB7IHRzVHlwZTogc3RyaW5nOyBkb2NzdHJpbmdUeXBlOiBzdHJpbmcgfSB7XG4gIGlmIChtb2RlbC5hY2NlcHRzUmVzb2x2YWJsZUFscmVhZHkpIHtcbiAgICByZXR1cm4geyB0c1R5cGU6IG1vZGVsLnRzVHlwZSwgZG9jc3RyaW5nVHlwZTogbW9kZWwuZG9jc3RyaW5nVHlwZSB9O1xuICB9XG4gIHJldHVybiB7XG4gICAgdHNUeXBlOiBgJHttb2RlbC50c1R5cGV9IHwgY2RrdG4uSVJlc29sdmFibGVgLFxuICAgIGRvY3N0cmluZ1R5cGU6IGAke21vZGVsLmRvY3N0cmluZ1R5cGV9IHwgSVJlc29sdmFibGVgLFxuICB9O1xufVxuXG4vKipcbiAqIEFwcGxpZXMgYGlzX251bGxhYmxlYCB0cmFpbGluZy1jb21wYXRpYmlsaXR5IHJ1bGVzIGFjcm9zcyBhIGZ1bmN0aW9uJ3NcbiAqIGZpeGVkIChub24tdmFyaWFkaWMpIHBhcmFtZXRlciBsaXN0LiBUaGlzIG5lZWRzIHRoZSB3aG9sZSBsaXN0IGluIHZpZXdcbiAqIChzZWUgYGJ1aWxkRnVuY3Rpb25Nb2RlbGApLCBzaW5jZSB3aGV0aGVyIGEgbnVsbGFibGUgcGFyYW1ldGVyIGNhbiBiZWNvbWVcbiAqIGpzaWktb3B0aW9uYWwgZGVwZW5kcyBvbiBldmVyeSBwYXJhbWV0ZXIgKmFmdGVyKiBpdCB0b286XG4gKlxuICogLSBBIG51bGxhYmxlIHBhcmFtZXRlciB3aGVyZSBpdCBhbmQgZXZlcnkgbGF0ZXIgZml4ZWQgcGFyYW1ldGVyIGFyZSBhbHNvXG4gKiAgIG51bGxhYmxlIGJlY29tZXMganNpaS1vcHRpb25hbCAoYG5hbWU/OiBUYCk6IG9taXR0aW5nIGl0IGluIFR5cGVTY3JpcHRcbiAqICAgbGVhdmVzIGB1bmRlZmluZWRgIGluIHRoZSBpbnZva2UgYXJncyBhcnJheSwgd2hpY2ggYEZ1bmN0aW9uQ2FsbGBcbiAqICAgYWxyZWFkeSByZW5kZXJzIGFzIHRoZSBUZXJyYWZvcm0gYG51bGxgIGtleXdvcmQuIEl0IGFkZGl0aW9uYWxseSBnYWluc1xuICogICB0aGUgYHwgY2RrdG4uSVJlc29sdmFibGVgIHVuaW9uIChzZWUgYHdpdGhOdWxsYWJsZVJlc29sdmFibGVVbmlvbmApLCBzb1xuICogICBhIGNhbGxlciB3aG8gZG9lcyBzdXBwbHkgdGhlIGFyZ3VtZW50IGNhbiBwYXNzXG4gKiAgIGBjZGt0bi5Ub2tlbi5udWxsVmFsdWUoKWAgZm9yIGFuIGV4cGxpY2l0IFRlcnJhZm9ybSBgbnVsbGAgd2l0aG91dFxuICogICBvbWl0dGluZyB0aGUgcGFyYW1ldGVyLlxuICogLSBBIG51bGxhYmxlIHBhcmFtZXRlciBmb2xsb3dlZCBieSBhIHJlcXVpcmVkIG9uZSBrZWVwcyBpdHMgcG9zaXRpb25cbiAqICAgKGpzaWkgY2FuJ3QgZXhwcmVzcyBcIm9wdGlvbmFsIGJ1dCBub3QgdHJhaWxpbmdcIiksIGFuZCBpbnN0ZWFkIGdhaW5zIHRoZVxuICogICBzYW1lIGB8IGNka3RuLklSZXNvbHZhYmxlYCB1bmlvbiBzbyBhIGNhbGxlciBjYW4gc3RpbGwgcGFzcyBhbiBleHBsaWNpdFxuICogICBgY2RrdG4uVG9rZW4ubnVsbFZhbHVlKClgIChhbiBgSVJlc29sdmFibGVgIHJlc29sdmluZyB0byBgbnVsbGAgLSBzZWVcbiAqICAgYFRva2VuLm51bGxWYWx1ZSgpYC9gVG9rZW4uYXNBbnkoKWApIGluIHRoYXQgZml4ZWQgcG9zaXRpb24gLSBrZWVwaW5nXG4gKiAgIHRoZSBwYXJhbWV0ZXIncyByZWFsIHR5cGUgcmF0aGVyIHRoYW4gZ2l2aW5nIHVwIGFsbCB0eXBlIHNhZmV0eSBieVxuICogICB3aWRlbmluZyBpdCB0byBgYW55YC5cbiAqXG4gKiBCb3RoIGNhc2VzIGRvY3VtZW50IHRoZSByZWFsIG1lY2hhbmlzbSBpbiB0aGUgZG9jc3RyaW5nIG5vdGUgcmF0aGVyIHRoYW5cbiAqIGltcGx5aW5nIHRoZSBwbGFpbiBUeXBlU2NyaXB0IGBudWxsYCBsaXRlcmFsIGlzIGFjY2VwdGVkOiB0aGUgdHJhaWxpbmdcbiAqIGNhc2UgY2FuIGFsc28ganVzdCBiZSBvbWl0dGVkLCB0aGUgbWlkLXBvc2l0aW9uIGNhc2UgY2FuJ3QgYmUgb21pdHRlZCBhdFxuICogYWxsIChqc2lpIGNhbid0IGV4cHJlc3MgXCJvcHRpb25hbCBidXQgbm90IHRyYWlsaW5nXCIpLlxuICovXG5mdW5jdGlvbiBhcHBseU51bGxhYmlsaXR5KFxuICBwYXJhbWV0ZXJzOiBGdW5jdGlvblBhcmFtZXRlcltdLFxuICBtb2RlbHM6IEludGVybmFsUGFyYW1ldGVyTW9kZWxbXSxcbik6IEludGVybmFsUGFyYW1ldGVyTW9kZWxbXSB7XG4gIGNvbnN0IHRyYWlsaW5nQ29tcGF0aWJsZSA9IG5ldyBBcnJheShwYXJhbWV0ZXJzLmxlbmd0aCkuZmlsbChmYWxzZSk7XG4gIGxldCBhbGxOdWxsYWJsZVNvRmFyID0gdHJ1ZTtcbiAgZm9yIChsZXQgaSA9IHBhcmFtZXRlcnMubGVuZ3RoIC0gMTsgaSA+PSAwOyBpLS0pIHtcbiAgICBhbGxOdWxsYWJsZVNvRmFyID0gYWxsTnVsbGFibGVTb0ZhciAmJiBwYXJhbWV0ZXJzW2ldLmlzX251bGxhYmxlID09PSB0cnVlO1xuICAgIHRyYWlsaW5nQ29tcGF0aWJsZVtpXSA9IGFsbE51bGxhYmxlU29GYXI7XG4gIH1cblxuICByZXR1cm4gbW9kZWxzLm1hcCgobW9kZWwsIGluZGV4KSA9PiB7XG4gICAgY29uc3QgcGFyYW1ldGVyID0gcGFyYW1ldGVyc1tpbmRleF07XG4gICAgaWYgKCFwYXJhbWV0ZXIuaXNfbnVsbGFibGUpIHJldHVybiBtb2RlbDtcblxuICAgIGNvbnN0IHsgdHNUeXBlLCBkb2NzdHJpbmdUeXBlIH0gPSB3aXRoTnVsbGFibGVSZXNvbHZhYmxlVW5pb24obW9kZWwpO1xuICAgIGNvbnN0IG51bGxhYmlsaXR5Tm90ZSA9IHRyYWlsaW5nQ29tcGF0aWJsZVtpbmRleF1cbiAgICAgID8gXCJPbWl0IG9yIHBhc3MgY2RrdG4uVG9rZW4ubnVsbFZhbHVlKCkgdG8gcmVuZGVyIHRoZSBUZXJyYWZvcm0gbnVsbCBrZXl3b3JkLlwiXG4gICAgICA6IFwiUGFzcyBjZGt0bi5Ub2tlbi5udWxsVmFsdWUoKSBmb3IgYW4gZXhwbGljaXQgVGVycmFmb3JtIG51bGwuXCI7XG5cbiAgICByZXR1cm4ge1xuICAgICAgLi4ubW9kZWwsXG4gICAgICAuLi4odHJhaWxpbmdDb21wYXRpYmxlW2luZGV4XSA/IHsgb3B0aW9uYWw6IHRydWUgfSA6IHt9KSxcbiAgICAgIHRzVHlwZSxcbiAgICAgIGRvY3N0cmluZ1R5cGUsXG4gICAgICBkb2NzdHJpbmdOb3RlOiBbbW9kZWwuZG9jc3RyaW5nTm90ZSwgbnVsbGFiaWxpdHlOb3RlXVxuICAgICAgICAuZmlsdGVyKEJvb2xlYW4pXG4gICAgICAgIC5qb2luKFwiIFwiKSxcbiAgICB9O1xuICB9KTtcbn1cblxuLyoqXG4gKiBNYXBzIGEgcHJvdmlkZXIgZnVuY3Rpb24ncyBkZWNsYXJlZCByZXR1cm4gdHlwZSB0byB0aGUganNpaS1zYWZlXG4gKiBUeXBlU2NyaXB0IHJldHVybiB0eXBlLCB0aGUgYEByZXR1cm5zYCBKU0RvYyB0eXBlLCBhbmQgdGhlIGV4cHJlc3Npb25cbiAqIHRoYXQgdW53cmFwcyB0aGUgYFRlcnJhZm9ybVByb3ZpZGVyRnVuY3Rpb24uaW52b2tlKC4uLilgIGBJUmVzb2x2YWJsZWBcbiAqIGludG8gaXQuXG4gKlxuICoganNpaSByZXR1cm4gcG9zaXRpb25zIGNhbid0IHVzZSB0aGUgYFQgfCBjZGt0bi5JUmVzb2x2YWJsZWAgdW5pb24gdGhhdFxuICogcGFyYW1ldGVycyBjYW4gKHNlZSBgbWFwUGFyYW1ldGVyVHlwZWApLCBzbyBldmVyeSBzaGFwZSB0aGF0IGNhbid0IGJlXG4gKiBsb3NzbGVzc2x5IHVud3JhcHBlZCB0aHJvdWdoIGFuIGBhc1h4eGAgVG9rZW4gaGVscGVyIGZhbGxzIGJhY2sgdG8gdGhlXG4gKiBwbGFpbiBgY2RrdG4uSVJlc29sdmFibGVgIHByb2R1Y2VkIGJ5IGBpbnZva2UoKWAgaXRzZWxmLCB1bndyYXBwZWQuXG4gKiBQcm92aWRlciBmdW5jdGlvbnMgZnJlcXVlbnRseSByZXR1cm4gb2JqZWN0cyAoZS5nLiBldmVyeSBmdW5jdGlvbiBpbiB0aGVcbiAqIGB0aW1lYCBwcm92aWRlciksIHNvIC0gdW5saWtlIGJ1aWx0LWluIGBGbi4qYCBmdW5jdGlvbnMgLSB0aGUgb2JqZWN0IGNhc2VcbiAqIGlzIGEgcHJpbWFyeSBwYXRoLCBub3QgYW4gZXJyb3I6IGl0IGlzIHRyZWF0ZWQgdGhlIHNhbWUgYXNcbiAqIGBkeW5hbWljYC9hIGBsaXN0YC9gc2V0YCBvZiBhbnl0aGluZyBvdGhlciB0aGFuIGBzdHJpbmdgL2BudW1iZXJgIChub1xuICogYGFzQW55TGlzdGAgVG9rZW4gaGVscGVyIGV4aXN0cyksIGFuZCByZXR1cm5lZCBhcyB0aGUgUkFXIGBpbnZva2UoKWBcbiAqIHJlc3VsdC4gYG1hcGAgcmV0dXJucywgdW5saWtlIHRob3NlLCBETyBoYXZlIGEgZnVsbCBzZXQgb2YgdHlwZWQgVG9rZW5cbiAqIGhlbHBlcnMgKGBhc1N0cmluZ01hcGAvYGFzTnVtYmVyTWFwYC9gYXNCb29sZWFuTWFwYC9gYXNBbnlNYXBgKSwgc28gZXZlcnlcbiAqIGBtYXBgIHNoYXBlIGdldHMgYW4gYWN0dWFsIHR5cGVkIHJlY29yZCByZXR1cm4gaW5zdGVhZCBvZiBmYWxsaW5nIGJhY2sgdG9cbiAqIGBjZGt0bi5JUmVzb2x2YWJsZWAuXG4gKlxuICogV2hlbmV2ZXIgdGhlIGRlY2xhcmVkIHJldHVybiB0eXBlIElTIGBjZGt0bi5JUmVzb2x2YWJsZWAgKG5vdCBgYW55YCk6XG4gKiB1bmxpa2UgYGhlbHBlcnMudHNgIGBhc0FueWAsIHRoaXMgbXVzdCBOT1QgZ28gdGhyb3VnaFxuICogYGNka3RuLlRva2VuLmFzU3RyaW5nKC4uLilgIC0gYFRva2VuLmFzU3RyaW5nKClgIHByb2R1Y2VzIGFuIGVuY29kZWRcbiAqIHN0cmluZyB0b2tlbiB0aGF0IGBUb2tlbml6YXRpb24uaXNSZXNvbHZhYmxlKClgIGRvZXMgbm90IHJlY29nbml6ZSwgc29cbiAqIGdlbmVyYXRlZCBzdHJ1Y3Qgc2V0dGVycyAoZS5nLiBhbiBgT3V0cHV0UmVmZXJlbmNlYCBgaW50ZXJuYWxWYWx1ZWApIHRyZWF0XG4gKiBpdCBhcyBhIHBsYWluIG9iamVjdCB3aXRoIG5vIGtub3duIGtleXMgYW5kIHRoZSBhdHRyaWJ1dGUgc2lsZW50bHlcbiAqIHZhbmlzaGVzIGZyb20gc3ludGggb3V0cHV0LiBUaGUgcmF3IGBJUmVzb2x2YWJsZWAgZnJvbSBgaW52b2tlKClgIElTXG4gKiByZWNvZ25pemVkIGJ5IGBUb2tlbml6YXRpb24uaXNSZXNvbHZhYmxlKClgIGFuZCByZXNvbHZlcyBjb3JyZWN0bHkuXG4gKiBEZWNsYXJpbmcgaXQgYXMgYGNka3RuLklSZXNvbHZhYmxlYCBpbnN0ZWFkIG9mIGBhbnlgIGFsc28gZ2l2ZXMgY2FsbGVyc1xuICogcmVhbCB0eXBlIHNhZmV0eTogYGFueWAgbGV0IGEgY2FsbGVyIHdyaXRlIGByZXN1bHQuaG91cnNgIG9uIGEgdG9rZW4gd2l0aFxuICogbm8gY29tcGlsZS10aW1lIGZlZWRiYWNrLCBzaWxlbnRseSBwcm9kdWNpbmcgYHVuZGVmaW5lZGAgYXQgcnVudGltZTtcbiAqIGBJUmVzb2x2YWJsZWAgaGFzIG5vIHN1Y2ggcHJvcGVydHkgYW5kIGZvcmNlcyB0aGUgY2FsbGVyIHRocm91Z2hcbiAqIGBjZGt0bi5Ub2tlbmAvdGhlIHByb3ZpZGVyJ3Mgc3RydWN0IHR5cGVzIGluc3RlYWQuIGBpbnZva2UoKWAgYWxyZWFkeVxuICogcmV0dXJucyBgSVJlc29sdmFibGVgLCBzbyBubyBjYXN0IGlzIG5lZWRlZCB0byByZXR1cm4gaXQgYXNcbiAqIGBjZGt0bi5JUmVzb2x2YWJsZWAuXG4gKi9cbmZ1bmN0aW9uIG1hcFJldHVyblR5cGUocmV0dXJuVHlwZTogQXR0cmlidXRlVHlwZSk6IHtcbiAgdHNUeXBlOiBzdHJpbmc7XG4gIGRvY3N0cmluZ1R5cGU6IHN0cmluZztcbiAgZG9jc3RyaW5nTm90ZT86IHN0cmluZztcbiAgd3JhcFJldHVybjogKGludm9rZUV4cHJlc3Npb246IHN0cmluZykgPT4gc3RyaW5nO1xufSB7XG4gIGlmIChyZXR1cm5UeXBlID09PSBcInN0cmluZ1wiKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHRzVHlwZTogXCJzdHJpbmdcIixcbiAgICAgIGRvY3N0cmluZ1R5cGU6IFwic3RyaW5nXCIsXG4gICAgICB3cmFwUmV0dXJuOiAoZXhwcikgPT4gYGNka3RuLlRva2VuLmFzU3RyaW5nKCR7ZXhwcn0pYCxcbiAgICB9O1xuICB9XG4gIGlmIChyZXR1cm5UeXBlID09PSBcIm51bWJlclwiKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHRzVHlwZTogXCJudW1iZXJcIixcbiAgICAgIGRvY3N0cmluZ1R5cGU6IFwibnVtYmVyXCIsXG4gICAgICB3cmFwUmV0dXJuOiAoZXhwcikgPT4gYGNka3RuLlRva2VuLmFzTnVtYmVyKCR7ZXhwcn0pYCxcbiAgICB9O1xuICB9XG4gIGlmIChyZXR1cm5UeXBlID09PSBcImJvb2xcIikge1xuICAgIC8vIEJvb2xlYW5zIGNhbid0IGJlIHJlcHJlc2VudGVkIGFzIHRva2VucyAoc2VlIGhlbHBlcnMudHMgYXNCb29sZWFuKTpcbiAgICAvLyByZXR1cm4gdGhlIElSZXNvbHZhYmxlIHByb2R1Y2VkIGJ5IGludm9rZSgpIHVud3JhcHBlZC4gVGhlIGRvY3N0cmluZ1xuICAgIC8vIHN0aWxsIGRvY3VtZW50cyB0aGUgcmVhbCBjb25jZXB0dWFsIHNoYXBlLlxuICAgIHJldHVybiB7XG4gICAgICB0c1R5cGU6IFwiY2RrdG4uSVJlc29sdmFibGVcIixcbiAgICAgIGRvY3N0cmluZ1R5cGU6IFwiYm9vbGVhbiB8IElSZXNvbHZhYmxlXCIsXG4gICAgICB3cmFwUmV0dXJuOiAoZXhwcikgPT4gZXhwcixcbiAgICB9O1xuICB9XG4gIGlmIChyZXR1cm5UeXBlID09PSBcImR5bmFtaWNcIikge1xuICAgIHJldHVybiB7XG4gICAgICB0c1R5cGU6IFwiY2RrdG4uSVJlc29sdmFibGVcIixcbiAgICAgIGRvY3N0cmluZ1R5cGU6IFwiYW55XCIsXG4gICAgICB3cmFwUmV0dXJuOiAoZXhwcikgPT4gZXhwcixcbiAgICB9O1xuICB9XG4gIGlmIChcbiAgICBBcnJheS5pc0FycmF5KHJldHVyblR5cGUpICYmXG4gICAgKHJldHVyblR5cGVbMF0gPT09IFwibGlzdFwiIHx8IHJldHVyblR5cGVbMF0gPT09IFwic2V0XCIpXG4gICkge1xuICAgIC8vIFNhbWUgZG9jdW1lbnRhdGlvbiBjb252ZW50aW9ucyBhcyBgbWFwTGlzdE9yU2V0UGFyYW1ldGVyVHlwZWA6IHRoZVxuICAgIC8vIG5vdGF0aW9uIChgQXJyYXk8Li4uPmAvYFNldDwuLi4+YCkgY2FycmllcyB0aGUgVGVycmFmb3JtIGNvbGxlY3Rpb25cbiAgICAvLyBzdHJ1Y3R1cmUgcmVjdXJzaXZlbHksIGFuZCBvbmx5IHNldHMgZ2V0IGEgcHJvc2Ugbm90ZS5cbiAgICBjb25zdCB3cmFwcGVyID0gcmV0dXJuVHlwZVswXSA9PT0gXCJzZXRcIiA/IFwiU2V0XCIgOiBcIkFycmF5XCI7XG4gICAgY29uc3QgZG9jc3RyaW5nTm90ZSA9XG4gICAgICByZXR1cm5UeXBlWzBdID09PSBcInNldFwiXG4gICAgICAgID8gXCJUZXJyYWZvcm0gc2V0OyBvcmRlcmluZyBpcyBub3QgZ3VhcmFudGVlZCBhbmQgZHVwbGljYXRlIHZhbHVlcyBhcmUgcmVtb3ZlZC5cIlxuICAgICAgICA6IHVuZGVmaW5lZDtcbiAgICBjb25zdCBlbGVtZW50ID0gcmV0dXJuVHlwZVsxXTtcbiAgICBpZiAoZWxlbWVudCA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgdHNUeXBlOiBcInN0cmluZ1tdXCIsXG4gICAgICAgIGRvY3N0cmluZ1R5cGU6IGAke3dyYXBwZXJ9PHN0cmluZz5gLFxuICAgICAgICBkb2NzdHJpbmdOb3RlLFxuICAgICAgICB3cmFwUmV0dXJuOiAoZXhwcikgPT4gYGNka3RuLlRva2VuLmFzTGlzdCgke2V4cHJ9KWAsXG4gICAgICB9O1xuICAgIH1cbiAgICBpZiAoZWxlbWVudCA9PT0gXCJudW1iZXJcIikge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgdHNUeXBlOiBcIm51bWJlcltdXCIsXG4gICAgICAgIGRvY3N0cmluZ1R5cGU6IGAke3dyYXBwZXJ9PG51bWJlcj5gLFxuICAgICAgICBkb2NzdHJpbmdOb3RlLFxuICAgICAgICB3cmFwUmV0dXJuOiAoZXhwcikgPT4gYGNka3RuLlRva2VuLmFzTnVtYmVyTGlzdCgke2V4cHJ9KWAsXG4gICAgICB9O1xuICAgIH1cbiAgICAvLyBsaXN0L3NldCBvZiBhbnl0aGluZyBlbHNlOiB0aGVyZSBpcyBubyBgYXNBbnlMaXN0YCBUb2tlbiBoZWxwZXIgLVxuICAgIC8vIGZhbGwgYmFjayB0byB0aGUgcmF3IElSZXNvbHZhYmxlLCBzYW1lIHJlYXNvbmluZyBhcyBkeW5hbWljL29iamVjdFxuICAgIC8vIGJlbG93LCBidXQga2VlcCB0aGUgZG9jc3RyaW5nIGhvbmVzdCBhYm91dCB0aGUgcmVhbCBlbGVtZW50IHNoYXBlXG4gICAgLy8gKHJldXNpbmcgbWFwUGFyYW1ldGVyVHlwZSBwdXJlbHkgZm9yIGl0cyBkZXNjcmlwdGl2ZSBkb2NzdHJpbmdUeXBlIC1cbiAgICAvLyBpdHMgdHNUeXBlL2FjY2VwdHNSZXNvbHZhYmxlQWxyZWFkeSBhcmUgaXJyZWxldmFudCBoZXJlKS5cbiAgICByZXR1cm4ge1xuICAgICAgdHNUeXBlOiBcImNka3RuLklSZXNvbHZhYmxlXCIsXG4gICAgICBkb2NzdHJpbmdUeXBlOiBgJHt3cmFwcGVyfTwke21hcFBhcmFtZXRlclR5cGUoZWxlbWVudCkuZG9jc3RyaW5nVHlwZX0+YCxcbiAgICAgIGRvY3N0cmluZ05vdGUsXG4gICAgICB3cmFwUmV0dXJuOiAoZXhwcikgPT4gZXhwcixcbiAgICB9O1xuICB9XG4gIGlmIChBcnJheS5pc0FycmF5KHJldHVyblR5cGUpICYmIHJldHVyblR5cGVbMF0gPT09IFwibWFwXCIpIHtcbiAgICAvLyBVbmxpa2UgbGlzdC9zZXQgYW5kIG9iamVjdC9keW5hbWljLCBldmVyeSBgbWFwYCBzaGFwZSBoYXMgYSBtYXRjaGluZ1xuICAgIC8vIHR5cGVkIFRva2VuIGhlbHBlciAoc2VlIHRva2VuLnRzKSwgc28gaXQgZ2V0cyBhIHJlYWwgdHlwZWQgcmVjb3JkXG4gICAgLy8gcmV0dXJuIGluc3RlYWQgb2YgZmFsbGluZyBiYWNrIHRvIHRoZSByYXcgSVJlc29sdmFibGUuXG4gICAgY29uc3QgZWxlbWVudCA9IHJldHVyblR5cGVbMV07XG4gICAgaWYgKGVsZW1lbnQgPT09IFwic3RyaW5nXCIpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHRzVHlwZTogXCJ7IFtrZXk6IHN0cmluZ106IHN0cmluZyB9XCIsXG4gICAgICAgIGRvY3N0cmluZ1R5cGU6IFwieyBba2V5OiBzdHJpbmddOiBzdHJpbmcgfVwiLFxuICAgICAgICB3cmFwUmV0dXJuOiAoZXhwcikgPT4gYGNka3RuLlRva2VuLmFzU3RyaW5nTWFwKCR7ZXhwcn0pYCxcbiAgICAgIH07XG4gICAgfVxuICAgIGlmIChlbGVtZW50ID09PSBcIm51bWJlclwiKSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICB0c1R5cGU6IFwieyBba2V5OiBzdHJpbmddOiBudW1iZXIgfVwiLFxuICAgICAgICBkb2NzdHJpbmdUeXBlOiBcInsgW2tleTogc3RyaW5nXTogbnVtYmVyIH1cIixcbiAgICAgICAgd3JhcFJldHVybjogKGV4cHIpID0+IGBjZGt0bi5Ub2tlbi5hc051bWJlck1hcCgke2V4cHJ9KWAsXG4gICAgICB9O1xuICAgIH1cbiAgICBpZiAoZWxlbWVudCA9PT0gXCJib29sXCIpIHtcbiAgICAgIC8vIFRva2VuLmFzQm9vbGVhbk1hcCdzIGRlY2xhcmVkIHJldHVybiB0eXBlIGlzIGB7IFtrZXk6IHN0cmluZ106XG4gICAgICAvLyBib29sZWFuIH1gIChzZWUgdG9rZW4udHMpIC0gdXNlZCB2ZXJiYXRpbSwgbm90IHVuaW9uZWQgd2l0aFxuICAgICAgLy8gSVJlc29sdmFibGU6IHRoZSBtYXAncyBpbmRpdmlkdWFsIGVudHJpZXMgYXJlIHBsYWluIGJvb2xlYW5zIG9uY2VcbiAgICAgIC8vIHVud3JhcHBlZCBieSB0aGUgaGVscGVyLlxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgdHNUeXBlOiBcInsgW2tleTogc3RyaW5nXTogYm9vbGVhbiB9XCIsXG4gICAgICAgIGRvY3N0cmluZ1R5cGU6IFwieyBba2V5OiBzdHJpbmddOiBib29sZWFuIH1cIixcbiAgICAgICAgd3JhcFJldHVybjogKGV4cHIpID0+IGBjZGt0bi5Ub2tlbi5hc0Jvb2xlYW5NYXAoJHtleHByfSlgLFxuICAgICAgfTtcbiAgICB9XG4gICAgLy8gbWFwIG9mIGFueXRoaW5nIGVsc2UgKG9iamVjdC9keW5hbWljL25lc3RlZCBjb2xsZWN0aW9uKTogYXNBbnlNYXBcbiAgICAvLyBzdGlsbCBnaXZlcyBhIHR5cGVkIChpZiBsb29zZWx5LXR5cGVkKSByZWNvcmQgcmF0aGVyIHRoYW4gZmFsbGluZ1xuICAgIC8vIGJhY2sgdG8gdGhlIHJhdyBJUmVzb2x2YWJsZS5cbiAgICByZXR1cm4ge1xuICAgICAgdHNUeXBlOiBcInsgW2tleTogc3RyaW5nXTogYW55IH1cIixcbiAgICAgIGRvY3N0cmluZ1R5cGU6IFwieyBba2V5OiBzdHJpbmddOiBhbnkgfVwiLFxuICAgICAgd3JhcFJldHVybjogKGV4cHIpID0+IGBjZGt0bi5Ub2tlbi5hc0FueU1hcCgke2V4cHJ9KWAsXG4gICAgfTtcbiAgfVxuICAvLyBvYmplY3Q6IG5vIHN0cnVjdHVyYWwgdHlwaW5nIGZvciBhcmJpdHJhcnkgcHJvdmlkZXIgZnVuY3Rpb24gcmVzdWx0cyAtXG4gIC8vIGRlY2xhcmVkIGFzIGBjZGt0bi5JUmVzb2x2YWJsZWAsIGFuZCByZXR1cm5lZCBhcyB0aGUgcmF3IGBJUmVzb2x2YWJsZWBcbiAgLy8gZnJvbSBpbnZva2UoKSAoTk9UIHdyYXBwZWQgaW4gYGNka3RuLlRva2VuLmFzU3RyaW5nKC4uLilgLCB3aGljaCB3b3VsZFxuICAvLyBtYWtlIHRoZSByZXN1bHQgdW5yZWNvZ25pemFibGUgdG8gYFRva2VuaXphdGlvbi5pc1Jlc29sdmFibGUoKWBcbiAgLy8gZG93bnN0cmVhbSAtIHNlZSB0aGUgbWFwUmV0dXJuVHlwZSBkb2NzdHJpbmcgYWJvdmUpLlxuICByZXR1cm4ge1xuICAgIHRzVHlwZTogXCJjZGt0bi5JUmVzb2x2YWJsZVwiLFxuICAgIGRvY3N0cmluZ1R5cGU6IFwib2JqZWN0XCIsXG4gICAgd3JhcFJldHVybjogKGV4cHIpID0+IGV4cHIsXG4gIH07XG59XG5cbmZ1bmN0aW9uIGJ1aWxkRnVuY3Rpb25Nb2RlbChcbiAgdGVycmFmb3JtTmFtZTogc3RyaW5nLFxuICBzaWduYXR1cmU6IEZ1bmN0aW9uU2lnbmF0dXJlLFxuKTogUHJvdmlkZXJGdW5jdGlvbk1vZGVsIHtcbiAgY29uc3Qge1xuICAgIHRzVHlwZTogcmV0dXJuVHNUeXBlLFxuICAgIGRvY3N0cmluZ1R5cGU6IHJldHVybkRvY3N0cmluZ1R5cGUsXG4gICAgZG9jc3RyaW5nTm90ZTogcmV0dXJuRG9jc3RyaW5nTm90ZSxcbiAgICB3cmFwUmV0dXJuLFxuICB9ID0gbWFwUmV0dXJuVHlwZShzaWduYXR1cmUucmV0dXJuX3R5cGUpO1xuXG4gIGNvbnN0IHJhd1BhcmFtZXRlcnMgPSBzaWduYXR1cmUucGFyYW1ldGVycyA/PyBbXTtcbiAgY29uc3QgcGFyYW1ldGVycyA9IGFwcGx5TnVsbGFiaWxpdHkoXG4gICAgcmF3UGFyYW1ldGVycyxcbiAgICByYXdQYXJhbWV0ZXJzLm1hcCgocGFyYW1ldGVyLCBpbmRleCkgPT5cbiAgICAgIGJ1aWxkUGFyYW1ldGVyTW9kZWwocGFyYW1ldGVyLCBgYXJnJHtpbmRleH1gKSxcbiAgICApLFxuICApO1xuXG4gIGxldCB2YXJpYWRpY1BhcmFtZXRlcjogSW50ZXJuYWxQYXJhbWV0ZXJNb2RlbCB8IHVuZGVmaW5lZDtcbiAgaWYgKHNpZ25hdHVyZS52YXJpYWRpY19wYXJhbWV0ZXIpIHtcbiAgICBjb25zdCBlbGVtZW50TW9kZWwgPSBidWlsZFBhcmFtZXRlck1vZGVsKFxuICAgICAgc2lnbmF0dXJlLnZhcmlhZGljX3BhcmFtZXRlcixcbiAgICAgIFwidmFsdWVzXCIsXG4gICAgKTtcbiAgICBpZiAoc2lnbmF0dXJlLnZhcmlhZGljX3BhcmFtZXRlci5pc19udWxsYWJsZSkge1xuICAgICAgLy8gQSBudWxsYWJsZSB2YXJpYWRpYyBwYXJhbWV0ZXI6IGpzaWkgY2FuJ3QgZXhwcmVzcyBcImVhY2ggaW5kaXZpZHVhbFxuICAgICAgLy8gYXJndW1lbnQgbWF5IGluZGVwZW5kZW50bHkgYmUgbnVsbFwiIG9uIHRoZSBnZW5lcmF0ZWQgYHZhbHVlczpcbiAgICAgIC8vIEFycmF5PFQ+YCBhcnJheSBwYXJhbWV0ZXIgKGl0J3MgYW4gb3JkaW5hcnkgYXJyYXkgcGFyYW1ldGVyLCBub3QgYVxuICAgICAgLy8gdHJ1ZSByZXN0L3NwcmVhZCBwYXJhbWV0ZXIgLSBvbmx5IHRoZSBpbnZva2UoKSBjYWxsIHNpdGUgc3ByZWFkc1xuICAgICAgLy8gaXQpLCBzbyBldmVyeSBlbGVtZW50J3MgdHlwZSBpbnN0ZWFkIHdpZGVucyB0byBhbHNvIGFjY2VwdCBhblxuICAgICAgLy8gZXhwbGljaXQgYGNka3RuLlRva2VuLm51bGxWYWx1ZSgpYCwgdGhlIHNhbWUgd2F5IGEgZml4ZWQgbnVsbGFibGVcbiAgICAgIC8vIHBhcmFtZXRlciBkb2VzIChzZWUgYHdpdGhOdWxsYWJsZVJlc29sdmFibGVVbmlvbmApOyB0aGUgZG9jc3RyaW5nXG4gICAgICAvLyBrZWVwcyB0aGUgaG9uZXN0IHBlci1lbGVtZW50IHR5cGUgcGx1cyB0aGF0IGd1aWRhbmNlIGluIGl0cyBub3RlLlxuICAgICAgY29uc3QgeyB0c1R5cGUsIGRvY3N0cmluZ1R5cGUgfSA9XG4gICAgICAgIHdpdGhOdWxsYWJsZVJlc29sdmFibGVVbmlvbihlbGVtZW50TW9kZWwpO1xuICAgICAgdmFyaWFkaWNQYXJhbWV0ZXIgPSB7XG4gICAgICAgIC4uLmVsZW1lbnRNb2RlbCxcbiAgICAgICAgdHNUeXBlLFxuICAgICAgICBkb2NzdHJpbmdUeXBlOiBgQXJyYXk8JHtkb2NzdHJpbmdUeXBlfT5gLFxuICAgICAgICBkb2NzdHJpbmdOb3RlOiBbXG4gICAgICAgICAgZWxlbWVudE1vZGVsLmRvY3N0cmluZ05vdGUsXG4gICAgICAgICAgXCJQYXNzIGNka3RuLlRva2VuLm51bGxWYWx1ZSgpIGZvciBhbiBleHBsaWNpdCBUZXJyYWZvcm0gbnVsbC5cIixcbiAgICAgICAgXVxuICAgICAgICAgIC5maWx0ZXIoQm9vbGVhbilcbiAgICAgICAgICAuam9pbihcIiBcIiksXG4gICAgICB9O1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBOb24tbnVsbGFibGU6IHRoZSBkb2NzdHJpbmcgd3JhcHMgdGhlIGVsZW1lbnQncyBkb2NzdHJpbmcgdHlwZSBpblxuICAgICAgLy8gYEFycmF5PC4uLj5gIGhlcmUgKHJhdGhlciB0aGFuIGluIHRoZSBlbWl0dGVyKSwgc28gZXZlcnkgcGFyYW1ldGVyXG4gICAgICAvLyAtIGZpeGVkIG9yIHZhcmlhZGljIC0gY2FuIHNoYXJlIG9uZSBgQHBhcmFtIHtkb2NzdHJpbmdUeXBlfWBcbiAgICAgIC8vIGVtaXNzaW9uIHBhdGguXG4gICAgICB2YXJpYWRpY1BhcmFtZXRlciA9IHtcbiAgICAgICAgLi4uZWxlbWVudE1vZGVsLFxuICAgICAgICBkb2NzdHJpbmdUeXBlOiBgQXJyYXk8JHtlbGVtZW50TW9kZWwuZG9jc3RyaW5nVHlwZX0+YCxcbiAgICAgIH07XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHtcbiAgICB0ZXJyYWZvcm1OYW1lLFxuICAgIG1ldGhvZE5hbWU6IHNhbml0aXplTWV0aG9kTmFtZSh0ZXJyYWZvcm1OYW1lKSxcbiAgICBkZXNjcmlwdGlvbjogc2lnbmF0dXJlLmRlc2NyaXB0aW9uLFxuICAgIHN1bW1hcnk6IHNpZ25hdHVyZS5zdW1tYXJ5LFxuICAgIGRlcHJlY2F0aW9uTWVzc2FnZTogc2lnbmF0dXJlLmRlcHJlY2F0aW9uX21lc3NhZ2UsXG4gICAgcmV0dXJuVHNUeXBlLFxuICAgIHJldHVybkRvY3N0cmluZ1R5cGUsXG4gICAgcmV0dXJuRG9jc3RyaW5nTm90ZSxcbiAgICB3cmFwUmV0dXJuLFxuICAgIHBhcmFtZXRlcnMsXG4gICAgdmFyaWFkaWNQYXJhbWV0ZXIsXG4gIH07XG59XG5cbi8qKlxuICogVGhyb3dzIGlmIHR3byBmdW5jdGlvbnMgaW4gdGhlIHNhbWUgcHJvdmlkZXIgc2FuaXRpemUgdG8gdGhlIHNhbWVcbiAqIGdlbmVyYXRlZCBtZXRob2QgbmFtZS4gVGVycmFmb3JtIGZ1bmN0aW9uIG5hbWVzIGFyZSB1bmlxdWUsIGJ1dFxuICogYHNhbml0aXplTWV0aG9kTmFtZWAgKGNhbWVsQ2FzaW5nLCBgbGVuZ3RoYCAtPiBgbGVuZ3RoT2ZgKSBpcyBub3RcbiAqIG5lY2Vzc2FyaWx5IGluamVjdGl2ZSwgc28gYSByZWFsIC0gaWYgdW5saWtlbHkgLSBwcm92aWRlciBzY2hlbWEgY291bGRcbiAqIHN0aWxsIHByb2R1Y2UgYSBkdXBsaWNhdGUgbWV0aG9kLiBHZW5lcmF0aW9uIGlzIGFib3J0ZWQgcmF0aGVyIHRoYW5cbiAqIHNpbGVudGx5IGVtaXR0aW5nIG9uZSBtZXRob2QgdGhhdCBzaGFkb3dzIHRoZSBvdGhlci5cbiAqL1xuZnVuY3Rpb24gYXNzZXJ0Tm9NZXRob2ROYW1lQ29sbGlzaW9ucyhcbiAgcHJvdmlkZXJOYW1lOiBzdHJpbmcsXG4gIGZ1bmN0aW9uczogUHJvdmlkZXJGdW5jdGlvbk1vZGVsW10sXG4pOiB2b2lkIHtcbiAgY29uc3Qgc2VlbkJ5ID0gbmV3IE1hcDxzdHJpbmcsIHN0cmluZz4oKTsgLy8gbWV0aG9kTmFtZSAtPiB0ZXJyYWZvcm1OYW1lXG5cbiAgZm9yIChjb25zdCBmbiBvZiBmdW5jdGlvbnMpIHtcbiAgICBjb25zdCBleGlzdGluZ1RlcnJhZm9ybU5hbWUgPSBzZWVuQnkuZ2V0KGZuLm1ldGhvZE5hbWUpO1xuICAgIGlmIChleGlzdGluZ1RlcnJhZm9ybU5hbWUgIT09IHVuZGVmaW5lZCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgUHJvdmlkZXIgXCIke3Byb3ZpZGVyTmFtZX1cIiBkZWNsYXJlcyB0d28gcHJvdmlkZXItZGVmaW5lZCBmdW5jdGlvbnMsIGAgK1xuICAgICAgICAgIGBcIiR7ZXhpc3RpbmdUZXJyYWZvcm1OYW1lfVwiIGFuZCBcIiR7Zm4udGVycmFmb3JtTmFtZX1cIiwgdGhhdCBib3RoIGAgK1xuICAgICAgICAgIGBzYW5pdGl6ZSB0byB0aGUgZ2VuZXJhdGVkIG1ldGhvZCBuYW1lIFwiJHtmbi5tZXRob2ROYW1lfVwiLiBgICtcbiAgICAgICAgICBgR2VuZXJhdGlvbiBhYm9ydGVkIHRvIGF2b2lkIHNpbGVudGx5IG92ZXJ3cml0aW5nIG9uZSBtZXRob2Qgd2l0aCBgICtcbiAgICAgICAgICBgdGhlIG90aGVyIC0gcGxlYXNlIHJlcG9ydCB0aGlzIGFzIGFuIGlzc3VlLmAsXG4gICAgICApO1xuICAgIH1cbiAgICBzZWVuQnkuc2V0KGZuLm1ldGhvZE5hbWUsIGZuLnRlcnJhZm9ybU5hbWUpO1xuICB9XG59XG5cbi8qKlxuICogVGhyb3dzIGlmIGEgZnVuY3Rpb24ncyBzYW5pdGl6ZWQgYG1ldGhvZE5hbWVgIGxhbmRzIG9uIGEgbWVtYmVyIG5hbWVcbiAqIGBQcm92aWRlckZ1bmN0aW9uc0VtaXR0ZXJgIGFscmVhZHkgcHV0cyBvbiBldmVyeSB3cmFwcGVyIGNsYXNzIChzZWVcbiAqIGBSRVNFUlZFRF9XUkFQUEVSX01FTUJFUl9OQU1FU2ApLiBVbmxpa2UgYGFzc2VydE5vTWV0aG9kTmFtZUNvbGxpc2lvbnNgLFxuICogd2hpY2ggb25seSBjYXRjaGVzIHR3byAqZnVuY3Rpb25zKiBjb2xsaWRpbmcgd2l0aCBlYWNoIG90aGVyLCB0aGlzIGNhdGNoZXNcbiAqIGEgc2luZ2xlIGZ1bmN0aW9uIGNvbGxpZGluZyB3aXRoIHRoZSB3cmFwcGVyIGNsYXNzIGl0c2VsZiAtIGUuZy4gYVxuICogVGVycmFmb3JtIGZ1bmN0aW9uIGxpdGVyYWxseSBuYW1lZCBcImNvbnN0cnVjdG9yXCIsIG9yIFwicHJvdmlkZXJfbG9jYWxfbmFtZVwiXG4gKiBjYW1lbENhc2luZyB0byBcInByb3ZpZGVyTG9jYWxOYW1lXCIuXG4gKlxuICogVGhpcyBpbnRlbnRpb25hbGx5IGRvZXMgTk9UIGFsc28gY2hlY2sgc2FuaXRpemVkICpwYXJhbWV0ZXIqIG5hbWVzIGFnYWluc3RcbiAqIFwicHJvdmlkZXJMb2NhbE5hbWVcIjogcGFyYW1ldGVycyBhcmUgZGVjbGFyZWQgaW4gdGhlIGdlbmVyYXRlZCBtZXRob2QncyBvd25cbiAqIHNjb3BlLCBub3QgdGhlIGNsYXNzJ3MsIHNvIGEgcGFyYW1ldGVyIG5hbWVkIGBwcm92aWRlckxvY2FsTmFtZWAgc2hhZG93c1xuICogdGhlIGNsYXNzIGZpZWxkIHdpdGhpbiB0aGF0IG1ldGhvZCBib2R5IHdpdGhvdXQgY29sbGlkaW5nIHdpdGggaXQgKHZhbGlkLFxuICogaWYgY29uZnVzaW5nLCBUeXBlU2NyaXB0KSAtIHRoZXJlIGlzIG5vdGhpbmcgdG8gYWJvcnQgZ2VuZXJhdGlvbiBvdmVyLlxuICovXG5mdW5jdGlvbiBhc3NlcnROb1Jlc2VydmVkV3JhcHBlck1lbWJlckNvbGxpc2lvbnMoXG4gIHByb3ZpZGVyTmFtZTogc3RyaW5nLFxuICBmdW5jdGlvbnM6IFByb3ZpZGVyRnVuY3Rpb25Nb2RlbFtdLFxuKTogdm9pZCB7XG4gIGZvciAoY29uc3QgZm4gb2YgZnVuY3Rpb25zKSB7XG4gICAgaWYgKFJFU0VSVkVEX1dSQVBQRVJfTUVNQkVSX05BTUVTLmhhcyhmbi5tZXRob2ROYW1lKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgUHJvdmlkZXIgXCIke3Byb3ZpZGVyTmFtZX1cIiBkZWNsYXJlcyBhIHByb3ZpZGVyLWRlZmluZWQgZnVuY3Rpb24gYCArXG4gICAgICAgICAgYFwiJHtmbi50ZXJyYWZvcm1OYW1lfVwiIHRoYXQgc2FuaXRpemVzIHRvIHRoZSBnZW5lcmF0ZWQgbWV0aG9kIG5hbWUgYCArXG4gICAgICAgICAgYFwiJHtmbi5tZXRob2ROYW1lfVwiLCB3aGljaCBjb2xsaWRlcyB3aXRoIGEgbWVtYmVyIHRoYXQgYCArXG4gICAgICAgICAgYFByb3ZpZGVyRnVuY3Rpb25zRW1pdHRlciBhbHJlYWR5IHB1dHMgb24gZXZlcnkgYCArXG4gICAgICAgICAgYFwiPFByb3ZpZGVyPlByb3ZpZGVyRnVuY3Rpb25zXCIgd3JhcHBlciBjbGFzcyAodGhlIGNsYXNzIGAgK1xuICAgICAgICAgIGBjb25zdHJ1Y3Rvciwgb3IgaXRzIFwicHJvdmlkZXJMb2NhbE5hbWVcIiBmaWVsZCkuIEdlbmVyYXRpb24gYCArXG4gICAgICAgICAgYGFib3J0ZWQgdG8gYXZvaWQgZW1pdHRpbmcgaW52YWxpZCBUeXBlU2NyaXB0IG9yIHNpbGVudGx5IGAgK1xuICAgICAgICAgIGBzaGFkb3dpbmcgdGhhdCBtZW1iZXIgLSBwbGVhc2UgcmVwb3J0IHRoaXMgYXMgYW4gaXNzdWUuYCxcbiAgICAgICk7XG4gICAgfVxuICB9XG59XG5cbi8qKlxuICogVGhyb3dzIGlmIHR3byBwYXJhbWV0ZXJzIG9mIHRoZSBzYW1lIGZ1bmN0aW9uIChpbmNsdWRpbmcgdGhlIHZhcmlhZGljXG4gKiBwYXJhbWV0ZXIpIHNhbml0aXplIHRvIHRoZSBzYW1lIGdlbmVyYXRlZCBwYXJhbWV0ZXIgbmFtZSwgZm9yIHRoZSBzYW1lXG4gKiByZWFzb24gYXMgYGFzc2VydE5vTWV0aG9kTmFtZUNvbGxpc2lvbnNgIGFib3ZlIGJ1dCBhdCB0aGUgcGFyYW1ldGVyIGxldmVsLlxuICovXG5mdW5jdGlvbiBhc3NlcnROb1BhcmFtZXRlck5hbWVDb2xsaXNpb25zKFxuICBwcm92aWRlck5hbWU6IHN0cmluZyxcbiAgZm46IFByb3ZpZGVyRnVuY3Rpb25Nb2RlbCxcbik6IHZvaWQge1xuICBjb25zdCBzZWVuQnkgPSBuZXcgTWFwPHN0cmluZywgc3RyaW5nPigpOyAvLyBzYW5pdGl6ZWQgbmFtZSAtPiB0ZXJyYWZvcm1OYW1lXG4gIGNvbnN0IGFsbFBhcmFtZXRlcnMgPSBmbi52YXJpYWRpY1BhcmFtZXRlclxuICAgID8gWy4uLmZuLnBhcmFtZXRlcnMsIGZuLnZhcmlhZGljUGFyYW1ldGVyXVxuICAgIDogZm4ucGFyYW1ldGVycztcblxuICBmb3IgKGNvbnN0IHBhcmFtIG9mIGFsbFBhcmFtZXRlcnMpIHtcbiAgICBjb25zdCBleGlzdGluZ1RlcnJhZm9ybU5hbWUgPSBzZWVuQnkuZ2V0KHBhcmFtLm5hbWUpO1xuICAgIGlmIChleGlzdGluZ1RlcnJhZm9ybU5hbWUgIT09IHVuZGVmaW5lZCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgUHJvdmlkZXIgXCIke3Byb3ZpZGVyTmFtZX1cIiBmdW5jdGlvbiBcIiR7Zm4udGVycmFmb3JtTmFtZX1cIiBkZWNsYXJlcyBgICtcbiAgICAgICAgICBgdHdvIHBhcmFtZXRlcnMsIFwiJHtleGlzdGluZ1RlcnJhZm9ybU5hbWV9XCIgYW5kIGAgK1xuICAgICAgICAgIGBcIiR7cGFyYW0udGVycmFmb3JtTmFtZX1cIiwgdGhhdCBib3RoIHNhbml0aXplIHRvIHRoZSBnZW5lcmF0ZWQgYCArXG4gICAgICAgICAgYHBhcmFtZXRlciBuYW1lIFwiJHtwYXJhbS5uYW1lfVwiLiBHZW5lcmF0aW9uIGFib3J0ZWQgdG8gYXZvaWQgYCArXG4gICAgICAgICAgYHNpbGVudGx5IGRyb3BwaW5nIG9uZSBwYXJhbWV0ZXIgLSBwbGVhc2UgcmVwb3J0IHRoaXMgYXMgYW4gaXNzdWUuYCxcbiAgICAgICk7XG4gICAgfVxuICAgIHNlZW5CeS5zZXQocGFyYW0ubmFtZSwgcGFyYW0udGVycmFmb3JtTmFtZSk7XG4gIH1cbn1cblxuLyoqXG4gKiBUaHJvd3MgaWYgdGhlIHByb3ZpZGVyJ3Mgb3duIGNvbmZpZyBzY2hlbWEgZGVjbGFyZXMgYW4gYXR0cmlidXRlIHdob3NlXG4gKiBnZW5lcmF0ZWQgcHJvcGVydHkgbmFtZSAoc2VlIGBBdHRyaWJ1dGVNb2RlbC5uYW1lYCAvXG4gKiBgZXNjYXBlQXR0cmlidXRlTmFtZWApIGlzIGV4YWN0bHkgXCJmdW5jdGlvbnNcIiwgd2hpbGUgdGhlIHByb3ZpZGVyIGFsc29cbiAqIGRlY2xhcmVzIHByb3ZpZGVyLWRlZmluZWQgZnVuY3Rpb25zLiBUaGF0IGNvbWJpbmF0aW9uIHdvdWxkIGNvbGxpZGUgd2l0aFxuICogdGhlIG1lbW9pemVkIGBmdW5jdGlvbnNgIGdldHRlciBgUmVzb3VyY2VFbWl0dGVyYCBlbWl0cyBvbiB0aGUgcHJvdmlkZXJcbiAqIGNsYXNzIChzZWUgYHJlc291cmNlLWVtaXR0ZXIudHNgJ3MgYGVtaXRGdW5jdGlvbnNHZXR0ZXJgKSAtIG9uZSB3b3VsZFxuICogc2lsZW50bHkgc2hhZG93IHRoZSBvdGhlci4gU2FtZSBsb3VkLWZhaWx1cmUgY29udmVudGlvbiBhc1xuICogYGFzc2VydE5vTWV0aG9kTmFtZUNvbGxpc2lvbnNgL2Bhc3NlcnROb1BhcmFtZXRlck5hbWVDb2xsaXNpb25zYCBhYm92ZTpcbiAqIGdlbmVyYXRpb24gaXMgYWJvcnRlZCByYXRoZXIgdGhhbiBzaWxlbnRseSBwaWNraW5nIGEgd2lubmVyLlxuICovXG5leHBvcnQgZnVuY3Rpb24gYXNzZXJ0Tm9GdW5jdGlvbnNHZXR0ZXJDb2xsaXNpb24oXG4gIHByb3ZpZGVyTmFtZTogc3RyaW5nLFxuICBhdHRyaWJ1dGVOYW1lczogc3RyaW5nW10sXG4pOiB2b2lkIHtcbiAgaWYgKGF0dHJpYnV0ZU5hbWVzLmluY2x1ZGVzKFwiZnVuY3Rpb25zXCIpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgYFByb3ZpZGVyIFwiJHtwcm92aWRlck5hbWV9XCIgZGVjbGFyZXMgcHJvdmlkZXItZGVmaW5lZCBmdW5jdGlvbnMgYW5kIGl0cyBgICtcbiAgICAgICAgYG93biBjb25maWcgc2NoZW1hIGFsc28gaGFzIGFuIGF0dHJpYnV0ZSB0aGF0IGdlbmVyYXRlcyB0aGUgcHJvcGVydHkgYCArXG4gICAgICAgIGBuYW1lIFwiZnVuY3Rpb25zXCIgb24gdGhlIHByb3ZpZGVyIGNsYXNzLiBUaGlzIGNvbGxpZGVzIHdpdGggdGhlIGAgK1xuICAgICAgICBgZ2VuZXJhdGVkIFwiZnVuY3Rpb25zXCIgZ2V0dGVyIHVzZWQgdG8gaW52b2tlIHByb3ZpZGVyLWRlZmluZWQgYCArXG4gICAgICAgIGBmdW5jdGlvbnMuIEdlbmVyYXRpb24gYWJvcnRlZCB0byBhdm9pZCBzaWxlbnRseSBzaGFkb3dpbmcgb25lIHdpdGggYCArXG4gICAgICAgIGB0aGUgb3RoZXIgLSBwbGVhc2UgcmVwb3J0IHRoaXMgYXMgYW4gaXNzdWUuYCxcbiAgICApO1xuICB9XG59XG5cbi8qKlxuICogQnVpbGRzIHRoZSBtb2RlbCBmb3IgYSBwcm92aWRlcidzIGBwcm92aWRlci1mdW5jdGlvbnMvaW5kZXgudHNgIGZpbGUgZnJvbVxuICogaXRzIHByb3ZpZGVyIHNjaGVtYSBgZnVuY3Rpb25zYCBtYXAuIFJldHVybnMgYHVuZGVmaW5lZGAgd2hlbiB0aGUgcHJvdmlkZXJcbiAqIGRlY2xhcmVzIG5vIGZ1bmN0aW9ucyAtIGNhbGxlcnMgc2hvdWxkIHNraXAgZW1pdHRpbmcgdGhlIGZpbGUgZW50aXJlbHkuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBidWlsZFByb3ZpZGVyRnVuY3Rpb25zTW9kZWwoXG4gIHByb3ZpZGVyTmFtZTogc3RyaW5nLFxuICBmdW5jdGlvbnM6IHsgW25hbWU6IHN0cmluZ106IEZ1bmN0aW9uU2lnbmF0dXJlIH0gfCB1bmRlZmluZWQsXG4pOiBQcm92aWRlckZ1bmN0aW9uc01vZGVsIHwgdW5kZWZpbmVkIHtcbiAgY29uc3QgZW50cmllcyA9IE9iamVjdC5lbnRyaWVzKGZ1bmN0aW9ucyA/PyB7fSk7XG4gIGlmIChlbnRyaWVzLmxlbmd0aCA9PT0gMCkgcmV0dXJuIHVuZGVmaW5lZDtcblxuICBjb25zdCBtYXBwZWRGdW5jdGlvbnMgPSBlbnRyaWVzXG4gICAgLnNvcnQoKFthXSwgW2JdKSA9PiBhLmxvY2FsZUNvbXBhcmUoYikpXG4gICAgLm1hcCgoW25hbWUsIHNpZ25hdHVyZV0pID0+IGJ1aWxkRnVuY3Rpb25Nb2RlbChuYW1lLCBzaWduYXR1cmUpKTtcblxuICBhc3NlcnROb01ldGhvZE5hbWVDb2xsaXNpb25zKHByb3ZpZGVyTmFtZSwgbWFwcGVkRnVuY3Rpb25zKTtcbiAgYXNzZXJ0Tm9SZXNlcnZlZFdyYXBwZXJNZW1iZXJDb2xsaXNpb25zKHByb3ZpZGVyTmFtZSwgbWFwcGVkRnVuY3Rpb25zKTtcbiAgZm9yIChjb25zdCBmbiBvZiBtYXBwZWRGdW5jdGlvbnMpIHtcbiAgICBhc3NlcnROb1BhcmFtZXRlck5hbWVDb2xsaXNpb25zKHByb3ZpZGVyTmFtZSwgZm4pO1xuICB9XG5cbiAgcmV0dXJuIHtcbiAgICBwcm92aWRlck5hbWUsXG4gICAgY2xhc3NOYW1lOiBgJHt0b1Bhc2NhbENhc2UocHJvdmlkZXJOYW1lKX1Qcm92aWRlckZ1bmN0aW9uc2AsXG4gICAgZnVuY3Rpb25zOiBtYXBwZWRGdW5jdGlvbnMsXG4gIH07XG59XG4iXX0=