@decohere/create 0.0.1-dev.48 → 0.0.1-dev.49

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 (124) hide show
  1. package/commonjs/src/cli.js +3 -3
  2. package/commonjs/src/resolve-launch.js +53 -0
  3. package/commonjs/src/runner.js +5 -45
  4. package/commonjs/src/version.js +1 -1
  5. package/es6/src/cli.js +3 -3
  6. package/es6/src/resolve-launch.js +46 -0
  7. package/es6/src/runner.js +8 -57
  8. package/es6/src/version.js +3 -3
  9. package/pack-builder-tgz.mjs +1 -1
  10. package/package.json +4 -11
  11. package/types/src/resolve-launch.d.ts +10 -0
  12. package/types/src/runner.d.ts +3 -13
  13. package/types/src/version.d.ts +0 -2
  14. package/commonjs/src/domain/prompt.js +0 -64
  15. package/commonjs/src/models/compose.model.js +0 -138
  16. package/commonjs/src/models/config-yaml.model.js +0 -88
  17. package/commonjs/src/models/const.js +0 -31
  18. package/commonjs/src/models/dev-container.model.js +0 -100
  19. package/commonjs/src/models/docker-image.model.js +0 -221
  20. package/commonjs/src/models/env-file.model.js +0 -47
  21. package/commonjs/src/models/gitignore.model.js +0 -31
  22. package/commonjs/src/models/launch-json.model.js +0 -74
  23. package/commonjs/src/models/package-json.model.js +0 -133
  24. package/commonjs/src/models/project.model.js +0 -134
  25. package/commonjs/src/models/source-file.js +0 -6
  26. package/commonjs/src/models/tsconfig.model.js +0 -34
  27. package/commonjs/src/models/vscode-settings.model.js +0 -31
  28. package/commonjs/src/program.js +0 -135
  29. package/commonjs/src/resolve-target-dir.js +0 -19
  30. package/commonjs/src/services/scaffold.service.js +0 -62
  31. package/commonjs/src/webapi/api-name.js +0 -95
  32. package/commonjs/src/webapi/const.js +0 -50
  33. package/commonjs/src/webapi/create-api.js +0 -285
  34. package/commonjs/src/webapi/features/auth.feature.js +0 -463
  35. package/commonjs/src/webapi/features/auth0-cli.js +0 -406
  36. package/commonjs/src/webapi/features/biome-format.js +0 -49
  37. package/commonjs/src/webapi/features/database.feature.js +0 -273
  38. package/commonjs/src/webapi/features/finalize.feature.js +0 -91
  39. package/commonjs/src/webapi/features/postman.feature.js +0 -319
  40. package/commonjs/src/webapi/models/api-package-json.model.js +0 -63
  41. package/commonjs/src/webapi/models/auth-config.model.js +0 -26
  42. package/commonjs/src/webapi/models/controller-source-file.model.js +0 -188
  43. package/commonjs/src/webapi/models/github-ci.model.js +0 -193
  44. package/commonjs/src/webapi/models/main-source-file.model.js +0 -165
  45. package/commonjs/src/webapi/models/production-dockerfile.model.js +0 -138
  46. package/commonjs/src/webapi/models/sample-files.model.js +0 -60
  47. package/commonjs/src/webapi/models/webapi-image.model.js +0 -22
  48. package/commonjs/src/webapi/postman/hello-openapi.js +0 -175
  49. package/commonjs/src/webapi/postman/local-view.js +0 -184
  50. package/commonjs/src/webapi/postman/openapi-to-postman.js +0 -202
  51. package/es6/src/domain/prompt.js +0 -43
  52. package/es6/src/models/compose.model.js +0 -132
  53. package/es6/src/models/config-yaml.model.js +0 -76
  54. package/es6/src/models/const.js +0 -21
  55. package/es6/src/models/dev-container.model.js +0 -90
  56. package/es6/src/models/docker-image.model.js +0 -185
  57. package/es6/src/models/env-file.model.js +0 -43
  58. package/es6/src/models/gitignore.model.js +0 -21
  59. package/es6/src/models/launch-json.model.js +0 -64
  60. package/es6/src/models/package-json.model.js +0 -129
  61. package/es6/src/models/project.model.js +0 -119
  62. package/es6/src/models/source-file.js +0 -3
  63. package/es6/src/models/tsconfig.model.js +0 -24
  64. package/es6/src/models/vscode-settings.model.js +0 -21
  65. package/es6/src/program.js +0 -76
  66. package/es6/src/resolve-target-dir.js +0 -9
  67. package/es6/src/services/scaffold.service.js +0 -52
  68. package/es6/src/webapi/api-name.js +0 -59
  69. package/es6/src/webapi/const.js +0 -20
  70. package/es6/src/webapi/create-api.js +0 -265
  71. package/es6/src/webapi/features/auth.feature.js +0 -412
  72. package/es6/src/webapi/features/auth0-cli.js +0 -348
  73. package/es6/src/webapi/features/biome-format.js +0 -42
  74. package/es6/src/webapi/features/database.feature.js +0 -263
  75. package/es6/src/webapi/features/finalize.feature.js +0 -81
  76. package/es6/src/webapi/features/postman.feature.js +0 -253
  77. package/es6/src/webapi/models/api-package-json.model.js +0 -58
  78. package/es6/src/webapi/models/auth-config.model.js +0 -22
  79. package/es6/src/webapi/models/controller-source-file.model.js +0 -179
  80. package/es6/src/webapi/models/github-ci.model.js +0 -186
  81. package/es6/src/webapi/models/main-source-file.model.js +0 -161
  82. package/es6/src/webapi/models/production-dockerfile.model.js +0 -126
  83. package/es6/src/webapi/models/sample-files.model.js +0 -42
  84. package/es6/src/webapi/models/webapi-image.model.js +0 -12
  85. package/es6/src/webapi/postman/hello-openapi.js +0 -168
  86. package/es6/src/webapi/postman/local-view.js +0 -169
  87. package/es6/src/webapi/postman/openapi-to-postman.js +0 -179
  88. package/types/src/domain/prompt.d.ts +0 -4
  89. package/types/src/models/compose.model.d.ts +0 -59
  90. package/types/src/models/config-yaml.model.d.ts +0 -27
  91. package/types/src/models/const.d.ts +0 -19
  92. package/types/src/models/dev-container.model.d.ts +0 -33
  93. package/types/src/models/docker-image.model.d.ts +0 -56
  94. package/types/src/models/env-file.model.d.ts +0 -15
  95. package/types/src/models/gitignore.model.d.ts +0 -6
  96. package/types/src/models/launch-json.model.d.ts +0 -7
  97. package/types/src/models/package-json.model.d.ts +0 -32
  98. package/types/src/models/project.model.d.ts +0 -60
  99. package/types/src/models/source-file.d.ts +0 -11
  100. package/types/src/models/tsconfig.model.d.ts +0 -5
  101. package/types/src/models/vscode-settings.model.d.ts +0 -7
  102. package/types/src/program.d.ts +0 -3
  103. package/types/src/resolve-target-dir.d.ts +0 -5
  104. package/types/src/services/scaffold.service.d.ts +0 -22
  105. package/types/src/webapi/api-name.d.ts +0 -14
  106. package/types/src/webapi/const.d.ts +0 -17
  107. package/types/src/webapi/create-api.d.ts +0 -15
  108. package/types/src/webapi/features/auth.feature.d.ts +0 -10
  109. package/types/src/webapi/features/auth0-cli.d.ts +0 -72
  110. package/types/src/webapi/features/biome-format.d.ts +0 -5
  111. package/types/src/webapi/features/database.feature.d.ts +0 -5
  112. package/types/src/webapi/features/finalize.feature.d.ts +0 -2
  113. package/types/src/webapi/features/postman.feature.d.ts +0 -16
  114. package/types/src/webapi/models/api-package-json.model.d.ts +0 -18
  115. package/types/src/webapi/models/auth-config.model.d.ts +0 -26
  116. package/types/src/webapi/models/controller-source-file.model.d.ts +0 -45
  117. package/types/src/webapi/models/github-ci.model.d.ts +0 -9
  118. package/types/src/webapi/models/main-source-file.model.d.ts +0 -54
  119. package/types/src/webapi/models/production-dockerfile.model.d.ts +0 -20
  120. package/types/src/webapi/models/sample-files.model.d.ts +0 -7
  121. package/types/src/webapi/models/webapi-image.model.d.ts +0 -5
  122. package/types/src/webapi/postman/hello-openapi.d.ts +0 -19
  123. package/types/src/webapi/postman/local-view.d.ts +0 -17
  124. package/types/src/webapi/postman/openapi-to-postman.d.ts +0 -62
