@decohere/create 0.0.1-dev.23 → 0.0.1-dev.25

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 (36) hide show
  1. package/commonjs/src/models/compose.model.js +56 -4
  2. package/commonjs/src/models/dev-container.model.js +29 -2
  3. package/commonjs/src/models/package-json.model.js +11 -6
  4. package/commonjs/src/runner.js +26 -2
  5. package/commonjs/src/webapi/create-api.js +66 -5
  6. package/commonjs/src/webapi/features/auth.feature.js +288 -7
  7. package/commonjs/src/webapi/features/auth0-cli.js +256 -9
  8. package/commonjs/src/webapi/features/database.feature.js +56 -24
  9. package/commonjs/src/webapi/features/postman.feature.js +337 -48
  10. package/commonjs/src/webapi/models/api-package-json.model.js +4 -1
  11. package/commonjs/src/webapi/models/auth-config.model.js +4 -1
  12. package/commonjs/src/webapi/models/controller-source-file.model.js +16 -8
  13. package/commonjs/src/webapi/models/main-source-file.model.js +28 -4
  14. package/es6/src/models/compose.model.js +57 -6
  15. package/es6/src/models/dev-container.model.js +30 -8
  16. package/es6/src/models/package-json.model.js +11 -6
  17. package/es6/src/runner.js +27 -3
  18. package/es6/src/webapi/create-api.js +66 -5
  19. package/es6/src/webapi/features/auth.feature.js +288 -7
  20. package/es6/src/webapi/features/auth0-cli.js +230 -9
  21. package/es6/src/webapi/features/database.feature.js +56 -24
  22. package/es6/src/webapi/features/postman.feature.js +324 -45
  23. package/es6/src/webapi/models/api-package-json.model.js +4 -1
  24. package/es6/src/webapi/models/auth-config.model.js +4 -1
  25. package/es6/src/webapi/models/controller-source-file.model.js +16 -8
  26. package/es6/src/webapi/models/main-source-file.model.js +28 -4
  27. package/package.json +2 -2
  28. package/types/src/models/compose.model.d.ts +27 -2
  29. package/types/src/models/dev-container.model.d.ts +12 -0
  30. package/types/src/models/package-json.model.d.ts +2 -0
  31. package/types/src/webapi/features/auth.feature.d.ts +3 -0
  32. package/types/src/webapi/features/auth0-cli.d.ts +50 -3
  33. package/types/src/webapi/features/postman.feature.d.ts +5 -0
  34. package/types/src/webapi/models/auth-config.model.d.ts +8 -0
  35. package/types/src/webapi/models/controller-source-file.model.d.ts +6 -3
  36. package/types/src/webapi/models/main-source-file.model.d.ts +12 -0
@@ -1,9 +1,154 @@
1
1
  import { ask, pick } from "../../domain/prompt.js";
2
2
  import { WELL_KNOWN_FILES } from "../../models/const.js";
3
+ import { WEBAPI_PROJECT_DIR } from "../create-api.js";
3
4
  import { AuthConfigModel } from "../models/auth-config.model.js";
4
5
  import { ControllerSourceFile } from "../models/controller-source-file.model.js";
5
6
  import * as auth0Cli from "./auth0-cli.js";