@@ -1,463 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- Object.defineProperty(exports, "AuthFeature", {
6
- enumerable: true,
7
- get: function() {
8
- return AuthFeature;
9
- }
10
- });
11
- const _prompt = require("../../domain/prompt.js");
12
- const _const = require("../../models/const.js");
13
- const _authconfigmodel = require("../models/auth-config.model.js");
14
- const _controllersourcefilemodel = require("../models/controller-source-file.model.js");
15
- const _auth0cli = /*#__PURE__*/ _interop_require_wildcard(require("./auth0-cli.js"));
16
- function _getRequireWildcardCache(nodeInterop) {
17
- if (typeof WeakMap !== "function") return null;
18
- var cacheBabelInterop = new WeakMap();
19
- var cacheNodeInterop = new WeakMap();
20
- return (_getRequireWildcardCache = function(nodeInterop) {
21
- return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
22
- })(nodeInterop);
23
- }
24
- function _interop_require_wildcard(obj, nodeInterop) {
25
- if (!nodeInterop && obj && obj.__esModule) {
26
- return obj;
27
- }
28
- if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
29
- return {
30
- default: obj
31
- };
32
- }
33
- var cache = _getRequireWildcardCache(nodeInterop);
34
- if (cache && cache.has(obj)) {
35
- return cache.get(obj);
36
- }
37
- var newObj = {
38
- __proto__: null
39
- };
40
- var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
41
- for(var key in obj){
42
- if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
43
- var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
44
- if (desc && (desc.get || desc.set)) {
45
- Object.defineProperty(newObj, key, desc);
46
- } else {
47
- newObj[key] = obj[key];
48
- }
49
- }
50
- }
51
- newObj.default = obj;
52
- if (cache) {
53
- cache.set(obj, newObj);
54
- }
55
- return newObj;
56
- }
57
- const ADMIN_ROLE = "admin";
58
- const USER_ENTITY_TS = `import { Column, Entity, PrimaryGeneratedColumn } from "typeorm";
59
- import type { Entity as IEntity } from "@decohere/codex";
60
-
61
- @Entity()
62
- export class UserEntity implements IEntity {
63
- \t@PrimaryGeneratedColumn()
64
- \tpublic id!: number;
65
-
66
- \t@Column({ unique: true })
67
- \tpublic sub!: string;
68
-
69
- \t@Column({ type: "varchar", nullable: true })
70
- \tpublic email!: string | null;
71
-
72
- \t@Column()
73
- \tpublic displayName!: string;
74
-
75
- \t/** App-owned roles. The \`admin\` role grants CASL \`manage\`/\`all\` (wildcard). */
76
- \t@Column({ type: "simple-json", default: "[]" })
77
- \tpublic roles!: string[];
78
- }
79
- `;
80
- const USER_REPOSITORY_TS = `import { injectable } from "@decohere/crucible/decorators";
81
- import { injectUnitOfWork } from "@decohere/codex";
82
- import { TypeOrmRepository, TypeOrmUnitOfWork } from "@decohere/codex-typeorm";
83
- import { UserEntity } from "../entities/user.entity.js";
84
-
85
- @injectable()
86
- export class UserEntityRepository extends TypeOrmRepository<UserEntity> {
87
- \tpublic constructor(@injectUnitOfWork() unitOfWork: TypeOrmUnitOfWork) {
88
- \t\tsuper(unitOfWork, UserEntity);
89
- \t}
90
-
91
- \tpublic findBySub(sub: string): Promise<UserEntity | null> {
92
- \t\treturn this.firstOrDefault({ where: { sub } });
93
- \t}
94
- }
95
- `;
96
- const USER_SERVICE_TS = `import { injectable } from "@decohere/crucible/decorators";
97
- import type { Principal } from "@decohere/cortex";
98
- import { UserEntity } from "../entities/user.entity.js";
99
- import { UserEntityRepository } from "../repositories/user.repository.js";
100
-
101
- function claimString(principal: Principal | undefined, key: string): string | undefined {
102
- \tconst value = principal?.[key];
103
- \treturn typeof value === "string" && value.length > 0 ? value : undefined;
104
- }
105
-
106
- @injectable()
107
- export class UserService {
108
- \tpublic constructor(private readonly users: UserEntityRepository) {}
109
-
110
- \t/**
111
- \t * Upsert a local profile keyed by JWT \`sub\`.
112
- \t * Profile fields from the token fill gaps; seeded rows keep displayName/email/roles.
113
- \t */
114
- \tpublic async ensureFromPrincipal(principal: Principal | undefined): Promise<UserEntity> {
115
- \t\tconst sub = principal?.sub;
116
- \t\tif (!sub) {
117
- \t\t\tthrow new Error("Authenticated request is missing principal.sub");
118
- \t\t}
119
-
120
- \t\tconst email =
121
- \t\t\tclaimString(principal, "email") ?? claimString(principal, "preferred_username");
122
- \t\tconst displayFromToken =
123
- \t\t\tclaimString(principal, "name") ??
124
- \t\t\tclaimString(principal, "nickname") ??
125
- \t\t\temail;
126
-
127
- \t\tconst existing = await this.users.findBySub(sub);
128
- \t\tif (existing) {
129
- \t\t\tlet dirty = false;
130
- \t\t\tif (!existing.email && email) {
131
- \t\t\t\texisting.email = email;
132
- \t\t\t\tdirty = true;
133
- \t\t\t}
134
- \t\t\tif (existing.displayName === existing.sub && displayFromToken) {
135
- \t\t\t\texisting.displayName = displayFromToken;
136
- \t\t\t\tdirty = true;
137
- \t\t\t}
138
- \t\t\treturn dirty ? this.users.save(existing) : existing;
139
- \t\t}
140
-
141
- \t\tconst created = new UserEntity();
142
- \t\tcreated.sub = sub;
143
- \t\tcreated.email = email ?? null;
144
- \t\tcreated.displayName = displayFromToken ?? sub;
145
- \t\tcreated.roles = Array.isArray(principal.roles)
146
- \t\t\t? principal.roles.filter((r): r is string => typeof r === "string")
147
- \t\t\t: [];
148
- \t\treturn this.users.save(created);
149
- \t}
150
- }
151
- `;
152
- const ABILITY_FACTORY_TS = `import { AbilityBuilder, createMongoAbility } from "@casl/ability";
153
- import type { Principal } from "@decohere/cortex";
154
-
155
- /** Root role — expands to CASL \`manage\`/\`all\` (covers every future ability). */
156
- export const ADMIN_ROLE = "admin";
157
-
158
- /**
159
- * Roles are collections of abilities. Admin is a wildcard, not an enumerated list.
160
- * Non-admin principals keep Auth0 scope / permission → ability mapping.
161
- */
162
- export function createAbilityFactory(principal: Principal) {
163
- \tconst { can, build } = new AbilityBuilder(createMongoAbility);
164
- \tif (principal.roles?.includes(ADMIN_ROLE)) {
165
- \t\tcan("manage", "all");
166
- \t\treturn build();
167
- \t}
168
- \tfor (const scope of principal.scopes ?? []) {
169
- \t\tconst [action, subject] = scope.split(":");
170
- \t\tif (action && subject) can(action, subject);
171
- \t}
172
- \treturn build();
173
- }
174
-
175
- /**
176
- * Map JWT payload → Principal.
177
- *
178
- * - \`roles\` come from the IdP (Auth0 RBAC / Action from app_metadata). Admins are
179
- * assigned in Auth0 — no server env change required for additional admins.
180
- * - \`AUTH0_ADMIN_USER_SUB\` is an optional bootstrap so the seeded admin works
181
- * before/without roles on the access token.
182
- * - API permissions are taken from \`scope\` and from Auth0's \`permissions\` claim.
183
- */
184
- export function mapPrincipal(payload: Record<string, unknown>): Principal {
185
- \tconst sub = typeof payload.sub === "string" ? payload.sub : "";
186
- \tconst fromScopeClaim =
187
- \t\ttypeof payload.scope === "string"
188
- \t\t\t? payload.scope.split(" ").filter(Boolean)
189
- \t\t\t: Array.isArray(payload.scopes)
190
- \t\t\t\t? (payload.scopes as unknown[]).filter((s): s is string => typeof s === "string")
191
- \t\t\t\t: [];
192
- \tconst fromPermissions = Array.isArray(payload.permissions)
193
- \t\t? (payload.permissions as unknown[]).filter((s): s is string => typeof s === "string")
194
- \t\t: [];
195
- \tconst merged = [...new Set([...fromScopeClaim, ...fromPermissions])];
196
- \tconst scopes = merged.length > 0 ? merged : undefined;
197
- \tconst fromToken = Array.isArray(payload.roles)
198
- \t\t? (payload.roles as unknown[]).filter((r): r is string => typeof r === "string")
199
- \t\t: [];
200
- \tconst roles =
201
- \t\tsub && sub === process.env.AUTH0_ADMIN_USER_SUB
202
- \t\t\t? [...new Set([ADMIN_ROLE, ...fromToken])]
203
- \t\t\t: fromToken.length > 0
204
- \t\t\t\t? fromToken
205
- \t\t\t\t: undefined;
206
- \treturn { ...payload, sub, roles, scopes };
207
- }
208
- `;
209
- async function getOptions(workspace, cliOptions) {
210
- if (cliOptions.authProvider === "auth0" && !cliOptions.issuerBaseUrl) {
211
- return getAuth0Options(workspace, cliOptions);
212
- }
213
- if (cliOptions.authProvider != null) return {};
214
- const choices = [
215
- {
216
- label: "none"
217
- },
218
- {
219
- label: "auth0"
220
- }
221
- ];
222
- const selected = await (0, _prompt.pick)("\n Auth provider: ", choices, (c)=>c.label);
223
- const provider = selected?.label ?? "none";
224
- if (provider !== "auth0") return {
225
- authProvider: "none"
226
- };
227
- return getAuth0Options(workspace, cliOptions);
228
- }
229
- async function getAuth0Options(workspace, cliOptions) {
230
- if (!_auth0cli.isInstalled()) {
231
- 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");
232
- process.exit(1);
233
- }
234
- process.stdout.write("\n Checking Auth0 credentials...");
235
- let tenants = _auth0cli.listTenants();
236
- if (tenants.length === 0) {
237
- process.stdout.write(" not logged in.\n");
238
- console.log(" Logging in to Auth0 (your browser will open)...");
239
- if (!_auth0cli.login()) {
240
- console.error("\n Auth0 login failed.");
241
- process.exit(1);
242
- }
243
- tenants = _auth0cli.listTenants();
244
- }
245
- try {
246
- _auth0cli.listApis();
247
- process.stdout.write(" ok.\n");
248
- } catch (err) {
249
- if (err instanceof _auth0cli.Auth0AuthError) {
250
- process.stdout.write(" token expired.\n");
251
- console.log(" Re-authenticating (your browser will open)...");
252
- if (!_auth0cli.login()) {
253
- console.error("\n Auth0 login failed.");
254
- process.exit(1);
255
- }
256
- }
257
- }
258
- const active = tenants.find((t)=>t.active) ?? tenants[0];
259
- const issuerBaseUrl = `https://${active.name}`;
260
- console.log(`\n ✓ Auth0 tenant: ${issuerBaseUrl}`);
261
- process.stdout.write("\n Fetching Auth0 APIs...");
262
- const userApis = _auth0cli.listApis().filter((a)=>!a.name.includes("Management API"));
263
- process.stdout.write(` found ${userApis.length}.\n`);
264
- const projectName = workspace.name;
265
- const apiChoices = [
266
- {
267
- label: `<new> https://api.${projectName}`,
268
- existing: null
269
- },
270
- ...userApis.map((a)=>({
271
- label: `${a.name} — ${a.identifier}`,
272
- existing: a.identifier
273
- }))
274
- ];
275
- const apiSelected = await (0, _prompt.pick)("\n Select Auth0 API: ", apiChoices, (c)=>c.label);
276
- let audience;
277
- if (!apiSelected || apiSelected.existing === null) {
278
- const defaultId = `https://api.${projectName}`;
279
- audience = await (0, _prompt.ask)(` API Identifier [${defaultId}]: `, defaultId);
280
- console.log("\n Creating Auth0 API...");
281
- audience = _auth0cli.createApi(`${projectName} API`, audience).identifier;
282
- console.log(` \u2713 API created: ${audience}`);
283
- } else {
284
- audience = apiSelected.existing;
285
- console.log(` \u2713 Selected: ${audience}`);
286
- try {
287
- _auth0cli.updateApiScopes(audience);
288
- console.log(` \u2713 API scopes ensured (${_auth0cli.HELLO_API_SCOPES.join(", ")})`);
289
- } catch {
290
- console.error(" ✗ Failed to update API scopes — add Hello scopes in the Auth0 dashboard.");
291
- }
292
- }
293
- const withLocalUsers = cliOptions.databaseProvider === "postgres/typeorm";
294
- let adminUsername;
295
- let adminPassword;
296
- if (withLocalUsers) {
297
- adminUsername = cliOptions.adminUsername ?? await (0, _prompt.ask)("\n Admin username [admin]: ", "admin");
298
- adminPassword = cliOptions.adminPassword;
299
- if (adminPassword == null) {
300
- adminPassword = await (0, _prompt.ask)(" Admin password (leave blank to generate): ");
301
- if (!adminPassword) {
302
- adminPassword = _auth0cli.generateAdminPassword();
303
- console.log(` ✓ Generated admin password (written to .env): ${adminPassword}`);
304
- }
305
- }
306
- }
307
- return {
308
- authProvider: "auth0",
309
- issuerBaseUrl,
310
- audience,
311
- ...withLocalUsers ? {
312
- adminUsername,
313
- adminPassword
314
- } : {}
315
- };
316
- }
317
- function adminEmail(workspaceName, username) {
318
- if (username.includes("@")) return username;
319
- const slug = workspaceName.toLowerCase().replace(/[^a-z0-9-]/g, "-");
320
- return `${username}@${slug}.example.com`;
321
- }
322
- function createAuth0AdminUser(workspace, options, authConfig) {
323
- const username = options.adminUsername ?? "admin";
324
- const password = options.adminPassword;
325
- if (!password) return;
326
- const email = adminEmail(workspace.name, username);
327
- try {
328
- const admin = _auth0cli.createAdminDatabaseUser({
329
- email,
330
- password,
331
- username
332
- });
333
- authConfig.setAdminUser({
334
- sub: admin.user_id,
335
- email: admin.email,
336
- password: admin.password,
337
- username: admin.username
338
- });
339
- workspace.getModel(_const.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);
340
- console.log(` ✓ Auth0 admin user ready: ${admin.email} (role: ${ADMIN_ROLE})`);
341
- console.log(` Login with EMAIL (not username): ${admin.email}`);
342
- console.log(` Password: see AUTH0_ADMIN_USER_PASSWORD in .env`);
343
- } catch (err) {
344
- console.error(` ✗ Failed to ensure Auth0 admin user (${email}): ${err instanceof Error ? err.message : err}`);
345
- }
346
- }
347
- function scaffoldLocalUserProfile(workspace) {
348
- workspace.getModel(_const.WELL_KNOWN_FILES.PACKAGE_JSON)?.addDependency("@casl/ability", "^6.8.1");
349
- for (const project of workspace.getProjects()){
350
- project.getModel(_const.WELL_KNOWN_FILES.API_PACKAGE_JSON)?.addDependency("@casl/ability", "^6.8.1");
351
- project.getModel(_const.WELL_KNOWN_FILES.MAIN_TS)?.addEntity({
352
- className: "UserEntity",
353
- importPath: "./entities/user.entity.js"
354
- }).addRepository({
355
- className: "UserEntityRepository",
356
- importPath: "./repositories/user.repository.js"
357
- }).addService({
358
- className: "UserService",
359
- importPath: "./services/user.service.js",
360
- scope: "request"
361
- }).addImport("createAbilityFactory", "./auth/ability.factory.js").addImport("mapPrincipal", "./auth/ability.factory.js").setTypeOrmSeed([
362
- "const sub = process.env.AUTH0_ADMIN_USER_SUB;",
363
- "if (!sub) return;",
364
- "const repo = dataSource.getRepository(UserEntity);",
365
- "const existing = await repo.findOne({ where: { sub } });",
366
- "if (existing) return;",
367
- "await repo.save(repo.create({",
368
- " sub,",
369
- " email: process.env.AUTH0_ADMIN_USER_EMAIL ?? null,",
370
- ' displayName: process.env.AUTH0_ADMIN_USERNAME ?? "admin",',
371
- ' roles: ["admin"],',
372
- "}));"
373
- ].join(" "));
374
- project.addFile({
375
- files: ()=>[
376
- {
377
- filePath: "src/entities/user.entity.ts",
378
- content: USER_ENTITY_TS
379
- },
380
- {
381
- filePath: "src/repositories/user.repository.ts",
382
- content: USER_REPOSITORY_TS
383
- },
384
- {
385
- filePath: "src/services/user.service.ts",
386
- content: USER_SERVICE_TS
387
- },
388
- {
389
- filePath: "src/auth/ability.factory.ts",
390
- content: ABILITY_FACTORY_TS
391
- }
392
- ]
393
- });
394
- }
395
- for (const controller of workspace.getModels(_controllersourcefilemodel.ControllerSourceFile)){
396
- controller.addImport("UserService", "../services/user.service.js").addConstructorParam("private readonly users: UserService");
397
- controller.getMethod("getOne").setAsync(true).setBody([
398
- "const user = await this.users.ensureFromPrincipal(this.principalProvider.currentPrincipal);",
399
- // biome-ignore lint/suspicious/noTemplateCurlyInString: template literal in generated code
400
- "return { id, message: `Hello ${user.displayName}!`, username: user.displayName };"
401
- ]);
402
- }
403
- }
404
- function scaffold(workspace, options) {
405
- if (options.authProvider !== "auth0") return;
406
- const resource = "Hello";
407
- const withLocalUsers = options.databaseProvider === "postgres/typeorm";
408
- for (const controller of workspace.getModels(_controllersourcefilemodel.ControllerSourceFile)){
409
- 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`);
410
- controller.getMethod("getAll").addDecorator("@AllowAnonymous()");
411
- if (!withLocalUsers) {
412
- controller.getMethod("getOne").setBody([
413
- "const principal = this.principalProvider.currentPrincipal;",
414
- "const username =",
415
- '\t(typeof principal?.name === "string" && principal.name) ||',
416
- '\t(typeof principal?.nickname === "string" && principal.nickname) ||',
417
- '\t(typeof principal?.email === "string" && principal.email) ||',
418
- '\t(typeof principal?.preferred_username === "string" && principal.preferred_username) ||',
419
- "\tprincipal?.sub ||",
420
- '\t"unknown";',
421
- // biome-ignore lint/suspicious/noTemplateCurlyInString: template literal in generated code
422
- "return { id, message: `Hello ${username}!`, username };"
423
- ]);
424
- }
425
- controller.getMethod("create").addDecorator(`@Authorize("create", "${resource}")`);
426
- controller.getMethod("update").addDecorator(`@Authorize("update", "${resource}")`);
427
- controller.getMethod("remove").addDecorator(`@Authorize("delete", "${resource}")`);
428
- }
429
- for (const project of workspace.getProjects()){
430
- project.getModel(_const.WELL_KNOWN_FILES.MAIN_TS)?.addSideEffectImport("@decohere/cortex/auth");
431
- }
432
- if (withLocalUsers) {
433
- scaffoldLocalUserProfile(workspace);
434
- for (const project of workspace.getProjects()){
435
- project.getModel(_const.WELL_KNOWN_FILES.MAIN_TS)?.addBuilderCall(".withAuth(createAbilityFactory, { principalMapper: mapPrincipal })");
436
- }
437
- } else {
438
- for (const project of workspace.getProjects()){
439
- project.getModel(_const.WELL_KNOWN_FILES.MAIN_TS)?.addBuilderCall(".withAuth()");
440
- }
441
- }
442
- // biome-ignore lint/suspicious/noTemplateCurlyInString: intentional YAML env-var placeholders
443
- const issuerPlaceholder = "${AUTH0_ISSUER_BASE_URL}";
444
- // biome-ignore lint/suspicious/noTemplateCurlyInString: intentional YAML env-var placeholders
445
- const audPlaceholder = "${AUTH0_AUDIENCE}";
446
- const configSection = `auth:\n discoveryUrl: ${issuerPlaceholder}\n audience: ${audPlaceholder}\n`;
447
- workspace.getModel(_const.WELL_KNOWN_FILES.CONFIG_YAML)?.addSection(configSection);
448
- workspace.getModel(_const.WELL_KNOWN_FILES.ENV_FILE)?.addEntry("AUTH0_ISSUER_BASE_URL", options.issuerBaseUrl ?? "").addEntry("AUTH0_AUDIENCE", options.audience ?? "");
449
- const authConfig = new _authconfigmodel.AuthConfigModel({
450
- issuerBaseUrl: options.issuerBaseUrl ?? "",
451
- audience: options.audience ?? ""
452
- });
453
- workspace.addModel(authConfig);
454
- if (withLocalUsers && options.adminPassword) {
455
- createAuth0AdminUser(workspace, options, authConfig);
456
- }
457
- }
458
- const AuthFeature = {
459
- getOptions,
460
- scaffold
461
- };
462
-
463
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL3J1bm5lci93b3JrL2RlY29oZXJlL2RlY29oZXJlL3Byb2plY3RzL2NyZWF0ZS9zcmMvd2ViYXBpL2ZlYXR1cmVzL2F1dGguZmVhdHVyZS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBhc2ssIHBpY2sgfSBmcm9tIFwiLi4vLi4vZG9tYWluL3Byb21wdC5qc1wiO1xuaW1wb3J0IHR5cGUgeyBDb25maWdZYW1sIH0gZnJvbSBcIi4uLy4uL21vZGVscy9jb25maWcteWFtbC5tb2RlbC5qc1wiO1xuaW1wb3J0IHsgV0VMTF9LTk9XTl9GSUxFUyB9IGZyb20gXCIuLi8uLi9tb2RlbHMvY29uc3QuanNcIjtcbmltcG9ydCB0eXBlIHsgRW52RmlsZSB9IGZyb20gXCIuLi8uLi9tb2RlbHMvZW52LWZpbGUubW9kZWwuanNcIjtcbmltcG9ydCB0eXBlIHsgUGFja2FnZUpzb24gfSBmcm9tIFwiLi4vLi4vbW9kZWxzL3BhY2thZ2UtanNvbi5tb2RlbC5qc1wiO1xuaW1wb3J0IHR5cGUgeyBXb3Jrc3BhY2VTY2FmZm9sZCB9IGZyb20gXCIuLi8uLi9tb2RlbHMvcHJvamVjdC5tb2RlbC5qc1wiO1xuaW1wb3J0IHR5cGUgeyBGZWF0dXJlIH0gZnJvbSBcIi4uLy4uL3NlcnZpY2VzL3NjYWZmb2xkLnNlcnZpY2UuanNcIjtcbmltcG9ydCB0eXBlIHsgQXBpUGFja2FnZUpzb24gfSBmcm9tIFwiLi4vbW9kZWxzL2FwaS1wYWNrYWdlLWpzb24ubW9kZWwuanNcIjtcbmltcG9ydCB7IEF1dGhDb25maWdNb2RlbCB9IGZyb20gXCIuLi9tb2RlbHMvYXV0aC1jb25maWcubW9kZWwuanNcIjtcbmltcG9ydCB7IENvbnRyb2xsZXJTb3VyY2VGaWxlIH0gZnJvbSBcIi4uL21vZGVscy9jb250cm9sbGVyLXNvdXJjZS1maWxlLm1vZGVsLmpzXCI7XG5pbXBvcnQgdHlwZSB7IE1haW5Tb3VyY2VGaWxlIH0gZnJvbSBcIi4uL21vZGVscy9tYWluLXNvdXJjZS1maWxlLm1vZGVsLmpzXCI7XG5pbXBvcnQgKiBhcyBhdXRoMENsaSBmcm9tIFwiLi9hdXRoMC1jbGkuanNcIjtcblxuZXhwb3J0IHR5cGUgQXV0aE9wdGlvbnMgPSB7XG5cdGF1dGhQcm92aWRlcj86IFwiYXV0aDBcIiB8IFwibm9uZVwiO1xuXHRpc3N1ZXJCYXNlVXJsPzogc3RyaW5nO1xuXHRhdWRpZW5jZT86IHN0cmluZztcblx0ZGF0YWJhc2VQcm92aWRlcj86IFwibm9uZVwiIHwgXCJwb3N0Z3Jlcy90eXBlb3JtXCI7XG5cdGFkbWluVXNlcm5hbWU/OiBzdHJpbmc7XG5cdGFkbWluUGFzc3dvcmQ/OiBzdHJpbmc7XG59O1xuXG5jb25zdCBBRE1JTl9ST0xFID0gXCJhZG1pblwiO1xuXG5jb25zdCBVU0VSX0VOVElUWV9UUyA9IGBpbXBvcnQgeyBDb2x1bW4sIEVudGl0eSwgUHJpbWFyeUdlbmVyYXRlZENvbHVtbiB9IGZyb20gXCJ0eXBlb3JtXCI7XG5pbXBvcnQgdHlwZSB7IEVudGl0eSBhcyBJRW50aXR5IH0gZnJvbSBcIkBkZWNvaGVyZS9jb2RleFwiO1xuXG5ARW50aXR5KClcbmV4cG9ydCBjbGFzcyBVc2VyRW50aXR5IGltcGxlbWVudHMgSUVudGl0eSB7XG5cXHRAUHJpbWFyeUdlbmVyYXRlZENvbHVtbigpXG5cXHRwdWJsaWMgaWQhOiBudW1iZXI7XG5cblxcdEBDb2x1bW4oeyB1bmlxdWU6IHRydWUgfSlcblxcdHB1YmxpYyBzdWIhOiBzdHJpbmc7XG5cblxcdEBDb2x1bW4oeyB0eXBlOiBcInZhcmNoYXJcIiwgbnVsbGFibGU6IHRydWUgfSlcblxcdHB1YmxpYyBlbWFpbCE6IHN0cmluZyB8IG51bGw7XG5cblxcdEBDb2x1bW4oKVxuXFx0cHVibGljIGRpc3BsYXlOYW1lITogc3RyaW5nO1xuXG5cXHQvKiogQXBwLW93bmVkIHJvbGVzLiBUaGUgXFxgYWRtaW5cXGAgcm9sZSBncmFudHMgQ0FTTCBcXGBtYW5hZ2VcXGAvXFxgYWxsXFxgICh3aWxkY2FyZCkuICovXG5cXHRAQ29sdW1uKHsgdHlwZTogXCJzaW1wbGUtanNvblwiLCBkZWZhdWx0OiBcIltdXCIgfSlcblxcdHB1YmxpYyByb2xlcyE6IHN0cmluZ1tdO1xufVxuYDtcblxuY29uc3QgVVNFUl9SRVBPU0lUT1JZX1RTID0gYGltcG9ydCB7IGluamVjdGFibGUgfSBmcm9tIFwiQGRlY29oZXJlL2NydWNpYmxlL2RlY29yYXRvcnNcIjtcbmltcG9ydCB7IGluamVjdFVuaXRPZldvcmsgfSBmcm9tIFwiQGRlY29oZXJlL2NvZGV4XCI7XG5pbXBvcnQgeyBUeXBlT3JtUmVwb3NpdG9yeSwgVHlwZU9ybVVuaXRPZldvcmsgfSBmcm9tIFwiQGRlY29oZXJlL2NvZGV4LXR5cGVvcm1cIjtcbmltcG9ydCB7IFVzZXJFbnRpdHkgfSBmcm9tIFwiLi4vZW50aXRpZXMvdXNlci5lbnRpdHkuanNcIjtcblxuQGluamVjdGFibGUoKVxuZXhwb3J0IGNsYXNzIFVzZXJFbnRpdHlSZXBvc2l0b3J5IGV4dGVuZHMgVHlwZU9ybVJlcG9zaXRvcnk8VXNlckVudGl0eT4ge1xuXFx0cHVibGljIGNvbnN0cnVjdG9yKEBpbmplY3RVbml0T2ZXb3JrKCkgdW5pdE9mV29yazogVHlwZU9ybVVuaXRPZldvcmspIHtcblxcdFxcdHN1cGVyKHVuaXRPZldvcmssIFVzZXJFbnRpdHkpO1xuXFx0fVxuXG5cXHRwdWJsaWMgZmluZEJ5U3ViKHN1Yjogc3RyaW5nKTogUHJvbWlzZTxVc2VyRW50aXR5IHwgbnVsbD4ge1xuXFx0XFx0cmV0dXJuIHRoaXMuZmlyc3RPckRlZmF1bHQoeyB3aGVyZTogeyBzdWIgfSB9KTtcblxcdH1cbn1cbmA7XG5cbmNvbnN0IFVTRVJfU0VSVklDRV9UUyA9IGBpbXBvcnQgeyBpbmplY3RhYmxlIH0gZnJvbSBcIkBkZWNvaGVyZS9jcnVjaWJsZS9kZWNvcmF0b3JzXCI7XG5pbXBvcnQgdHlwZSB7IFByaW5jaXBhbCB9IGZyb20gXCJAZGVjb2hlcmUvY29ydGV4XCI7XG5pbXBvcnQgeyBVc2VyRW50aXR5IH0gZnJvbSBcIi4uL2VudGl0aWVzL3VzZXIuZW50aXR5LmpzXCI7XG5pbXBvcnQgeyBVc2VyRW50aXR5UmVwb3NpdG9yeSB9IGZyb20gXCIuLi9yZXBvc2l0b3JpZXMvdXNlci5yZXBvc2l0b3J5LmpzXCI7XG5cbmZ1bmN0aW9uIGNsYWltU3RyaW5nKHByaW5jaXBhbDogUHJpbmNpcGFsIHwgdW5kZWZpbmVkLCBrZXk6IHN0cmluZyk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG5cXHRjb25zdCB2YWx1ZSA9IHByaW5jaXBhbD8uW2tleV07XG5cXHRyZXR1cm4gdHlwZW9mIHZhbHVlID09PSBcInN0cmluZ1wiICYmIHZhbHVlLmxlbmd0aCA+IDAgPyB2YWx1ZSA6IHVuZGVmaW5lZDtcbn1cblxuQGluamVjdGFibGUoKVxuZXhwb3J0IGNsYXNzIFVzZXJTZXJ2aWNlIHtcblxcdHB1YmxpYyBjb25zdHJ1Y3Rvcihwcml2YXRlIHJlYWRvbmx5IHVzZXJzOiBVc2VyRW50aXR5UmVwb3NpdG9yeSkge31cblxuXFx0LyoqXG5cXHQgKiBVcHNlcnQgYSBsb2NhbCBwcm9maWxlIGtleWVkIGJ5IEpXVCBcXGBzdWJcXGAuXG5cXHQgKiBQcm9maWxlIGZpZWxkcyBmcm9tIHRoZSB0b2tlbiBmaWxsIGdhcHM7IHNlZWRlZCByb3dzIGtlZXAgZGlzcGxheU5hbWUvZW1haWwvcm9sZXMuXG5cXHQgKi9cblxcdHB1YmxpYyBhc3luYyBlbnN1cmVGcm9tUHJpbmNpcGFsKHByaW5jaXBhbDogUHJpbmNpcGFsIHwgdW5kZWZpbmVkKTogUHJvbWlzZTxVc2VyRW50aXR5PiB7XG5cXHRcXHRjb25zdCBzdWIgPSBwcmluY2lwYWw/LnN1YjtcblxcdFxcdGlmICghc3ViKSB7XG5cXHRcXHRcXHR0aHJvdyBuZXcgRXJyb3IoXCJBdXRoZW50aWNhdGVkIHJlcXVlc3QgaXMgbWlzc2luZyBwcmluY2lwYWwuc3ViXCIpO1xuXFx0XFx0fVxuXG5cXHRcXHRjb25zdCBlbWFpbCA9XG5cXHRcXHRcXHRjbGFpbVN0cmluZyhwcmluY2lwYWwsIFwiZW1haWxcIikgPz8gY2xhaW1TdHJpbmcocHJpbmNpcGFsLCBcInByZWZlcnJlZF91c2VybmFtZVwiKTtcblxcdFxcdGNvbnN0IGRpc3BsYXlGcm9tVG9rZW4gPVxuXFx0XFx0XFx0Y2xhaW1TdHJpbmcocHJpbmNpcGFsLCBcIm5hbWVcIikgPz9cblxcdFxcdFxcdGNsYWltU3RyaW5nKHByaW5jaXBhbCwgXCJuaWNrbmFtZVwiKSA/P1xuXFx0XFx0XFx0ZW1haWw7XG5cblxcdFxcdGNvbnN0IGV4aXN0aW5nID0gYXdhaXQgdGhpcy51c2Vycy5maW5kQnlTdWIoc3ViKTtcblxcdFxcdGlmIChleGlzdGluZykge1xuXFx0XFx0XFx0bGV0IGRpcnR5ID0gZmFsc2U7XG5cXHRcXHRcXHRpZiAoIWV4aXN0aW5nLmVtYWlsICYmIGVtYWlsKSB7XG5cXHRcXHRcXHRcXHRleGlzdGluZy5lbWFpbCA9IGVtYWlsO1xuXFx0XFx0XFx0XFx0ZGlydHkgPSB0cnVlO1xuXFx0XFx0XFx0fVxuXFx0XFx0XFx0aWYgKGV4aXN0aW5nLmRpc3BsYXlOYW1lID09PSBleGlzdGluZy5zdWIgJiYgZGlzcGxheUZyb21Ub2tlbikge1xuXFx0XFx0XFx0XFx0ZXhpc3RpbmcuZGlzcGxheU5hbWUgPSBkaXNwbGF5RnJvbVRva2VuO1xuXFx0XFx0XFx0XFx0ZGlydHkgPSB0cnVlO1xuXFx0XFx0XFx0fVxuXFx0XFx0XFx0cmV0dXJuIGRpcnR5ID8gdGhpcy51c2Vycy5zYXZlKGV4aXN0aW5nKSA6IGV4aXN0aW5nO1xuXFx0XFx0fVxuXG5cXHRcXHRjb25zdCBjcmVhdGVkID0gbmV3IFVzZXJFbnRpdHkoKTtcblxcdFxcdGNyZWF0ZWQuc3ViID0gc3ViO1xuXFx0XFx0Y3JlYXRlZC5lbWFpbCA9IGVtYWlsID8/IG51bGw7XG5cXHRcXHRjcmVhdGVkLmRpc3BsYXlOYW1lID0gZGlzcGxheUZyb21Ub2tlbiA/PyBzdWI7XG5cXHRcXHRjcmVhdGVkLnJvbGVzID0gQXJyYXkuaXNBcnJheShwcmluY2lwYWwucm9sZXMpXG5cXHRcXHRcXHQ/IHByaW5jaXBhbC5yb2xlcy5maWx0ZXIoKHIpOiByIGlzIHN0cmluZyA9PiB0eXBlb2YgciA9PT0gXCJzdHJpbmdcIilcblxcdFxcdFxcdDogW107XG5cXHRcXHRyZXR1cm4gdGhpcy51c2Vycy5zYXZlKGNyZWF0ZWQpO1xuXFx0fVxufVxuYDtcblxuY29uc3QgQUJJTElUWV9GQUNUT1JZX1RTID0gYGltcG9ydCB7IEFiaWxpdHlCdWlsZGVyLCBjcmVhdGVNb25nb0FiaWxpdHkgfSBmcm9tIFwiQGNhc2wvYWJpbGl0eVwiO1xuaW1wb3J0IHR5cGUgeyBQcmluY2lwYWwgfSBmcm9tIFwiQGRlY29oZXJlL2NvcnRleFwiO1xuXG4vKiogUm9vdCByb2xlIOKAlCBleHBhbmRzIHRvIENBU0wgXFxgbWFuYWdlXFxgL1xcYGFsbFxcYCAoY292ZXJzIGV2ZXJ5IGZ1dHVyZSBhYmlsaXR5KS4gKi9cbmV4cG9ydCBjb25zdCBBRE1JTl9ST0xFID0gXCJhZG1pblwiO1xuXG4vKipcbiAqIFJvbGVzIGFyZSBjb2xsZWN0aW9ucyBvZiBhYmlsaXRpZXMuIEFkbWluIGlzIGEgd2lsZGNhcmQsIG5vdCBhbiBlbnVtZXJhdGVkIGxpc3QuXG4gKiBOb24tYWRtaW4gcHJpbmNpcGFscyBrZWVwIEF1dGgwIHNjb3BlIC8gcGVybWlzc2lvbiDihpIgYWJpbGl0eSBtYXBwaW5nLlxuICovXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlQWJpbGl0eUZhY3RvcnkocHJpbmNpcGFsOiBQcmluY2lwYWwpIHtcblxcdGNvbnN0IHsgY2FuLCBidWlsZCB9ID0gbmV3IEFiaWxpdHlCdWlsZGVyKGNyZWF0ZU1vbmdvQWJpbGl0eSk7XG5cXHRpZiAocHJpbmNpcGFsLnJvbGVzPy5pbmNsdWRlcyhBRE1JTl9ST0xFKSkge1xuXFx0XFx0Y2FuKFwibWFuYWdlXCIsIFwiYWxsXCIpO1xuXFx0XFx0cmV0dXJuIGJ1aWxkKCk7XG5cXHR9XG5cXHRmb3IgKGNvbnN0IHNjb3BlIG9mIHByaW5jaXBhbC5zY29wZXMgPz8gW10pIHtcblxcdFxcdGNvbnN0IFthY3Rpb24sIHN1YmplY3RdID0gc2NvcGUuc3BsaXQoXCI6XCIpO1xuXFx0XFx0aWYgKGFjdGlvbiAmJiBzdWJqZWN0KSBjYW4oYWN0aW9uLCBzdWJqZWN0KTtcblxcdH1cblxcdHJldHVybiBidWlsZCgpO1xufVxuXG4vKipcbiAqIE1hcCBKV1QgcGF5bG9hZCDihpIgUHJpbmNpcGFsLlxuICpcbiAqIC0gXFxgcm9sZXNcXGAgY29tZSBmcm9tIHRoZSBJZFAgKEF1dGgwIFJCQUMgLyBBY3Rpb24gZnJvbSBhcHBfbWV0YWRhdGEpLiBBZG1pbnMgYXJlXG4gKiAgIGFzc2lnbmVkIGluIEF1dGgwIOKAlCBubyBzZXJ2ZXIgZW52IGNoYW5nZSByZXF1aXJlZCBmb3IgYWRkaXRpb25hbCBhZG1pbnMuXG4gKiAtIFxcYEFVVEgwX0FETUlOX1VTRVJfU1VCXFxgIGlzIGFuIG9wdGlvbmFsIGJvb3RzdHJhcCBzbyB0aGUgc2VlZGVkIGFkbWluIHdvcmtzXG4gKiAgIGJlZm9yZS93aXRob3V0IHJvbGVzIG9uIHRoZSBhY2Nlc3MgdG9rZW4uXG4gKiAtIEFQSSBwZXJtaXNzaW9ucyBhcmUgdGFrZW4gZnJvbSBcXGBzY29wZVxcYCBhbmQgZnJvbSBBdXRoMCdzIFxcYHBlcm1pc3Npb25zXFxgIGNsYWltLlxuICovXG5leHBvcnQgZnVuY3Rpb24gbWFwUHJpbmNpcGFsKHBheWxvYWQ6IFJlY29yZDxzdHJpbmcsIHVua25vd24+KTogUHJpbmNpcGFsIHtcblxcdGNvbnN0IHN1YiA9IHR5cGVvZiBwYXlsb2FkLnN1YiA9PT0gXCJzdHJpbmdcIiA/IHBheWxvYWQuc3ViIDogXCJcIjtcblxcdGNvbnN0IGZyb21TY29wZUNsYWltID1cblxcdFxcdHR5cGVvZiBwYXlsb2FkLnNjb3BlID09PSBcInN0cmluZ1wiXG5cXHRcXHRcXHQ/IHBheWxvYWQuc2NvcGUuc3BsaXQoXCIgXCIpLmZpbHRlcihCb29sZWFuKVxuXFx0XFx0XFx0OiBBcnJheS5pc0FycmF5KHBheWxvYWQuc2NvcGVzKVxuXFx0XFx0XFx0XFx0PyAocGF5bG9hZC5zY29wZXMgYXMgdW5rbm93bltdKS5maWx0ZXIoKHMpOiBzIGlzIHN0cmluZyA9PiB0eXBlb2YgcyA9PT0gXCJzdHJpbmdcIilcblxcdFxcdFxcdFxcdDogW107XG5cXHRjb25zdCBmcm9tUGVybWlzc2lvbnMgPSBBcnJheS5pc0FycmF5KHBheWxvYWQucGVybWlzc2lvbnMpXG5cXHRcXHQ/IChwYXlsb2FkLnBlcm1pc3Npb25zIGFzIHVua25vd25bXSkuZmlsdGVyKChzKTogcyBpcyBzdHJpbmcgPT4gdHlwZW9mIHMgPT09IFwic3RyaW5nXCIpXG5cXHRcXHQ6IFtdO1xuXFx0Y29uc3QgbWVyZ2VkID0gWy4uLm5ldyBTZXQoWy4uLmZyb21TY29wZUNsYWltLCAuLi5mcm9tUGVybWlzc2lvbnNdKV07XG5cXHRjb25zdCBzY29wZXMgPSBtZXJnZWQubGVuZ3RoID4gMCA/IG1lcmdlZCA6IHVuZGVmaW5lZDtcblxcdGNvbnN0IGZyb21Ub2tlbiA9IEFycmF5LmlzQXJyYXkocGF5bG9hZC5yb2xlcylcblxcdFxcdD8gKHBheWxvYWQucm9sZXMgYXMgdW5rbm93bltdKS5maWx0ZXIoKHIpOiByIGlzIHN0cmluZyA9PiB0eXBlb2YgciA9PT0gXCJzdHJpbmdcIilcblxcdFxcdDogW107XG5cXHRjb25zdCByb2xlcyA9XG5cXHRcXHRzdWIgJiYgc3ViID09PSBwcm9jZXNzLmVudi5BVVRIMF9BRE1JTl9VU0VSX1NVQlxuXFx0XFx0XFx0PyBbLi4ubmV3IFNldChbQURNSU5fUk9MRSwgLi4uZnJvbVRva2VuXSldXG5cXHRcXHRcXHQ6IGZyb21Ub2tlbi5sZW5ndGggPiAwXG5cXHRcXHRcXHRcXHQ/IGZyb21Ub2tlblxuXFx0XFx0XFx0XFx0OiB1bmRlZmluZWQ7XG5cXHRyZXR1cm4geyAuLi5wYXlsb2FkLCBzdWIsIHJvbGVzLCBzY29wZXMgfTtcbn1cbmA7XG5cbmFzeW5jIGZ1bmN0aW9uIGdldE9wdGlvbnMoXG5cdHdvcmtzcGFjZTogV29ya3NwYWNlU2NhZmZvbGQsXG5cdGNsaU9wdGlvbnM6IFBhcnRpYWw8QXV0aE9wdGlvbnM+LFxuKTogUHJvbWlzZTxQYXJ0aWFsPEF1dGhPcHRpb25zPj4ge1xuXHRpZiAoY2xpT3B0aW9ucy5hdXRoUHJvdmlkZXIgPT09IFwiYXV0aDBcIiAmJiAhY2xpT3B0aW9ucy5pc3N1ZXJCYXNlVXJsKSB7XG5cdFx0cmV0dXJuIGdldEF1dGgwT3B0aW9ucyh3b3Jrc3BhY2UsIGNsaU9wdGlvbnMpO1xuXHR9XG5cdGlmIChjbGlPcHRpb25zLmF1dGhQcm92aWRlciAhPSBudWxsKSByZXR1cm4ge307XG5cblx0Y29uc3QgY2hvaWNlcyA9IFt7IGxhYmVsOiBcIm5vbmVcIiBhcyBjb25zdCB9LCB7IGxhYmVsOiBcImF1dGgwXCIgYXMgY29uc3QgfV07XG5cdGNvbnN0IHNlbGVjdGVkID0gYXdhaXQgcGljayhcIlxcbiAgQXV0aCBwcm92aWRlcjogXCIsIGNob2ljZXMsIChjKSA9PiBjLmxhYmVsKTtcblx0Y29uc3QgcHJvdmlkZXIgPSBzZWxlY3RlZD8ubGFiZWwgPz8gXCJub25lXCI7XG5cblx0aWYgKHByb3ZpZGVyICE9PSBcImF1dGgwXCIpIHJldHVybiB7IGF1dGhQcm92aWRlcjogXCJub25lXCIgfTtcblxuXHRyZXR1cm4gZ2V0QXV0aDBPcHRpb25zKHdvcmtzcGFjZSwgY2xpT3B0aW9ucyk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGdldEF1dGgwT3B0aW9ucyhcblx0d29ya3NwYWNlOiBXb3Jrc3BhY2VTY2FmZm9sZCxcblx0Y2xpT3B0aW9uczogUGFydGlhbDxBdXRoT3B0aW9ucz4sXG4pOiBQcm9taXNlPFBhcnRpYWw8QXV0aE9wdGlvbnM+PiB7XG5cdGlmICghYXV0aDBDbGkuaXNJbnN0YWxsZWQoKSkge1xuXHRcdGNvbnNvbGUuZXJyb3IoXG5cdFx0XHRcIlxcbiAgVGhlIEF1dGgwIENMSSBpcyByZXF1aXJlZCBmb3IgYXV0b21hdGVkIHNldHVwLlxcblwiICtcblx0XHRcdFx0XCIgIEluc3RhbGw6IGJyZXcgaW5zdGFsbCBhdXRoMC9hdXRoMC1jbGkvYXV0aDBcXG5cIiArXG5cdFx0XHRcdFwiICBPciB2aXNpdDogaHR0cHM6Ly9naXRodWIuY29tL2F1dGgwL2F1dGgwLWNsaVxcblwiLFxuXHRcdCk7XG5cdFx0cHJvY2Vzcy5leGl0KDEpO1xuXHR9XG5cblx0cHJvY2Vzcy5zdGRvdXQud3JpdGUoXCJcXG4gIENoZWNraW5nIEF1dGgwIGNyZWRlbnRpYWxzLi4uXCIpO1xuXHRsZXQgdGVuYW50cyA9IGF1dGgwQ2xpLmxpc3RUZW5hbnRzKCk7XG5cdGlmICh0ZW5hbnRzLmxlbmd0aCA9PT0gMCkge1xuXHRcdHByb2Nlc3Muc3Rkb3V0LndyaXRlKFwiIG5vdCBsb2dnZWQgaW4uXFxuXCIpO1xuXHRcdGNvbnNvbGUubG9nKFwiICBMb2dnaW5nIGluIHRvIEF1dGgwICh5b3VyIGJyb3dzZXIgd2lsbCBvcGVuKS4uLlwiKTtcblx0XHRpZiAoIWF1dGgwQ2xpLmxvZ2luKCkpIHtcblx0XHRcdGNvbnNvbGUuZXJyb3IoXCJcXG4gIEF1dGgwIGxvZ2luIGZhaWxlZC5cIik7XG5cdFx0XHRwcm9jZXNzLmV4aXQoMSk7XG5cdFx0fVxuXHRcdHRlbmFudHMgPSBhdXRoMENsaS5saXN0VGVuYW50cygpO1xuXHR9XG5cblx0dHJ5IHtcblx0XHRhdXRoMENsaS5saXN0QXBpcygpO1xuXHRcdHByb2Nlc3Muc3Rkb3V0LndyaXRlKFwiIG9rLlxcblwiKTtcblx0fSBjYXRjaCAoZXJyKSB7XG5cdFx0aWYgKGVyciBpbnN0YW5jZW9mIGF1dGgwQ2xpLkF1dGgwQXV0aEVycm9yKSB7XG5cdFx0XHRwcm9jZXNzLnN0ZG91dC53cml0ZShcIiB0b2tlbiBleHBpcmVkLlxcblwiKTtcblx0XHRcdGNvbnNvbGUubG9nKFwiICBSZS1hdXRoZW50aWNhdGluZyAoeW91ciBicm93c2VyIHdpbGwgb3BlbikuLi5cIik7XG5cdFx0XHRpZiAoIWF1dGgwQ2xpLmxvZ2luKCkpIHtcblx0XHRcdFx0Y29uc29sZS5lcnJvcihcIlxcbiAgQXV0aDAgbG9naW4gZmFpbGVkLlwiKTtcblx0XHRcdFx0cHJvY2Vzcy5leGl0KDEpO1xuXHRcdFx0fVxuXHRcdH1cblx0fVxuXG5cdGNvbnN0IGFjdGl2ZSA9IHRlbmFudHMuZmluZCgodCkgPT4gdC5hY3RpdmUpID8/IHRlbmFudHNbMF07XG5cdGNvbnN0IGlzc3VlckJhc2VVcmwgPSBgaHR0cHM6Ly8ke2FjdGl2ZS5uYW1lfWA7XG5cdGNvbnNvbGUubG9nKGBcXG4gIOKckyBBdXRoMCB0ZW5hbnQ6ICR7aXNzdWVyQmFzZVVybH1gKTtcblxuXHRwcm9jZXNzLnN0ZG91dC53cml0ZShcIlxcbiAgRmV0Y2hpbmcgQXV0aDAgQVBJcy4uLlwiKTtcblx0Y29uc3QgdXNlckFwaXMgPSBhdXRoMENsaS5saXN0QXBpcygpLmZpbHRlcigoYSkgPT4gIWEubmFtZS5pbmNsdWRlcyhcIk1hbmFnZW1lbnQgQVBJXCIpKTtcblx0cHJvY2Vzcy5zdGRvdXQud3JpdGUoYCBmb3VuZCAke3VzZXJBcGlzLmxlbmd0aH0uXFxuYCk7XG5cblx0dHlwZSBBcGlDaG9pY2UgPSB7IGxhYmVsOiBzdHJpbmc7IGV4aXN0aW5nOiBzdHJpbmcgfCBudWxsIH07XG5cdGNvbnN0IHByb2plY3ROYW1lID0gd29ya3NwYWNlLm5hbWU7XG5cdGNvbnN0IGFwaUNob2ljZXM6IEFwaUNob2ljZVtdID0gW1xuXHRcdHsgbGFiZWw6IGA8bmV3PiBodHRwczovL2FwaS4ke3Byb2plY3ROYW1lfWAsIGV4aXN0aW5nOiBudWxsIH0sXG5cdFx0Li4udXNlckFwaXMubWFwKChhKSA9PiAoeyBsYWJlbDogYCR7YS5uYW1lfSDigJQgJHthLmlkZW50aWZpZXJ9YCwgZXhpc3Rpbmc6IGEuaWRlbnRpZmllciB9KSksXG5cdF07XG5cblx0Y29uc3QgYXBpU2VsZWN0ZWQgPSBhd2FpdCBwaWNrKFwiXFxuICBTZWxlY3QgQXV0aDAgQVBJOiBcIiwgYXBpQ2hvaWNlcywgKGMpID0+IGMubGFiZWwpO1xuXG5cdGxldCBhdWRpZW5jZTogc3RyaW5nO1xuXHRpZiAoIWFwaVNlbGVjdGVkIHx8IGFwaVNlbGVjdGVkLmV4aXN0aW5nID09PSBudWxsKSB7XG5cdFx0Y29uc3QgZGVmYXVsdElkID0gYGh0dHBzOi8vYXBpLiR7cHJvamVjdE5hbWV9YDtcblx0XHRhdWRpZW5jZSA9IGF3YWl0IGFzayhgICBBUEkgSWRlbnRpZmllciBbJHtkZWZhdWx0SWR9XTogYCwgZGVmYXVsdElkKTtcblx0XHRjb25zb2xlLmxvZyhcIlxcbiAgQ3JlYXRpbmcgQXV0aDAgQVBJLi4uXCIpO1xuXHRcdGF1ZGllbmNlID0gYXV0aDBDbGkuY3JlYXRlQXBpKGAke3Byb2plY3ROYW1lfSBBUElgLCBhdWRpZW5jZSkuaWRlbnRpZmllcjtcblx0XHRjb25zb2xlLmxvZyhgICBcXHUyNzEzIEFQSSBjcmVhdGVkOiAke2F1ZGllbmNlfWApO1xuXHR9IGVsc2Uge1xuXHRcdGF1ZGllbmNlID0gYXBpU2VsZWN0ZWQuZXhpc3Rpbmc7XG5cdFx0Y29uc29sZS5sb2coYCAgXFx1MjcxMyBTZWxlY3RlZDogJHthdWRpZW5jZX1gKTtcblx0XHR0cnkge1xuXHRcdFx0YXV0aDBDbGkudXBkYXRlQXBpU2NvcGVzKGF1ZGllbmNlKTtcblx0XHRcdGNvbnNvbGUubG9nKGAgIFxcdTI3MTMgQVBJIHNjb3BlcyBlbnN1cmVkICgke2F1dGgwQ2xpLkhFTExPX0FQSV9TQ09QRVMuam9pbihcIiwgXCIpfSlgKTtcblx0XHR9IGNhdGNoIHtcblx0XHRcdGNvbnNvbGUuZXJyb3IoXG5cdFx0XHRcdFwiICDinJcgRmFpbGVkIHRvIHVwZGF0ZSBBUEkgc2NvcGVzIOKAlCBhZGQgSGVsbG8gc2NvcGVzIGluIHRoZSBBdXRoMCBkYXNoYm9hcmQuXCIsXG5cdFx0XHQpO1xuXHRcdH1cblx0fVxuXG5cdGNvbnN0IHdpdGhMb2NhbFVzZXJzID0gY2xpT3B0aW9ucy5kYXRhYmFzZVByb3ZpZGVyID09PSBcInBvc3RncmVzL3R5cGVvcm1cIjtcblx0bGV0IGFkbWluVXNlcm5hbWU6IHN0cmluZyB8IHVuZGVmaW5lZDtcblx0bGV0IGFkbWluUGFzc3dvcmQ6IHN0cmluZyB8IHVuZGVmaW5lZDtcblx0aWYgKHdpdGhMb2NhbFVzZXJzKSB7XG5cdFx0YWRtaW5Vc2VybmFtZSA9XG5cdFx0XHRjbGlPcHRpb25zLmFkbWluVXNlcm5hbWUgPz8gKGF3YWl0IGFzayhcIlxcbiAgQWRtaW4gdXNlcm5hbWUgW2FkbWluXTogXCIsIFwiYWRtaW5cIikpO1xuXHRcdGFkbWluUGFzc3dvcmQgPSBjbGlPcHRpb25zLmFkbWluUGFzc3dvcmQ7XG5cdFx0aWYgKGFkbWluUGFzc3dvcmQgPT0gbnVsbCkge1xuXHRcdFx0YWRtaW5QYXNzd29yZCA9IGF3YWl0IGFzayhcIiAgQWRtaW4gcGFzc3dvcmQgKGxlYXZlIGJsYW5rIHRvIGdlbmVyYXRlKTogXCIpO1xuXHRcdFx0aWYgKCFhZG1pblBhc3N3b3JkKSB7XG5cdFx0XHRcdGFkbWluUGFzc3dvcmQgPSBhdXRoMENsaS5nZW5lcmF0ZUFkbWluUGFzc3dvcmQoKTtcblx0XHRcdFx0Y29uc29sZS5sb2coYCAg4pyTIEdlbmVyYXRlZCBhZG1pbiBwYXNzd29yZCAod3JpdHRlbiB0byAuZW52KTogJHthZG1pblBhc3N3b3JkfWApO1xuXHRcdFx0fVxuXHRcdH1cblx0fVxuXG5cdHJldHVybiB7XG5cdFx0YXV0aFByb3ZpZGVyOiBcImF1dGgwXCIsXG5cdFx0aXNzdWVyQmFzZVVybCxcblx0XHRhdWRpZW5jZSxcblx0XHQuLi4od2l0aExvY2FsVXNlcnMgPyB7IGFkbWluVXNlcm5hbWUsIGFkbWluUGFzc3dvcmQgfSA6IHt9KSxcblx0fTtcbn1cblxuZnVuY3Rpb24gYWRtaW5FbWFpbCh3b3Jrc3BhY2VOYW1lOiBzdHJpbmcsIHVzZXJuYW1lOiBzdHJpbmcpOiBzdHJpbmcge1xuXHRpZiAodXNlcm5hbWUuaW5jbHVkZXMoXCJAXCIpKSByZXR1cm4gdXNlcm5hbWU7XG5cdGNvbnN0IHNsdWcgPSB3b3Jrc3BhY2VOYW1lLnRvTG93ZXJDYXNlKCkucmVwbGFjZSgvW15hLXowLTktXS9nLCBcIi1cIik7XG5cdHJldHVybiBgJHt1c2VybmFtZX1AJHtzbHVnfS5leGFtcGxlLmNvbWA7XG59XG5cbmZ1bmN0aW9uIGNyZWF0ZUF1dGgwQWRtaW5Vc2VyKFxuXHR3b3Jrc3BhY2U6IFdvcmtzcGFjZVNjYWZmb2xkLFxuXHRvcHRpb25zOiBBdXRoT3B0aW9ucyxcblx0YXV0aENvbmZpZzogQXV0aENvbmZpZ01vZGVsLFxuKTogdm9pZCB7XG5cdGNvbnN0IHVzZXJuYW1lID0gb3B0aW9ucy5hZG1pblVzZXJuYW1lID8/IFwiYWRtaW5cIjtcblx0Y29uc3QgcGFzc3dvcmQgPSBvcHRpb25zLmFkbWluUGFzc3dvcmQ7XG5cdGlmICghcGFzc3dvcmQpIHJldHVybjtcblxuXHRjb25zdCBlbWFpbCA9IGFkbWluRW1haWwod29ya3NwYWNlLm5hbWUsIHVzZXJuYW1lKTtcblx0dHJ5IHtcblx0XHRjb25zdCBhZG1pbiA9IGF1dGgwQ2xpLmNyZWF0ZUFkbWluRGF0YWJhc2VVc2VyKHsgZW1haWwsIHBhc3N3b3JkLCB1c2VybmFtZSB9KTtcblx0XHRhdXRoQ29uZmlnLnNldEFkbWluVXNlcih7XG5cdFx0XHRzdWI6IGFkbWluLnVzZXJfaWQsXG5cdFx0XHRlbWFpbDogYWRtaW4uZW1haWwsXG5cdFx0XHRwYXNzd29yZDogYWRtaW4ucGFzc3dvcmQsXG5cdFx0XHR1c2VybmFtZTogYWRtaW4udXNlcm5hbWUsXG5cdFx0fSk7XG5cdFx0d29ya3NwYWNlXG5cdFx0XHQuZ2V0TW9kZWw8RW52RmlsZT4oV0VMTF9LTk9XTl9GSUxFUy5FTlZfRklMRSlcblx0XHRcdD8uYWRkRW50cnkoXCJBVVRIMF9BRE1JTl9VU0VSX1NVQlwiLCBhZG1pbi51c2VyX2lkKVxuXHRcdFx0LmFkZEVudHJ5KFwiQVVUSDBfQURNSU5fVVNFUl9FTUFJTFwiLCBhZG1pbi5lbWFpbClcblx0XHRcdC5hZGRFbnRyeShcIkFVVEgwX0FETUlOX1VTRVJfUEFTU1dPUkRcIiwgYWRtaW4ucGFzc3dvcmQpXG5cdFx0XHQuYWRkRW50cnkoXCJBVVRIMF9BRE1JTl9VU0VSTkFNRVwiLCBhZG1pbi51c2VybmFtZSk7XG5cdFx0Y29uc29sZS5sb2coYCAg4pyTIEF1dGgwIGFkbWluIHVzZXIgcmVhZHk6ICR7YWRtaW4uZW1haWx9IChyb2xlOiAke0FETUlOX1JPTEV9KWApO1xuXHRcdGNvbnNvbGUubG9nKGAgICAgTG9naW4gd2l0aCBFTUFJTCAobm90IHVzZXJuYW1lKTogJHthZG1pbi5lbWFpbH1gKTtcblx0XHRjb25zb2xlLmxvZyhgICAgIFBhc3N3b3JkOiBzZWUgQVVUSDBfQURNSU5fVVNFUl9QQVNTV09SRCBpbiAuZW52YCk7XG5cdH0gY2F0Y2ggKGVycikge1xuXHRcdGNvbnNvbGUuZXJyb3IoXG5cdFx0XHRgICDinJcgRmFpbGVkIHRvIGVuc3VyZSBBdXRoMCBhZG1pbiB1c2VyICgke2VtYWlsfSk6ICR7ZXJyIGluc3RhbmNlb2YgRXJyb3IgPyBlcnIubWVzc2FnZSA6IGVycn1gLFxuXHRcdCk7XG5cdH1cbn1cblxuZnVuY3Rpb24gc2NhZmZvbGRMb2NhbFVzZXJQcm9maWxlKHdvcmtzcGFjZTogV29ya3NwYWNlU2NhZmZvbGQpOiB2b2lkIHtcblx0d29ya3NwYWNlXG5cdFx0LmdldE1vZGVsPFBhY2thZ2VKc29uPihXRUxMX0tOT1dOX0ZJTEVTLlBBQ0tBR0VfSlNPTilcblx0XHQ/LmFkZERlcGVuZGVuY3koXCJAY2FzbC9hYmlsaXR5XCIsIFwiXjYuOC4xXCIpO1xuXG5cdGZvciAoY29uc3QgcHJvamVjdCBvZiB3b3Jrc3BhY2UuZ2V0UHJvamVjdHMoKSkge1xuXHRcdHByb2plY3Rcblx0XHRcdC5nZXRNb2RlbDxBcGlQYWNrYWdlSnNvbj4oV0VMTF9LTk9XTl9GSUxFUy5BUElfUEFDS0FHRV9KU09OKVxuXHRcdFx0Py5hZGREZXBlbmRlbmN5KFwiQGNhc2wvYWJpbGl0eVwiLCBcIl42LjguMVwiKTtcblxuXHRcdHByb2plY3Rcblx0XHRcdC5nZXRNb2RlbDxNYWluU291cmNlRmlsZT4oV0VMTF9LTk9XTl9GSUxFUy5NQUlOX1RTKVxuXHRcdFx0Py5hZGRFbnRpdHkoeyBjbGFzc05hbWU6IFwiVXNlckVudGl0eVwiLCBpbXBvcnRQYXRoOiBcIi4vZW50aXRpZXMvdXNlci5lbnRpdHkuanNcIiB9KVxuXHRcdFx0LmFkZFJlcG9zaXRvcnkoe1xuXHRcdFx0XHRjbGFzc05hbWU6IFwiVXNlckVudGl0eVJlcG9zaXRvcnlcIixcblx0XHRcdFx0aW1wb3J0UGF0aDogXCIuL3JlcG9zaXRvcmllcy91c2VyLnJlcG9zaXRvcnkuanNcIixcblx0XHRcdH0pXG5cdFx0XHQuYWRkU2VydmljZSh7XG5cdFx0XHRcdGNsYXNzTmFtZTogXCJVc2VyU2VydmljZVwiLFxuXHRcdFx0XHRpbXBvcnRQYXRoOiBcIi4vc2VydmljZXMvdXNlci5zZXJ2aWNlLmpzXCIsXG5cdFx0XHRcdHNjb3BlOiBcInJlcXVlc3RcIixcblx0XHRcdH0pXG5cdFx0XHQuYWRkSW1wb3J0KFwiY3JlYXRlQWJpbGl0eUZhY3RvcnlcIiwgXCIuL2F1dGgvYWJpbGl0eS5mYWN0b3J5LmpzXCIpXG5cdFx0XHQuYWRkSW1wb3J0KFwibWFwUHJpbmNpcGFsXCIsIFwiLi9hdXRoL2FiaWxpdHkuZmFjdG9yeS5qc1wiKVxuXHRcdFx0LnNldFR5cGVPcm1TZWVkKFxuXHRcdFx0XHRbXG5cdFx0XHRcdFx0XCJjb25zdCBzdWIgPSBwcm9jZXNzLmVudi5BVVRIMF9BRE1JTl9VU0VSX1NVQjtcIixcblx0XHRcdFx0XHRcImlmICghc3ViKSByZXR1cm47XCIsXG5cdFx0XHRcdFx0XCJjb25zdCByZXBvID0gZGF0YVNvdXJjZS5nZXRSZXBvc2l0b3J5KFVzZXJFbnRpdHkpO1wiLFxuXHRcdFx0XHRcdFwiY29uc3QgZXhpc3RpbmcgPSBhd2FpdCByZXBvLmZpbmRPbmUoeyB3aGVyZTogeyBzdWIgfSB9KTtcIixcblx0XHRcdFx0XHRcImlmIChleGlzdGluZykgcmV0dXJuO1wiLFxuXHRcdFx0XHRcdFwiYXdhaXQgcmVwby5zYXZlKHJlcG8uY3JlYXRlKHtcIixcblx0XHRcdFx0XHRcIiAgc3ViLFwiLFxuXHRcdFx0XHRcdFwiICBlbWFpbDogcHJvY2Vzcy5lbnYuQVVUSDBfQURNSU5fVVNFUl9FTUFJTCA/PyBudWxsLFwiLFxuXHRcdFx0XHRcdCcgIGRpc3BsYXlOYW1lOiBwcm9jZXNzLmVudi5BVVRIMF9BRE1JTl9VU0VSTkFNRSA/PyBcImFkbWluXCIsJyxcblx0XHRcdFx0XHQnICByb2xlczogW1wiYWRtaW5cIl0sJyxcblx0XHRcdFx0XHRcIn0pKTtcIixcblx0XHRcdFx0XS5qb2luKFwiIFwiKSxcblx0XHRcdCk7XG5cblx0XHRwcm9qZWN0LmFkZEZpbGUoe1xuXHRcdFx0ZmlsZXM6ICgpID0+IFtcblx0XHRcdFx0eyBmaWxlUGF0aDogXCJzcmMvZW50aXRpZXMvdXNlci5lbnRpdHkudHNcIiwgY29udGVudDogVVNFUl9FTlRJVFlfVFMgfSxcblx0XHRcdFx0eyBmaWxlUGF0aDogXCJzcmMvcmVwb3NpdG9yaWVzL3VzZXIucmVwb3NpdG9yeS50c1wiLCBjb250ZW50OiBVU0VSX1JFUE9TSVRPUllfVFMgfSxcblx0XHRcdFx0eyBmaWxlUGF0aDogXCJzcmMvc2VydmljZXMvdXNlci5zZXJ2aWNlLnRzXCIsIGNvbnRlbnQ6IFVTRVJfU0VSVklDRV9UUyB9LFxuXHRcdFx0XHR7IGZpbGVQYXRoOiBcInNyYy9hdXRoL2FiaWxpdHkuZmFjdG9yeS50c1wiLCBjb250ZW50OiBBQklMSVRZX0ZBQ1RPUllfVFMgfSxcblx0XHRcdF0sXG5cdFx0fSk7XG5cdH1cblxuXHRmb3IgKGNvbnN0IGNvbnRyb2xsZXIgb2Ygd29ya3NwYWNlLmdldE1vZGVscyhDb250cm9sbGVyU291cmNlRmlsZSkpIHtcblx0XHRjb250cm9sbGVyXG5cdFx0XHQuYWRkSW1wb3J0KFwiVXNlclNlcnZpY2VcIiwgXCIuLi9zZXJ2aWNlcy91c2VyLnNlcnZpY2UuanNcIilcblx0XHRcdC5hZGRDb25zdHJ1Y3RvclBhcmFtKFwicHJpdmF0ZSByZWFkb25seSB1c2VyczogVXNlclNlcnZpY2VcIik7XG5cdFx0Y29udHJvbGxlci5nZXRNZXRob2QoXCJnZXRPbmVcIikuc2V0QXN5bmModHJ1ZSkuc2V0Qm9keShbXG5cdFx0XHRcImNvbnN0IHVzZXIgPSBhd2FpdCB0aGlzLnVzZXJzLmVuc3VyZUZyb21QcmluY2lwYWwodGhpcy5wcmluY2lwYWxQcm92aWRlci5jdXJyZW50UHJpbmNpcGFsKTtcIixcblx0XHRcdC8vIGJpb21lLWlnbm9yZSBsaW50L3N1c3BpY2lvdXMvbm9UZW1wbGF0ZUN1cmx5SW5TdHJpbmc6IHRlbXBsYXRlIGxpdGVyYWwgaW4gZ2VuZXJhdGVkIGNvZGVcblx0XHRcdFwicmV0dXJuIHsgaWQsIG1lc3NhZ2U6IGBIZWxsbyAke3VzZXIuZGlzcGxheU5hbWV9IWAsIHVzZXJuYW1lOiB1c2VyLmRpc3BsYXlOYW1lIH07XCIsXG5cdFx0XSk7XG5cdH1cbn1cblxuZnVuY3Rpb24gc2NhZmZvbGQod29ya3NwYWNlOiBXb3Jrc3BhY2VTY2FmZm9sZCwgb3B0aW9uczogQXV0aE9wdGlvbnMpOiB2b2lkIHtcblx0aWYgKG9wdGlvbnMuYXV0aFByb3ZpZGVyICE9PSBcImF1dGgwXCIpIHJldHVybjtcblxuXHRjb25zdCByZXNvdXJjZSA9IFwiSGVsbG9cIjtcblx0Y29uc3Qgd2l0aExvY2FsVXNlcnMgPSBvcHRpb25zLmRhdGFiYXNlUHJvdmlkZXIgPT09IFwicG9zdGdyZXMvdHlwZW9ybVwiO1xuXG5cdGZvciAoY29uc3QgY29udHJvbGxlciBvZiB3b3Jrc3BhY2UuZ2V0TW9kZWxzKENvbnRyb2xsZXJTb3VyY2VGaWxlKSkge1xuXHRcdGNvbnRyb2xsZXJcblx0XHRcdC5hZGREZWNvcmF0b3IoYEBBdXRob3JpemUoXCJyZWFkXCIsIFwiJHtyZXNvdXJjZX1cIilgKVxuXHRcdFx0LmFkZENvcnRleEltcG9ydChcIkFsbG93QW5vbnltb3VzXCIpXG5cdFx0XHQuYWRkQ29ydGV4SW1wb3J0KFwiQXV0aG9yaXplXCIpXG5cdFx0XHQuYWRkQ29ydGV4SW1wb3J0KFwiSVByaW5jaXBhbFByb3ZpZGVyVG9rZW5cIilcblx0XHRcdC5hZGRDb3J0ZXhJbXBvcnQoXCJJUHJpbmNpcGFsUHJvdmlkZXJcIiwgdHJ1ZSlcblx0XHRcdC5hZGRJbXBvcnQoXCJpbmplY3RcIiwgXCJAZGVjb2hlcmUvY3J1Y2libGUvZGVjb3JhdG9yc1wiKVxuXHRcdFx0LmFkZENvbnN0cnVjdG9yUGFyYW0oXG5cdFx0XHRcdGBAaW5qZWN0KElQcmluY2lwYWxQcm92aWRlclRva2VuKSBwcml2YXRlIHJlYWRvbmx5IHByaW5jaXBhbFByb3ZpZGVyOiBJUHJpbmNpcGFsUHJvdmlkZXJgLFxuXHRcdFx0KTtcblx0XHRjb250cm9sbGVyLmdldE1ldGhvZChcImdldEFsbFwiKS5hZGREZWNvcmF0b3IoXCJAQWxsb3dBbm9ueW1vdXMoKVwiKTtcblx0XHRpZiAoIXdpdGhMb2NhbFVzZXJzKSB7XG5cdFx0XHRjb250cm9sbGVyLmdldE1ldGhvZChcImdldE9uZVwiKS5zZXRCb2R5KFtcblx0XHRcdFx0XCJjb25zdCBwcmluY2lwYWwgPSB0aGlzLnByaW5jaXBhbFByb3ZpZGVyLmN1cnJlbnRQcmluY2lwYWw7XCIsXG5cdFx0XHRcdFwiY29uc3QgdXNlcm5hbWUgPVwiLFxuXHRcdFx0XHQnXFx0KHR5cGVvZiBwcmluY2lwYWw/Lm5hbWUgPT09IFwic3RyaW5nXCIgJiYgcHJpbmNpcGFsLm5hbWUpIHx8Jyxcblx0XHRcdFx0J1xcdCh0eXBlb2YgcHJpbmNpcGFsPy5uaWNrbmFtZSA9PT0gXCJzdHJpbmdcIiAmJiBwcmluY2lwYWwubmlja25hbWUpIHx8Jyxcblx0XHRcdFx0J1xcdCh0eXBlb2YgcHJpbmNpcGFsPy5lbWFpbCA9PT0gXCJzdHJpbmdcIiAmJiBwcmluY2lwYWwuZW1haWwpIHx8Jyxcblx0XHRcdFx0J1xcdCh0eXBlb2YgcHJpbmNpcGFsPy5wcmVmZXJyZWRfdXNlcm5hbWUgPT09IFwic3RyaW5nXCIgJiYgcHJpbmNpcGFsLnByZWZlcnJlZF91c2VybmFtZSkgfHwnLFxuXHRcdFx0XHRcIlxcdHByaW5jaXBhbD8uc3ViIHx8XCIsXG5cdFx0XHRcdCdcXHRcInVua25vd25cIjsnLFxuXHRcdFx0XHQvLyBiaW9tZS1pZ25vcmUgbGludC9zdXNwaWNpb3VzL25vVGVtcGxhdGVDdXJseUluU3RyaW5nOiB0ZW1wbGF0ZSBsaXRlcmFsIGluIGdlbmVyYXRlZCBjb2RlXG5cdFx0XHRcdFwicmV0dXJuIHsgaWQsIG1lc3NhZ2U6IGBIZWxsbyAke3VzZXJuYW1lfSFgLCB1c2VybmFtZSB9O1wiLFxuXHRcdFx0XSk7XG5cdFx0fVxuXHRcdGNvbnRyb2xsZXIuZ2V0TWV0aG9kKFwiY3JlYXRlXCIpLmFkZERlY29yYXRvcihgQEF1dGhvcml6ZShcImNyZWF0ZVwiLCBcIiR7cmVzb3VyY2V9XCIpYCk7XG5cdFx0Y29udHJvbGxlci5nZXRNZXRob2QoXCJ1cGRhdGVcIikuYWRkRGVjb3JhdG9yKGBAQXV0aG9yaXplKFwidXBkYXRlXCIsIFwiJHtyZXNvdXJjZX1cIilgKTtcblx0XHRjb250cm9sbGVyLmdldE1ldGhvZChcInJlbW92ZVwiKS5hZGREZWNvcmF0b3IoYEBBdXRob3JpemUoXCJkZWxldGVcIiwgXCIke3Jlc291cmNlfVwiKWApO1xuXHR9XG5cblx0Zm9yIChjb25zdCBwcm9qZWN0IG9mIHdvcmtzcGFjZS5nZXRQcm9qZWN0cygpKSB7XG5cdFx0cHJvamVjdFxuXHRcdFx0LmdldE1vZGVsPE1haW5Tb3VyY2VGaWxlPihXRUxMX0tOT1dOX0ZJTEVTLk1BSU5fVFMpXG5cdFx0XHQ/LmFkZFNpZGVFZmZlY3RJbXBvcnQoXCJAZGVjb2hlcmUvY29ydGV4L2F1dGhcIik7XG5cdH1cblxuXHRpZiAod2l0aExvY2FsVXNlcnMpIHtcblx0XHRzY2FmZm9sZExvY2FsVXNlclByb2ZpbGUod29ya3NwYWNlKTtcblx0XHRmb3IgKGNvbnN0IHByb2plY3Qgb2Ygd29ya3NwYWNlLmdldFByb2plY3RzKCkpIHtcblx0XHRcdHByb2plY3Rcblx0XHRcdFx0LmdldE1vZGVsPE1haW5Tb3VyY2VGaWxlPihXRUxMX0tOT1dOX0ZJTEVTLk1BSU5fVFMpXG5cdFx0XHRcdD8uYWRkQnVpbGRlckNhbGwoXCIud2l0aEF1dGgoY3JlYXRlQWJpbGl0eUZhY3RvcnksIHsgcHJpbmNpcGFsTWFwcGVyOiBtYXBQcmluY2lwYWwgfSlcIik7XG5cdFx0fVxuXHR9IGVsc2Uge1xuXHRcdGZvciAoY29uc3QgcHJvamVjdCBvZiB3b3Jrc3BhY2UuZ2V0UHJvamVjdHMoKSkge1xuXHRcdFx0cHJvamVjdFxuXHRcdFx0XHQuZ2V0TW9kZWw8TWFpblNvdXJjZUZpbGU+KFdFTExfS05PV05fRklMRVMuTUFJTl9UUylcblx0XHRcdFx0Py5hZGRCdWlsZGVyQ2FsbChcIi53aXRoQXV0aCgpXCIpO1xuXHRcdH1cblx0fVxuXG5cdC8vIGJpb21lLWlnbm9yZSBsaW50L3N1c3BpY2lvdXMvbm9UZW1wbGF0ZUN1cmx5SW5TdHJpbmc6IGludGVudGlvbmFsIFlBTUwgZW52LXZhciBwbGFjZWhvbGRlcnNcblx0Y29uc3QgaXNzdWVyUGxhY2Vob2xkZXIgPSBcIiR7QVVUSDBfSVNTVUVSX0JBU0VfVVJMfVwiO1xuXHQvLyBiaW9tZS1pZ25vcmUgbGludC9zdXNwaWNpb3VzL25vVGVtcGxhdGVDdXJseUluU3RyaW5nOiBpbnRlbnRpb25hbCBZQU1MIGVudi12YXIgcGxhY2Vob2xkZXJzXG5cdGNvbnN0IGF1ZFBsYWNlaG9sZGVyID0gXCIke0FVVEgwX0FVRElFTkNFfVwiO1xuXG5cdGNvbnN0IGNvbmZpZ1NlY3Rpb24gPSBgYXV0aDpcXG4gIGRpc2NvdmVyeVVybDogJHtpc3N1ZXJQbGFjZWhvbGRlcn1cXG4gIGF1ZGllbmNlOiAke2F1ZFBsYWNlaG9sZGVyfVxcbmA7XG5cblx0d29ya3NwYWNlLmdldE1vZGVsPENvbmZpZ1lhbWw+KFdFTExfS05PV05fRklMRVMuQ09ORklHX1lBTUwpPy5hZGRTZWN0aW9uKGNvbmZpZ1NlY3Rpb24pO1xuXG5cdHdvcmtzcGFjZVxuXHRcdC5nZXRNb2RlbDxFbnZGaWxlPihXRUxMX0tOT1dOX0ZJTEVTLkVOVl9GSUxFKVxuXHRcdD8uYWRkRW50cnkoXCJBVVRIMF9JU1NVRVJfQkFTRV9VUkxcIiwgb3B0aW9ucy5pc3N1ZXJCYXNlVXJsID8/IFwiXCIpXG5cdFx0LmFkZEVudHJ5KFwiQVVUSDBfQVVESUVOQ0VcIiwgb3B0aW9ucy5hdWRpZW5jZSA/PyBcIlwiKTtcblxuXHRjb25zdCBhdXRoQ29uZmlnID0gbmV3IEF1dGhDb25maWdNb2RlbCh7XG5cdFx0aXNzdWVyQmFzZVVybDogb3B0aW9ucy5pc3N1ZXJCYXNlVXJsID8/IFwiXCIsXG5cdFx0YXVkaWVuY2U6IG9wdGlvbnMuYXVkaWVuY2UgPz8gXCJcIixcblx0fSk7XG5cdHdvcmtzcGFjZS5hZGRNb2RlbChhdXRoQ29uZmlnKTtcblxuXHRpZiAod2l0aExvY2FsVXNlcnMgJiYgb3B0aW9ucy5hZG1pblBhc3N3b3JkKSB7XG5cdFx0Y3JlYXRlQXV0aDBBZG1pblVzZXIod29ya3NwYWNlLCBvcHRpb25zLCBhdXRoQ29uZmlnKTtcblx0fVxufVxuXG5leHBvcnQgY29uc3QgQXV0aEZlYXR1cmU6IEZlYXR1cmU8QXV0aE9wdGlvbnM+ID0geyBnZXRPcHRpb25zLCBzY2FmZm9sZCB9O1xuIl0sIm5hbWVzIjpbIkF1dGhGZWF0dXJlIiwiQURNSU5fUk9MRSIsIlVTRVJfRU5USVRZX1RTIiwiVVNFUl9SRVBPU0lUT1JZX1RTIiwiVVNFUl9TRVJWSUNFX1RTIiwiQUJJTElUWV9GQUNUT1JZX1RTIiwiZ2V0T3B0aW9ucyIsIndvcmtzcGFjZSIsImNsaU9wdGlvbnMiLCJhdXRoUHJvdmlkZXIiLCJpc3N1ZXJCYXNlVXJsIiwiZ2V0QXV0aDBPcHRpb25zIiwiY2hvaWNlcyIsImxhYmVsIiwic2VsZWN0ZWQiLCJwaWNrIiwiYyIsInByb3ZpZGVyIiwiYXV0aDBDbGkiLCJpc0luc3RhbGxlZCIsImNvbnNvbGUiLCJlcnJvciIsInByb2Nlc3MiLCJleGl0Iiwic3Rkb3V0Iiwid3JpdGUiLCJ0ZW5hbnRzIiwibGlzdFRlbmFudHMiLCJsZW5ndGgiLCJsb2ciLCJsb2dpbiIsImxpc3RBcGlzIiwiZXJyIiwiQXV0aDBBdXRoRXJyb3IiLCJhY3RpdmUiLCJmaW5kIiwidCIsIm5hbWUiLCJ1c2VyQXBpcyIsImZpbHRlciIsImEiLCJpbmNsdWRlcyIsInByb2plY3ROYW1lIiwiYXBpQ2hvaWNlcyIsImV4aXN0aW5nIiwibWFwIiwiaWRlbnRpZmllciIsImFwaVNlbGVjdGVkIiwiYXVkaWVuY2UiLCJkZWZhdWx0SWQiLCJhc2siLCJjcmVhdGVBcGkiLCJ1cGRhdGVBcGlTY29wZXMiLCJIRUxMT19BUElfU0NPUEVTIiwiam9pbiIsIndpdGhMb2NhbFVzZXJzIiwiZGF0YWJhc2VQcm92aWRlciIsImFkbWluVXNlcm5hbWUiLCJhZG1pblBhc3N3b3JkIiwiZ2VuZXJhdGVBZG1pblBhc3N3b3JkIiwiYWRtaW5FbWFpbCIsIndvcmtzcGFjZU5hbWUiLCJ1c2VybmFtZSIsInNsdWciLCJ0b0xvd2VyQ2FzZSIsInJlcGxhY2UiLCJjcmVhdGVBdXRoMEFkbWluVXNlciIsIm9wdGlvbnMiLCJhdXRoQ29uZmlnIiwicGFzc3dvcmQiLCJlbWFpbCIsImFkbWluIiwiY3JlYXRlQWRtaW5EYXRhYmFzZVVzZXIiLCJzZXRBZG1pblVzZXIiLCJzdWIiLCJ1c2VyX2lkIiwiZ2V0TW9kZWwiLCJXRUxMX0tOT1dOX0ZJTEVTIiwiRU5WX0ZJTEUiLCJhZGRFbnRyeSIsIkVycm9yIiwibWVzc2FnZSIsInNjYWZmb2xkTG9jYWxVc2VyUHJvZmlsZSIsIlBBQ0tBR0VfSlNPTiIsImFkZERlcGVuZGVuY3kiLCJwcm9qZWN0IiwiZ2V0UHJvamVjdHMiLCJBUElfUEFDS0FHRV9KU09OIiwiTUFJTl9UUyIsImFkZEVudGl0eSIsImNsYXNzTmFtZSIsImltcG9ydFBhdGgiLCJhZGRSZXBvc2l0b3J5IiwiYWRkU2VydmljZSIsInNjb3BlIiwiYWRkSW1wb3J0Iiwic2V0VHlwZU9ybVNlZWQiLCJhZGRGaWxlIiwiZmlsZXMiLCJmaWxlUGF0aCIsImNvbnRlbnQiLCJjb250cm9sbGVyIiwiZ2V0TW9kZWxzIiwiQ29udHJvbGxlclNvdXJjZUZpbGUiLCJhZGRDb25zdHJ1Y3RvclBhcmFtIiwiZ2V0TWV0aG9kIiwic2V0QXN5bmMiLCJzZXRCb2R5Iiwic2NhZmZvbGQiLCJyZXNvdXJjZSIsImFkZERlY29yYXRvciIsImFkZENvcnRleEltcG9ydCIsImFkZFNpZGVFZmZlY3RJbXBvcnQiLCJhZGRCdWlsZGVyQ2FsbCIsImlzc3VlclBsYWNlaG9sZGVyIiwiYXVkUGxhY2Vob2xkZXIiLCJjb25maWdTZWN0aW9uIiwiQ09ORklHX1lBTUwiLCJhZGRTZWN0aW9uIiwiQXV0aENvbmZpZ01vZGVsIiwiYWRkTW9kZWwiXSwibWFwcGluZ3MiOiI7Ozs7K0JBa2VhQTs7O2VBQUFBOzs7d0JBbGVhO3VCQUVPO2lDQU1EOzJDQUNLO2tFQUVYOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFXMUIsTUFBTUMsYUFBYTtBQUVuQixNQUFNQyxpQkFBaUIsQ0FBQzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBcUJ4QixDQUFDO0FBRUQsTUFBTUMscUJBQXFCLENBQUM7Ozs7Ozs7Ozs7Ozs7OztBQWU1QixDQUFDO0FBRUQsTUFBTUMsa0JBQWtCLENBQUM7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUF1RHpCLENBQUM7QUFFRCxNQUFNQyxxQkFBcUIsQ0FBQzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUF3RDVCLENBQUM7QUFFRCxlQUFlQyxXQUNkQyxTQUE0QixFQUM1QkMsVUFBZ0M7SUFFaEMsSUFBSUEsV0FBV0MsWUFBWSxLQUFLLFdBQVcsQ0FBQ0QsV0FBV0UsYUFBYSxFQUFFO1FBQ3JFLE9BQU9DLGdCQUFnQkosV0FBV0M7SUFDbkM7SUFDQSxJQUFJQSxXQUFXQyxZQUFZLElBQUksTUFBTSxPQUFPLENBQUM7SUFFN0MsTUFBTUcsVUFBVTtRQUFDO1lBQUVDLE9BQU87UUFBZ0I7UUFBRztZQUFFQSxPQUFPO1FBQWlCO0tBQUU7SUFDekUsTUFBTUMsV0FBVyxNQUFNQyxJQUFBQSxZQUFJLEVBQUMsdUJBQXVCSCxTQUFTLENBQUNJLElBQU1BLEVBQUVILEtBQUs7SUFDMUUsTUFBTUksV0FBV0gsVUFBVUQsU0FBUztJQUVwQyxJQUFJSSxhQUFhLFNBQVMsT0FBTztRQUFFUixjQUFjO0lBQU87SUFFeEQsT0FBT0UsZ0JBQWdCSixXQUFXQztBQUNuQztBQUVBLGVBQWVHLGdCQUNkSixTQUE0QixFQUM1QkMsVUFBZ0M7SUFFaEMsSUFBSSxDQUFDVSxVQUFTQyxXQUFXLElBQUk7UUFDNUJDLFFBQVFDLEtBQUssQ0FDWix5REFDQyxvREFDQTtRQUVGQyxRQUFRQyxJQUFJLENBQUM7SUFDZDtJQUVBRCxRQUFRRSxNQUFNLENBQUNDLEtBQUssQ0FBQztJQUNyQixJQUFJQyxVQUFVUixVQUFTUyxXQUFXO0lBQ2xDLElBQUlELFFBQVFFLE1BQU0sS0FBSyxHQUFHO1FBQ3pCTixRQUFRRSxNQUFNLENBQUNDLEtBQUssQ0FBQztRQUNyQkwsUUFBUVMsR0FBRyxDQUFDO1FBQ1osSUFBSSxDQUFDWCxVQUFTWSxLQUFLLElBQUk7WUFDdEJWLFFBQVFDLEtBQUssQ0FBQztZQUNkQyxRQUFRQyxJQUFJLENBQUM7UUFDZDtRQUNBRyxVQUFVUixVQUFTUyxXQUFXO0lBQy9CO0lBRUEsSUFBSTtRQUNIVCxVQUFTYSxRQUFRO1FBQ2pCVCxRQUFRRSxNQUFNLENBQUNDLEtBQUssQ0FBQztJQUN0QixFQUFFLE9BQU9PLEtBQUs7UUFDYixJQUFJQSxlQUFlZCxVQUFTZSxjQUFjLEVBQUU7WUFDM0NYLFFBQVFFLE1BQU0sQ0FBQ0MsS0FBSyxDQUFDO1lBQ3JCTCxRQUFRUyxHQUFHLENBQUM7WUFDWixJQUFJLENBQUNYLFVBQVNZLEtBQUssSUFBSTtnQkFDdEJWLFFBQVFDLEtBQUssQ0FBQztnQkFDZEMsUUFBUUMsSUFBSSxDQUFDO1lBQ2Q7UUFDRDtJQUNEO0lBRUEsTUFBTVcsU0FBU1IsUUFBUVMsSUFBSSxDQUFDLENBQUNDLElBQU1BLEVBQUVGLE1BQU0sS0FBS1IsT0FBTyxDQUFDLEVBQUU7SUFDMUQsTUFBTWhCLGdCQUFnQixDQUFDLFFBQVEsRUFBRXdCLE9BQU9HLElBQUksRUFBRTtJQUM5Q2pCLFFBQVFTLEdBQUcsQ0FBQyxDQUFDLG9CQUFvQixFQUFFbkIsZUFBZTtJQUVsRFksUUFBUUUsTUFBTSxDQUFDQyxLQUFLLENBQUM7SUFDckIsTUFBTWEsV0FBV3BCLFVBQVNhLFFBQVEsR0FBR1EsTUFBTSxDQUFDLENBQUNDLElBQU0sQ0FBQ0EsRUFBRUgsSUFBSSxDQUFDSSxRQUFRLENBQUM7SUFDcEVuQixRQUFRRSxNQUFNLENBQUNDLEtBQUssQ0FBQyxDQUFDLE9BQU8sRUFBRWEsU0FBU1YsTUFBTSxDQUFDLEdBQUcsQ0FBQztJQUduRCxNQUFNYyxjQUFjbkMsVUFBVThCLElBQUk7SUFDbEMsTUFBTU0sYUFBMEI7UUFDL0I7WUFBRTlCLE9BQU8sQ0FBQyxrQkFBa0IsRUFBRTZCLGFBQWE7WUFBRUUsVUFBVTtRQUFLO1dBQ3pETixTQUFTTyxHQUFHLENBQUMsQ0FBQ0wsSUFBTyxDQUFBO2dCQUFFM0IsT0FBTyxHQUFHMkIsRUFBRUgsSUFBSSxDQUFDLEdBQUcsRUFBRUcsRUFBRU0sVUFBVSxFQUFFO2dCQUFFRixVQUFVSixFQUFFTSxVQUFVO1lBQUMsQ0FBQTtLQUN2RjtJQUVELE1BQU1DLGNBQWMsTUFBTWhDLElBQUFBLFlBQUksRUFBQywwQkFBMEI0QixZQUFZLENBQUMzQixJQUFNQSxFQUFFSCxLQUFLO0lBRW5GLElBQUltQztJQUNKLElBQUksQ0FBQ0QsZUFBZUEsWUFBWUgsUUFBUSxLQUFLLE1BQU07UUFDbEQsTUFBTUssWUFBWSxDQUFDLFlBQVksRUFBRVAsYUFBYTtRQUM5Q00sV0FBVyxNQUFNRSxJQUFBQSxXQUFHLEVBQUMsQ0FBQyxrQkFBa0IsRUFBRUQsVUFBVSxHQUFHLENBQUMsRUFBRUE7UUFDMUQ3QixRQUFRUyxHQUFHLENBQUM7UUFDWm1CLFdBQVc5QixVQUFTaUMsU0FBUyxDQUFDLEdBQUdULFlBQVksSUFBSSxDQUFDLEVBQUVNLFVBQVVGLFVBQVU7UUFDeEUxQixRQUFRUyxHQUFHLENBQUMsQ0FBQyxzQkFBc0IsRUFBRW1CLFVBQVU7SUFDaEQsT0FBTztRQUNOQSxXQUFXRCxZQUFZSCxRQUFRO1FBQy9CeEIsUUFBUVMsR0FBRyxDQUFDLENBQUMsbUJBQW1CLEVBQUVtQixVQUFVO1FBQzVDLElBQUk7WUFDSDlCLFVBQVNrQyxlQUFlLENBQUNKO1lBQ3pCNUIsUUFBUVMsR0FBRyxDQUFDLENBQUMsNkJBQTZCLEVBQUVYLFVBQVNtQyxnQkFBZ0IsQ0FBQ0MsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ3BGLEVBQUUsT0FBTTtZQUNQbEMsUUFBUUMsS0FBSyxDQUNaO1FBRUY7SUFDRDtJQUVBLE1BQU1rQyxpQkFBaUIvQyxXQUFXZ0QsZ0JBQWdCLEtBQUs7SUFDdkQsSUFBSUM7SUFDSixJQUFJQztJQUNKLElBQUlILGdCQUFnQjtRQUNuQkUsZ0JBQ0NqRCxXQUFXaUQsYUFBYSxJQUFLLE1BQU1QLElBQUFBLFdBQUcsRUFBQyxnQ0FBZ0M7UUFDeEVRLGdCQUFnQmxELFdBQVdrRCxhQUFhO1FBQ3hDLElBQUlBLGlCQUFpQixNQUFNO1lBQzFCQSxnQkFBZ0IsTUFBTVIsSUFBQUEsV0FBRyxFQUFDO1lBQzFCLElBQUksQ0FBQ1EsZUFBZTtnQkFDbkJBLGdCQUFnQnhDLFVBQVN5QyxxQkFBcUI7Z0JBQzlDdkMsUUFBUVMsR0FBRyxDQUFDLENBQUMsZ0RBQWdELEVBQUU2QixlQUFlO1lBQy9FO1FBQ0Q7SUFDRDtJQUVBLE9BQU87UUFDTmpELGNBQWM7UUFDZEM7UUFDQXNDO1FBQ0EsR0FBSU8saUJBQWlCO1lBQUVFO1lBQWVDO1FBQWMsSUFBSSxDQUFDLENBQUM7SUFDM0Q7QUFDRDtBQUVBLFNBQVNFLFdBQVdDLGFBQXFCLEVBQUVDLFFBQWdCO0lBQzFELElBQUlBLFNBQVNyQixRQUFRLENBQUMsTUFBTSxPQUFPcUI7SUFDbkMsTUFBTUMsT0FBT0YsY0FBY0csV0FBVyxHQUFHQyxPQUFPLENBQUMsZUFBZTtJQUNoRSxPQUFPLEdBQUdILFNBQVMsQ0FBQyxFQUFFQyxLQUFLLFlBQVksQ0FBQztBQUN6QztBQUVBLFNBQVNHLHFCQUNSM0QsU0FBNEIsRUFDNUI0RCxPQUFvQixFQUNwQkMsVUFBMkI7SUFFM0IsTUFBTU4sV0FBV0ssUUFBUVYsYUFBYSxJQUFJO0lBQzFDLE1BQU1ZLFdBQVdGLFFBQVFULGFBQWE7SUFDdEMsSUFBSSxDQUFDVyxVQUFVO0lBRWYsTUFBTUMsUUFBUVYsV0FBV3JELFVBQVU4QixJQUFJLEVBQUV5QjtJQUN6QyxJQUFJO1FBQ0gsTUFBTVMsUUFBUXJELFVBQVNzRCx1QkFBdUIsQ0FBQztZQUFFRjtZQUFPRDtZQUFVUDtRQUFTO1FBQzNFTSxXQUFXSyxZQUFZLENBQUM7WUFDdkJDLEtBQUtILE1BQU1JLE9BQU87WUFDbEJMLE9BQU9DLE1BQU1ELEtBQUs7WUFDbEJELFVBQVVFLE1BQU1GLFFBQVE7WUFDeEJQLFVBQVVTLE1BQU1ULFFBQVE7UUFDekI7UUFDQXZELFVBQ0VxRSxRQUFRLENBQVVDLHVCQUFnQixDQUFDQyxRQUFRLEdBQzFDQyxTQUFTLHdCQUF3QlIsTUFBTUksT0FBTyxFQUMvQ0ksU0FBUywwQkFBMEJSLE1BQU1ELEtBQUssRUFDOUNTLFNBQVMsNkJBQTZCUixNQUFNRixRQUFRLEVBQ3BEVSxTQUFTLHdCQUF3QlIsTUFBTVQsUUFBUTtRQUNqRDFDLFFBQVFTLEdBQUcsQ0FBQyxDQUFDLDRCQUE0QixFQUFFMEMsTUFBTUQsS0FBSyxDQUFDLFFBQVEsRUFBRXJFLFdBQVcsQ0FBQyxDQUFDO1FBQzlFbUIsUUFBUVMsR0FBRyxDQUFDLENBQUMscUNBQXFDLEVBQUUwQyxNQUFNRCxLQUFLLEVBQUU7UUFDakVsRCxRQUFRUyxHQUFHLENBQUMsQ0FBQyxtREFBbUQsQ0FBQztJQUNsRSxFQUFFLE9BQU9HLEtBQUs7UUFDYlosUUFBUUMsS0FBSyxDQUNaLENBQUMsdUNBQXVDLEVBQUVpRCxNQUFNLEdBQUcsRUFBRXRDLGVBQWVnRCxRQUFRaEQsSUFBSWlELE9BQU8sR0FBR2pELEtBQUs7SUFFakc7QUFDRDtBQUVBLFNBQVNrRCx5QkFBeUIzRSxTQUE0QjtJQUM3REEsVUFDRXFFLFFBQVEsQ0FBY0MsdUJBQWdCLENBQUNNLFlBQVksR0FDbERDLGNBQWMsaUJBQWlCO0lBRWxDLEtBQUssTUFBTUMsV0FBVzlFLFVBQVUrRSxXQUFXLEdBQUk7UUFDOUNELFFBQ0VULFFBQVEsQ0FBaUJDLHVCQUFnQixDQUFDVSxnQkFBZ0IsR0FDekRILGNBQWMsaUJBQWlCO1FBRWxDQyxRQUNFVCxRQUFRLENBQWlCQyx1QkFBZ0IsQ0FBQ1csT0FBTyxHQUNoREMsVUFBVTtZQUFFQyxXQUFXO1lBQWNDLFlBQVk7UUFBNEIsR0FDOUVDLGNBQWM7WUFDZEYsV0FBVztZQUNYQyxZQUFZO1FBQ2IsR0FDQ0UsV0FBVztZQUNYSCxXQUFXO1lBQ1hDLFlBQVk7WUFDWkcsT0FBTztRQUNSLEdBQ0NDLFVBQVUsd0JBQXdCLDZCQUNsQ0EsVUFBVSxnQkFBZ0IsNkJBQzFCQyxlQUNBO1lBQ0M7WUFDQTtZQUNBO1lBQ0E7WUFDQTtZQUNBO1lBQ0E7WUFDQTtZQUNBO1lBQ0E7WUFDQTtTQUNBLENBQUMxQyxJQUFJLENBQUM7UUFHVCtCLFFBQVFZLE9BQU8sQ0FBQztZQUNmQyxPQUFPLElBQU07b0JBQ1o7d0JBQUVDLFVBQVU7d0JBQStCQyxTQUFTbEc7b0JBQWU7b0JBQ25FO3dCQUFFaUcsVUFBVTt3QkFBdUNDLFNBQVNqRztvQkFBbUI7b0JBQy9FO3dCQUFFZ0csVUFBVTt3QkFBZ0NDLFNBQVNoRztvQkFBZ0I7b0JBQ3JFO3dCQUFFK0YsVUFBVTt3QkFBK0JDLFNBQVMvRjtvQkFBbUI7aUJBQ3ZFO1FBQ0Y7SUFDRDtJQUVBLEtBQUssTUFBTWdHLGNBQWM5RixVQUFVK0YsU0FBUyxDQUFDQywrQ0FBb0IsRUFBRztRQUNuRUYsV0FDRU4sU0FBUyxDQUFDLGVBQWUsK0JBQ3pCUyxtQkFBbUIsQ0FBQztRQUN0QkgsV0FBV0ksU0FBUyxDQUFDLFVBQVVDLFFBQVEsQ0FBQyxNQUFNQyxPQUFPLENBQUM7WUFDckQ7WUFDQSwyRkFBMkY7WUFDM0Y7U0FDQTtJQUNGO0FBQ0Q7QUFFQSxTQUFTQyxTQUFTckcsU0FBNEIsRUFBRTRELE9BQW9CO0lBQ25FLElBQUlBLFFBQVExRCxZQUFZLEtBQUssU0FBUztJQUV0QyxNQUFNb0csV0FBVztJQUNqQixNQUFNdEQsaUJBQWlCWSxRQUFRWCxnQkFBZ0IsS0FBSztJQUVwRCxLQUFLLE1BQU02QyxjQUFjOUYsVUFBVStGLFNBQVMsQ0FBQ0MsK0NBQW9CLEVBQUc7UUFDbkVGLFdBQ0VTLFlBQVksQ0FBQyxDQUFDLG9CQUFvQixFQUFFRCxTQUFTLEVBQUUsQ0FBQyxFQUNoREUsZUFBZSxDQUFDLGtCQUNoQkEsZUFBZSxDQUFDLGFBQ2hCQSxlQUFlLENBQUMsMkJBQ2hCQSxlQUFlLENBQUMsc0JBQXNCLE1BQ3RDaEIsU0FBUyxDQUFDLFVBQVUsaUNBQ3BCUyxtQkFBbUIsQ0FDbkIsQ0FBQyx1RkFBdUYsQ0FBQztRQUUzRkgsV0FBV0ksU0FBUyxDQUFDLFVBQVVLLFlBQVksQ0FBQztRQUM1QyxJQUFJLENBQUN2RCxnQkFBZ0I7WUFDcEI4QyxXQUFXSSxTQUFTLENBQUMsVUFBVUUsT0FBTyxDQUFDO2dCQUN0QztnQkFDQTtnQkFDQTtnQkFDQTtnQkFDQTtnQkFDQTtnQkFDQTtnQkFDQTtnQkFDQSwyRkFBMkY7Z0JBQzNGO2FBQ0E7UUFDRjtRQUNBTixXQUFXSSxTQUFTLENBQUMsVUFBVUssWUFBWSxDQUFDLENBQUMsc0JBQXNCLEVBQUVELFNBQVMsRUFBRSxDQUFDO1FBQ2pGUixXQUFXSSxTQUFTLENBQUMsVUFBVUssWUFBWSxDQUFDLENBQUMsc0JBQXNCLEVBQUVELFNBQVMsRUFBRSxDQUFDO1FBQ2pGUixXQUFXSSxTQUFTLENBQUMsVUFBVUssWUFBWSxDQUFDLENBQUMsc0JBQXNCLEVBQUVELFNBQVMsRUFBRSxDQUFDO0lBQ2xGO0lBRUEsS0FBSyxNQUFNeEIsV0FBVzlFLFVBQVUrRSxXQUFXLEdBQUk7UUFDOUNELFFBQ0VULFFBQVEsQ0FBaUJDLHVCQUFnQixDQUFDVyxPQUFPLEdBQ2hEd0Isb0JBQW9CO0lBQ3hCO0lBRUEsSUFBSXpELGdCQUFnQjtRQUNuQjJCLHlCQUF5QjNFO1FBQ3pCLEtBQUssTUFBTThFLFdBQVc5RSxVQUFVK0UsV0FBVyxHQUFJO1lBQzlDRCxRQUNFVCxRQUFRLENBQWlCQyx1QkFBZ0IsQ0FBQ1csT0FBTyxHQUNoRHlCLGVBQWU7UUFDbkI7SUFDRCxPQUFPO1FBQ04sS0FBSyxNQUFNNUIsV0FBVzlFLFVBQVUrRSxXQUFXLEdBQUk7WUFDOUNELFFBQ0VULFFBQVEsQ0FBaUJDLHVCQUFnQixDQUFDVyxPQUFPLEdBQ2hEeUIsZUFBZTtRQUNuQjtJQUNEO0lBRUEsOEZBQThGO0lBQzlGLE1BQU1DLG9CQUFvQjtJQUMxQiw4RkFBOEY7SUFDOUYsTUFBTUMsaUJBQWlCO0lBRXZCLE1BQU1DLGdCQUFnQixDQUFDLHVCQUF1QixFQUFFRixrQkFBa0IsY0FBYyxFQUFFQyxlQUFlLEVBQUUsQ0FBQztJQUVwRzVHLFVBQVVxRSxRQUFRLENBQWFDLHVCQUFnQixDQUFDd0MsV0FBVyxHQUFHQyxXQUFXRjtJQUV6RTdHLFVBQ0VxRSxRQUFRLENBQVVDLHVCQUFnQixDQUFDQyxRQUFRLEdBQzFDQyxTQUFTLHlCQUF5QlosUUFBUXpELGFBQWEsSUFBSSxJQUM1RHFFLFNBQVMsa0JBQWtCWixRQUFRbkIsUUFBUSxJQUFJO0lBRWpELE1BQU1vQixhQUFhLElBQUltRCxnQ0FBZSxDQUFDO1FBQ3RDN0csZUFBZXlELFFBQVF6RCxhQUFhLElBQUk7UUFDeENzQyxVQUFVbUIsUUFBUW5CLFFBQVEsSUFBSTtJQUMvQjtJQUNBekMsVUFBVWlILFFBQVEsQ0FBQ3BEO0lBRW5CLElBQUliLGtCQUFrQlksUUFBUVQsYUFBYSxFQUFFO1FBQzVDUSxxQkFBcUIzRCxXQUFXNEQsU0FBU0M7SUFDMUM7QUFDRDtBQUVPLE1BQU1wRSxjQUFvQztJQUFFTTtJQUFZc0c7QUFBUyJ9