7
+ const ADMIN_ROLE = "admin";
8
+ const USER_ENTITY_TS = `import { Column, Entity, PrimaryGeneratedColumn } from "typeorm";
9
+ import type { Entity as IEntity } from "@decohere/codex";
10
+
11
+ @Entity()
12
+ export class UserEntity implements IEntity {
13
+ \t@PrimaryGeneratedColumn()
14
+ \tpublic id!: number;
15
+
16
+ \t@Column({ unique: true })
17
+ \tpublic sub!: string;
18
+
19
+ \t@Column({ type: "varchar", nullable: true })
20
+ \tpublic email!: string | null;
21
+
22
+ \t@Column()
23
+ \tpublic displayName!: string;
24
+
25
+ \t/** App-owned roles. The \`admin\` role grants CASL \`manage\`/\`all\` (wildcard). */
26
+ \t@Column({ type: "simple-json", default: "[]" })
27
+ \tpublic roles!: string[];
28
+ }
29
+ `;
30
+ const USER_REPOSITORY_TS = `import { injectable } from "@decohere/crucible/decorators";
31
+ import { injectUnitOfWork } from "@decohere/codex";
32
+ import { TypeOrmRepository, TypeOrmUnitOfWork } from "@decohere/codex-typeorm";
33
+ import { UserEntity } from "../entities/user.entity.js";
34
+
35
+ @injectable()
36
+ export class UserEntityRepository extends TypeOrmRepository<UserEntity> {
37
+ \tpublic constructor(@injectUnitOfWork() unitOfWork: TypeOrmUnitOfWork) {
38
+ \t\tsuper(unitOfWork, UserEntity);
39
+ \t}
40
+
41
+ \tpublic findBySub(sub: string): Promise<UserEntity | null> {
42
+ \t\treturn this.firstOrDefault({ where: { sub } });
43
+ \t}
44
+ }
45
+ `;
46
+ const USER_SERVICE_TS = `import { injectable } from "@decohere/crucible/decorators";
47
+ import type { Principal } from "@decohere/cortex";
48
+ import { UserEntity } from "../entities/user.entity.js";
49
+ import { UserEntityRepository } from "../repositories/user.repository.js";
50
+
51
+ function claimString(principal: Principal | undefined, key: string): string | undefined {
52
+ \tconst value = principal?.[key];
53
+ \treturn typeof value === "string" && value.length > 0 ? value : undefined;
54
+ }
55
+
56
+ @injectable()
57
+ export class UserService {
58
+ \tpublic constructor(private readonly users: UserEntityRepository) {}
59
+
60
+ \t/**
61
+ \t * Upsert a local profile keyed by JWT \`sub\`.
62
+ \t * Profile fields from the token fill gaps; seeded rows keep displayName/email/roles.
63
+ \t */
64
+ \tpublic async ensureFromPrincipal(principal: Principal | undefined): Promise<UserEntity> {
65
+ \t\tconst sub = principal?.sub;
66
+ \t\tif (!sub) {
67
+ \t\t\tthrow new Error("Authenticated request is missing principal.sub");
68
+ \t\t}
69
+
70
+ \t\tconst email =
71
+ \t\t\tclaimString(principal, "email") ?? claimString(principal, "preferred_username");
72
+ \t\tconst displayFromToken =
73
+ \t\t\tclaimString(principal, "name") ??
74
+ \t\t\tclaimString(principal, "nickname") ??
75
+ \t\t\temail;
76
+
77
+ \t\tconst existing = await this.users.findBySub(sub);
78
+ \t\tif (existing) {
79
+ \t\t\tlet dirty = false;
80
+ \t\t\tif (!existing.email && email) {
81
+ \t\t\t\texisting.email = email;
82
+ \t\t\t\tdirty = true;
83
+ \t\t\t}
84
+ \t\t\tif (existing.displayName === existing.sub && displayFromToken) {
85
+ \t\t\t\texisting.displayName = displayFromToken;
86
+ \t\t\t\tdirty = true;
87
+ \t\t\t}
88
+ \t\t\treturn dirty ? this.users.save(existing) : existing;
89
+ \t\t}
90
+
91
+ \t\tconst created = new UserEntity();
92
+ \t\tcreated.sub = sub;
93
+ \t\tcreated.email = email ?? null;
94
+ \t\tcreated.displayName = displayFromToken ?? sub;
95
+ \t\tcreated.roles = Array.isArray(principal.roles)
96
+ \t\t\t? principal.roles.filter((r): r is string => typeof r === "string")
97
+ \t\t\t: [];
98
+ \t\treturn this.users.save(created);
99
+ \t}
100
+ }
101
+ `;
102
+ const ABILITY_FACTORY_TS = `import { AbilityBuilder, createMongoAbility } from "@casl/ability";
103
+ import type { Principal } from "@decohere/cortex";
104
+
105
+ /** Root role — expands to CASL \`manage\`/\`all\` (covers every future ability). */
106
+ export const ADMIN_ROLE = "admin";
107
+
108
+ /**
109
+ * Roles are collections of abilities. Admin is a wildcard, not an enumerated list.
110
+ * Non-admin principals keep the default Auth0 scope → ability mapping.
111
+ */
112
+ export function createAbilityFactory(principal: Principal) {
113
+ \tconst { can, build } = new AbilityBuilder(createMongoAbility);
114
+ \tif (principal.roles?.includes(ADMIN_ROLE)) {
115
+ \t\tcan("manage", "all");
116
+ \t\treturn build();
117
+ \t}
118
+ \tfor (const scope of principal.scopes ?? []) {
119
+ \t\tconst [action, subject] = scope.split(":");
120
+ \t\tif (action && subject) can(action, subject);
121
+ \t}
122
+ \treturn build();
123
+ }
124
+
125
+ /**
126
+ * Map JWT payload → Principal. Bootstraps the seeded Auth0 admin \`sub\` with
127
+ * the admin role so authorization works before/without roles in the access token.
128
+ */
129
+ export function mapPrincipal(payload: Record<string, unknown>): Principal {
130
+ \tconst sub = typeof payload.sub === "string" ? payload.sub : "";
131
+ \tconst scopes = Array.isArray(payload.scopes)
132
+ \t\t? (payload.scopes as string[])
133
+ \t\t: typeof payload.scope === "string"
134
+ \t\t\t? payload.scope.split(" ")
135
+ \t\t\t: undefined;
136
+ \tconst fromToken = Array.isArray(payload.roles)
137
+ \t\t? (payload.roles as unknown[]).filter((r): r is string => typeof r === "string")
138
+ \t\t: [];
139
+ \tconst roles =
140
+ \t\tsub && sub === process.env.AUTH0_ADMIN_USER_SUB
141
+ \t\t\t? [...new Set([ADMIN_ROLE, ...fromToken])]
142
+ \t\t\t: fromToken.length > 0
143
+ \t\t\t\t? fromToken
144
+ \t\t\t\t: undefined;
145
+ \treturn { ...payload, sub, roles, scopes };
146
+ }
147
+ `;
6
148
  async function getOptions(workspace, cliOptions) {
149
+ if (cliOptions.authProvider === "auth0" && !cliOptions.issuerBaseUrl) {
150
+ return getAuth0Options(workspace, cliOptions);
151
+ }
7
152
  if (cliOptions.authProvider != null) return {};
8
153
  const choices = [
9
154
  {
@@ -18,9 +163,9 @@ async function getOptions(workspace, cliOptions) {
18
163
  if (provider !== "auth0") return {
19
164
  authProvider: "none"
20
165
  };
21
- return getAuth0Options(workspace);
166
+ return getAuth0Options(workspace, cliOptions);
22
167
  }
23
- async function getAuth0Options(workspace) {
168
+ async function getAuth0Options(workspace, cliOptions) {
24
169
  if (!auth0Cli.isInstalled()) {
25
170
  console.error("\n The Auth0 CLI is required for automated setup.\n" + " Install: brew install auth0/auth0-cli/auth0\n" + " Or visit: https://github.com/auth0/auth0-cli\n");
26
171
  process.exit(1);
@@ -77,24 +222,156 @@ async function getAuth0Options(workspace) {
77
222
  } else {
78
223
  audience = apiSelected.existing;
79
224
  console.log(` \u2713 Selected: ${audience}`);
225
+ try {
226
+ auth0Cli.updateApiScopes(audience);
227
+ console.log(` \u2713 API scopes ensured (${auth0Cli.HELLO_API_SCOPES.join(", ")})`);
228
+ } catch {
229
+ console.error(" ✗ Failed to update API scopes — add Hello scopes in the Auth0 dashboard.");
230
+ }
231
+ }
232
+ const withLocalUsers = cliOptions.databaseProvider === "postgres/typeorm";
233
+ let adminUsername;
234
+ let adminPassword;
235
+ if (withLocalUsers) {
236
+ adminUsername = cliOptions.adminUsername ?? await ask("\n Admin username [admin]: ", "admin");
237
+ adminPassword = cliOptions.adminPassword;
238
+ if (adminPassword == null) {
239
+ adminPassword = await ask(" Admin password (leave blank to generate): ");
240
+ if (!adminPassword) {
241
+ adminPassword = auth0Cli.generateAdminPassword();
242
+ console.log(` ✓ Generated admin password (written to .env): ${adminPassword}`);
243
+ }
244
+ }
80
245
  }
81
246
  return {
82
247
  authProvider: "auth0",
83
248
  issuerBaseUrl,
84
- audience
249
+ audience,
250
+ ...withLocalUsers ? {
251
+ adminUsername,
252
+ adminPassword
253
+ } : {}
85
254
  };
86
255
  }
256
+ function adminEmail(workspaceName, username) {
257
+ if (username.includes("@")) return username;
258
+ const slug = workspaceName.toLowerCase().replace(/[^a-z0-9-]/g, "-");
259
+ return `${username}@${slug}.example.com`;
260
+ }
261
+ function createAuth0AdminUser(workspace, options, authConfig) {
262
+ const username = options.adminUsername ?? "admin";
263
+ const password = options.adminPassword;
264
+ if (!password) return;
265
+ const email = adminEmail(workspace.name, username);
266
+ try {
267
+ const admin = auth0Cli.createAdminDatabaseUser({
268
+ email,
269
+ password,
270
+ username
271
+ });
272
+ authConfig.setAdminUser({
273
+ sub: admin.user_id,
274
+ email: admin.email,
275
+ password: admin.password,
276
+ username: admin.username
277
+ });
278
+ workspace.getModel(WELL_KNOWN_FILES.ENV_FILE)?.addEntry("AUTH0_ADMIN_USER_SUB", admin.user_id).addEntry("AUTH0_ADMIN_USER_EMAIL", admin.email).addEntry("AUTH0_ADMIN_USER_PASSWORD", admin.password).addEntry("AUTH0_ADMIN_USERNAME", admin.username);
279
+ console.log(` ✓ Auth0 admin user ready: ${admin.email} (role: ${ADMIN_ROLE})`);
280
+ console.log(` Login with EMAIL (not username): ${admin.email}`);
281
+ console.log(` Password: see AUTH0_ADMIN_USER_PASSWORD in .env`);
282
+ } catch (err) {
283
+ console.error(` ✗ Failed to ensure Auth0 admin user (${email}): ${err instanceof Error ? err.message : err}`);
284
+ }
285
+ }
286
+ function scaffoldLocalUserProfile(workspace) {
287
+ workspace.getModel(WELL_KNOWN_FILES.PACKAGE_JSON)?.addDependency("@casl/ability", "^6.8.1");
288
+ workspace.getModel(WELL_KNOWN_FILES.API_PACKAGE_JSON)?.addDependency("@casl/ability", "^6.8.1");
289
+ const main = workspace.getModel(WELL_KNOWN_FILES.MAIN_TS);
290
+ main?.addEntity({
291
+ className: "UserEntity",
292
+ importPath: "./entities/user.entity.js"
293
+ }).addRepository({
294
+ className: "UserEntityRepository",
295
+ importPath: "./repositories/user.repository.js"
296
+ }).addService({
297
+ className: "UserService",
298
+ importPath: "./services/user.service.js",
299
+ scope: "request"
300
+ }).addImport("createAbilityFactory", "./auth/ability.factory.js").addImport("mapPrincipal", "./auth/ability.factory.js").setTypeOrmSeed([
301
+ "const sub = process.env.AUTH0_ADMIN_USER_SUB;",
302
+ "if (!sub) return;",
303
+ "const repo = dataSource.getRepository(UserEntity);",
304
+ "const existing = await repo.findOne({ where: { sub } });",
305
+ "if (existing) return;",
306
+ "await repo.save(repo.create({",
307
+ " sub,",
308
+ " email: process.env.AUTH0_ADMIN_USER_EMAIL ?? null,",
309
+ ' displayName: process.env.AUTH0_ADMIN_USERNAME ?? "admin",',
310
+ ' roles: ["admin"],',
311
+ "}));"
312
+ ].join(" "));
313
+ workspace.getProject(WEBAPI_PROJECT_DIR)?.addFile({
314
+ files: ()=>[
315
+ {
316
+ filePath: "src/entities/user.entity.ts",
317
+ content: USER_ENTITY_TS
318
+ },
319
+ {
320
+ filePath: "src/repositories/user.repository.ts",
321
+ content: USER_REPOSITORY_TS
322
+ },
323
+ {
324
+ filePath: "src/services/user.service.ts",
325
+ content: USER_SERVICE_TS
326
+ },
327
+ {
328
+ filePath: "src/auth/ability.factory.ts",
329
+ content: ABILITY_FACTORY_TS
330
+ }
331
+ ]
332
+ });
333
+ for (const controller of workspace.getModels(ControllerSourceFile)){
334
+ controller.addImport("UserService", "../services/user.service.js").addConstructorParam("private readonly users: UserService");
335
+ controller.getMethod("getOne").setAsync(true).setBody([
336
+ "const user = await this.users.ensureFromPrincipal(this.principalProvider.currentPrincipal);",
337
+ // biome-ignore lint/suspicious/noTemplateCurlyInString: template literal in generated code
338
+ "return { id, message: `Hello ${user.displayName}!`, username: user.displayName };"
339
+ ]);
340
+ }
341
+ }
87
342
  function scaffold(workspace, options) {
88
343
  if (options.authProvider !== "auth0") return;
89
344
  const resource = "Hello";
345
+ const withLocalUsers = options.databaseProvider === "postgres/typeorm";
90
346
  for (const controller of workspace.getModels(ControllerSourceFile)){
91
347
  controller.addDecorator(`@Authorize("read", "${resource}")`).addCortexImport("AllowAnonymous").addCortexImport("Authorize").addCortexImport("IPrincipalProviderToken").addCortexImport("IPrincipalProvider", true).addImport("inject", "@decohere/crucible/decorators").addConstructorParam(`@inject(IPrincipalProviderToken) private readonly principalProvider: IPrincipalProvider`);
92
348
  controller.getMethod("getAll").addDecorator("@AllowAnonymous()");
349
+ if (!withLocalUsers) {
350
+ controller.getMethod("getOne").setBody([
351
+ "const principal = this.principalProvider.currentPrincipal;",
352
+ "const username =",
353
+ '\t(typeof principal?.name === "string" && principal.name) ||',
354
+ '\t(typeof principal?.nickname === "string" && principal.nickname) ||',
355
+ '\t(typeof principal?.email === "string" && principal.email) ||',
356
+ '\t(typeof principal?.preferred_username === "string" && principal.preferred_username) ||',
357
+ "\tprincipal?.sub ||",
358
+ '\t"unknown";',
359
+ // biome-ignore lint/suspicious/noTemplateCurlyInString: template literal in generated code
360
+ "return { id, message: `Hello ${username}!`, username };"
361
+ ]);
362
+ }
93
363
  controller.getMethod("create").addDecorator(`@Authorize("create", "${resource}")`);
94
364
  controller.getMethod("update").addDecorator(`@Authorize("update", "${resource}")`);
95
365
  controller.getMethod("remove").addDecorator(`@Authorize("delete", "${resource}")`);
96
366
  }
97
- workspace.getModel(WELL_KNOWN_FILES.MAIN_TS)?.addSideEffectImport("@decohere/cortex/auth").addBuilderCall(".withAuth()");
367
+ const main = workspace.getModel(WELL_KNOWN_FILES.MAIN_TS);
368
+ main?.addSideEffectImport("@decohere/cortex/auth");
369
+ if (withLocalUsers) {
370
+ scaffoldLocalUserProfile(workspace);
371
+ main?.addBuilderCall(".withAuth(createAbilityFactory, { principalMapper: mapPrincipal })");
372
+ } else {
373
+ main?.addBuilderCall(".withAuth()");
374
+ }
98
375
  // biome-ignore lint/suspicious/noTemplateCurlyInString: intentional YAML env-var placeholders
99
376
  const issuerPlaceholder = "${AUTH0_ISSUER_BASE_URL}";
100
377
  // biome-ignore lint/suspicious/noTemplateCurlyInString: intentional YAML env-var placeholders
@@ -102,14 +379,18 @@ function scaffold(workspace, options) {
102
379
  const configSection = `auth:\n discoveryUrl: ${issuerPlaceholder}\n audience: ${audPlaceholder}\n`;
103
380
  workspace.getModel(WELL_KNOWN_FILES.CONFIG_YAML)?.addSection(configSection);
104
381
  workspace.getModel(WELL_KNOWN_FILES.ENV_FILE)?.addEntry("AUTH0_ISSUER_BASE_URL", options.issuerBaseUrl ?? "").addEntry("AUTH0_AUDIENCE", options.audience ?? "");
105
- workspace.addModel(new AuthConfigModel({
382
+ const authConfig = new AuthConfigModel({
106
383
  issuerBaseUrl: options.issuerBaseUrl ?? "",
107
384
  audience: options.audience ?? ""
108
- }));
385
+ });
386
+ workspace.addModel(authConfig);
387
+ if (withLocalUsers && options.adminPassword) {
388
+ createAuth0AdminUser(workspace, options, authConfig);
389
+ }
109
390
  }
110
391
  export const AuthFeature = {
111
392
  getOptions,
112
393
  scaffold
113
394
  };
114
395
 
115
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL3J1bm5lci93b3JrL2RlY29oZXJlL2RlY29oZXJlL3Byb2plY3RzL2NyZWF0ZS9zcmMvd2ViYXBpL2ZlYXR1cmVzL2F1dGguZmVhdHVyZS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBhc2ssIHBpY2sgfSBmcm9tIFwiLi4vLi4vZG9tYWluL3Byb21wdC5qc1wiO1xuaW1wb3J0IHR5cGUgeyBDb25maWdZYW1sIH0gZnJvbSBcIi4uLy4uL21vZGVscy9jb25maWcteWFtbC5tb2RlbC5qc1wiO1xuaW1wb3J0IHsgV0VMTF9LTk9XTl9GSUxFUyB9IGZyb20gXCIuLi8uLi9tb2RlbHMvY29uc3QuanNcIjtcbmltcG9ydCB0eXBlIHsgRW52RmlsZSB9IGZyb20gXCIuLi8uLi9tb2RlbHMvZW52LWZpbGUubW9kZWwuanNcIjtcbmltcG9ydCB0eXBlIHsgV29ya3NwYWNlU2NhZmZvbGQgfSBmcm9tIFwiLi4vLi4vbW9kZWxzL3Byb2plY3QubW9kZWwuanNcIjtcbmltcG9ydCB0eXBlIHsgRmVhdHVyZSB9IGZyb20gXCIuLi8uLi9zZXJ2aWNlcy9zY2FmZm9sZC5zZXJ2aWNlLmpzXCI7XG5pbXBvcnQgeyBBdXRoQ29uZmlnTW9kZWwgfSBmcm9tIFwiLi4vbW9kZWxzL2F1dGgtY29uZmlnLm1vZGVsLmpzXCI7XG5pbXBvcnQgeyBDb250cm9sbGVyU291cmNlRmlsZSB9IGZyb20gXCIuLi9tb2RlbHMvY29udHJvbGxlci1zb3VyY2UtZmlsZS5tb2RlbC5qc1wiO1xuaW1wb3J0IHR5cGUgeyBNYWluU291cmNlRmlsZSB9IGZyb20gXCIuLi9tb2RlbHMvbWFpbi1zb3VyY2UtZmlsZS5tb2RlbC5qc1wiO1xuaW1wb3J0ICogYXMgYXV0aDBDbGkgZnJvbSBcIi4vYXV0aDAtY2xpLmpzXCI7XG5cbmV4cG9ydCB0eXBlIEF1dGhPcHRpb25zID0ge1xuXHRhdXRoUHJvdmlkZXI/OiBcImF1dGgwXCIgfCBcIm5vbmVcIjtcblx0aXNzdWVyQmFzZVVybD86IHN0cmluZztcblx0YXVkaWVuY2U/OiBzdHJpbmc7XG59O1xuXG5hc3luYyBmdW5jdGlvbiBnZXRPcHRpb25zKFxuXHR3b3Jrc3BhY2U6IFdvcmtzcGFjZVNjYWZmb2xkLFxuXHRjbGlPcHRpb25zOiBQYXJ0aWFsPEF1dGhPcHRpb25zPixcbik6IFByb21pc2U8UGFydGlhbDxBdXRoT3B0aW9ucz4+IHtcblx0aWYgKGNsaU9wdGlvbnMuYXV0aFByb3ZpZGVyICE9IG51bGwpIHJldHVybiB7fTtcblxuXHRjb25zdCBjaG9pY2VzID0gW3sgbGFiZWw6IFwibm9uZVwiIGFzIGNvbnN0IH0sIHsgbGFiZWw6IFwiYXV0aDBcIiBhcyBjb25zdCB9XTtcblx0Y29uc3Qgc2VsZWN0ZWQgPSBhd2FpdCBwaWNrKFwiXFxuICBBdXRoIHByb3ZpZGVyOiBcIiwgY2hvaWNlcywgKGMpID0+IGMubGFiZWwpO1xuXHRjb25zdCBwcm92aWRlciA9IHNlbGVjdGVkPy5sYWJlbCA/PyBcIm5vbmVcIjtcblxuXHRpZiAocHJvdmlkZXIgIT09IFwiYXV0aDBcIikgcmV0dXJuIHsgYXV0aFByb3ZpZGVyOiBcIm5vbmVcIiB9O1xuXG5cdHJldHVybiBnZXRBdXRoME9wdGlvbnMod29ya3NwYWNlKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gZ2V0QXV0aDBPcHRpb25zKHdvcmtzcGFjZTogV29ya3NwYWNlU2NhZmZvbGQpOiBQcm9taXNlPFBhcnRpYWw8QXV0aE9wdGlvbnM+PiB7XG5cdGlmICghYXV0aDBDbGkuaXNJbnN0YWxsZWQoKSkge1xuXHRcdGNvbnNvbGUuZXJyb3IoXG5cdFx0XHRcIlxcbiAgVGhlIEF1dGgwIENMSSBpcyByZXF1aXJlZCBmb3IgYXV0b21hdGVkIHNldHVwLlxcblwiICtcblx0XHRcdFx0XCIgIEluc3RhbGw6IGJyZXcgaW5zdGFsbCBhdXRoMC9hdXRoMC1jbGkvYXV0aDBcXG5cIiArXG5cdFx0XHRcdFwiICBPciB2aXNpdDogaHR0cHM6Ly9naXRodWIuY29tL2F1dGgwL2F1dGgwLWNsaVxcblwiLFxuXHRcdCk7XG5cdFx0cHJvY2Vzcy5leGl0KDEpO1xuXHR9XG5cblx0cHJvY2Vzcy5zdGRvdXQud3JpdGUoXCJcXG4gIENoZWNraW5nIEF1dGgwIGNyZWRlbnRpYWxzLi4uXCIpO1xuXHRsZXQgdGVuYW50cyA9IGF1dGgwQ2xpLmxpc3RUZW5hbnRzKCk7XG5cdGlmICh0ZW5hbnRzLmxlbmd0aCA9PT0gMCkge1xuXHRcdHByb2Nlc3Muc3Rkb3V0LndyaXRlKFwiIG5vdCBsb2dnZWQgaW4uXFxuXCIpO1xuXHRcdGNvbnNvbGUubG9nKFwiICBMb2dnaW5nIGluIHRvIEF1dGgwICh5b3VyIGJyb3dzZXIgd2lsbCBvcGVuKS4uLlwiKTtcblx0XHRpZiAoIWF1dGgwQ2xpLmxvZ2luKCkpIHtcblx0XHRcdGNvbnNvbGUuZXJyb3IoXCJcXG4gIEF1dGgwIGxvZ2luIGZhaWxlZC5cIik7XG5cdFx0XHRwcm9jZXNzLmV4aXQoMSk7XG5cdFx0fVxuXHRcdHRlbmFudHMgPSBhdXRoMENsaS5saXN0VGVuYW50cygpO1xuXHR9XG5cblx0dHJ5IHtcblx0XHRhdXRoMENsaS5saXN0QXBpcygpO1xuXHRcdHByb2Nlc3Muc3Rkb3V0LndyaXRlKFwiIG9rLlxcblwiKTtcblx0fSBjYXRjaCAoZXJyKSB7XG5cdFx0aWYgKGVyciBpbnN0YW5jZW9mIGF1dGgwQ2xpLkF1dGgwQXV0aEVycm9yKSB7XG5cdFx0XHRwcm9jZXNzLnN0ZG91dC53cml0ZShcIiB0b2tlbiBleHBpcmVkLlxcblwiKTtcblx0XHRcdGNvbnNvbGUubG9nKFwiICBSZS1hdXRoZW50aWNhdGluZyAoeW91ciBicm93c2VyIHdpbGwgb3BlbikuLi5cIik7XG5cdFx0XHRpZiAoIWF1dGgwQ2xpLmxvZ2luKCkpIHtcblx0XHRcdFx0Y29uc29sZS5lcnJvcihcIlxcbiAgQXV0aDAgbG9naW4gZmFpbGVkLlwiKTtcblx0XHRcdFx0cHJvY2Vzcy5leGl0KDEpO1xuXHRcdFx0fVxuXHRcdH1cblx0fVxuXG5cdGNvbnN0IGFjdGl2ZSA9IHRlbmFudHMuZmluZCgodCkgPT4gdC5hY3RpdmUpID8/IHRlbmFudHNbMF07XG5cdGNvbnN0IGlzc3VlckJhc2VVcmwgPSBgaHR0cHM6Ly8ke2FjdGl2ZS5uYW1lfWA7XG5cdGNvbnNvbGUubG9nKGBcXG4gIOKckyBBdXRoMCB0ZW5hbnQ6ICR7aXNzdWVyQmFzZVVybH1gKTtcblxuXHRwcm9jZXNzLnN0ZG91dC53cml0ZShcIlxcbiAgRmV0Y2hpbmcgQXV0aDAgQVBJcy4uLlwiKTtcblx0Y29uc3QgdXNlckFwaXMgPSBhdXRoMENsaS5saXN0QXBpcygpLmZpbHRlcigoYSkgPT4gIWEubmFtZS5pbmNsdWRlcyhcIk1hbmFnZW1lbnQgQVBJXCIpKTtcblx0cHJvY2Vzcy5zdGRvdXQud3JpdGUoYCBmb3VuZCAke3VzZXJBcGlzLmxlbmd0aH0uXFxuYCk7XG5cblx0dHlwZSBBcGlDaG9pY2UgPSB7IGxhYmVsOiBzdHJpbmc7IGV4aXN0aW5nOiBzdHJpbmcgfCBudWxsIH07XG5cdGNvbnN0IHByb2plY3ROYW1lID0gd29ya3NwYWNlLm5hbWU7XG5cdGNvbnN0IGFwaUNob2ljZXM6IEFwaUNob2ljZVtdID0gW1xuXHRcdHsgbGFiZWw6IGA8bmV3PiBodHRwczovL2FwaS4ke3Byb2plY3ROYW1lfWAsIGV4aXN0aW5nOiBudWxsIH0sXG5cdFx0Li4udXNlckFwaXMubWFwKChhKSA9PiAoeyBsYWJlbDogYCR7YS5uYW1lfSDigJQgJHthLmlkZW50aWZpZXJ9YCwgZXhpc3Rpbmc6IGEuaWRlbnRpZmllciB9KSksXG5cdF07XG5cblx0Y29uc3QgYXBpU2VsZWN0ZWQgPSBhd2FpdCBwaWNrKFwiXFxuICBTZWxlY3QgQXV0aDAgQVBJOiBcIiwgYXBpQ2hvaWNlcywgKGMpID0+IGMubGFiZWwpO1xuXG5cdGxldCBhdWRpZW5jZTogc3RyaW5nO1xuXHRpZiAoIWFwaVNlbGVjdGVkIHx8IGFwaVNlbGVjdGVkLmV4aXN0aW5nID09PSBudWxsKSB7XG5cdFx0Y29uc3QgZGVmYXVsdElkID0gYGh0dHBzOi8vYXBpLiR7cHJvamVjdE5hbWV9YDtcblx0XHRhdWRpZW5jZSA9IGF3YWl0IGFzayhgICBBUEkgSWRlbnRpZmllciBbJHtkZWZhdWx0SWR9XTogYCwgZGVmYXVsdElkKTtcblx0XHRjb25zb2xlLmxvZyhcIlxcbiAgQ3JlYXRpbmcgQXV0aDAgQVBJLi4uXCIpO1xuXHRcdGF1ZGllbmNlID0gYXV0aDBDbGkuY3JlYXRlQXBpKGAke3Byb2plY3ROYW1lfSBBUElgLCBhdWRpZW5jZSkuaWRlbnRpZmllcjtcblx0XHRjb25zb2xlLmxvZyhgICBcXHUyNzEzIEFQSSBjcmVhdGVkOiAke2F1ZGllbmNlfWApO1xuXHR9IGVsc2Uge1xuXHRcdGF1ZGllbmNlID0gYXBpU2VsZWN0ZWQuZXhpc3Rpbmc7XG5cdFx0Y29uc29sZS5sb2coYCAgXFx1MjcxMyBTZWxlY3RlZDogJHthdWRpZW5jZX1gKTtcblx0fVxuXG5cdHJldHVybiB7IGF1dGhQcm92aWRlcjogXCJhdXRoMFwiLCBpc3N1ZXJCYXNlVXJsLCBhdWRpZW5jZSB9O1xufVxuXG5mdW5jdGlvbiBzY2FmZm9sZCh3b3Jrc3BhY2U6IFdvcmtzcGFjZVNjYWZmb2xkLCBvcHRpb25zOiBBdXRoT3B0aW9ucyk6IHZvaWQge1xuXHRpZiAob3B0aW9ucy5hdXRoUHJvdmlkZXIgIT09IFwiYXV0aDBcIikgcmV0dXJuO1xuXG5cdGNvbnN0IHJlc291cmNlID0gXCJIZWxsb1wiO1xuXG5cdGZvciAoY29uc3QgY29udHJvbGxlciBvZiB3b3Jrc3BhY2UuZ2V0TW9kZWxzKENvbnRyb2xsZXJTb3VyY2VGaWxlKSkge1xuXHRcdGNvbnRyb2xsZXJcblx0XHRcdC5hZGREZWNvcmF0b3IoYEBBdXRob3JpemUoXCJyZWFkXCIsIFwiJHtyZXNvdXJjZX1cIilgKVxuXHRcdFx0LmFkZENvcnRleEltcG9ydChcIkFsbG93QW5vbnltb3VzXCIpXG5cdFx0XHQuYWRkQ29ydGV4SW1wb3J0KFwiQXV0aG9yaXplXCIpXG5cdFx0XHQuYWRkQ29ydGV4SW1wb3J0KFwiSVByaW5jaXBhbFByb3ZpZGVyVG9rZW5cIilcblx0XHRcdC5hZGRDb3J0ZXhJbXBvcnQoXCJJUHJpbmNpcGFsUHJvdmlkZXJcIiwgdHJ1ZSlcblx0XHRcdC5hZGRJbXBvcnQoXCJpbmplY3RcIiwgXCJAZGVjb2hlcmUvY3J1Y2libGUvZGVjb3JhdG9yc1wiKVxuXHRcdFx0LmFkZENvbnN0cnVjdG9yUGFyYW0oXG5cdFx0XHRcdGBAaW5qZWN0KElQcmluY2lwYWxQcm92aWRlclRva2VuKSBwcml2YXRlIHJlYWRvbmx5IHByaW5jaXBhbFByb3ZpZGVyOiBJUHJpbmNpcGFsUHJvdmlkZXJgLFxuXHRcdFx0KTtcblx0XHRjb250cm9sbGVyLmdldE1ldGhvZChcImdldEFsbFwiKS5hZGREZWNvcmF0b3IoXCJAQWxsb3dBbm9ueW1vdXMoKVwiKTtcblx0XHRjb250cm9sbGVyLmdldE1ldGhvZChcImNyZWF0ZVwiKS5hZGREZWNvcmF0b3IoYEBBdXRob3JpemUoXCJjcmVhdGVcIiwgXCIke3Jlc291cmNlfVwiKWApO1xuXHRcdGNvbnRyb2xsZXIuZ2V0TWV0aG9kKFwidXBkYXRlXCIpLmFkZERlY29yYXRvcihgQEF1dGhvcml6ZShcInVwZGF0ZVwiLCBcIiR7cmVzb3VyY2V9XCIpYCk7XG5cdFx0Y29udHJvbGxlci5nZXRNZXRob2QoXCJyZW1vdmVcIikuYWRkRGVjb3JhdG9yKGBAQXV0aG9yaXplKFwiZGVsZXRlXCIsIFwiJHtyZXNvdXJjZX1cIilgKTtcblx0fVxuXG5cdHdvcmtzcGFjZVxuXHRcdC5nZXRNb2RlbDxNYWluU291cmNlRmlsZT4oV0VMTF9LTk9XTl9GSUxFUy5NQUlOX1RTKVxuXHRcdD8uYWRkU2lkZUVmZmVjdEltcG9ydChcIkBkZWNvaGVyZS9jb3J0ZXgvYXV0aFwiKVxuXHRcdC5hZGRCdWlsZGVyQ2FsbChcIi53aXRoQXV0aCgpXCIpO1xuXG5cdC8vIGJpb21lLWlnbm9yZSBsaW50L3N1c3BpY2lvdXMvbm9UZW1wbGF0ZUN1cmx5SW5TdHJpbmc6IGludGVudGlvbmFsIFlBTUwgZW52LXZhciBwbGFjZWhvbGRlcnNcblx0Y29uc3QgaXNzdWVyUGxhY2Vob2xkZXIgPSBcIiR7QVVUSDBfSVNTVUVSX0JBU0VfVVJMfVwiO1xuXHQvLyBiaW9tZS1pZ25vcmUgbGludC9zdXNwaWNpb3VzL25vVGVtcGxhdGVDdXJseUluU3RyaW5nOiBpbnRlbnRpb25hbCBZQU1MIGVudi12YXIgcGxhY2Vob2xkZXJzXG5cdGNvbnN0IGF1ZFBsYWNlaG9sZGVyID0gXCIke0FVVEgwX0FVRElFTkNFfVwiO1xuXG5cdGNvbnN0IGNvbmZpZ1NlY3Rpb24gPSBgYXV0aDpcXG4gIGRpc2NvdmVyeVVybDogJHtpc3N1ZXJQbGFjZWhvbGRlcn1cXG4gIGF1ZGllbmNlOiAke2F1ZFBsYWNlaG9sZGVyfVxcbmA7XG5cblx0d29ya3NwYWNlLmdldE1vZGVsPENvbmZpZ1lhbWw+KFdFTExfS05PV05fRklMRVMuQ09ORklHX1lBTUwpPy5hZGRTZWN0aW9uKGNvbmZpZ1NlY3Rpb24pO1xuXG5cdHdvcmtzcGFjZVxuXHRcdC5nZXRNb2RlbDxFbnZGaWxlPihXRUxMX0tOT1dOX0ZJTEVTLkVOVl9GSUxFKVxuXHRcdD8uYWRkRW50cnkoXCJBVVRIMF9JU1NVRVJfQkFTRV9VUkxcIiwgb3B0aW9ucy5pc3N1ZXJCYXNlVXJsID8/IFwiXCIpXG5cdFx0LmFkZEVudHJ5KFwiQVVUSDBfQVVESUVOQ0VcIiwgb3B0aW9ucy5hdWRpZW5jZSA/PyBcIlwiKTtcblxuXHR3b3Jrc3BhY2UuYWRkTW9kZWwoXG5cdFx0bmV3IEF1dGhDb25maWdNb2RlbCh7XG5cdFx0XHRpc3N1ZXJCYXNlVXJsOiBvcHRpb25zLmlzc3VlckJhc2VVcmwgPz8gXCJcIixcblx0XHRcdGF1ZGllbmNlOiBvcHRpb25zLmF1ZGllbmNlID8/IFwiXCIsXG5cdFx0fSksXG5cdCk7XG59XG5cbmV4cG9ydCBjb25zdCBBdXRoRmVhdHVyZTogRmVhdHVyZTxBdXRoT3B0aW9ucz4gPSB7IGdldE9wdGlvbnMsIHNjYWZmb2xkIH07XG4iXSwibmFtZXMiOlsiYXNrIiwicGljayIsIldFTExfS05PV05fRklMRVMiLCJBdXRoQ29uZmlnTW9kZWwiLCJDb250cm9sbGVyU291cmNlRmlsZSIsImF1dGgwQ2xpIiwiZ2V0T3B0aW9ucyIsIndvcmtzcGFjZSIsImNsaU9wdGlvbnMiLCJhdXRoUHJvdmlkZXIiLCJjaG9pY2VzIiwibGFiZWwiLCJzZWxlY3RlZCIsImMiLCJwcm92aWRlciIsImdldEF1dGgwT3B0aW9ucyIsImlzSW5zdGFsbGVkIiwiY29uc29sZSIsImVycm9yIiwicHJvY2VzcyIsImV4aXQiLCJzdGRvdXQiLCJ3cml0ZSIsInRlbmFudHMiLCJsaXN0VGVuYW50cyIsImxlbmd0aCIsImxvZyIsImxvZ2luIiwibGlzdEFwaXMiLCJlcnIiLCJBdXRoMEF1dGhFcnJvciIsImFjdGl2ZSIsImZpbmQiLCJ0IiwiaXNzdWVyQmFzZVVybCIsIm5hbWUiLCJ1c2VyQXBpcyIsImZpbHRlciIsImEiLCJpbmNsdWRlcyIsInByb2plY3ROYW1lIiwiYXBpQ2hvaWNlcyIsImV4aXN0aW5nIiwibWFwIiwiaWRlbnRpZmllciIsImFwaVNlbGVjdGVkIiwiYXVkaWVuY2UiLCJkZWZhdWx0SWQiLCJjcmVhdGVBcGkiLCJzY2FmZm9sZCIsIm9wdGlvbnMiLCJyZXNvdXJjZSIsImNvbnRyb2xsZXIiLCJnZXRNb2RlbHMiLCJhZGREZWNvcmF0b3IiLCJhZGRDb3J0ZXhJbXBvcnQiLCJhZGRJbXBvcnQiLCJhZGRDb25zdHJ1Y3RvclBhcmFtIiwiZ2V0TWV0aG9kIiwiZ2V0TW9kZWwiLCJNQUlOX1RTIiwiYWRkU2lkZUVmZmVjdEltcG9ydCIsImFkZEJ1aWxkZXJDYWxsIiwiaXNzdWVyUGxhY2Vob2xkZXIiLCJhdWRQbGFjZWhvbGRlciIsImNvbmZpZ1NlY3Rpb24iLCJDT05GSUdfWUFNTCIsImFkZFNlY3Rpb24iLCJFTlZfRklMRSIsImFkZEVudHJ5IiwiYWRkTW9kZWwiLCJBdXRoRmVhdHVyZSJdLCJtYXBwaW5ncyI6IkFBQUEsU0FBU0EsR0FBRyxFQUFFQyxJQUFJLFFBQVEseUJBQXlCO0FBRW5ELFNBQVNDLGdCQUFnQixRQUFRLHdCQUF3QjtBQUl6RCxTQUFTQyxlQUFlLFFBQVEsaUNBQWlD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
396
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL3J1bm5lci93b3JrL2RlY29oZXJlL2RlY29oZXJlL3Byb2plY3RzL2NyZWF0ZS9zcmMvd2ViYXBpL2ZlYXR1cmVzL2F1dGguZmVhdHVyZS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBhc2ssIHBpY2sgfSBmcm9tIFwiLi4vLi4vZG9tYWluL3Byb21wdC5qc1wiO1xuaW1wb3J0IHR5cGUgeyBDb25maWdZYW1sIH0gZnJvbSBcIi4uLy4uL21vZGVscy9jb25maWcteWFtbC5tb2RlbC5qc1wiO1xuaW1wb3J0IHsgV0VMTF9LTk9XTl9GSUxFUyB9IGZyb20gXCIuLi8uLi9tb2RlbHMvY29uc3QuanNcIjtcbmltcG9ydCB0eXBlIHsgRW52RmlsZSB9IGZyb20gXCIuLi8uLi9tb2RlbHMvZW52LWZpbGUubW9kZWwuanNcIjtcbmltcG9ydCB0eXBlIHsgUGFja2FnZUpzb24gfSBmcm9tIFwiLi4vLi4vbW9kZWxzL3BhY2thZ2UtanNvbi5tb2RlbC5qc1wiO1xuaW1wb3J0IHR5cGUgeyBXb3Jrc3BhY2VTY2FmZm9sZCB9IGZyb20gXCIuLi8uLi9tb2RlbHMvcHJvamVjdC5tb2RlbC5qc1wiO1xuaW1wb3J0IHR5cGUgeyBGZWF0dXJlIH0gZnJvbSBcIi4uLy4uL3NlcnZpY2VzL3NjYWZmb2xkLnNlcnZpY2UuanNcIjtcbmltcG9ydCB7IFdFQkFQSV9QUk9KRUNUX0RJUiB9IGZyb20gXCIuLi9jcmVhdGUtYXBpLmpzXCI7XG5pbXBvcnQgdHlwZSB7IEFwaVBhY2thZ2VKc29uIH0gZnJvbSBcIi4uL21vZGVscy9hcGktcGFja2FnZS1qc29uLm1vZGVsLmpzXCI7XG5pbXBvcnQgeyBBdXRoQ29uZmlnTW9kZWwgfSBmcm9tIFwiLi4vbW9kZWxzL2F1dGgtY29uZmlnLm1vZGVsLmpzXCI7XG5pbXBvcnQgeyBDb250cm9sbGVyU291cmNlRmlsZSB9IGZyb20gXCIuLi9tb2RlbHMvY29udHJvbGxlci1zb3VyY2UtZmlsZS5tb2RlbC5qc1wiO1xuaW1wb3J0IHR5cGUgeyBNYWluU291cmNlRmlsZSB9IGZyb20gXCIuLi9tb2RlbHMvbWFpbi1zb3VyY2UtZmlsZS5tb2RlbC5qc1wiO1xuaW1wb3J0ICogYXMgYXV0aDBDbGkgZnJvbSBcIi4vYXV0aDAtY2xpLmpzXCI7XG5cbmV4cG9ydCB0eXBlIEF1dGhPcHRpb25zID0ge1xuXHRhdXRoUHJvdmlkZXI/OiBcImF1dGgwXCIgfCBcIm5vbmVcIjtcblx0aXNzdWVyQmFzZVVybD86IHN0cmluZztcblx0YXVkaWVuY2U/OiBzdHJpbmc7XG5cdGRhdGFiYXNlUHJvdmlkZXI/OiBcIm5vbmVcIiB8IFwicG9zdGdyZXMvdHlwZW9ybVwiO1xuXHRhZG1pblVzZXJuYW1lPzogc3RyaW5nO1xuXHRhZG1pblBhc3N3b3JkPzogc3RyaW5nO1xufTtcblxuY29uc3QgQURNSU5fUk9MRSA9IFwiYWRtaW5cIjtcblxuY29uc3QgVVNFUl9FTlRJVFlfVFMgPSBgaW1wb3J0IHsgQ29sdW1uLCBFbnRpdHksIFByaW1hcnlHZW5lcmF0ZWRDb2x1bW4gfSBmcm9tIFwidHlwZW9ybVwiO1xuaW1wb3J0IHR5cGUgeyBFbnRpdHkgYXMgSUVudGl0eSB9IGZyb20gXCJAZGVjb2hlcmUvY29kZXhcIjtcblxuQEVudGl0eSgpXG5leHBvcnQgY2xhc3MgVXNlckVudGl0eSBpbXBsZW1lbnRzIElFbnRpdHkge1xuXFx0QFByaW1hcnlHZW5lcmF0ZWRDb2x1bW4oKVxuXFx0cHVibGljIGlkITogbnVtYmVyO1xuXG5cXHRAQ29sdW1uKHsgdW5pcXVlOiB0cnVlIH0pXG5cXHRwdWJsaWMgc3ViITogc3RyaW5nO1xuXG5cXHRAQ29sdW1uKHsgdHlwZTogXCJ2YXJjaGFyXCIsIG51bGxhYmxlOiB0cnVlIH0pXG5cXHRwdWJsaWMgZW1haWwhOiBzdHJpbmcgfCBudWxsO1xuXG5cXHRAQ29sdW1uKClcblxcdHB1YmxpYyBkaXNwbGF5TmFtZSE6IHN0cmluZztcblxuXFx0LyoqIEFwcC1vd25lZCByb2xlcy4gVGhlIFxcYGFkbWluXFxgIHJvbGUgZ3JhbnRzIENBU0wgXFxgbWFuYWdlXFxgL1xcYGFsbFxcYCAod2lsZGNhcmQpLiAqL1xuXFx0QENvbHVtbih7IHR5cGU6IFwic2ltcGxlLWpzb25cIiwgZGVmYXVsdDogXCJbXVwiIH0pXG5cXHRwdWJsaWMgcm9sZXMhOiBzdHJpbmdbXTtcbn1cbmA7XG5cbmNvbnN0IFVTRVJfUkVQT1NJVE9SWV9UUyA9IGBpbXBvcnQgeyBpbmplY3RhYmxlIH0gZnJvbSBcIkBkZWNvaGVyZS9jcnVjaWJsZS9kZWNvcmF0b3JzXCI7XG5pbXBvcnQgeyBpbmplY3RVbml0T2ZXb3JrIH0gZnJvbSBcIkBkZWNvaGVyZS9jb2RleFwiO1xuaW1wb3J0IHsgVHlwZU9ybVJlcG9zaXRvcnksIFR5cGVPcm1Vbml0T2ZXb3JrIH0gZnJvbSBcIkBkZWNvaGVyZS9jb2RleC10eXBlb3JtXCI7XG5pbXBvcnQgeyBVc2VyRW50aXR5IH0gZnJvbSBcIi4uL2VudGl0aWVzL3VzZXIuZW50aXR5LmpzXCI7XG5cbkBpbmplY3RhYmxlKClcbmV4cG9ydCBjbGFzcyBVc2VyRW50aXR5UmVwb3NpdG9yeSBleHRlbmRzIFR5cGVPcm1SZXBvc2l0b3J5PFVzZXJFbnRpdHk+IHtcblxcdHB1YmxpYyBjb25zdHJ1Y3RvcihAaW5qZWN0VW5pdE9mV29yaygpIHVuaXRPZldvcms6IFR5cGVPcm1Vbml0T2ZXb3JrKSB7XG5cXHRcXHRzdXBlcih1bml0T2ZXb3JrLCBVc2VyRW50aXR5KTtcblxcdH1cblxuXFx0cHVibGljIGZpbmRCeVN1YihzdWI6IHN0cmluZyk6IFByb21pc2U8VXNlckVudGl0eSB8IG51bGw+IHtcblxcdFxcdHJldHVybiB0aGlzLmZpcnN0T3JEZWZhdWx0KHsgd2hlcmU6IHsgc3ViIH0gfSk7XG5cXHR9XG59XG5gO1xuXG5jb25zdCBVU0VSX1NFUlZJQ0VfVFMgPSBgaW1wb3J0IHsgaW5qZWN0YWJsZSB9IGZyb20gXCJAZGVjb2hlcmUvY3J1Y2libGUvZGVjb3JhdG9yc1wiO1xuaW1wb3J0IHR5cGUgeyBQcmluY2lwYWwgfSBmcm9tIFwiQGRlY29oZXJlL2NvcnRleFwiO1xuaW1wb3J0IHsgVXNlckVudGl0eSB9IGZyb20gXCIuLi9lbnRpdGllcy91c2VyLmVudGl0eS5qc1wiO1xuaW1wb3J0IHsgVXNlckVudGl0eVJlcG9zaXRvcnkgfSBmcm9tIFwiLi4vcmVwb3NpdG9yaWVzL3VzZXIucmVwb3NpdG9yeS5qc1wiO1xuXG5mdW5jdGlvbiBjbGFpbVN0cmluZyhwcmluY2lwYWw6IFByaW5jaXBhbCB8IHVuZGVmaW5lZCwga2V5OiBzdHJpbmcpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuXFx0Y29uc3QgdmFsdWUgPSBwcmluY2lwYWw/LltrZXldO1xuXFx0cmV0dXJuIHR5cGVvZiB2YWx1ZSA9PT0gXCJzdHJpbmdcIiAmJiB2YWx1ZS5sZW5ndGggPiAwID8gdmFsdWUgOiB1bmRlZmluZWQ7XG59XG5cbkBpbmplY3RhYmxlKClcbmV4cG9ydCBjbGFzcyBVc2VyU2VydmljZSB7XG5cXHRwdWJsaWMgY29uc3RydWN0b3IocHJpdmF0ZSByZWFkb25seSB1c2VyczogVXNlckVudGl0eVJlcG9zaXRvcnkpIHt9XG5cblxcdC8qKlxuXFx0ICogVXBzZXJ0IGEgbG9jYWwgcHJvZmlsZSBrZXllZCBieSBKV1QgXFxgc3ViXFxgLlxuXFx0ICogUHJvZmlsZSBmaWVsZHMgZnJvbSB0aGUgdG9rZW4gZmlsbCBnYXBzOyBzZWVkZWQgcm93cyBrZWVwIGRpc3BsYXlOYW1lL2VtYWlsL3JvbGVzLlxuXFx0ICovXG5cXHRwdWJsaWMgYXN5bmMgZW5zdXJlRnJvbVByaW5jaXBhbChwcmluY2lwYWw6IFByaW5jaXBhbCB8IHVuZGVmaW5lZCk6IFByb21pc2U8VXNlckVudGl0eT4ge1xuXFx0XFx0Y29uc3Qgc3ViID0gcHJpbmNpcGFsPy5zdWI7XG5cXHRcXHRpZiAoIXN1Yikge1xuXFx0XFx0XFx0dGhyb3cgbmV3IEVycm9yKFwiQXV0aGVudGljYXRlZCByZXF1ZXN0IGlzIG1pc3NpbmcgcHJpbmNpcGFsLnN1YlwiKTtcblxcdFxcdH1cblxuXFx0XFx0Y29uc3QgZW1haWwgPVxuXFx0XFx0XFx0Y2xhaW1TdHJpbmcocHJpbmNpcGFsLCBcImVtYWlsXCIpID8/IGNsYWltU3RyaW5nKHByaW5jaXBhbCwgXCJwcmVmZXJyZWRfdXNlcm5hbWVcIik7XG5cXHRcXHRjb25zdCBkaXNwbGF5RnJvbVRva2VuID1cblxcdFxcdFxcdGNsYWltU3RyaW5nKHByaW5jaXBhbCwgXCJuYW1lXCIpID8/XG5cXHRcXHRcXHRjbGFpbVN0cmluZyhwcmluY2lwYWwsIFwibmlja25hbWVcIikgPz9cblxcdFxcdFxcdGVtYWlsO1xuXG5cXHRcXHRjb25zdCBleGlzdGluZyA9IGF3YWl0IHRoaXMudXNlcnMuZmluZEJ5U3ViKHN1Yik7XG5cXHRcXHRpZiAoZXhpc3RpbmcpIHtcblxcdFxcdFxcdGxldCBkaXJ0eSA9IGZhbHNlO1xuXFx0XFx0XFx0aWYgKCFleGlzdGluZy5lbWFpbCAmJiBlbWFpbCkge1xuXFx0XFx0XFx0XFx0ZXhpc3RpbmcuZW1haWwgPSBlbWFpbDtcblxcdFxcdFxcdFxcdGRpcnR5ID0gdHJ1ZTtcblxcdFxcdFxcdH1cblxcdFxcdFxcdGlmIChleGlzdGluZy5kaXNwbGF5TmFtZSA9PT0gZXhpc3Rpbmcuc3ViICYmIGRpc3BsYXlGcm9tVG9rZW4pIHtcblxcdFxcdFxcdFxcdGV4aXN0aW5nLmRpc3BsYXlOYW1lID0gZGlzcGxheUZyb21Ub2tlbjtcblxcdFxcdFxcdFxcdGRpcnR5ID0gdHJ1ZTtcblxcdFxcdFxcdH1cblxcdFxcdFxcdHJldHVybiBkaXJ0eSA/IHRoaXMudXNlcnMuc2F2ZShleGlzdGluZykgOiBleGlzdGluZztcblxcdFxcdH1cblxuXFx0XFx0Y29uc3QgY3JlYXRlZCA9IG5ldyBVc2VyRW50aXR5KCk7XG5cXHRcXHRjcmVhdGVkLnN1YiA9IHN1YjtcblxcdFxcdGNyZWF0ZWQuZW1haWwgPSBlbWFpbCA/PyBudWxsO1xuXFx0XFx0Y3JlYXRlZC5kaXNwbGF5TmFtZSA9IGRpc3BsYXlGcm9tVG9rZW4gPz8gc3ViO1xuXFx0XFx0Y3JlYXRlZC5yb2xlcyA9IEFycmF5LmlzQXJyYXkocHJpbmNpcGFsLnJvbGVzKVxuXFx0XFx0XFx0PyBwcmluY2lwYWwucm9sZXMuZmlsdGVyKChyKTogciBpcyBzdHJpbmcgPT4gdHlwZW9mIHIgPT09IFwic3RyaW5nXCIpXG5cXHRcXHRcXHQ6IFtdO1xuXFx0XFx0cmV0dXJuIHRoaXMudXNlcnMuc2F2ZShjcmVhdGVkKTtcblxcdH1cbn1cbmA7XG5cbmNvbnN0IEFCSUxJVFlfRkFDVE9SWV9UUyA9IGBpbXBvcnQgeyBBYmlsaXR5QnVpbGRlciwgY3JlYXRlTW9uZ29BYmlsaXR5IH0gZnJvbSBcIkBjYXNsL2FiaWxpdHlcIjtcbmltcG9ydCB0eXBlIHsgUHJpbmNpcGFsIH0gZnJvbSBcIkBkZWNvaGVyZS9jb3J0ZXhcIjtcblxuLyoqIFJvb3Qgcm9sZSDigJQgZXhwYW5kcyB0byBDQVNMIFxcYG1hbmFnZVxcYC9cXGBhbGxcXGAgKGNvdmVycyBldmVyeSBmdXR1cmUgYWJpbGl0eSkuICovXG5leHBvcnQgY29uc3QgQURNSU5fUk9MRSA9IFwiYWRtaW5cIjtcblxuLyoqXG4gKiBSb2xlcyBhcmUgY29sbGVjdGlvbnMgb2YgYWJpbGl0aWVzLiBBZG1pbiBpcyBhIHdpbGRjYXJkLCBub3QgYW4gZW51bWVyYXRlZCBsaXN0LlxuICogTm9uLWFkbWluIHByaW5jaXBhbHMga2VlcCB0aGUgZGVmYXVsdCBBdXRoMCBzY29wZSDihpIgYWJpbGl0eSBtYXBwaW5nLlxuICovXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlQWJpbGl0eUZhY3RvcnkocHJpbmNpcGFsOiBQcmluY2lwYWwpIHtcblxcdGNvbnN0IHsgY2FuLCBidWlsZCB9ID0gbmV3IEFiaWxpdHlCdWlsZGVyKGNyZWF0ZU1vbmdvQWJpbGl0eSk7XG5cXHRpZiAocHJpbmNpcGFsLnJvbGVzPy5pbmNsdWRlcyhBRE1JTl9ST0xFKSkge1xuXFx0XFx0Y2FuKFwibWFuYWdlXCIsIFwiYWxsXCIpO1xuXFx0XFx0cmV0dXJuIGJ1aWxkKCk7XG5cXHR9XG5cXHRmb3IgKGNvbnN0IHNjb3BlIG9mIHByaW5jaXBhbC5zY29wZXMgPz8gW10pIHtcblxcdFxcdGNvbnN0IFthY3Rpb24sIHN1YmplY3RdID0gc2NvcGUuc3BsaXQoXCI6XCIpO1xuXFx0XFx0aWYgKGFjdGlvbiAmJiBzdWJqZWN0KSBjYW4oYWN0aW9uLCBzdWJqZWN0KTtcblxcdH1cblxcdHJldHVybiBidWlsZCgpO1xufVxuXG4vKipcbiAqIE1hcCBKV1QgcGF5bG9hZCDihpIgUHJpbmNpcGFsLiBCb290c3RyYXBzIHRoZSBzZWVkZWQgQXV0aDAgYWRtaW4gXFxgc3ViXFxgIHdpdGhcbiAqIHRoZSBhZG1pbiByb2xlIHNvIGF1dGhvcml6YXRpb24gd29ya3MgYmVmb3JlL3dpdGhvdXQgcm9sZXMgaW4gdGhlIGFjY2VzcyB0b2tlbi5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG1hcFByaW5jaXBhbChwYXlsb2FkOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPik6IFByaW5jaXBhbCB7XG5cXHRjb25zdCBzdWIgPSB0eXBlb2YgcGF5bG9hZC5zdWIgPT09IFwic3RyaW5nXCIgPyBwYXlsb2FkLnN1YiA6IFwiXCI7XG5cXHRjb25zdCBzY29wZXMgPSBBcnJheS5pc0FycmF5KHBheWxvYWQuc2NvcGVzKVxuXFx0XFx0PyAocGF5bG9hZC5zY29wZXMgYXMgc3RyaW5nW10pXG5cXHRcXHQ6IHR5cGVvZiBwYXlsb2FkLnNjb3BlID09PSBcInN0cmluZ1wiXG5cXHRcXHRcXHQ/IHBheWxvYWQuc2NvcGUuc3BsaXQoXCIgXCIpXG5cXHRcXHRcXHQ6IHVuZGVmaW5lZDtcblxcdGNvbnN0IGZyb21Ub2tlbiA9IEFycmF5LmlzQXJyYXkocGF5bG9hZC5yb2xlcylcblxcdFxcdD8gKHBheWxvYWQucm9sZXMgYXMgdW5rbm93bltdKS5maWx0ZXIoKHIpOiByIGlzIHN0cmluZyA9PiB0eXBlb2YgciA9PT0gXCJzdHJpbmdcIilcblxcdFxcdDogW107XG5cXHRjb25zdCByb2xlcyA9XG5cXHRcXHRzdWIgJiYgc3ViID09PSBwcm9jZXNzLmVudi5BVVRIMF9BRE1JTl9VU0VSX1NVQlxuXFx0XFx0XFx0PyBbLi4ubmV3IFNldChbQURNSU5fUk9MRSwgLi4uZnJvbVRva2VuXSldXG5cXHRcXHRcXHQ6IGZyb21Ub2tlbi5sZW5ndGggPiAwXG5cXHRcXHRcXHRcXHQ/IGZyb21Ub2tlblxuXFx0XFx0XFx0XFx0OiB1bmRlZmluZWQ7XG5cXHRyZXR1cm4geyAuLi5wYXlsb2FkLCBzdWIsIHJvbGVzLCBzY29wZXMgfTtcbn1cbmA7XG5cbmFzeW5jIGZ1bmN0aW9uIGdldE9wdGlvbnMoXG5cdHdvcmtzcGFjZTogV29ya3NwYWNlU2NhZmZvbGQsXG5cdGNsaU9wdGlvbnM6IFBhcnRpYWw8QXV0aE9wdGlvbnM+LFxuKTogUHJvbWlzZTxQYXJ0aWFsPEF1dGhPcHRpb25zPj4ge1xuXHRpZiAoY2xpT3B0aW9ucy5hdXRoUHJvdmlkZXIgPT09IFwiYXV0aDBcIiAmJiAhY2xpT3B0aW9ucy5pc3N1ZXJCYXNlVXJsKSB7XG5cdFx0cmV0dXJuIGdldEF1dGgwT3B0aW9ucyh3b3Jrc3BhY2UsIGNsaU9wdGlvbnMpO1xuXHR9XG5cdGlmIChjbGlPcHRpb25zLmF1dGhQcm92aWRlciAhPSBudWxsKSByZXR1cm4ge307XG5cblx0Y29uc3QgY2hvaWNlcyA9IFt7IGxhYmVsOiBcIm5vbmVcIiBhcyBjb25zdCB9LCB7IGxhYmVsOiBcImF1dGgwXCIgYXMgY29uc3QgfV07XG5cdGNvbnN0IHNlbGVjdGVkID0gYXdhaXQgcGljayhcIlxcbiAgQXV0aCBwcm92aWRlcjogXCIsIGNob2ljZXMsIChjKSA9PiBjLmxhYmVsKTtcblx0Y29uc3QgcHJvdmlkZXIgPSBzZWxlY3RlZD8ubGFiZWwgPz8gXCJub25lXCI7XG5cblx0aWYgKHByb3ZpZGVyICE9PSBcImF1dGgwXCIpIHJldHVybiB7IGF1dGhQcm92aWRlcjogXCJub25lXCIgfTtcblxuXHRyZXR1cm4gZ2V0QXV0aDBPcHRpb25zKHdvcmtzcGFjZSwgY2xpT3B0aW9ucyk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGdldEF1dGgwT3B0aW9ucyhcblx0d29ya3NwYWNlOiBXb3Jrc3BhY2VTY2FmZm9sZCxcblx0Y2xpT3B0aW9uczogUGFydGlhbDxBdXRoT3B0aW9ucz4sXG4pOiBQcm9taXNlPFBhcnRpYWw8QXV0aE9wdGlvbnM+PiB7XG5cdGlmICghYXV0aDBDbGkuaXNJbnN0YWxsZWQoKSkge1xuXHRcdGNvbnNvbGUuZXJyb3IoXG5cdFx0XHRcIlxcbiAgVGhlIEF1dGgwIENMSSBpcyByZXF1aXJlZCBmb3IgYXV0b21hdGVkIHNldHVwLlxcblwiICtcblx0XHRcdFx0XCIgIEluc3RhbGw6IGJyZXcgaW5zdGFsbCBhdXRoMC9hdXRoMC1jbGkvYXV0aDBcXG5cIiArXG5cdFx0XHRcdFwiICBPciB2aXNpdDogaHR0cHM6Ly9naXRodWIuY29tL2F1dGgwL2F1dGgwLWNsaVxcblwiLFxuXHRcdCk7XG5cdFx0cHJvY2Vzcy5leGl0KDEpO1xuXHR9XG5cblx0cHJvY2Vzcy5zdGRvdXQud3JpdGUoXCJcXG4gIENoZWNraW5nIEF1dGgwIGNyZWRlbnRpYWxzLi4uXCIpO1xuXHRsZXQgdGVuYW50cyA9IGF1dGgwQ2xpLmxpc3RUZW5hbnRzKCk7XG5cdGlmICh0ZW5hbnRzLmxlbmd0aCA9PT0gMCkge1xuXHRcdHByb2Nlc3Muc3Rkb3V0LndyaXRlKFwiIG5vdCBsb2dnZWQgaW4uXFxuXCIpO1xuXHRcdGNvbnNvbGUubG9nKFwiICBMb2dnaW5nIGluIHRvIEF1dGgwICh5b3VyIGJyb3dzZXIgd2lsbCBvcGVuKS4uLlwiKTtcblx0XHRpZiAoIWF1dGgwQ2xpLmxvZ2luKCkpIHtcblx0XHRcdGNvbnNvbGUuZXJyb3IoXCJcXG4gIEF1dGgwIGxvZ2luIGZhaWxlZC5cIik7XG5cdFx0XHRwcm9jZXNzLmV4aXQoMSk7XG5cdFx0fVxuXHRcdHRlbmFudHMgPSBhdXRoMENsaS5saXN0VGVuYW50cygpO1xuXHR9XG5cblx0dHJ5IHtcblx0XHRhdXRoMENsaS5saXN0QXBpcygpO1xuXHRcdHByb2Nlc3Muc3Rkb3V0LndyaXRlKFwiIG9rLlxcblwiKTtcblx0fSBjYXRjaCAoZXJyKSB7XG5cdFx0aWYgKGVyciBpbnN0YW5jZW9mIGF1dGgwQ2xpLkF1dGgwQXV0aEVycm9yKSB7XG5cdFx0XHRwcm9jZXNzLnN0ZG91dC53cml0ZShcIiB0b2tlbiBleHBpcmVkLlxcblwiKTtcblx0XHRcdGNvbnNvbGUubG9nKFwiICBSZS1hdXRoZW50aWNhdGluZyAoeW91ciBicm93c2VyIHdpbGwgb3BlbikuLi5cIik7XG5cdFx0XHRpZiAoIWF1dGgwQ2xpLmxvZ2luKCkpIHtcblx0XHRcdFx0Y29uc29sZS5lcnJvcihcIlxcbiAgQXV0aDAgbG9naW4gZmFpbGVkLlwiKTtcblx0XHRcdFx0cHJvY2Vzcy5leGl0KDEpO1xuXHRcdFx0fVxuXHRcdH1cblx0fVxuXG5cdGNvbnN0IGFjdGl2ZSA9IHRlbmFudHMuZmluZCgodCkgPT4gdC5hY3RpdmUpID8/IHRlbmFudHNbMF07XG5cdGNvbnN0IGlzc3VlckJhc2VVcmwgPSBgaHR0cHM6Ly8ke2FjdGl2ZS5uYW1lfWA7XG5cdGNvbnNvbGUubG9nKGBcXG4gIOKckyBBdXRoMCB0ZW5hbnQ6ICR7aXNzdWVyQmFzZVVybH1gKTtcblxuXHRwcm9jZXNzLnN0ZG91dC53cml0ZShcIlxcbiAgRmV0Y2hpbmcgQXV0aDAgQVBJcy4uLlwiKTtcblx0Y29uc3QgdXNlckFwaXMgPSBhdXRoMENsaS5saXN0QXBpcygpLmZpbHRlcigoYSkgPT4gIWEubmFtZS5pbmNsdWRlcyhcIk1hbmFnZW1lbnQgQVBJXCIpKTtcblx0cHJvY2Vzcy5zdGRvdXQud3JpdGUoYCBmb3VuZCAke3VzZXJBcGlzLmxlbmd0aH0uXFxuYCk7XG5cblx0dHlwZSBBcGlDaG9pY2UgPSB7IGxhYmVsOiBzdHJpbmc7IGV4aXN0aW5nOiBzdHJpbmcgfCBudWxsIH07XG5cdGNvbnN0IHByb2plY3ROYW1lID0gd29ya3NwYWNlLm5hbWU7XG5cdGNvbnN0IGFwaUNob2ljZXM6IEFwaUNob2ljZVtdID0gW1xuXHRcdHsgbGFiZWw6IGA8bmV3PiBodHRwczovL2FwaS4ke3Byb2plY3ROYW1lfWAsIGV4aXN0aW5nOiBudWxsIH0sXG5cdFx0Li4udXNlckFwaXMubWFwKChhKSA9PiAoeyBsYWJlbDogYCR7YS5uYW1lfSDigJQgJHthLmlkZW50aWZpZXJ9YCwgZXhpc3Rpbmc6IGEuaWRlbnRpZmllciB9KSksXG5cdF07XG5cblx0Y29uc3QgYXBpU2VsZWN0ZWQgPSBhd2FpdCBwaWNrKFwiXFxuICBTZWxlY3QgQXV0aDAgQVBJOiBcIiwgYXBpQ2hvaWNlcywgKGMpID0+IGMubGFiZWwpO1xuXG5cdGxldCBhdWRpZW5jZTogc3RyaW5nO1xuXHRpZiAoIWFwaVNlbGVjdGVkIHx8IGFwaVNlbGVjdGVkLmV4aXN0aW5nID09PSBudWxsKSB7XG5cdFx0Y29uc3QgZGVmYXVsdElkID0gYGh0dHBzOi8vYXBpLiR7cHJvamVjdE5hbWV9YDtcblx0XHRhdWRpZW5jZSA9IGF3YWl0IGFzayhgICBBUEkgSWRlbnRpZmllciBbJHtkZWZhdWx0SWR9XTogYCwgZGVmYXVsdElkKTtcblx0XHRjb25zb2xlLmxvZyhcIlxcbiAgQ3JlYXRpbmcgQXV0aDAgQVBJLi4uXCIpO1xuXHRcdGF1ZGllbmNlID0gYXV0aDBDbGkuY3JlYXRlQXBpKGAke3Byb2plY3ROYW1lfSBBUElgLCBhdWRpZW5jZSkuaWRlbnRpZmllcjtcblx0XHRjb25zb2xlLmxvZyhgICBcXHUyNzEzIEFQSSBjcmVhdGVkOiAke2F1ZGllbmNlfWApO1xuXHR9IGVsc2Uge1xuXHRcdGF1ZGllbmNlID0gYXBpU2VsZWN0ZWQuZXhpc3Rpbmc7XG5cdFx0Y29uc29sZS5sb2coYCAgXFx1MjcxMyBTZWxlY3RlZDogJHthdWRpZW5jZX1gKTtcblx0XHR0cnkge1xuXHRcdFx0YXV0aDBDbGkudXBkYXRlQXBpU2NvcGVzKGF1ZGllbmNlKTtcblx0XHRcdGNvbnNvbGUubG9nKGAgIFxcdTI3MTMgQVBJIHNjb3BlcyBlbnN1cmVkICgke2F1dGgwQ2xpLkhFTExPX0FQSV9TQ09QRVMuam9pbihcIiwgXCIpfSlgKTtcblx0XHR9IGNhdGNoIHtcblx0XHRcdGNvbnNvbGUuZXJyb3IoXG5cdFx0XHRcdFwiICDinJcgRmFpbGVkIHRvIHVwZGF0ZSBBUEkgc2NvcGVzIOKAlCBhZGQgSGVsbG8gc2NvcGVzIGluIHRoZSBBdXRoMCBkYXNoYm9hcmQuXCIsXG5cdFx0XHQpO1xuXHRcdH1cblx0fVxuXG5cdGNvbnN0IHdpdGhMb2NhbFVzZXJzID0gY2xpT3B0aW9ucy5kYXRhYmFzZVByb3ZpZGVyID09PSBcInBvc3RncmVzL3R5cGVvcm1cIjtcblx0bGV0IGFkbWluVXNlcm5hbWU6IHN0cmluZyB8IHVuZGVmaW5lZDtcblx0bGV0IGFkbWluUGFzc3dvcmQ6IHN0cmluZyB8IHVuZGVmaW5lZDtcblx0aWYgKHdpdGhMb2NhbFVzZXJzKSB7XG5cdFx0YWRtaW5Vc2VybmFtZSA9XG5cdFx0XHRjbGlPcHRpb25zLmFkbWluVXNlcm5hbWUgPz8gKGF3YWl0IGFzayhcIlxcbiAgQWRtaW4gdXNlcm5hbWUgW2FkbWluXTogXCIsIFwiYWRtaW5cIikpO1xuXHRcdGFkbWluUGFzc3dvcmQgPSBjbGlPcHRpb25zLmFkbWluUGFzc3dvcmQ7XG5cdFx0aWYgKGFkbWluUGFzc3dvcmQgPT0gbnVsbCkge1xuXHRcdFx0YWRtaW5QYXNzd29yZCA9IGF3YWl0IGFzayhcIiAgQWRtaW4gcGFzc3dvcmQgKGxlYXZlIGJsYW5rIHRvIGdlbmVyYXRlKTogXCIpO1xuXHRcdFx0aWYgKCFhZG1pblBhc3N3b3JkKSB7XG5cdFx0XHRcdGFkbWluUGFzc3dvcmQgPSBhdXRoMENsaS5nZW5lcmF0ZUFkbWluUGFzc3dvcmQoKTtcblx0XHRcdFx0Y29uc29sZS5sb2coYCAg4pyTIEdlbmVyYXRlZCBhZG1pbiBwYXNzd29yZCAod3JpdHRlbiB0byAuZW52KTogJHthZG1pblBhc3N3b3JkfWApO1xuXHRcdFx0fVxuXHRcdH1cblx0fVxuXG5cdHJldHVybiB7XG5cdFx0YXV0aFByb3ZpZGVyOiBcImF1dGgwXCIsXG5cdFx0aXNzdWVyQmFzZVVybCxcblx0XHRhdWRpZW5jZSxcblx0XHQuLi4od2l0aExvY2FsVXNlcnMgPyB7IGFkbWluVXNlcm5hbWUsIGFkbWluUGFzc3dvcmQgfSA6IHt9KSxcblx0fTtcbn1cblxuZnVuY3Rpb24gYWRtaW5FbWFpbCh3b3Jrc3BhY2VOYW1lOiBzdHJpbmcsIHVzZXJuYW1lOiBzdHJpbmcpOiBzdHJpbmcge1xuXHRpZiAodXNlcm5hbWUuaW5jbHVkZXMoXCJAXCIpKSByZXR1cm4gdXNlcm5hbWU7XG5cdGNvbnN0IHNsdWcgPSB3b3Jrc3BhY2VOYW1lLnRvTG93ZXJDYXNlKCkucmVwbGFjZSgvW15hLXowLTktXS9nLCBcIi1cIik7XG5cdHJldHVybiBgJHt1c2VybmFtZX1AJHtzbHVnfS5leGFtcGxlLmNvbWA7XG59XG5cbmZ1bmN0aW9uIGNyZWF0ZUF1dGgwQWRtaW5Vc2VyKFxuXHR3b3Jrc3BhY2U6IFdvcmtzcGFjZVNjYWZmb2xkLFxuXHRvcHRpb25zOiBBdXRoT3B0aW9ucyxcblx0YXV0aENvbmZpZzogQXV0aENvbmZpZ01vZGVsLFxuKTogdm9pZCB7XG5cdGNvbnN0IHVzZXJuYW1lID0gb3B0aW9ucy5hZG1pblVzZXJuYW1lID8/IFwiYWRtaW5cIjtcblx0Y29uc3QgcGFzc3dvcmQgPSBvcHRpb25zLmFkbWluUGFzc3dvcmQ7XG5cdGlmICghcGFzc3dvcmQpIHJldHVybjtcblxuXHRjb25zdCBlbWFpbCA9IGFkbWluRW1haWwod29ya3NwYWNlLm5hbWUsIHVzZXJuYW1lKTtcblx0dHJ5IHtcblx0XHRjb25zdCBhZG1pbiA9IGF1dGgwQ2xpLmNyZWF0ZUFkbWluRGF0YWJhc2VVc2VyKHsgZW1haWwsIHBhc3N3b3JkLCB1c2VybmFtZSB9KTtcblx0XHRhdXRoQ29uZmlnLnNldEFkbWluVXNlcih7XG5cdFx0XHRzdWI6IGFkbWluLnVzZXJfaWQsXG5cdFx0XHRlbWFpbDogYWRtaW4uZW1haWwsXG5cdFx0XHRwYXNzd29yZDogYWRtaW4ucGFzc3dvcmQsXG5cdFx0XHR1c2VybmFtZTogYWRtaW4udXNlcm5hbWUsXG5cdFx0fSk7XG5cdFx0d29ya3NwYWNlXG5cdFx0XHQuZ2V0TW9kZWw8RW52RmlsZT4oV0VMTF9LTk9XTl9GSUxFUy5FTlZfRklMRSlcblx0XHRcdD8uYWRkRW50cnkoXCJBVVRIMF9BRE1JTl9VU0VSX1NVQlwiLCBhZG1pbi51c2VyX2lkKVxuXHRcdFx0LmFkZEVudHJ5KFwiQVVUSDBfQURNSU5fVVNFUl9FTUFJTFwiLCBhZG1pbi5lbWFpbClcblx0XHRcdC5hZGRFbnRyeShcIkFVVEgwX0FETUlOX1VTRVJfUEFTU1dPUkRcIiwgYWRtaW4ucGFzc3dvcmQpXG5cdFx0XHQuYWRkRW50cnkoXCJBVVRIMF9BRE1JTl9VU0VSTkFNRVwiLCBhZG1pbi51c2VybmFtZSk7XG5cdFx0Y29uc29sZS5sb2coYCAg4pyTIEF1dGgwIGFkbWluIHVzZXIgcmVhZHk6ICR7YWRtaW4uZW1haWx9IChyb2xlOiAke0FETUlOX1JPTEV9KWApO1xuXHRcdGNvbnNvbGUubG9nKGAgICAgTG9naW4gd2l0aCBFTUFJTCAobm90IHVzZXJuYW1lKTogJHthZG1pbi5lbWFpbH1gKTtcblx0XHRjb25zb2xlLmxvZyhgICAgIFBhc3N3b3JkOiBzZWUgQVVUSDBfQURNSU5fVVNFUl9QQVNTV09SRCBpbiAuZW52YCk7XG5cdH0gY2F0Y2ggKGVycikge1xuXHRcdGNvbnNvbGUuZXJyb3IoXG5cdFx0XHRgICDinJcgRmFpbGVkIHRvIGVuc3VyZSBBdXRoMCBhZG1pbiB1c2VyICgke2VtYWlsfSk6ICR7ZXJyIGluc3RhbmNlb2YgRXJyb3IgPyBlcnIubWVzc2FnZSA6IGVycn1gLFxuXHRcdCk7XG5cdH1cbn1cblxuZnVuY3Rpb24gc2NhZmZvbGRMb2NhbFVzZXJQcm9maWxlKHdvcmtzcGFjZTogV29ya3NwYWNlU2NhZmZvbGQpOiB2b2lkIHtcblx0d29ya3NwYWNlXG5cdFx0LmdldE1vZGVsPFBhY2thZ2VKc29uPihXRUxMX0tOT1dOX0ZJTEVTLlBBQ0tBR0VfSlNPTilcblx0XHQ/LmFkZERlcGVuZGVuY3koXCJAY2FzbC9hYmlsaXR5XCIsIFwiXjYuOC4xXCIpO1xuXHR3b3Jrc3BhY2Vcblx0XHQuZ2V0TW9kZWw8QXBpUGFja2FnZUpzb24+KFdFTExfS05PV05fRklMRVMuQVBJX1BBQ0tBR0VfSlNPTilcblx0XHQ/LmFkZERlcGVuZGVuY3koXCJAY2FzbC9hYmlsaXR5XCIsIFwiXjYuOC4xXCIpO1xuXG5cdGNvbnN0IG1haW4gPSB3b3Jrc3BhY2UuZ2V0TW9kZWw8TWFpblNvdXJjZUZpbGU+KFdFTExfS05PV05fRklMRVMuTUFJTl9UUyk7XG5cdG1haW5cblx0XHQ/LmFkZEVudGl0eSh7IGNsYXNzTmFtZTogXCJVc2VyRW50aXR5XCIsIGltcG9ydFBhdGg6IFwiLi9lbnRpdGllcy91c2VyLmVudGl0eS5qc1wiIH0pXG5cdFx0LmFkZFJlcG9zaXRvcnkoe1xuXHRcdFx0Y2xhc3NOYW1lOiBcIlVzZXJFbnRpdHlSZXBvc2l0b3J5XCIsXG5cdFx0XHRpbXBvcnRQYXRoOiBcIi4vcmVwb3NpdG9yaWVzL3VzZXIucmVwb3NpdG9yeS5qc1wiLFxuXHRcdH0pXG5cdFx0LmFkZFNlcnZpY2Uoe1xuXHRcdFx0Y2xhc3NOYW1lOiBcIlVzZXJTZXJ2aWNlXCIsXG5cdFx0XHRpbXBvcnRQYXRoOiBcIi4vc2VydmljZXMvdXNlci5zZXJ2aWNlLmpzXCIsXG5cdFx0XHRzY29wZTogXCJyZXF1ZXN0XCIsXG5cdFx0fSlcblx0XHQuYWRkSW1wb3J0KFwiY3JlYXRlQWJpbGl0eUZhY3RvcnlcIiwgXCIuL2F1dGgvYWJpbGl0eS5mYWN0b3J5LmpzXCIpXG5cdFx0LmFkZEltcG9ydChcIm1hcFByaW5jaXBhbFwiLCBcIi4vYXV0aC9hYmlsaXR5LmZhY3RvcnkuanNcIilcblx0XHQuc2V0VHlwZU9ybVNlZWQoXG5cdFx0XHRbXG5cdFx0XHRcdFwiY29uc3Qgc3ViID0gcHJvY2Vzcy5lbnYuQVVUSDBfQURNSU5fVVNFUl9TVUI7XCIsXG5cdFx0XHRcdFwiaWYgKCFzdWIpIHJldHVybjtcIixcblx0XHRcdFx0XCJjb25zdCByZXBvID0gZGF0YVNvdXJjZS5nZXRSZXBvc2l0b3J5KFVzZXJFbnRpdHkpO1wiLFxuXHRcdFx0XHRcImNvbnN0IGV4aXN0aW5nID0gYXdhaXQgcmVwby5maW5kT25lKHsgd2hlcmU6IHsgc3ViIH0gfSk7XCIsXG5cdFx0XHRcdFwiaWYgKGV4aXN0aW5nKSByZXR1cm47XCIsXG5cdFx0XHRcdFwiYXdhaXQgcmVwby5zYXZlKHJlcG8uY3JlYXRlKHtcIixcblx0XHRcdFx0XCIgIHN1YixcIixcblx0XHRcdFx0XCIgIGVtYWlsOiBwcm9jZXNzLmVudi5BVVRIMF9BRE1JTl9VU0VSX0VNQUlMID8/IG51bGwsXCIsXG5cdFx0XHRcdCcgIGRpc3BsYXlOYW1lOiBwcm9jZXNzLmVudi5BVVRIMF9BRE1JTl9VU0VSTkFNRSA/PyBcImFkbWluXCIsJyxcblx0XHRcdFx0JyAgcm9sZXM6IFtcImFkbWluXCJdLCcsXG5cdFx0XHRcdFwifSkpO1wiLFxuXHRcdFx0XS5qb2luKFwiIFwiKSxcblx0XHQpO1xuXG5cdHdvcmtzcGFjZS5nZXRQcm9qZWN0KFdFQkFQSV9QUk9KRUNUX0RJUik/LmFkZEZpbGUoe1xuXHRcdGZpbGVzOiAoKSA9PiBbXG5cdFx0XHR7IGZpbGVQYXRoOiBcInNyYy9lbnRpdGllcy91c2VyLmVudGl0eS50c1wiLCBjb250ZW50OiBVU0VSX0VOVElUWV9UUyB9LFxuXHRcdFx0eyBmaWxlUGF0aDogXCJzcmMvcmVwb3NpdG9yaWVzL3VzZXIucmVwb3NpdG9yeS50c1wiLCBjb250ZW50OiBVU0VSX1JFUE9TSVRPUllfVFMgfSxcblx0XHRcdHsgZmlsZVBhdGg6IFwic3JjL3NlcnZpY2VzL3VzZXIuc2VydmljZS50c1wiLCBjb250ZW50OiBVU0VSX1NFUlZJQ0VfVFMgfSxcblx0XHRcdHsgZmlsZVBhdGg6IFwic3JjL2F1dGgvYWJpbGl0eS5mYWN0b3J5LnRzXCIsIGNvbnRlbnQ6IEFCSUxJVFlfRkFDVE9SWV9UUyB9LFxuXHRcdF0sXG5cdH0pO1xuXG5cdGZvciAoY29uc3QgY29udHJvbGxlciBvZiB3b3Jrc3BhY2UuZ2V0TW9kZWxzKENvbnRyb2xsZXJTb3VyY2VGaWxlKSkge1xuXHRcdGNvbnRyb2xsZXJcblx0XHRcdC5hZGRJbXBvcnQoXCJVc2VyU2VydmljZVwiLCBcIi4uL3NlcnZpY2VzL3VzZXIuc2VydmljZS5qc1wiKVxuXHRcdFx0LmFkZENvbnN0cnVjdG9yUGFyYW0oXCJwcml2YXRlIHJlYWRvbmx5IHVzZXJzOiBVc2VyU2VydmljZVwiKTtcblx0XHRjb250cm9sbGVyLmdldE1ldGhvZChcImdldE9uZVwiKS5zZXRBc3luYyh0cnVlKS5zZXRCb2R5KFtcblx0XHRcdFwiY29uc3QgdXNlciA9IGF3YWl0IHRoaXMudXNlcnMuZW5zdXJlRnJvbVByaW5jaXBhbCh0aGlzLnByaW5jaXBhbFByb3ZpZGVyLmN1cnJlbnRQcmluY2lwYWwpO1wiLFxuXHRcdFx0Ly8gYmlvbWUtaWdub3JlIGxpbnQvc3VzcGljaW91cy9ub1RlbXBsYXRlQ3VybHlJblN0cmluZzogdGVtcGxhdGUgbGl0ZXJhbCBpbiBnZW5lcmF0ZWQgY29kZVxuXHRcdFx0XCJyZXR1cm4geyBpZCwgbWVzc2FnZTogYEhlbGxvICR7dXNlci5kaXNwbGF5TmFtZX0hYCwgdXNlcm5hbWU6IHVzZXIuZGlzcGxheU5hbWUgfTtcIixcblx0XHRdKTtcblx0fVxufVxuXG5mdW5jdGlvbiBzY2FmZm9sZCh3b3Jrc3BhY2U6IFdvcmtzcGFjZVNjYWZmb2xkLCBvcHRpb25zOiBBdXRoT3B0aW9ucyk6IHZvaWQge1xuXHRpZiAob3B0aW9ucy5hdXRoUHJvdmlkZXIgIT09IFwiYXV0aDBcIikgcmV0dXJuO1xuXG5cdGNvbnN0IHJlc291cmNlID0gXCJIZWxsb1wiO1xuXHRjb25zdCB3aXRoTG9jYWxVc2VycyA9IG9wdGlvbnMuZGF0YWJhc2VQcm92aWRlciA9PT0gXCJwb3N0Z3Jlcy90eXBlb3JtXCI7XG5cblx0Zm9yIChjb25zdCBjb250cm9sbGVyIG9mIHdvcmtzcGFjZS5nZXRNb2RlbHMoQ29udHJvbGxlclNvdXJjZUZpbGUpKSB7XG5cdFx0Y29udHJvbGxlclxuXHRcdFx0LmFkZERlY29yYXRvcihgQEF1dGhvcml6ZShcInJlYWRcIiwgXCIke3Jlc291cmNlfVwiKWApXG5cdFx0XHQuYWRkQ29ydGV4SW1wb3J0KFwiQWxsb3dBbm9ueW1vdXNcIilcblx0XHRcdC5hZGRDb3J0ZXhJbXBvcnQoXCJBdXRob3JpemVcIilcblx0XHRcdC5hZGRDb3J0ZXhJbXBvcnQoXCJJUHJpbmNpcGFsUHJvdmlkZXJUb2tlblwiKVxuXHRcdFx0LmFkZENvcnRleEltcG9ydChcIklQcmluY2lwYWxQcm92aWRlclwiLCB0cnVlKVxuXHRcdFx0LmFkZEltcG9ydChcImluamVjdFwiLCBcIkBkZWNvaGVyZS9jcnVjaWJsZS9kZWNvcmF0b3JzXCIpXG5cdFx0XHQuYWRkQ29uc3RydWN0b3JQYXJhbShcblx0XHRcdFx0YEBpbmplY3QoSVByaW5jaXBhbFByb3ZpZGVyVG9rZW4pIHByaXZhdGUgcmVhZG9ubHkgcHJpbmNpcGFsUHJvdmlkZXI6IElQcmluY2lwYWxQcm92aWRlcmAsXG5cdFx0XHQpO1xuXHRcdGNvbnRyb2xsZXIuZ2V0TWV0aG9kKFwiZ2V0QWxsXCIpLmFkZERlY29yYXRvcihcIkBBbGxvd0Fub255bW91cygpXCIpO1xuXHRcdGlmICghd2l0aExvY2FsVXNlcnMpIHtcblx0XHRcdGNvbnRyb2xsZXIuZ2V0TWV0aG9kKFwiZ2V0T25lXCIpLnNldEJvZHkoW1xuXHRcdFx0XHRcImNvbnN0IHByaW5jaXBhbCA9IHRoaXMucHJpbmNpcGFsUHJvdmlkZXIuY3VycmVudFByaW5jaXBhbDtcIixcblx0XHRcdFx0XCJjb25zdCB1c2VybmFtZSA9XCIsXG5cdFx0XHRcdCdcXHQodHlwZW9mIHByaW5jaXBhbD8ubmFtZSA9PT0gXCJzdHJpbmdcIiAmJiBwcmluY2lwYWwubmFtZSkgfHwnLFxuXHRcdFx0XHQnXFx0KHR5cGVvZiBwcmluY2lwYWw/Lm5pY2tuYW1lID09PSBcInN0cmluZ1wiICYmIHByaW5jaXBhbC5uaWNrbmFtZSkgfHwnLFxuXHRcdFx0XHQnXFx0KHR5cGVvZiBwcmluY2lwYWw/LmVtYWlsID09PSBcInN0cmluZ1wiICYmIHByaW5jaXBhbC5lbWFpbCkgfHwnLFxuXHRcdFx0XHQnXFx0KHR5cGVvZiBwcmluY2lwYWw/LnByZWZlcnJlZF91c2VybmFtZSA9PT0gXCJzdHJpbmdcIiAmJiBwcmluY2lwYWwucHJlZmVycmVkX3VzZXJuYW1lKSB8fCcsXG5cdFx0XHRcdFwiXFx0cHJpbmNpcGFsPy5zdWIgfHxcIixcblx0XHRcdFx0J1xcdFwidW5rbm93blwiOycsXG5cdFx0XHRcdC8vIGJpb21lLWlnbm9yZSBsaW50L3N1c3BpY2lvdXMvbm9UZW1wbGF0ZUN1cmx5SW5TdHJpbmc6IHRlbXBsYXRlIGxpdGVyYWwgaW4gZ2VuZXJhdGVkIGNvZGVcblx0XHRcdFx0XCJyZXR1cm4geyBpZCwgbWVzc2FnZTogYEhlbGxvICR7dXNlcm5hbWV9IWAsIHVzZXJuYW1lIH07XCIsXG5cdFx0XHRdKTtcblx0XHR9XG5cdFx0Y29udHJvbGxlci5nZXRNZXRob2QoXCJjcmVhdGVcIikuYWRkRGVjb3JhdG9yKGBAQXV0aG9yaXplKFwiY3JlYXRlXCIsIFwiJHtyZXNvdXJjZX1cIilgKTtcblx0XHRjb250cm9sbGVyLmdldE1ldGhvZChcInVwZGF0ZVwiKS5hZGREZWNvcmF0b3IoYEBBdXRob3JpemUoXCJ1cGRhdGVcIiwgXCIke3Jlc291cmNlfVwiKWApO1xuXHRcdGNvbnRyb2xsZXIuZ2V0TWV0aG9kKFwicmVtb3ZlXCIpLmFkZERlY29yYXRvcihgQEF1dGhvcml6ZShcImRlbGV0ZVwiLCBcIiR7cmVzb3VyY2V9XCIpYCk7XG5cdH1cblxuXHRjb25zdCBtYWluID0gd29ya3NwYWNlLmdldE1vZGVsPE1haW5Tb3VyY2VGaWxlPihXRUxMX0tOT1dOX0ZJTEVTLk1BSU5fVFMpO1xuXHRtYWluPy5hZGRTaWRlRWZmZWN0SW1wb3J0KFwiQGRlY29oZXJlL2NvcnRleC9hdXRoXCIpO1xuXG5cdGlmICh3aXRoTG9jYWxVc2Vycykge1xuXHRcdHNjYWZmb2xkTG9jYWxVc2VyUHJvZmlsZSh3b3Jrc3BhY2UpO1xuXHRcdG1haW4/LmFkZEJ1aWxkZXJDYWxsKFwiLndpdGhBdXRoKGNyZWF0ZUFiaWxpdHlGYWN0b3J5LCB7IHByaW5jaXBhbE1hcHBlcjogbWFwUHJpbmNpcGFsIH0pXCIpO1xuXHR9IGVsc2Uge1xuXHRcdG1haW4/LmFkZEJ1aWxkZXJDYWxsKFwiLndpdGhBdXRoKClcIik7XG5cdH1cblxuXHQvLyBiaW9tZS1pZ25vcmUgbGludC9zdXNwaWNpb3VzL25vVGVtcGxhdGVDdXJseUluU3RyaW5nOiBpbnRlbnRpb25hbCBZQU1MIGVudi12YXIgcGxhY2Vob2xkZXJzXG5cdGNvbnN0IGlzc3VlclBsYWNlaG9sZGVyID0gXCIke0FVVEgwX0lTU1VFUl9CQVNFX1VSTH1cIjtcblx0Ly8gYmlvbWUtaWdub3JlIGxpbnQvc3VzcGljaW91cy9ub1RlbXBsYXRlQ3VybHlJblN0cmluZzogaW50ZW50aW9uYWwgWUFNTCBlbnYtdmFyIHBsYWNlaG9sZGVyc1xuXHRjb25zdCBhdWRQbGFjZWhvbGRlciA9IFwiJHtBVVRIMF9BVURJRU5DRX1cIjtcblxuXHRjb25zdCBjb25maWdTZWN0aW9uID0gYGF1dGg6XFxuICBkaXNjb3ZlcnlVcmw6ICR7aXNzdWVyUGxhY2Vob2xkZXJ9XFxuICBhdWRpZW5jZTogJHthdWRQbGFjZWhvbGRlcn1cXG5gO1xuXG5cdHdvcmtzcGFjZS5nZXRNb2RlbDxDb25maWdZYW1sPihXRUxMX0tOT1dOX0ZJTEVTLkNPTkZJR19ZQU1MKT8uYWRkU2VjdGlvbihjb25maWdTZWN0aW9uKTtcblxuXHR3b3Jrc3BhY2Vcblx0XHQuZ2V0TW9kZWw8RW52RmlsZT4oV0VMTF9LTk9XTl9GSUxFUy5FTlZfRklMRSlcblx0XHQ/LmFkZEVudHJ5KFwiQVVUSDBfSVNTVUVSX0JBU0VfVVJMXCIsIG9wdGlvbnMuaXNzdWVyQmFzZVVybCA/PyBcIlwiKVxuXHRcdC5hZGRFbnRyeShcIkFVVEgwX0FVRElFTkNFXCIsIG9wdGlvbnMuYXVkaWVuY2UgPz8gXCJcIik7XG5cblx0Y29uc3QgYXV0aENvbmZpZyA9IG5ldyBBdXRoQ29uZmlnTW9kZWwoe1xuXHRcdGlzc3VlckJhc2VVcmw6IG9wdGlvbnMuaXNzdWVyQmFzZVVybCA/PyBcIlwiLFxuXHRcdGF1ZGllbmNlOiBvcHRpb25zLmF1ZGllbmNlID8/IFwiXCIsXG5cdH0pO1xuXHR3b3Jrc3BhY2UuYWRkTW9kZWwoYXV0aENvbmZpZyk7XG5cblx0aWYgKHdpdGhMb2NhbFVzZXJzICYmIG9wdGlvbnMuYWRtaW5QYXNzd29yZCkge1xuXHRcdGNyZWF0ZUF1dGgwQWRtaW5Vc2VyKHdvcmtzcGFjZSwgb3B0aW9ucywgYXV0aENvbmZpZyk7XG5cdH1cbn1cblxuZXhwb3J0IGNvbnN0IEF1dGhGZWF0dXJlOiBGZWF0dXJlPEF1dGhPcHRpb25zPiA9IHsgZ2V0T3B0aW9ucywgc2NhZmZvbGQgfTtcbiJdLCJuYW1lcyI6WyJhc2siLCJwaWNrIiwiV0VMTF9LTk9XTl9GSUxFUyIsIldFQkFQSV9QUk9KRUNUX0RJUiIsIkF1dGhDb25maWdNb2RlbCIsIkNvbnRyb2xsZXJTb3VyY2VGaWxlIiwiYXV0aDBDbGkiLCJBRE1JTl9ST0xFIiwiVVNFUl9FTlRJVFlfVFMiLCJVU0VSX1JFUE9TSVRPUllfVFMiLCJVU0VSX1NFUlZJQ0VfVFMiLCJBQklMSVRZX0ZBQ1RPUllfVFMiLCJnZXRPcHRpb25zIiwid29ya3NwYWNlIiwiY2xpT3B0aW9ucyIsImF1dGhQcm92aWRlciIsImlzc3VlckJhc2VVcmwiLCJnZXRBdXRoME9wdGlvbnMiLCJjaG9pY2VzIiwibGFiZWwiLCJzZWxlY3RlZCIsImMiLCJwcm92aWRlciIsImlzSW5zdGFsbGVkIiwiY29uc29sZSIsImVycm9yIiwicHJvY2VzcyIsImV4aXQiLCJzdGRvdXQiLCJ3cml0ZSIsInRlbmFudHMiLCJsaXN0VGVuYW50cyIsImxlbmd0aCIsImxvZyIsImxvZ2luIiwibGlzdEFwaXMiLCJlcnIiLCJBdXRoMEF1dGhFcnJvciIsImFjdGl2ZSIsImZpbmQiLCJ0IiwibmFtZSIsInVzZXJBcGlzIiwiZmlsdGVyIiwiYSIsImluY2x1ZGVzIiwicHJvamVjdE5hbWUiLCJhcGlDaG9pY2VzIiwiZXhpc3RpbmciLCJtYXAiLCJpZGVudGlmaWVyIiwiYXBpU2VsZWN0ZWQiLCJhdWRpZW5jZSIsImRlZmF1bHRJZCIsImNyZWF0ZUFwaSIsInVwZGF0ZUFwaVNjb3BlcyIsIkhFTExPX0FQSV9TQ09QRVMiLCJqb2luIiwid2l0aExvY2FsVXNlcnMiLCJkYXRhYmFzZVByb3ZpZGVyIiwiYWRtaW5Vc2VybmFtZSIsImFkbWluUGFzc3dvcmQiLCJnZW5lcmF0ZUFkbWluUGFzc3dvcmQiLCJhZG1pbkVtYWlsIiwid29ya3NwYWNlTmFtZSIsInVzZXJuYW1lIiwic2x1ZyIsInRvTG93ZXJDYXNlIiwicmVwbGFjZSIsImNyZWF0ZUF1dGgwQWRtaW5Vc2VyIiwib3B0aW9ucyIsImF1dGhDb25maWciLCJwYXNzd29yZCIsImVtYWlsIiwiYWRtaW4iLCJjcmVhdGVBZG1pbkRhdGFiYXNlVXNlciIsInNldEFkbWluVXNlciIsInN1YiIsInVzZXJfaWQiLCJnZXRNb2RlbCIsIkVOVl9GSUxFIiwiYWRkRW50cnkiLCJFcnJvciIsIm1lc3NhZ2UiLCJzY2FmZm9sZExvY2FsVXNlclByb2ZpbGUiLCJQQUNLQUdFX0pTT04iLCJhZGREZXBlbmRlbmN5IiwiQVBJX1BBQ0tBR0VfSlNPTiIsIm1haW4iLCJNQUlOX1RTIiwiYWRkRW50aXR5IiwiY2xhc3NOYW1lIiwiaW1wb3J0UGF0aCIsImFkZFJlcG9zaXRvcnkiLCJhZGRTZXJ2aWNlIiwic2NvcGUiLCJhZGRJbXBvcnQiLCJzZXRUeXBlT3JtU2VlZCIsImdldFByb2plY3QiLCJhZGRGaWxlIiwiZmlsZXMiLCJmaWxlUGF0aCIsImNvbnRlbnQiLCJjb250cm9sbGVyIiwiZ2V0TW9kZWxzIiwiYWRkQ29uc3RydWN0b3JQYXJhbSIsImdldE1ldGhvZCIsInNldEFzeW5jIiwic2V0Qm9keSIsInNjYWZmb2xkIiwicmVzb3VyY2UiLCJhZGREZWNvcmF0b3IiLCJhZGRDb3J0ZXhJbXBvcnQiLCJhZGRTaWRlRWZmZWN0SW1wb3J0IiwiYWRkQnVpbGRlckNhbGwiLCJpc3N1ZXJQbGFjZWhvbGRlciIsImF1ZFBsYWNlaG9sZGVyIiwiY29uZmlnU2VjdGlvbiIsIkNPTkZJR19ZQU1MIiwiYWRkU2VjdGlvbiIsImFkZE1vZGVsIiwiQXV0aEZlYXR1cmUiXSwibWFwcGluZ3MiOiJBQUFBLFNBQVNBLEdBQUcsRUFBRUMsSUFBSSxRQUFRLHlCQUF5QjtBQUVuRCxTQUFTQyxnQkFBZ0IsUUFBUSx3QkFBd0I7QUFLekQsU0FBU0Msa0JBQWtCLFFBQVEsbUJBQW1CO0FBRXRELFNBQVNDLGVBQWUsUUFBUSxpQ0FBaUM7QUFDakUsU0FBU0Msb0JBQW9CLFFBQVEsNENBQTRDO0FBRWpGLFlBQVlDLGNBQWMsaUJBQWlCO0FBVzNDLE1BQU1DLGFBQWE7QUFFbkIsTUFBTUMsaUJBQWlCLENBQUM7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQXFCeEIsQ0FBQztBQUVELE1BQU1DLHFCQUFxQixDQUFDOzs7Ozs7Ozs7Ozs7Ozs7QUFlNUIsQ0FBQztBQUVELE1BQU1DLGtCQUFrQixDQUFDOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBdUR6QixDQUFDO0FBRUQsTUFBTUMscUJBQXFCLENBQUM7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQTZDNUIsQ0FBQztBQUVELGVBQWVDLFdBQ2RDLFNBQTRCLEVBQzVCQyxVQUFnQztJQUVoQyxJQUFJQSxXQUFXQyxZQUFZLEtBQUssV0FBVyxDQUFDRCxXQUFXRSxhQUFhLEVBQUU7UUFDckUsT0FBT0MsZ0JBQWdCSixXQUFXQztJQUNuQztJQUNBLElBQUlBLFdBQVdDLFlBQVksSUFBSSxNQUFNLE9BQU8sQ0FBQztJQUU3QyxNQUFNRyxVQUFVO1FBQUM7WUFBRUMsT0FBTztRQUFnQjtRQUFHO1lBQUVBLE9BQU87UUFBaUI7S0FBRTtJQUN6RSxNQUFNQyxXQUFXLE1BQU1uQixLQUFLLHVCQUF1QmlCLFNBQVMsQ0FBQ0csSUFBTUEsRUFBRUYsS0FBSztJQUMxRSxNQUFNRyxXQUFXRixVQUFVRCxTQUFTO0lBRXBDLElBQUlHLGFBQWEsU0FBUyxPQUFPO1FBQUVQLGNB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