@aws-amplify/backend-notifications 0.0.0-test-20260708085627

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 (59) hide show
  1. package/README.md +235 -0
  2. package/lib/campaign-association-asset/index.js +48413 -0
  3. package/lib/constants.d.ts +122 -0
  4. package/lib/constants.js +125 -0
  5. package/lib/construct.d.ts +283 -0
  6. package/lib/construct.js +824 -0
  7. package/lib/factory.d.ts +53 -0
  8. package/lib/factory.js +158 -0
  9. package/lib/handler-asset/index.js +530 -0
  10. package/lib/index.d.ts +7 -0
  11. package/lib/index.js +5 -0
  12. package/lib/lambda/campaign-association/handler.d.ts +29 -0
  13. package/lib/lambda/campaign-association/handler.js +80 -0
  14. package/lib/lambda/campaign-association/integration.d.ts +59 -0
  15. package/lib/lambda/campaign-association/integration.js +108 -0
  16. package/lib/lambda/campaign-association/onboarding.d.ts +25 -0
  17. package/lib/lambda/campaign-association/onboarding.js +74 -0
  18. package/lib/lambda/identify/device_resolver.d.ts +18 -0
  19. package/lib/lambda/identify/device_resolver.js +56 -0
  20. package/lib/lambda/identify/handler.d.ts +17 -0
  21. package/lib/lambda/identify/handler.js +124 -0
  22. package/lib/lambda/identify/mapping.d.ts +61 -0
  23. package/lib/lambda/identify/mapping.js +171 -0
  24. package/lib/lambda/identify/merge_resolver.d.ts +26 -0
  25. package/lib/lambda/identify/merge_resolver.js +36 -0
  26. package/lib/lambda/identify/principal.d.ts +68 -0
  27. package/lib/lambda/identify/principal.js +48 -0
  28. package/lib/lambda/identify/profile_resolver.d.ts +35 -0
  29. package/lib/lambda/identify/profile_resolver.js +65 -0
  30. package/lib/lambda/identify/types.d.ts +90 -0
  31. package/lib/lambda/identify/types.js +10 -0
  32. package/lib/lambda/identify/validation.d.ts +15 -0
  33. package/lib/lambda/identify/validation.js +99 -0
  34. package/lib/lambda/push/delivery.d.ts +49 -0
  35. package/lib/lambda/push/delivery.js +120 -0
  36. package/lib/lambda/push/device_lookup.d.ts +35 -0
  37. package/lib/lambda/push/device_lookup.js +88 -0
  38. package/lib/lambda/push/eum_client.d.ts +31 -0
  39. package/lib/lambda/push/eum_client.js +140 -0
  40. package/lib/lambda/push/event.d.ts +32 -0
  41. package/lib/lambda/push/event.js +122 -0
  42. package/lib/lambda/push/fixtures/real_journey_event.d.ts +19 -0
  43. package/lib/lambda/push/fixtures/real_journey_event.js +22 -0
  44. package/lib/lambda/push/handler.d.ts +15 -0
  45. package/lib/lambda/push/handler.js +86 -0
  46. package/lib/lambda/push/message_template.d.ts +72 -0
  47. package/lib/lambda/push/message_template.js +270 -0
  48. package/lib/lambda/push/payload.d.ts +25 -0
  49. package/lib/lambda/push/payload.js +53 -0
  50. package/lib/lambda/push/types.d.ts +153 -0
  51. package/lib/lambda/push/types.js +4 -0
  52. package/lib/lambda/shared/retry.d.ts +18 -0
  53. package/lib/lambda/shared/retry.js +45 -0
  54. package/lib/object_types.d.ts +63 -0
  55. package/lib/object_types.js +131 -0
  56. package/lib/push-handler-asset/index.js +75517 -0
  57. package/lib/types.d.ts +125 -0
  58. package/lib/types.js +2 -0
  59. package/package.json +49 -0
@@ -0,0 +1,824 @@
1
+ import * as path from 'path';
2
+ import { createHash } from 'node:crypto';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { Arn, ArnFormat, CfnOutput, CustomResource, Duration, Stack, } from 'aws-cdk-lib';
5
+ import { Construct } from 'constructs';
6
+ import * as lambda from 'aws-cdk-lib/aws-lambda';
7
+ import * as iam from 'aws-cdk-lib/aws-iam';
8
+ import { Provider } from 'aws-cdk-lib/custom-resources';
9
+ import { CfnDomain, CfnIntegration, CfnObjectType, } from 'aws-cdk-lib/aws-customerprofiles';
10
+ import { CfnInstance, CfnIntegrationAssociation, } from 'aws-cdk-lib/aws-connect';
11
+ import { CfnKnowledgeBase } from 'aws-cdk-lib/aws-wisdom';
12
+ import { CfnAPNSChannel, CfnAPNSSandboxChannel, CfnApp, CfnGCMChannel, } from 'aws-cdk-lib/aws-pinpoint';
13
+ import * as apigwv2 from 'aws-cdk-lib/aws-apigatewayv2';
14
+ import { HttpIamAuthorizer, HttpJwtAuthorizer, } from 'aws-cdk-lib/aws-apigatewayv2-authorizers';
15
+ import { HttpLambdaIntegration } from 'aws-cdk-lib/aws-apigatewayv2-integrations';
16
+ import { CONNECT_CAMPAIGNS_SERVICE_NAME, CONNECT_INVOKE_SERVICE_PRINCIPALS, DEFAULT_EXPIRATION_DAYS, ENV_DOMAIN_NAME, ENV_EUM_APPLICATION_ID, } from './constants.js';
17
+ import { AMPLIFY_DEVICE_FIELDS, AMPLIFY_DEVICE_KEYS, AMPLIFY_GUEST_PROFILE_FIELDS, AMPLIFY_GUEST_PROFILE_KEYS, AMPLIFY_PROFILE_FIELDS, AMPLIFY_PROFILE_KEYS, OBJECT_TYPE_NAMES, } from './object_types.js';
18
+ /**
19
+ * The pre-bundled identify-user Lambda asset ships alongside the compiled
20
+ * construct at `<packageRoot>/lib/handler-asset` (produced by the package's
21
+ * `post:compile` esbuild step). Resolving relative to the package root — rather
22
+ * than to this module — means the path is correct whether the code runs from
23
+ * the compiled `lib/` output or from `src/` under `tsx` (as the unit tests do).
24
+ */
25
+ const packageRoot = fileURLToPath(new URL('..', import.meta.url));
26
+ const defaultLambdaCodePath = path.join(packageRoot, 'lib', 'handler-asset');
27
+ const defaultPushLambdaCodePath = path.join(packageRoot, 'lib', 'push-handler-asset');
28
+ const defaultCampaignAssociationLambdaCodePath = path.join(packageRoot, 'lib', 'campaign-association-asset');
29
+ /**
30
+ * Amazon Connect Customer Profiles backend for the identifyUser contract,
31
+ * packaged as an AWS CDK construct. Provisions:
32
+ * - AmplifyProfile object type: searchable `cognitoUserKey` (PROFILE + UNIQUE)
33
+ * identity key + person / targeting attribute schema.
34
+ * - AmplifyDevice object type: PROFILE-resolution key = `cognitoUserKey`,
35
+ * UNIQUE object key = stable `deviceId`; device fields stored raw.
36
+ * - identify-user Lambda with least-privilege profile:* on this domain only.
37
+ * - HTTP API + JWT authorizer bound to the supplied issuer / audience.
38
+ * - push-delivery Lambda (Connect Journey Custom-action target) + a minimal
39
+ * AWS End User Messaging (Pinpoint) application for `SendMessages`.
40
+ *
41
+ * It operates in one of two modes, chosen by whether `domainName` is provided:
42
+ *
43
+ * - CREATE-FROM-SCRATCH (default, `domainName` omitted): the construct also
44
+ * provisions a brand-new Amazon Connect instance (`AWS::Connect::Instance`,
45
+ * CONNECT_MANAGED, inbound/outbound enabled) AND a brand-new Customer
46
+ * Profiles domain (`AWS::CustomerProfiles::Domain`) with generated, stable
47
+ * names, then registers the object types INTO that new domain. The object
48
+ * types depend on the created domain so they provision after it and are torn
49
+ * down before it. A caller needs zero pre-existing Connect setup.
50
+ * - ATTACH (`domainName` provided): the construct registers the two object
51
+ * types INTO the existing `domainName` (additive) — such as the domain
52
+ * Amazon Connect auto-creates when Customer Profiles is enabled on an
53
+ * instance — WITHOUT creating an instance or a domain, and without touching
54
+ * the domain's other integrations (CTR, Outbound Campaigns) or its Identity
55
+ * Resolution setting.
56
+ *
57
+ * In either mode, identify works against the domain standalone. Outbound
58
+ * Campaigns association — so journeys can target these profiles — is AUTOMATIC
59
+ * in create-from-scratch mode (a Lambda-backed custom resource associates the
60
+ * new domain with the new instance's Outbound Campaigns v2 at deploy time). In
61
+ * attach mode, associating the pre-existing domain is the user's responsibility
62
+ * and is left untouched.
63
+ *
64
+ * This construct is framework-agnostic (aws-cdk-lib + constructs only). The
65
+ * `defineNotifications` factory wraps it for Amplify Gen2 backends, wiring the
66
+ * JWT authorizer to the app's Cognito user pool and surfacing the endpoint via
67
+ * backend outputs.
68
+ */
69
+ export class AmplifyNotifications extends Construct {
70
+ /** CDK resources for lower-level access. */
71
+ resources;
72
+ /** The stack this construct belongs to. */
73
+ stack;
74
+ /** Base invoke URL. Clients call `POST {apiEndpoint}/identify-user`. */
75
+ apiEndpoint;
76
+ /** The route path appended to {@link apiEndpoint}. */
77
+ identifyUserPath = '/identify-user';
78
+ /**
79
+ * The GUEST route path appended to {@link apiEndpoint}.
80
+ * IAM/SigV4-authorized; unauthenticated Identity Pool callers sign requests to
81
+ * `POST {apiEndpoint}/identify-user-guest`.
82
+ */
83
+ guestIdentifyUserPath = '/identify-user-guest';
84
+ /**
85
+ * The `execute-api:Invoke` ARN of the GUEST route, to
86
+ * grant to the app's Cognito Identity Pool UNAUTHENTICATED role so guests can
87
+ * call the route. Scoped to POST on the guest path of this API's default
88
+ * stage.
89
+ */
90
+ guestRouteInvokeArn;
91
+ /** The Customer Profiles domain name the object types are registered into. */
92
+ domainName;
93
+ /**
94
+ * `true` when this construct created the Customer Profiles domain + Connect
95
+ * instance (create-from-scratch mode); `false` when it attached to an existing
96
+ * domain named by `domainName`.
97
+ */
98
+ createsResources;
99
+ /**
100
+ * Id of the Amazon Connect instance created in create-from-scratch mode.
101
+ * `undefined` in attach mode.
102
+ */
103
+ connectInstanceId;
104
+ /**
105
+ * ARN of the Amazon Connect instance created in create-from-scratch mode.
106
+ * `undefined` in attach mode.
107
+ */
108
+ connectInstanceArn;
109
+ /**
110
+ * ARN of the push-delivery Lambda, to wire as a Connect Journey Custom-action
111
+ * (Invoke Lambda) target.
112
+ */
113
+ pushFunctionArn;
114
+ /**
115
+ * The AWS End User Messaging / Pinpoint application id this construct created
116
+ * and the push Lambda calls `SendMessages` against.
117
+ */
118
+ eumApplicationId;
119
+ /**
120
+ * Registers the AmplifyProfile / AmplifyDevice object types into the Customer
121
+ * Profiles domain (created here in create-from-scratch mode, or the existing
122
+ * `domainName` in attach mode), the identify-user Lambda + JWT-authorized HTTP
123
+ * API, and the push-delivery Lambda + AWS End User Messaging application for
124
+ * this notifications backend.
125
+ */
126
+ constructor(scope, id, props) {
127
+ super(scope, id);
128
+ const stack = Stack.of(this);
129
+ this.stack = stack;
130
+ const expirationDays = props.expirationDays ?? DEFAULT_EXPIRATION_DAYS;
131
+ // ---- Mode selection: create-from-scratch (default) vs attach -----------
132
+ // If a `domainName` is supplied, ATTACH the object types to that existing
133
+ // domain (create nothing). Otherwise (the zero-config default) CREATE a
134
+ // brand-new Connect instance + Customer Profiles domain with generated,
135
+ // stable names and register the object types into the new domain.
136
+ const createFromScratch = !props.domainName;
137
+ this.createsResources = createFromScratch;
138
+ let domainName;
139
+ let profilesDomain;
140
+ let connectInstance;
141
+ if (createFromScratch) {
142
+ // Deterministic-yet-unique base name derived from the construct's scope so
143
+ // it is STABLE across deploy/delete (same tree → same name) and unique per
144
+ // app / environment (the root stack name embeds the Amplify app + branch).
145
+ const baseName = this.generateResourceName();
146
+ domainName = baseName;
147
+ connectInstance = new CfnInstance(this, 'ConnectInstance', {
148
+ // Minimal telephony surface: Connect requires at least one of
149
+ // inbound/outbound; enable both so the instance is usable for outbound
150
+ // journeys later. Directory is Connect-managed (no external identity).
151
+ //
152
+ // highVolumeOutBound enables the instance's Outbound Campaigns feature.
153
+ // This is what makes Amazon Connect attach the
154
+ // `HighVolumeOutboundCommunicationAccess` inline policy to the instance's
155
+ // OWN service-linked role — the policy granting the `connect-campaigns:*`
156
+ // (CreateCampaign / ListCampaigns / ...) actions the Connect console
157
+ // drives Journey + campaign authoring through. Onboarding to Outbound
158
+ // Campaigns v2 (the campaign-association custom resource) does NOT set
159
+ // it, so without this the console's Journey / segment builder fails with
160
+ // connect-campaigns AccessDenied on the instance SLR.
161
+ attributes: {
162
+ inboundCalls: true,
163
+ outboundCalls: true,
164
+ highVolumeOutBound: true,
165
+ },
166
+ identityManagementType: 'CONNECT_MANAGED',
167
+ instanceAlias: this.sanitizeInstanceAlias(props.instanceAlias ?? baseName),
168
+ });
169
+ profilesDomain = new CfnDomain(this, 'ProfilesDomain', {
170
+ domainName,
171
+ defaultExpirationDays: expirationDays,
172
+ });
173
+ this.connectInstanceId = connectInstance.attrId;
174
+ this.connectInstanceArn = connectInstance.attrArn;
175
+ // Instance-level Customer Profiles feature binding: registers the created
176
+ // domain as the instance's CTR (contact-record) profiles store — the
177
+ // "Customer Profiles enabled" integration the Connect console and Journey
178
+ // segment builder require, distinct from the Outbound Campaigns
179
+ // integration the association custom resource wires below. PutIntegration
180
+ // auto-resolves the Connect service-linked role for a connect-instance
181
+ // URI; that SLR can only reach the domain because it is named
182
+ // `amazon-connect-*` (see generateResourceName).
183
+ const ctrIntegration = new CfnIntegration(this, 'ConnectProfilesIntegration', {
184
+ domainName,
185
+ uri: connectInstance.attrArn,
186
+ objectTypeName: 'CTR',
187
+ });
188
+ ctrIntegration.addDependency(connectInstance);
189
+ ctrIntegration.addDependency(profilesDomain);
190
+ // Message-templates knowledge base + its instance association. Both the
191
+ // Connect console's message-template authoring UI and the push-delivery
192
+ // Lambda's runtime discovery (ListIntegrationAssociations filtered to
193
+ // Q_MESSAGE_TEMPLATES → the KB it renders templates from) require a
194
+ // MESSAGE_TEMPLATES knowledge base linked to the instance. We provision
195
+ // the empty KB + the Q_MESSAGE_TEMPLATES association only; the templates
196
+ // themselves are the marketer's job (a template's name must match the
197
+ // journey Custom-action id, e.g. "Push Notification"). A MESSAGE_TEMPLATES
198
+ // KB needs no Q assistant. The name is derived from the same deterministic
199
+ // base as the instance/domain so redeploys stay stable and avoid the
200
+ // CreateKnowledgeBase ConflictException on duplicate names.
201
+ const templatesKb = new CfnKnowledgeBase(this, 'MessageTemplatesKb', {
202
+ name: `${baseName}-message-templates`,
203
+ knowledgeBaseType: 'MESSAGE_TEMPLATES',
204
+ });
205
+ const templatesAssociation = new CfnIntegrationAssociation(this, 'MessageTemplatesAssociation', {
206
+ instanceId: connectInstance.attrArn,
207
+ integrationType: 'Q_MESSAGE_TEMPLATES',
208
+ integrationArn: templatesKb.attrKnowledgeBaseArn,
209
+ });
210
+ templatesAssociation.addDependency(connectInstance);
211
+ templatesAssociation.addDependency(templatesKb);
212
+ }
213
+ else {
214
+ domainName = props.domainName;
215
+ }
216
+ this.domainName = domainName;
217
+ // ---- Object types ------------------------------------------------------
218
+ // Registered INTO `domainName`. In attach mode this is purely additive to a
219
+ // pre-existing (e.g. Connect-managed) domain. In create mode the object
220
+ // types depend on the domain created above, so CFN provisions the domain
221
+ // first and — on teardown — removes the object types before the domain (a
222
+ // clean, in-construct dependency; no cross-stack ordering hack needed).
223
+ const profileType = new CfnObjectType(this, 'AmplifyProfileType', {
224
+ domainName,
225
+ objectTypeName: OBJECT_TYPE_NAMES.profile,
226
+ description: 'Amplify identifyUser person profile (find-or-create by verified Cognito sub)',
227
+ allowProfileCreation: true,
228
+ fields: AMPLIFY_PROFILE_FIELDS,
229
+ keys: AMPLIFY_PROFILE_KEYS,
230
+ expirationDays,
231
+ });
232
+ const deviceType = new CfnObjectType(this, 'AmplifyDeviceType', {
233
+ domainName,
234
+ objectTypeName: OBJECT_TYPE_NAMES.device,
235
+ description: 'Amplify identifyUser device (unique per stable deviceId; token is a mutable field; resolves to profile by cognitoUserKey)',
236
+ allowProfileCreation: true,
237
+ fields: AMPLIFY_DEVICE_FIELDS,
238
+ keys: AMPLIFY_DEVICE_KEYS,
239
+ expirationDays,
240
+ });
241
+ // A distinct object type for GUEST profiles. Customer
242
+ // Profiles permits exactly one UNIQUE key per object type and PutProfileObject
243
+ // requires the ingested object to carry it; the authed AmplifyProfile reserves
244
+ // its UNIQUE key for cognitoSub, so guest profiles (keyed on the Identity Pool
245
+ // cognitoIdentityId) get their own type with cognitoIdentityKey as UNIQUE.
246
+ const guestProfileType = new CfnObjectType(this, 'AmplifyGuestProfileType', {
247
+ domainName,
248
+ objectTypeName: OBJECT_TYPE_NAMES.guestProfile,
249
+ description: 'Amplify identifyUser GUEST person profile (find-or-create by verified Cognito Identity Pool identityId)',
250
+ allowProfileCreation: true,
251
+ fields: AMPLIFY_GUEST_PROFILE_FIELDS,
252
+ keys: AMPLIFY_GUEST_PROFILE_KEYS,
253
+ expirationDays,
254
+ });
255
+ if (profilesDomain) {
256
+ profileType.addDependency(profilesDomain);
257
+ deviceType.addDependency(profilesDomain);
258
+ guestProfileType.addDependency(profilesDomain);
259
+ }
260
+ // ---- Outbound Campaigns association (create-from-scratch ONLY) ----------
261
+ // When this construct created the instance + domain, a Lambda-backed custom
262
+ // resource associates the new domain with the instance's Outbound Campaigns
263
+ // v2 at deploy time — so Connect Journeys can target the domain's profiles
264
+ // with NO manual console step. In attach mode the existing domain's
265
+ // association is the user's responsibility, so this resource is NOT added.
266
+ if (createFromScratch && connectInstance && profilesDomain) {
267
+ this.addCampaignAssociation(connectInstance, profilesDomain, domainName, props.campaignAssociationLambdaCodePath ??
268
+ defaultCampaignAssociationLambdaCodePath);
269
+ }
270
+ // ---- Lambda handler ----------------------------------------------------
271
+ // Pre-bundled at build time (esbuild) into a self-contained asset, so the
272
+ // construct works regardless of the consuming project's root (Amplify's
273
+ // NodejsFunction guardrail forbids an entry outside the app root).
274
+ const codePath = props.lambdaCodePath ?? defaultLambdaCodePath;
275
+ const fn = new lambda.Function(this, 'IdentifyUserFn', {
276
+ code: lambda.Code.fromAsset(codePath),
277
+ handler: 'index.handler',
278
+ runtime: lambda.Runtime.NODEJS_20_X,
279
+ timeout: Duration.seconds(15),
280
+ memorySize: 256,
281
+ environment: {
282
+ [ENV_DOMAIN_NAME]: domainName,
283
+ },
284
+ });
285
+ // ---- Least-privilege IAM ----------------------------------------------
286
+ const domainArn = Arn.format({
287
+ service: 'profile',
288
+ resource: 'domains',
289
+ resourceName: domainName,
290
+ arnFormat: ArnFormat.SLASH_RESOURCE_NAME,
291
+ }, stack);
292
+ const objectTypesArn = Arn.format({
293
+ service: 'profile',
294
+ resource: 'domains',
295
+ resourceName: `${domainName}/object-types/*`,
296
+ arnFormat: ArnFormat.SLASH_RESOURCE_NAME,
297
+ }, stack);
298
+ fn.addToRolePolicy(new iam.PolicyStatement({
299
+ effect: iam.Effect.ALLOW,
300
+ actions: [
301
+ // PutProfileObject find-or-create (AmplifyProfile) + read-back.
302
+ 'profile:PutProfileObject',
303
+ 'profile:SearchProfiles',
304
+ // Read back the existing device object to preserve immutable createdAt.
305
+ 'profile:ListProfileObjects',
306
+ // Set targeting / person attributes on the resolved profile.
307
+ 'profile:UpdateProfile',
308
+ ],
309
+ resources: [domainArn, objectTypesArn],
310
+ }));
311
+ // Merge-on-sign-in folds a prior guest profile
312
+ // (+ its device objects) into the authed profile via MergeProfiles.
313
+ // NOTE: the Service Authorization Reference lists MergeProfiles under the
314
+ // `domains` resource type, but the service ACTUALLY authorizes it against
315
+ // an undocumented, differently-shaped resource ARN (note the leading slash
316
+ // and the /profiles/objects/merge suffix):
317
+ // arn:<partition>:profile:<region>:<account>:/domains/<domain>/profiles/objects/merge
318
+ // Granting the documented domain ARN is NOT sufficient. This dedicated
319
+ // statement targets the enforced resource.
320
+ const mergeProfilesArn = `arn:${stack.partition}:profile:${stack.region}:${stack.account}:/domains/${domainName}/profiles/objects/merge`;
321
+ fn.addToRolePolicy(new iam.PolicyStatement({
322
+ effect: iam.Effect.ALLOW,
323
+ actions: ['profile:MergeProfiles'],
324
+ resources: [mergeProfilesArn],
325
+ }));
326
+ // ---- HTTP API + JWT authorizer ----------------------------------------
327
+ const authorizer = new HttpJwtAuthorizer('JwtAuthorizer', props.jwtIssuer, {
328
+ jwtAudience: props.jwtAudience,
329
+ identitySource: ['$request.header.Authorization'],
330
+ });
331
+ const httpApi = new apigwv2.HttpApi(this, 'IdentifyUserApi', {
332
+ apiName: 'identify-user-api',
333
+ createDefaultStage: true,
334
+ });
335
+ httpApi.addRoutes({
336
+ path: this.identifyUserPath,
337
+ methods: [apigwv2.HttpMethod.POST],
338
+ integration: new HttpLambdaIntegration('IdentifyUserIntegration', fn),
339
+ authorizer,
340
+ });
341
+ // ---- Guest (unauthenticated) route ------------------------------------
342
+ // A second route to the SAME identify Lambda, but
343
+ // authorized with IAM/SigV4 instead of a JWT — so an UNAUTHENTICATED Cognito
344
+ // Identity Pool caller (guest credentials) can register a device / seed a
345
+ // profile BEFORE login (the pre-login push-token case).
346
+ //
347
+ // The integration MUST use payload format 1.0: HTTP API payload format 2.0
348
+ // has NO `requestContext.identity` block, so the verified Cognito
349
+ // `cognitoIdentityId` (+ `cognitoAuthenticationType`) the Lambda keys the
350
+ // guest profile on is only present under format 1.0. The Lambda derives the
351
+ // guest identity SOLELY from that authorizer-verified field.
352
+ const iamAuthorizer = new HttpIamAuthorizer();
353
+ httpApi.addRoutes({
354
+ path: this.guestIdentifyUserPath,
355
+ methods: [apigwv2.HttpMethod.POST],
356
+ integration: new HttpLambdaIntegration('GuestIdentifyIntegration', fn, {
357
+ payloadFormatVersion: apigwv2.PayloadFormatVersion.VERSION_1_0,
358
+ }),
359
+ authorizer: iamAuthorizer,
360
+ });
361
+ // `execute-api:Invoke` ARN for the guest route — the app grants this to its
362
+ // Identity Pool UNAUTHENTICATED role so guests can call the route. Scoped as
363
+ // tightly as execute-api allows: `$default/POST/identify-user-guest` pins the
364
+ // grant to the POST method on the guest path of the API's single default
365
+ // stage, so the unauth role can invoke NEITHER other methods, NOR other
366
+ // stages, NOR the authed `/identify-user` route. (HTTP APIs auto-create the
367
+ // `$default` stage; this construct never adds another.)
368
+ this.guestRouteInvokeArn = Arn.format({
369
+ service: 'execute-api',
370
+ resource: httpApi.apiId,
371
+ resourceName: `$default/POST${this.guestIdentifyUserPath}`,
372
+ arnFormat: ArnFormat.SLASH_RESOURCE_NAME,
373
+ }, stack);
374
+ this.apiEndpoint = httpApi.apiEndpoint;
375
+ // Scoped to the stack (not `this`) so the output keeps a stable, readable
376
+ // logical id (`IdentifyUserApiEndpoint`) that a human can find in the
377
+ // CloudFormation console. The construct is provisioned once per stack (the
378
+ // Gen2 factory places it in a dedicated nested stack), so there is no
379
+ // collision risk from the verbatim id.
380
+ new CfnOutput(stack, 'IdentifyUserApiEndpoint', {
381
+ value: httpApi.apiEndpoint,
382
+ description: 'POST {value}/identify-user',
383
+ });
384
+ // Surface the guest route's invoke ARN so a human /
385
+ // the app can grant it to the Identity Pool unauthenticated role.
386
+ new CfnOutput(stack, 'GuestIdentifyRouteInvokeArn', {
387
+ value: this.guestRouteInvokeArn,
388
+ description: 'Grant execute-api:Invoke on this ARN to the Cognito Identity Pool unauthenticated role',
389
+ });
390
+ // ---- Push-delivery path -----------------------------------------------
391
+ // Amazon Connect has no native mobile-push channel, so a Lambda bridges the
392
+ // gap: Connect invokes it via a Journey Custom-action to deliver push
393
+ // through AWS End User Messaging (Pinpoint SendMessages). A minimal Pinpoint
394
+ // application is always created so SendMessages has a valid ApplicationId.
395
+ // The APNs / GCM channels on it are configured only when the caller supplies
396
+ // credentials (see `apnsChannel` / `fcmChannel`); otherwise the application
397
+ // is created with no channel enabled (delivery will 404 until configured).
398
+ const pushApplication = new CfnApp(this, 'PushApp', {
399
+ name: `${domainName}-push`,
400
+ });
401
+ const eumApplicationId = pushApplication.ref;
402
+ this.eumApplicationId = eumApplicationId;
403
+ // ---- Optional push channels (secret-driven) ---------------------------
404
+ // The Amplify Gen2 factory resolves the APNs `.p8` key / FCM service-account
405
+ // JSON from Amplify `secret()`s to deploy-time CFN tokens and passes them as
406
+ // plain strings. Channel credentials flow through CloudFormation the same way
407
+ // Amplify's own external-auth-provider secrets do (defineAuth) — via the
408
+ // secret custom resource's token, never as literal template plain text. The
409
+ // channels attach to THIS construct's own EUM app, so they are provisioned
410
+ // after it and torn down with the stack. The `applicationId` prop resolves to
411
+ // a `Ref` on the EUM app, so CloudFormation infers the create/delete ordering
412
+ // — no explicit `addDependency` needed.
413
+ const { apnsChannel: apnsConfig, fcmChannel: fcmConfig } = props;
414
+ let apnsChannel;
415
+ if (apnsConfig) {
416
+ // Token (`.p8`) authentication: the CFN `DefaultAuthenticationMethod`
417
+ // property accepts `TOKEN` (signing-key auth) or `CERTIFICATE`; token auth
418
+ // uses the `.p8` signing key. Sandbox selects the development APNs endpoint
419
+ // used by development-signed builds.
420
+ const apnsProps = {
421
+ applicationId: eumApplicationId,
422
+ enabled: true,
423
+ defaultAuthenticationMethod: 'TOKEN',
424
+ tokenKey: apnsConfig.tokenKey,
425
+ tokenKeyId: apnsConfig.keyId,
426
+ teamId: apnsConfig.teamId,
427
+ bundleId: apnsConfig.bundleId,
428
+ };
429
+ apnsChannel = apnsConfig.sandbox
430
+ ? new CfnAPNSSandboxChannel(this, 'ApnsSandboxChannel', apnsProps)
431
+ : new CfnAPNSChannel(this, 'ApnsChannel', apnsProps);
432
+ }
433
+ let gcmChannel;
434
+ if (fcmConfig) {
435
+ // FCM HTTP v1: `TOKEN` auth with a service-account JSON credential. Google
436
+ // deprecated the legacy server-key (`ApiKey` / `KEY`) API, so only the v1
437
+ // `ServiceJson` (FCM v1) path is used.
438
+ gcmChannel = new CfnGCMChannel(this, 'GcmChannel', {
439
+ applicationId: eumApplicationId,
440
+ enabled: true,
441
+ defaultAuthenticationMethod: 'TOKEN',
442
+ serviceJson: fcmConfig.serviceJson,
443
+ });
444
+ }
445
+ const pushCodePath = props.pushLambdaCodePath ?? defaultPushLambdaCodePath;
446
+ const pushFn = new lambda.Function(this, 'PushHandlerFn', {
447
+ code: lambda.Code.fromAsset(pushCodePath),
448
+ handler: 'index.handler',
449
+ runtime: lambda.Runtime.NODEJS_20_X,
450
+ timeout: Duration.seconds(30),
451
+ memorySize: 256,
452
+ environment: {
453
+ [ENV_DOMAIN_NAME]: domainName,
454
+ [ENV_EUM_APPLICATION_ID]: eumApplicationId,
455
+ },
456
+ });
457
+ // Least-privilege: read + delete device objects on THIS domain only, and
458
+ // SendMessages scoped to THIS EUM application.
459
+ pushFn.addToRolePolicy(new iam.PolicyStatement({
460
+ effect: iam.Effect.ALLOW,
461
+ actions: [
462
+ // Resolve a profile's registered devices (tokens + channels).
463
+ 'profile:ListProfileObjects',
464
+ // Stale-token cleanup: delete a device whose token is dead.
465
+ 'profile:DeleteProfileObject',
466
+ ],
467
+ resources: [domainArn, objectTypesArn],
468
+ }));
469
+ const appMessagesArn = Arn.format({
470
+ service: 'mobiletargeting',
471
+ resource: 'apps',
472
+ resourceName: `${eumApplicationId}/messages`,
473
+ arnFormat: ArnFormat.SLASH_RESOURCE_NAME,
474
+ }, stack);
475
+ pushFn.addToRolePolicy(new iam.PolicyStatement({
476
+ effect: iam.Effect.ALLOW,
477
+ actions: ['mobiletargeting:SendMessages'],
478
+ resources: [appMessagesArn],
479
+ }));
480
+ // ---- Runtime message-template resolution (Q in Connect) ---------------
481
+ // The push Lambda resolves per-profile copy from a Q in Connect (Wisdom)
482
+ // PUSH message template at runtime: it discovers the knowledge base from the
483
+ // journey's campaign (DescribeCampaign -> connectInstanceId ->
484
+ // ListIntegrationAssociations) and renders the template whose name matches
485
+ // the Custom-action ActionId. Least-privilege, scoped to this account /
486
+ // region. IAM prefixes confirmed empirically: campaign actions use
487
+ // `connect-campaigns`, integration listing uses `connect`, and Q in Connect
488
+ // message-template actions use the `wisdom` prefix (Q in Connect is the
489
+ // rebrand of Amazon Connect Wisdom; the SDK client is `@aws-sdk/client-qconnect`
490
+ // but IAM/ARNs remain `wisdom`).
491
+ pushFn.addToRolePolicy(new iam.PolicyStatement({
492
+ effect: iam.Effect.ALLOW,
493
+ actions: ['connect-campaigns:DescribeCampaign'],
494
+ resources: [
495
+ Arn.format({
496
+ service: 'connect-campaigns',
497
+ resource: 'campaign',
498
+ resourceName: '*',
499
+ arnFormat: ArnFormat.SLASH_RESOURCE_NAME,
500
+ }, stack),
501
+ ],
502
+ }));
503
+ pushFn.addToRolePolicy(new iam.PolicyStatement({
504
+ effect: iam.Effect.ALLOW,
505
+ actions: ['connect:ListIntegrationAssociations'],
506
+ resources: [
507
+ Arn.format({
508
+ service: 'connect',
509
+ resource: 'instance',
510
+ resourceName: '*',
511
+ arnFormat: ArnFormat.SLASH_RESOURCE_NAME,
512
+ }, stack),
513
+ ],
514
+ }));
515
+ pushFn.addToRolePolicy(new iam.PolicyStatement({
516
+ effect: iam.Effect.ALLOW,
517
+ actions: [
518
+ 'wisdom:ListMessageTemplates',
519
+ 'wisdom:GetMessageTemplate',
520
+ 'wisdom:RenderMessageTemplate',
521
+ ],
522
+ resources: [
523
+ Arn.format({
524
+ service: 'wisdom',
525
+ resource: 'knowledge-base',
526
+ resourceName: '*',
527
+ arnFormat: ArnFormat.SLASH_RESOURCE_NAME,
528
+ }, stack),
529
+ Arn.format({
530
+ service: 'wisdom',
531
+ resource: 'message-template',
532
+ resourceName: '*',
533
+ arnFormat: ArnFormat.SLASH_RESOURCE_NAME,
534
+ }, stack),
535
+ ],
536
+ }));
537
+ // ---- Invoke resource policy for Amazon Connect ------------------------
538
+ // A Connect Journey Custom-action (and Outbound Campaigns v2) invokes this
539
+ // Lambda through the connect / connect-campaigns service principal. Grant
540
+ // lambda:InvokeFunction to both, scoped to THIS account (`sourceAccount`) so
541
+ // only Connect instances in the deploying account — not any Connect instance
542
+ // anywhere — can invoke it (confused-deputy guard). The Connect instance ARN
543
+ // isn't known at synth time, so account scoping is the tightest guard here.
544
+ for (const servicePrincipal of CONNECT_INVOKE_SERVICE_PRINCIPALS) {
545
+ pushFn.addPermission(`Invoke-${servicePrincipal.replace(/[^a-zA-Z0-9]/g, '-')}`, {
546
+ principal: new iam.ServicePrincipal(servicePrincipal),
547
+ action: 'lambda:InvokeFunction',
548
+ sourceAccount: stack.account,
549
+ });
550
+ }
551
+ this.pushFunctionArn = pushFn.functionArn;
552
+ // Scoped to the stack (not `this`) so the output keeps a stable, readable
553
+ // logical id (`PushHandlerFunctionArn`) that a human can find in the
554
+ // CloudFormation console and copy to wire the Journey Custom-action.
555
+ new CfnOutput(stack, 'PushHandlerFunctionArn', {
556
+ value: pushFn.functionArn,
557
+ description: 'Wire as a Connect Journey Custom-action (Invoke Lambda) target',
558
+ });
559
+ // ---- Create-mode outputs ----------------------------------------------
560
+ // Surface the resources this construct provisioned from scratch so a human
561
+ // can find the new instance / domain in the console. Their Outbound
562
+ // Campaigns association is handled automatically by the custom resource above.
563
+ if (connectInstance) {
564
+ new CfnOutput(stack, 'ConnectInstanceId', {
565
+ value: connectInstance.attrId,
566
+ description: 'Amazon Connect instance created for notifications',
567
+ });
568
+ new CfnOutput(stack, 'ConnectInstanceArn', {
569
+ value: connectInstance.attrArn,
570
+ description: 'Amazon Connect instance ARN',
571
+ });
572
+ }
573
+ if (profilesDomain) {
574
+ new CfnOutput(stack, 'ProfilesDomainName', {
575
+ value: domainName,
576
+ description: 'Customer Profiles domain created for notifications',
577
+ });
578
+ }
579
+ this.resources = {
580
+ identifyUserFunction: fn,
581
+ httpApi,
582
+ profileObjectType: profileType,
583
+ guestProfileObjectType: guestProfileType,
584
+ deviceObjectType: deviceType,
585
+ pushFunction: pushFn,
586
+ pushApplication,
587
+ apnsChannel,
588
+ gcmChannel,
589
+ connectInstance,
590
+ profilesDomain,
591
+ };
592
+ }
593
+ /**
594
+ * Create-from-scratch ONLY: a Lambda-backed CDK custom resource that
595
+ * associates the created Customer Profiles domain with the created Amazon
596
+ * Connect instance's Outbound Campaigns v2 at deploy time, so Connect Journeys
597
+ * can target the domain's profiles with no manual console step.
598
+ *
599
+ * A `custom-resources.Provider` fronts the handler because onboarding is
600
+ * asynchronous: the handler starts the instance-onboarding job, then POLLS
601
+ * GetInstanceOnboardingJobStatus until SUCCEEDED (an `AwsCustomResource` can't
602
+ * poll). onCreate/onUpdate are idempotent; onDelete best-effort reverses the
603
+ * integrations + offboards, never failing teardown. The resource depends on
604
+ * both the instance and the domain so it runs after they exist and is torn
605
+ * down before them.
606
+ */
607
+ addCampaignAssociation(connectInstance, profilesDomain, domainName, codePath) {
608
+ const stack = this.stack;
609
+ const associationFn = new lambda.Function(this, 'CampaignAssociationFn', {
610
+ code: lambda.Code.fromAsset(codePath),
611
+ handler: 'index.handler',
612
+ runtime: lambda.Runtime.NODEJS_20_X,
613
+ // Onboarding polls GetInstanceOnboardingJobStatus until SUCCEEDED (~20s,
614
+ // capped ~2min); allow generous headroom for onboarding + both integrations.
615
+ timeout: Duration.minutes(10),
616
+ memorySize: 256,
617
+ });
618
+ // These instance-onboarding / instance-integration actions operate on the
619
+ // Connect instance's Outbound Campaigns configuration, not on a campaign
620
+ // resource. connect-campaigns does NOT support resource-level permissions
621
+ // for them (IAM evaluates them against `campaign/*` and denies an
622
+ // `instance/*`-scoped grant), so they must be granted on `*`.
623
+ associationFn.addToRolePolicy(new iam.PolicyStatement({
624
+ effect: iam.Effect.ALLOW,
625
+ actions: [
626
+ 'connect-campaigns:StartInstanceOnboardingJob',
627
+ 'connect-campaigns:GetInstanceOnboardingJobStatus',
628
+ 'connect-campaigns:DeleteInstanceOnboardingJob',
629
+ 'connect-campaigns:PutConnectInstanceIntegration',
630
+ 'connect-campaigns:DeleteConnectInstanceIntegration',
631
+ ],
632
+ resources: ['*'],
633
+ }));
634
+ // connect-campaigns onboarding + PutConnectInstanceIntegration validate the
635
+ // target Connect instance on the caller's behalf, so the handler role also
636
+ // needs connect:DescribeInstance on the (construct-owned) instance.
637
+ associationFn.addToRolePolicy(new iam.PolicyStatement({
638
+ effect: iam.Effect.ALLOW,
639
+ actions: ['connect:DescribeInstance'],
640
+ resources: [connectInstance.attrArn],
641
+ }));
642
+ // Reciprocal Customer Profiles integration on THIS domain only (IAM prefix
643
+ // for Customer Profiles is `profile`). GetDomain is read-only and required
644
+ // because PutConnectInstanceIntegration validates the Customer Profiles
645
+ // domain before wiring the integration.
646
+ const domainArn = Arn.format({
647
+ service: 'profile',
648
+ resource: 'domains',
649
+ resourceName: domainName,
650
+ arnFormat: ArnFormat.SLASH_RESOURCE_NAME,
651
+ }, stack);
652
+ associationFn.addToRolePolicy(new iam.PolicyStatement({
653
+ effect: iam.Effect.ALLOW,
654
+ actions: [
655
+ 'profile:PutIntegration',
656
+ 'profile:DeleteIntegration',
657
+ 'profile:GetDomain',
658
+ ],
659
+ resources: [
660
+ domainArn,
661
+ Arn.format({
662
+ service: 'profile',
663
+ resource: 'domains',
664
+ resourceName: `${domainName}/integrations/*`,
665
+ arnFormat: ArnFormat.SLASH_RESOURCE_NAME,
666
+ }, stack),
667
+ ],
668
+ }));
669
+ // PutConnectInstanceIntegration validates the four built-in campaign
670
+ // object-type TEMPLATES referenced by objectTypeNames (Campaign-Email,
671
+ // Campaign-SMS, Campaign-Telephony, Campaign-Orchestration) via
672
+ // profile:GetProfileObjectTypeTemplate, using the CALLER's credentials.
673
+ // Templates are account/region-level resources whose ARN carries a leading
674
+ // slash (`:/templates/<name>`), distinct from the domain, so they need their
675
+ // own grant.
676
+ const profileTemplatesArn = `arn:${stack.partition}:profile:${stack.region}:${stack.account}:/templates/*`;
677
+ associationFn.addToRolePolicy(new iam.PolicyStatement({
678
+ effect: iam.Effect.ALLOW,
679
+ actions: [
680
+ 'profile:GetProfileObjectTypeTemplate',
681
+ 'profile:ListProfileObjectTypeTemplates',
682
+ ],
683
+ resources: [profileTemplatesArn],
684
+ }));
685
+ // Onboarding auto-creates the Outbound Campaigns service-linked role; the
686
+ // handler then lists roles to resolve its ARN. iam:ListRoles has no
687
+ // resource-level scoping, so it must target `*`.
688
+ associationFn.addToRolePolicy(new iam.PolicyStatement({
689
+ effect: iam.Effect.ALLOW,
690
+ actions: ['iam:ListRoles'],
691
+ resources: ['*'],
692
+ }));
693
+ // Each StartInstanceOnboardingJob for a NEW Connect instance creates its own
694
+ // connect-campaigns service-linked role (the role name carries a
695
+ // service-generated random suffix), so the grant must use `*` for the
696
+ // resource and is instead scoped safely by the iam:AWSServiceName condition
697
+ // to ONLY the connect-campaigns SLR. A path-scoped resource ARN is denied by
698
+ // IAM here (surfaced as the onboarding job's IAM_ACCESS_DENIED failureCode).
699
+ const campaignsSlrArn = `arn:${stack.partition}:iam::${stack.account}:role/aws-service-role/${CONNECT_CAMPAIGNS_SERVICE_NAME}/*`;
700
+ associationFn.addToRolePolicy(new iam.PolicyStatement({
701
+ effect: iam.Effect.ALLOW,
702
+ actions: ['iam:CreateServiceLinkedRole'],
703
+ resources: ['*'],
704
+ conditions: {
705
+ StringEquals: {
706
+ 'iam:AWSServiceName': CONNECT_CAMPAIGNS_SERVICE_NAME,
707
+ },
708
+ },
709
+ }));
710
+ associationFn.addToRolePolicy(new iam.PolicyStatement({
711
+ effect: iam.Effect.ALLOW,
712
+ actions: ['iam:PassRole'],
713
+ resources: [campaignsSlrArn],
714
+ }));
715
+ // During onboarding, connect-campaigns customizes its service-linked role
716
+ // with instance-specific inline permissions (the "additional permissions
717
+ // added for the service-linked role to access the resources", incl. the
718
+ // Customer Profiles integration access) via iam:PutRolePolicy /
719
+ // iam:AttachRolePolicy, performed with the CALLER's credentials. Without
720
+ // these the onboarding job fails with failureCode IAM_ACCESS_DENIED. The
721
+ // reverse (Delete/Detach) mirrors this so the best-effort teardown can
722
+ // remove those inline permissions when disassociating. Scoped to ONLY the
723
+ // connect-campaigns service-linked role.
724
+ associationFn.addToRolePolicy(new iam.PolicyStatement({
725
+ effect: iam.Effect.ALLOW,
726
+ actions: [
727
+ 'iam:PutRolePolicy',
728
+ 'iam:AttachRolePolicy',
729
+ 'iam:DeleteRolePolicy',
730
+ 'iam:DetachRolePolicy',
731
+ ],
732
+ resources: [campaignsSlrArn],
733
+ }));
734
+ // Onboarding also provisions a managed EventBridge rule (named
735
+ // `ConnectCampaignsRule*`) that drives campaign event delivery, created with
736
+ // the CALLER's credentials. Without these the onboarding job fails with
737
+ // failureCode EVENT_BRIDGE_ACCESS_DENIED. ListRules has no resource-level
738
+ // scoping; the mutating actions are scoped to the ConnectCampaignsRule* name.
739
+ const connectCampaignsRuleArn = `arn:${stack.partition}:events:${stack.region}:${stack.account}:rule/ConnectCampaignsRule*`;
740
+ associationFn.addToRolePolicy(new iam.PolicyStatement({
741
+ effect: iam.Effect.ALLOW,
742
+ actions: ['events:ListRules'],
743
+ resources: ['*'],
744
+ }));
745
+ associationFn.addToRolePolicy(new iam.PolicyStatement({
746
+ effect: iam.Effect.ALLOW,
747
+ actions: [
748
+ 'events:PutRule',
749
+ 'events:PutTargets',
750
+ 'events:DeleteRule',
751
+ 'events:RemoveTargets',
752
+ 'events:ListTargetsByRule',
753
+ 'events:DescribeRule',
754
+ ],
755
+ resources: [connectCampaignsRuleArn],
756
+ }));
757
+ const provider = new Provider(this, 'CampaignAssociationProvider', {
758
+ onEventHandler: associationFn,
759
+ });
760
+ const association = new CustomResource(this, 'CampaignAssociation', {
761
+ serviceToken: provider.serviceToken,
762
+ resourceType: 'Custom::OutboundCampaignsDomainAssociation',
763
+ properties: {
764
+ ConnectInstanceId: connectInstance.attrId,
765
+ DomainName: domainName,
766
+ Account: stack.account,
767
+ Region: stack.region,
768
+ },
769
+ });
770
+ // Provision after — and tear down before — the instance + domain it links.
771
+ association.node.addDependency(connectInstance);
772
+ association.node.addDependency(profilesDomain);
773
+ }
774
+ /**
775
+ * Deterministic, stable, per-app base name for the created Connect instance
776
+ * and Customer Profiles domain (create-from-scratch mode).
777
+ *
778
+ * The name must be STABLE across deploy and delete (so CFN resolves the same
779
+ * resource on teardown) and UNIQUE per app / environment (so two apps in the
780
+ * same account don't collide on the globally-unique Connect alias). It is
781
+ * derived from a short hash of the root stack name (which, in Amplify Gen2,
782
+ * embeds the app namespace + branch) plus this construct's path — both stable
783
+ * inputs.
784
+ *
785
+ * The `amazon-connect-` prefix is REQUIRED, not cosmetic: Amazon Connect's
786
+ * AWS-managed service-linked-role policy (`AmazonConnectServiceLinkedRolePolicy`,
787
+ * statement `AllowCustomerProfilesForConnectDomain`) grants the instance's
788
+ * role `profile:*` ONLY on `arn:aws:profile:*:*:domains/amazon-connect-*`. A
789
+ * domain named otherwise is unreachable by the instance — the Connect console
790
+ * and Journey segment builder then report "does not have permissions to access
791
+ * Customer Profiles". The SLR is AWS-protected (no inline policy can be added)
792
+ * and the managed policy is not editable, so the domain name is the only lever.
793
+ */
794
+ generateResourceName() {
795
+ let root = this.stack;
796
+ while (root.nestedStackParent) {
797
+ root = root.nestedStackParent;
798
+ }
799
+ const seed = `${root.stackName}::${this.node.path}`;
800
+ const suffix = createHash('sha256').update(seed).digest('hex').slice(0, 12);
801
+ return `amazon-connect-notifications-${suffix}`;
802
+ }
803
+ /**
804
+ * Coerce an arbitrary string into a valid Amazon Connect instance alias:
805
+ * lowercase alphanumeric characters + single hyphens, no leading/trailing hyphen, not
806
+ * starting with the reserved `d-` prefix, and within Connect's 1–62 char
807
+ * bound.
808
+ */
809
+ sanitizeInstanceAlias(raw) {
810
+ let alias = raw
811
+ .toLowerCase()
812
+ .replace(/[^a-z0-9-]/g, '-')
813
+ .replace(/-+/g, '-')
814
+ .replace(/^-+|-+$/g, '');
815
+ if (alias.startsWith('d-')) {
816
+ alias = `a${alias}`;
817
+ }
818
+ if (alias.length === 0) {
819
+ alias = 'amplify-notifications';
820
+ }
821
+ return alias.slice(0, 62).replace(/-+$/g, '');
822
+ }
823
+ }
824
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uc3RydWN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2NvbnN0cnVjdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssSUFBSSxNQUFNLE1BQU0sQ0FBQztBQUM3QixPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQ3pDLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxVQUFVLENBQUM7QUFDekMsT0FBTyxFQUNMLEdBQUcsRUFDSCxTQUFTLEVBQ1QsU0FBUyxFQUNULGNBQWMsRUFDZCxRQUFRLEVBQ1IsS0FBSyxHQUNOLE1BQU0sYUFBYSxDQUFDO0FBQ3JCLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFDdkMsT0FBTyxLQUFLLE1BQU0sTUFBTSx3QkFBd0IsQ0FBQztBQUNqRCxPQUFPLEtBQUssR0FBRyxNQUFNLHFCQUFxQixDQUFDO0FBQzNDLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUN4RCxPQUFPLEVBQ0wsU0FBUyxFQUNULGNBQWMsRUFDZCxhQUFhLEdBQ2QsTUFBTSxrQ0FBa0MsQ0FBQztBQUMxQyxPQUFPLEVBQ0wsV0FBVyxFQUNYLHlCQUF5QixHQUMxQixNQUFNLHlCQUF5QixDQUFDO0FBQ2pDLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQzFELE9BQU8sRUFDTCxjQUFjLEVBQ2QscUJBQXFCLEVBQ3JCLE1BQU0sRUFDTixhQUFhLEdBQ2QsTUFBTSwwQkFBMEIsQ0FBQztBQUNsQyxPQUFPLEtBQUssT0FBTyxNQUFNLDhCQUE4QixDQUFDO0FBQ3hELE9BQU8sRUFDTCxpQkFBaUIsRUFDakIsaUJBQWlCLEdBQ2xCLE1BQU0sMENBQTBDLENBQUM7QUFDbEQsT0FBTyxFQUFFLHFCQUFxQixFQUFFLE1BQU0sMkNBQTJDLENBQUM7QUFHbEYsT0FBTyxFQUNMLDhCQUE4QixFQUM5QixpQ0FBaUMsRUFDakMs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QUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsT0FBTyxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsQ0FBQztJQUNoRCxDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IHsgY3JlYXRlSGFzaCB9IGZyb20gJ25vZGU6Y3J5cHRvJztcbmltcG9ydCB7IGZpbGVVUkxUb1BhdGggfSBmcm9tICdub2RlOnVybCc7XG5pbXBvcnQge1xuICBBcm4sXG4gIEFybkZvcm1hdCxcbiAgQ2ZuT3V0cHV0LFxuICBDdXN0b21SZXNvdXJjZSxcbiAgRHVyYXRpb24sXG4gIFN0YWNrLFxufSBmcm9tICdhd3MtY2RrLWxpYic7XG5pbXBvcnQgeyBDb25zdHJ1Y3QgfSBmcm9tICdjb25zdHJ1Y3RzJztcbmltcG9ydCAqIGFzIGxhbWJkYSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtbGFtYmRhJztcbmltcG9ydCAqIGFzIGlhbSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtaWFtJztcbmltcG9ydCB7IFByb3ZpZGVyIH0gZnJvbSAnYXdzLWNkay1saWIvY3VzdG9tLXJlc291cmNlcyc7XG5pbXBvcnQge1xuICBDZm5Eb21haW4sXG4gIENmbkludGVncmF0aW9uLFxuICBDZm5PYmplY3RUeXBlLFxufSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtY3VzdG9tZXJwcm9maWxlcyc7XG5pbXBvcnQge1xuICBDZm5JbnN0YW5jZSxcbiAgQ2ZuSW50ZWdyYXRpb25Bc3NvY2lhdGlvbixcbn0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWNvbm5lY3QnO1xuaW1wb3J0IHsgQ2ZuS25vd2xlZGdlQmFzZSB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy13aXNkb20nO1xuaW1wb3J0IHtcbiAgQ2ZuQVBOU0NoYW5uZWwsXG4gIENmbkFQTlNTYW5kYm94Q2hhbm5lbCxcbiAgQ2ZuQXBwLFxuICBDZm5HQ01DaGFubmVsLFxufSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtcGlucG9pbnQnO1xuaW1wb3J0ICogYXMgYXBpZ3d2MiBmcm9tICdhd3MtY2RrLWxpYi9hd3MtYXBpZ2F0ZXdheXYyJztcbmltcG9ydCB7XG4gIEh0dHBJYW1BdXRob3JpemVyLFxuICBIdHRwSnd0QXV0aG9yaXplcixcbn0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWFwaWdhdGV3YXl2Mi1hdXRob3JpemVycyc7XG5pbXBvcnQgeyBIdHRwTGFtYmRhSW50ZWdyYXRpb24gfSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtYXBpZ2F0ZXdheXYyLWludGVncmF0aW9ucyc7XG5pbXBvcnQgeyBSZXNvdXJjZVByb3ZpZGVyLCBTdGFja1Byb3ZpZGVyIH0gZnJvbSAnQGF3cy1hbXBsaWZ5L3BsdWdpbi10eXBlcyc7XG5cbmltcG9ydCB7XG4gIENPTk5FQ1RfQ0FNUEFJR05TX1NFUlZJQ0VfTkFNRSxcbiAgQ09OTkVDVF9JTlZPS0VfU0VSVklDRV9QUklOQ0lQQUxTLFxuICBERUZBVUxUX0VYUElSQVRJT05fREFZUyxcbiAgRU5WX0RPTUFJTl9OQU1FLFxuICBFTlZfRVVNX0FQUExJQ0FUSU9OX0lELFxufSBmcm9tICcuL2NvbnN0YW50cy5qcyc7XG5pbXBvcnQge1xuICBBTVBMSUZZX0RFVklDRV9GSUVMRFMsXG4gIEFNUExJRllfREVWSUNFX0tFWVMsXG4gIEFNUExJRllfR1VFU1RfUFJPRklMRV9GSUVMRFMsXG4gIEFNUExJRllfR1VFU1RfUFJPRklMRV9LRVlTLFxuICBBTVBMSUZZX1BST0ZJTEVfRklFTERTLFxuICBBTVBMSUZZX1BST0ZJTEVfS0VZUyxcbiAgT0JKRUNUX1RZUEVfTkFNRVMsXG59IGZyb20gJy4vb2JqZWN0X3R5cGVzLmpzJztcblxuLyoqXG4gKiBUaGUgcHJlLWJ1bmRsZWQgaWRlbnRpZnktdXNlciBMYW1iZGEgYXNzZXQgc2hpcHMgYWxvbmdzaWRlIHRoZSBjb21waWxlZFxuICogY29uc3RydWN0IGF0IGA8cGFja2FnZVJvb3Q+L2xpYi9oYW5kbGVyLWFzc2V0YCAocHJvZHVjZWQgYnkgdGhlIHBhY2thZ2Unc1xuICogYHBvc3Q6Y29tcGlsZWAgZXNidWlsZCBzdGVwKS4gUmVzb2x2aW5nIHJlbGF0aXZlIHRvIHRoZSBwYWNrYWdlIHJvb3Qg4oCUIHJhdGhlclxuICogdGhhbiB0byB0aGlzIG1vZHVsZSDigJQgbWVhbnMgdGhlIHBhdGggaXMgY29ycmVjdCB3aGV0aGVyIHRoZSBjb2RlIHJ1bnMgZnJvbVxuICogdGhlIGNvbXBpbGVkIGBsaWIvYCBvdXRwdXQgb3IgZnJvbSBgc3JjL2AgdW5kZXIgYHRzeGAgKGFzIHRoZSB1bml0IHRlc3RzIGRvKS5cbiAqL1xuY29uc3QgcGFja2FnZVJvb3QgPSBmaWxlVVJMVG9QYXRoKG5ldyBVUkwoJy4uJywgaW1wb3J0Lm1ldGEudXJsKSk7XG5jb25zdCBkZWZhdWx0TGFtYmRhQ29kZVBhdGggPSBwYXRoLmpvaW4ocGFja2FnZVJvb3QsICdsaWInLCAnaGFuZGxlci1hc3NldCcpO1xuY29uc3QgZGVmYXVsdFB1c2hMYW1iZGFDb2RlUGF0aCA9IHBhdGguam9pbihcbiAgcGFja2FnZVJvb3QsXG4gICdsaWInLFxuICAncHVzaC1oYW5kbGVyLWFzc2V0Jyxcbik7XG5jb25zdCBkZWZhdWx0Q2FtcGFpZ25Bc3NvY2lhdGlvbkxhbWJkYUNvZGVQYXRoID0gcGF0aC5qb2luKFxuICBwYWNrYWdlUm9vdCxcbiAgJ2xpYicsXG4gICdjYW1wYWlnbi1hc3NvY2lhdGlvbi1hc3NldCcsXG4pO1xuXG4vKiogQ0RLIHJlc291cmNlcyBleHBvc2VkIGJ5IHtAbGluayBBbXBsaWZ5Tm90aWZpY2F0aW9uc30uICovXG5leHBvcnQgdHlwZSBOb3RpZmljYXRpb25zUmVzb3VyY2VzID0ge1xuICAvKiogVGhlIGlkZW50aWZ5LXVzZXIgTGFtYmRhIGZ1bmN0aW9uLiAqL1xuICBpZGVudGlmeVVzZXJGdW5jdGlvbjogbGFtYmRhLklGdW5jdGlvbjtcbiAgLyoqIFRoZSBIVFRQIEFQSSBmcm9udGluZyB0aGUgaWRlbnRpZnktdXNlciByb3V0ZS4gKi9cbiAgaHR0cEFwaTogYXBpZ3d2Mi5IdHRwQXBpO1xuICAvKiogVGhlIEFtcGxpZnlQcm9maWxlIG9iamVjdCB0eXBlIHJlZ2lzdGVyZWQgb24gdGhlIGRvbWFpbi4gKi9cbiAgcHJvZmlsZU9iamVjdFR5cGU6IENmbk9iamVjdFR5cGU7XG4gIC8qKiBUaGUgQW1wbGlmeUd1ZXN0UHJvZmlsZSBvYmplY3QgdHlwZSByZWdpc3RlcmVkIG9uIHRoZSBkb21haW4uICovXG4gIGd1ZXN0UHJvZmlsZU9iamVjdFR5cGU6IENmbk9iamVjdFR5cGU7XG4gIC8qKiBUaGUgQW1wbGlmeURldmljZSBvYmplY3QgdHlwZSByZWdpc3RlcmVkIG9uIHRoZSBkb21haW4uICovXG4gIGRldmljZU9iamVjdFR5cGU6IENmbk9iamVjdFR5cGU7XG4gIC8qKlxuICAgKiBUaGUgcHVzaC1kZWxpdmVyeSBMYW1iZGEgZnVuY3Rpb24sIHdpcmVkIGFzIHRoZSB0YXJnZXQgb2YgYSBDb25uZWN0IEpvdXJuZXlcbiAgICogQ3VzdG9tLWFjdGlvbiAoSW52b2tlIExhbWJkYSkuXG4gICAqL1xuICBwdXNoRnVuY3Rpb246IGxhbWJkYS5JRnVuY3Rpb247XG4gIC8qKiBUaGUgQVdTIEVuZCBVc2VyIE1lc3NhZ2luZyAvIFBpbnBvaW50IGFwcGxpY2F0aW9uIGJhY2tpbmcgcHVzaCBkZWxpdmVyeS4gKi9cbiAgcHVzaEFwcGxpY2F0aW9uOiBDZm5BcHA7XG4gIC8qKlxuICAgKiBUaGUgQVBOcyBjaGFubmVsIGVuYWJsZWQgb24gdGhlIHB1c2ggYXBwbGljYXRpb24sIHdoZW4gYGFwbnNDaGFubmVsYCBpc1xuICAgKiBjb25maWd1cmVkLiBgdW5kZWZpbmVkYCB3aGVuIG5vIEFQTnMgY29uZmlndXJhdGlvbiB3YXMgcHJvdmlkZWQuIEVpdGhlciB0aGVcbiAgICogcHJvZHVjdGlvbiAoYENmbkFQTlNDaGFubmVsYCkgb3Igc2FuZGJveCAoYENmbkFQTlNTYW5kYm94Q2hhbm5lbGApIGNoYW5uZWwsXG4gICAqIGRlcGVuZGluZyBvbiBgYXBuc0NoYW5uZWwuc2FuZGJveGAuXG4gICAqL1xuICBhcG5zQ2hhbm5lbD86IENmbkFQTlNDaGFubmVsIHwgQ2ZuQVBOU1NhbmRib3hDaGFubmVsO1xuICAvKipcbiAgICogVGhlIEdDTS9GQ00gY2hhbm5lbCBlbmFibGVkIG9uIHRoZSBwdXNoIGFwcGxpY2F0aW9uLCB3aGVuIGBmY21DaGFubmVsYCBpc1xuICAgKiBjb25maWd1cmVkLiBgdW5kZWZpbmVkYCB3aGVuIG5vIEZDTSBjb25maWd1cmF0aW9uIHdhcyBwcm92aWRlZC5cbiAgICovXG4gIGdjbUNoYW5uZWw/OiBDZm5HQ01DaGFubmVsO1xuICAvKipcbiAgICogVGhlIEFtYXpvbiBDb25uZWN0IGluc3RhbmNlIGNyZWF0ZWQgaW4gY3JlYXRlLWZyb20tc2NyYXRjaCBtb2RlICh3aGVuXG4gICAqIGBkb21haW5OYW1lYCBpcyBvbWl0dGVkKS4gYHVuZGVmaW5lZGAgaW4gYXR0YWNoIG1vZGUuXG4gICAqL1xuICBjb25uZWN0SW5zdGFuY2U/OiBDZm5JbnN0YW5jZTtcbiAgLyoqXG4gICAqIFRoZSBDdXN0b21lciBQcm9maWxlcyBkb21haW4gY3JlYXRlZCBpbiBjcmVhdGUtZnJvbS1zY3JhdGNoIG1vZGUgKHdoZW5cbiAgICogYGRvbWFpbk5hbWVgIGlzIG9taXR0ZWQpLiBgdW5kZWZpbmVkYCBpbiBhdHRhY2ggbW9kZSwgd2hlcmUgdGhlIG9iamVjdCB0eXBlc1xuICAgKiBhcmUgcmVnaXN0ZXJlZCBpbnRvIGEgcHJlLWV4aXN0aW5nIGRvbWFpbiB0aGUgY29uc3RydWN0IGRvZXMgbm90IG93bi5cbiAgICovXG4gIHByb2ZpbGVzRG9tYWluPzogQ2ZuRG9tYWluO1xufTtcblxuZXhwb3J0IHR5cGUgQW1wbGlmeU5vdGlmaWNhdGlvbnNQcm9wcyA9IHtcbiAgLyoqXG4gICAqIFRoZSBKV1QgaXNzdWVyIFVSTCB0aGUgSFRUUCBBUEkgYXV0aG9yaXplciB0cnVzdHMuIEZvciBhIENvZ25pdG8gdXNlciBwb29sXG4gICAqIHRoaXMgaXMgYGh0dHBzOi8vY29nbml0by1pZHAuPHJlZ2lvbj4uYW1hem9uYXdzLmNvbS88dXNlclBvb2xJZD5gLlxuICAgKi9cbiAgcmVhZG9ubHkgand0SXNzdWVyOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIEFsbG93ZWQgSldUIGF1ZGllbmNlcy4gRm9yIGEgQ29nbml0byB1c2VyIHBvb2wgdGhpcyBpcyB0aGUgYXBwIGNsaWVudCBpZChzKVxuICAgKiAobWF0Y2hlZCBhZ2FpbnN0IGBhdWRgIGZvciBpZCB0b2tlbnMgLyBgY2xpZW50X2lkYCBmb3IgYWNjZXNzIHRva2VucykuXG4gICAqL1xuICByZWFkb25seSBqd3RBdWRpZW5jZTogc3RyaW5nW107XG5cbiAgLyoqXG4gICAqIE5hbWUgb2YgYW4gRVhJU1RJTkcgQ3VzdG9tZXIgUHJvZmlsZXMgZG9tYWluIHRvIGF0dGFjaCB0byDigJQgZS5nLiB0aGUgZG9tYWluXG4gICAqIEFtYXpvbiBDb25uZWN0IGF1dG8tY3JlYXRlcyB3aGVuIEN1c3RvbWVyIFByb2ZpbGVzIGlzIGVuYWJsZWQgb24gYW5cbiAgICogaW5zdGFuY2UuIFdoZW4gcHJvdmlkZWQsIHRoZSBjb25zdHJ1Y3QgcnVucyBpbiBBVFRBQ0ggbW9kZTogaXQgcmVnaXN0ZXJzIHRoZVxuICAgKiBBbXBsaWZ5UHJvZmlsZSAvIEFtcGxpZnlEZXZpY2Ugb2JqZWN0IHR5cGVzIElOVE8gdGhpcyBkb21haW4gYW5kIG5ldmVyXG4gICAqIGNyZWF0ZXMgYW4gaW5zdGFuY2Ugb3IgYSBkb21haW4uXG4gICAqXG4gICAqIE9NSVQgdGhpcyB0byBydW4gaW4gdGhlIGRlZmF1bHQgQ1JFQVRFLUZST00tU0NSQVRDSCBtb2RlOiB0aGUgY29uc3RydWN0XG4gICAqIHByb3Zpc2lvbnMgYSBicmFuZC1uZXcgQW1hem9uIENvbm5lY3QgaW5zdGFuY2UgQU5EIGEgYnJhbmQtbmV3IEN1c3RvbWVyXG4gICAqIFByb2ZpbGVzIGRvbWFpbiAod2l0aCBnZW5lcmF0ZWQsIHN0YWJsZSBuYW1lcykgYW5kIHdpcmVzIGV2ZXJ5dGhpbmcgaW50b1xuICAgKiB0aGF0IG5ldyBkb21haW4g4oCUIHNvIGEgY2FsbGVyIG5lZWRzIHplcm8gcHJlLWV4aXN0aW5nIENvbm5lY3Qgc2V0dXAuXG4gICAqL1xuICByZWFkb25seSBkb21haW5OYW1lPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBDUkVBVEUgbW9kZSBvbmx5OiBvdmVycmlkZSB0aGUgYXV0by1nZW5lcmF0ZWQgQW1hem9uIENvbm5lY3QgaW5zdGFuY2UgYWxpYXMuXG4gICAqIElnbm9yZWQgaW4gYXR0YWNoIG1vZGUuIFdoZW4gb21pdHRlZCwgYSBkZXRlcm1pbmlzdGljLXlldC11bmlxdWUgYWxpYXMgaXNcbiAgICogZGVyaXZlZCBmcm9tIHRoZSBjb25zdHJ1Y3QncyBzY29wZSBzbyBpdCBpcyBzdGFibGUgYWNyb3NzIGRlcGxveS9kZWxldGUgYW5kXG4gICAqIHVuaXF1ZSBwZXIgYXBwLiBMb3dlcmNhc2UgYWxwaGFudW1lcmljIGNoYXJhY3RlcnMgKyBoeXBoZW5zOyBtdXN0IG5vdCBzdGFydFxuICAgKiB3aXRoXG4gICAqIGBkLWAuXG4gICAqL1xuICByZWFkb25seSBpbnN0YW5jZUFsaWFzPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBPdmVycmlkZSB0aGUgZGlyZWN0b3J5IGNvbnRhaW5pbmcgdGhlIHByZS1idW5kbGVkIExhbWJkYSBhc3NldCAoYW5cbiAgICogYGluZGV4LmpzYCBleHBvcnRpbmcgYGhhbmRsZXJgKS4gRGVmYXVsdHMgdG8gdGhlIGhhbmRsZXIgYnVuZGxlZCBpbnNpZGUgdGhpc1xuICAgKiBwYWNrYWdlIChgbGliL2hhbmRsZXItYXNzZXRgLCBwcm9kdWNlZCBieSBgcG9zdDpjb21waWxlYCkuXG4gICAqL1xuICByZWFkb25seSBsYW1iZGFDb2RlUGF0aD86IHN0cmluZztcblxuICAvKiogUHJvZmlsZSAvIG9iamVjdC10eXBlIGV4cGlyYXRpb24gaW4gZGF5cy4gRGVmYXVsdDogMzY2LiAqL1xuICByZWFkb25seSBleHBpcmF0aW9uRGF5cz86IG51bWJlcjtcblxuICAvKipcbiAgICogT3ZlcnJpZGUgdGhlIGRpcmVjdG9yeSBjb250YWluaW5nIHRoZSBwcmUtYnVuZGxlZCBwdXNoIExhbWJkYSBhc3NldCAoYW5cbiAgICogYGluZGV4LmpzYCBleHBvcnRpbmcgYGhhbmRsZXJgKS4gRGVmYXVsdHMgdG8gdGhlIGhhbmRsZXIgYnVuZGxlZCBpbnNpZGUgdGhpc1xuICAgKiBwYWNrYWdlIChgbGliL3B1c2gtaGFuZGxlci1hc3NldGAsIHByb2R1Y2VkIGJ5IGBwb3N0OmNvbXBpbGVgKS5cbiAgICovXG4gIHJlYWRvbmx5IHB1c2hMYW1iZGFDb2RlUGF0aD86IHN0cmluZztcblxuICAvKipcbiAgICogT3ZlcnJpZGUgdGhlIGRpcmVjdG9yeSBjb250YWluaW5nIHRoZSBwcmUtYnVuZGxlZCBjYW1wYWlnbi1hc3NvY2lhdGlvblxuICAgKiBjdXN0b20tcmVzb3VyY2UgTGFtYmRhIGFzc2V0IChhbiBgaW5kZXguanNgIGV4cG9ydGluZyBgaGFuZGxlcmApLiBEZWZhdWx0cyB0b1xuICAgKiB0aGUgaGFuZGxlciBidW5kbGVkIGluc2lkZSB0aGlzIHBhY2thZ2UgKGBsaWIvY2FtcGFpZ24tYXNzb2NpYXRpb24tYXNzZXRgLFxuICAgKiBwcm9kdWNlZCBieSBgcG9zdDpjb21waWxlYCkuIE9ubHkgdXNlZCBpbiBjcmVhdGUtZnJvbS1zY3JhdGNoIG1vZGUuXG4gICAqL1xuICByZWFkb25seSBjYW1wYWlnbkFzc29jaWF0aW9uTGFtYmRhQ29kZVBhdGg/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIE9QVElPTkFMIEFQTnMgY2hhbm5lbCBjb25maWd1cmF0aW9uICh0b2tlbiAvIGAucDhgIGF1dGgpLiBXaGVuIHByb3ZpZGVkLCB0aGVcbiAgICogY29uc3RydWN0IGVuYWJsZXMgdGhlIEFQTnMgY2hhbm5lbCBvbiB0aGUgY3JlYXRlZCBFbmQgVXNlciBNZXNzYWdpbmdcbiAgICogKFBpbnBvaW50KSBhcHBsaWNhdGlvbi4gQWxsIHZhbHVlcyBhcmUgcGxhaW4gc3RyaW5ncyDigJQgdGhlIEFtcGxpZnkgR2VuMlxuICAgKiBmYWN0b3J5IHJlc29sdmVzIHRoZSBgLnA4YCBrZXkgZnJvbSBhbiBBbXBsaWZ5IGBzZWNyZXQoKWAgYmVmb3JlIHBhc3NpbmcgaXRcbiAgICogaGVyZSwga2VlcGluZyB0aGlzIGNvbnN0cnVjdCBmcmFtZXdvcmstYWdub3N0aWMuIFdoZW4gb21pdHRlZCwgbm8gQVBOc1xuICAgKiBjaGFubmVsIGlzIGNvbmZpZ3VyZWQuXG4gICAqL1xuICByZWFkb25seSBhcG5zQ2hhbm5lbD86IHtcbiAgICAvKiogVGhlIEFQTnMgdG9rZW4gc2lnbmluZyBrZXkgY29udGVudHMgKHRoZSBgQXV0aEtleV88a2V5SWQ+LnA4YCBmaWxlKS4gKi9cbiAgICByZWFkb25seSB0b2tlbktleTogc3RyaW5nO1xuICAgIC8qKiBUaGUgMTAtY2hhcmFjdGVyIGtleSBpZGVudGlmaWVyIGFzc2lnbmVkIHRvIHRoZSBBUE5zIHNpZ25pbmcga2V5LiAqL1xuICAgIHJlYWRvbmx5IGtleUlkOiBzdHJpbmc7XG4gICAgLyoqIFRoZSBBcHBsZSBEZXZlbG9wZXIgYWNjb3VudCB0ZWFtIGlkZW50aWZpZXIuICovXG4gICAgcmVhZG9ubHkgdGVhbUlkOiBzdHJpbmc7XG4gICAgLyoqIFRoZSBpT1MgYXBwIGJ1bmRsZSBpZGVudGlmaWVyLiAqL1xuICAgIHJlYWRvbmx5IGJ1bmRsZUlkOiBzdHJpbmc7XG4gICAgLyoqXG4gICAgICogQ29uZmlndXJlIHRoZSBBUE5zICoqc2FuZGJveCoqIGNoYW5uZWwgaW5zdGVhZCBvZiB0aGUgcHJvZHVjdGlvbiBjaGFubmVsLlxuICAgICAqIEBkZWZhdWx0IGZhbHNlXG4gICAgICovXG4gICAgcmVhZG9ubHkgc2FuZGJveD86IGJvb2xlYW47XG4gIH07XG5cbiAgLyoqXG4gICAqIE9QVElPTkFMIEZDTS9HQ00gY2hhbm5lbCBjb25maWd1cmF0aW9uIChGQ00gSFRUUCB2MSBhdXRoKS4gV2hlbiBwcm92aWRlZCwgdGhlXG4gICAqIGNvbnN0cnVjdCBlbmFibGVzIHRoZSBHQ00gY2hhbm5lbCBvbiB0aGUgY3JlYXRlZCBFbmQgVXNlciBNZXNzYWdpbmdcbiAgICogKFBpbnBvaW50KSBhcHBsaWNhdGlvbi4gVGhlIHZhbHVlIGlzIGEgcGxhaW4gc3RyaW5nIOKAlCB0aGUgQW1wbGlmeSBHZW4yXG4gICAqIGZhY3RvcnkgcmVzb2x2ZXMgdGhlIHNlcnZpY2UtYWNjb3VudCBKU09OIGZyb20gYW4gQW1wbGlmeSBgc2VjcmV0KClgIGJlZm9yZVxuICAgKiBwYXNzaW5nIGl0IGhlcmUuIFdoZW4gb21pdHRlZCwgbm8gR0NNIGNoYW5uZWwgaXMgY29uZmlndXJlZC5cbiAgICovXG4gIHJlYWRvbmx5IGZjbUNoYW5uZWw/OiB7XG4gICAgLyoqIFRoZSBGQ00gSFRUUCB2MSBzZXJ2aWNlLWFjY291bnQgSlNPTiBjcmVkZW50aWFsIGNvbnRlbnRzLiAqL1xuICAgIHJlYWRvbmx5IHNlcnZpY2VKc29uOiBzdHJpbmc7XG4gIH07XG59O1xuXG4vKipcbiAqIEFtYXpvbiBDb25uZWN0IEN1c3RvbWVyIFByb2ZpbGVzIGJhY2tlbmQgZm9yIHRoZSBpZGVudGlmeVVzZXIgY29udHJhY3QsXG4gKiBwYWNrYWdlZCBhcyBhbiBBV1MgQ0RLIGNvbnN0cnVjdC4gUHJvdmlzaW9uczpcbiAqICAgLSBBbXBsaWZ5UHJvZmlsZSBvYmplY3QgdHlwZTogc2VhcmNoYWJsZSBgY29nbml0b1VzZXJLZXlgIChQUk9GSUxFICsgVU5JUVVFKVxuICogICAgIGlkZW50aXR5IGtleSArIHBlcnNvbiAvIHRhcmdldGluZyBhdHRyaWJ1dGUgc2NoZW1hLlxuICogICAtIEFtcGxpZnlEZXZpY2Ugb2JqZWN0IHR5cGU6IFBST0ZJTEUtcmVzb2x1dGlvbiBrZXkgPSBgY29nbml0b1VzZXJLZXlgLFxuICogICAgIFVOSVFVRSBvYmplY3Qga2V5ID0gc3RhYmxlIGBkZXZpY2VJZGA7IGRldmljZSBmaWVsZHMgc3RvcmVkIHJhdy5cbiAqICAgLSBpZGVudGlmeS11c2VyIExhbWJkYSB3aXRoIGxlYXN0LXByaXZpbGVnZSBwcm9maWxlOiogb24gdGhpcyBkb21haW4gb25seS5cbiAqICAgLSBIVFRQIEFQSSArIEpXVCBhdXRob3JpemVyIGJvdW5kIHRvIHRoZSBzdXBwbGllZCBpc3N1ZXIgLyBhdWRpZW5jZS5cbiAqICAgLSBwdXNoLWRlbGl2ZXJ5IExhbWJkYSAoQ29ubmVjdCBKb3VybmV5IEN1c3RvbS1hY3Rpb24gdGFyZ2V0KSArIGEgbWluaW1hbFxuICogICAgIEFXUyBFbmQgVXNlciBNZXNzYWdpbmcgKFBpbnBvaW50KSBhcHBsaWNhdGlvbiBmb3IgYFNlbmRNZXNzYWdlc2AuXG4gKlxuICogSXQgb3BlcmF0ZXMgaW4gb25lIG9mIHR3byBtb2RlcywgY2hvc2VuIGJ5IHdoZXRoZXIgYGRvbWFpbk5hbWVgIGlzIHByb3ZpZGVkOlxuICpcbiAqICAgLSBDUkVBVEUtRlJPTS1TQ1JBVENIIChkZWZhdWx0LCBgZG9tYWluTmFtZWAgb21pdHRlZCk6IHRoZSBjb25zdHJ1Y3QgYWxzb1xuICogICAgIHByb3Zpc2lvbnMgYSBicmFuZC1uZXcgQW1hem9uIENvbm5lY3QgaW5zdGFuY2UgKGBBV1M6OkNvbm5lY3Q6Okluc3RhbmNlYCxcbiAqICAgICBDT05ORUNUX01BTkFHRUQsIGluYm91bmQvb3V0Ym91bmQgZW5hYmxlZCkgQU5EIGEgYnJhbmQtbmV3IEN1c3RvbWVyXG4gKiAgICAgUHJvZmlsZXMgZG9tYWluIChgQVdTOjpDdXN0b21lclByb2ZpbGVzOjpEb21haW5gKSB3aXRoIGdlbmVyYXRlZCwgc3RhYmxlXG4gKiAgICAgbmFtZXMsIHRoZW4gcmVnaXN0ZXJzIHRoZSBvYmplY3QgdHlwZXMgSU5UTyB0aGF0IG5ldyBkb21haW4uIFRoZSBvYmplY3RcbiAqICAgICB0eXBlcyBkZXBlbmQgb24gdGhlIGNyZWF0ZWQgZG9tYWluIHNvIHRoZXkgcHJvdmlzaW9uIGFmdGVyIGl0IGFuZCBhcmUgdG9yblxuICogICAgIGRvd24gYmVmb3JlIGl0LiBBIGNhbGxlciBuZWVkcyB6ZXJvIHByZS1leGlzdGluZyBDb25uZWN0IHNldHVwLlxuICogICAtIEFUVEFDSCAoYGRvbWFpbk5hbWVgIHByb3ZpZGVkKTogdGhlIGNvbnN0cnVjdCByZWdpc3RlcnMgdGhlIHR3byBvYmplY3RcbiAqICAgICB0eXBlcyBJTlRPIHRoZSBleGlzdGluZyBgZG9tYWluTmFtZWAgKGFkZGl0aXZlKSDigJQgc3VjaCBhcyB0aGUgZG9tYWluXG4gKiAgICAgQW1hem9uIENvbm5lY3QgYXV0by1jcmVhdGVzIHdoZW4gQ3VzdG9tZXIgUHJvZmlsZXMgaXMgZW5hYmxlZCBvbiBhblxuICogICAgIGluc3RhbmNlIOKAlCBXSVRIT1VUIGNyZWF0aW5nIGFuIGluc3RhbmNlIG9yIGEgZG9tYWluLCBhbmQgd2l0aG91dCB0b3VjaGluZ1xuICogICAgIHRoZSBkb21haW4ncyBvdGhlciBpbnRlZ3JhdGlvbnMgKENUUiwgT3V0Ym91bmQgQ2FtcGFpZ25zKSBvciBpdHMgSWRlbnRpdHlcbiAqICAgICBSZXNvbHV0aW9uIHNldHRpbmcuXG4gKlxuICogSW4gZWl0aGVyIG1vZGUsIGlkZW50aWZ5IHdvcmtzIGFnYWluc3QgdGhlIGRvbWFpbiBzdGFuZGFsb25lLiBPdXRib3VuZFxuICogQ2FtcGFpZ25zIGFzc29jaWF0aW9uIOKAlCBzbyBqb3VybmV5cyBjYW4gdGFyZ2V0IHRoZXNlIHByb2ZpbGVzIOKAlCBpcyBBVVRPTUFUSUNcbiAqIGluIGNyZWF0ZS1mcm9tLXNjcmF0Y2ggbW9kZSAoYSBMYW1iZGEtYmFja2VkIGN1c3RvbSByZXNvdXJjZSBhc3NvY2lhdGVzIHRoZVxuICogbmV3IGRvbWFpbiB3aXRoIHRoZSBuZXcgaW5zdGFuY2UncyBPdXRib3VuZCBDYW1wYWlnbnMgdjIgYXQgZGVwbG95IHRpbWUpLiBJblxuICogYXR0YWNoIG1vZGUsIGFzc29jaWF0aW5nIHRoZSBwcmUtZXhpc3RpbmcgZG9tYWluIGlzIHRoZSB1c2VyJ3MgcmVzcG9uc2liaWxpdHlcbiAqIGFuZCBpcyBsZWZ0IHVudG91Y2hlZC5cbiAqXG4gKiBUaGlzIGNvbnN0cnVjdCBpcyBmcmFtZXdvcmstYWdub3N0aWMgKGF3cy1jZGstbGliICsgY29uc3RydWN0cyBvbmx5KS4gVGhlXG4gKiBgZGVmaW5lTm90aWZpY2F0aW9uc2AgZmFjdG9yeSB3cmFwcyBpdCBmb3IgQW1wbGlmeSBHZW4yIGJhY2tlbmRzLCB3aXJpbmcgdGhlXG4gKiBKV1QgYXV0aG9yaXplciB0byB0aGUgYXBwJ3MgQ29nbml0byB1c2VyIHBvb2wgYW5kIHN1cmZhY2luZyB0aGUgZW5kcG9pbnQgdmlhXG4gKiBiYWNrZW5kIG91dHB1dHMuXG4gKi9cbmV4cG9ydCBjbGFzcyBBbXBsaWZ5Tm90aWZpY2F0aW9uc1xuICBleHRlbmRzIENvbnN0cnVjdFxuICBpbXBsZW1lbnRzIFJlc291cmNlUHJvdmlkZXI8Tm90aWZpY2F0aW9uc1Jlc291cmNlcz4sIFN0YWNrUHJvdmlkZXJcbntcbiAgLyoqIENESyByZXNvdXJjZXMgZm9yIGxvd2VyLWxldmVsIGFjY2Vzcy4gKi9cbiAgcHVibGljIHJlYWRvbmx5IHJlc291cmNlczogTm90aWZpY2F0aW9uc1Jlc291cmNlcztcbiAgLyoqIFRoZSBzdGFjayB0aGlzIGNvbnN0cnVjdCBiZWxvbmdzIHRvLiAqL1xuICBwdWJsaWMgcmVhZG9ubHkgc3RhY2s6IFN0YWNrO1xuICAvKiogQmFzZSBpbnZva2UgVVJMLiBDbGllbnRzIGNhbGwgYFBPU1Qge2FwaUVuZHBvaW50fS9pZGVudGlmeS11c2VyYC4gKi9cbiAgcHVibGljIHJlYWRvbmx5IGFwaUVuZHBvaW50OiBzdHJpbmc7XG4gIC8qKiBUaGUgcm91dGUgcGF0aCBhcHBlbmRlZCB0byB7QGxpbmsgYXBpRW5kcG9pbnR9LiAqL1xuICBwdWJsaWMgcmVhZG9ubHkgaWRlbnRpZnlVc2VyUGF0aCA9ICcvaWRlbnRpZnktdXNlcic7XG4gIC8qKlxuICAgKiBUaGUgR1VFU1Qgcm91dGUgcGF0aCBhcHBlbmRlZCB0byB7QGxpbmsgYXBpRW5kcG9pbnR9LlxuICAgKiBJQU0vU2lnVjQtYXV0aG9yaXplZDsgdW5hdXRoZW50aWNhdGVkIElkZW50aXR5IFBvb2wgY2FsbGVycyBzaWduIHJlcXVlc3RzIHRvXG4gICAqIGBQT1NUIHthcGlFbmRwb2ludH0vaWRlbnRpZnktdXNlci1ndWVzdGAuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgZ3Vlc3RJZGVudGlmeVVzZXJQYXRoID0gJy9pZGVudGlmeS11c2VyLWd1ZXN0JztcbiAgLyoqXG4gICAqIFRoZSBgZXhlY3V0ZS1hcGk6SW52b2tlYCBBUk4gb2YgdGhlIEdVRVNUIHJvdXRlLCB0b1xuICAgKiBncmFudCB0byB0aGUgYXBwJ3MgQ29nbml0byBJZGVudGl0eSBQb29sIFVOQVVUSEVOVElDQVRFRCByb2xlIHNvIGd1ZXN0cyBjYW5cbiAgICogY2FsbCB0aGUgcm91dGUuIFNjb3BlZCB0byBQT1NUIG9uIHRoZSBndWVzdCBwYXRoIG9mIHRoaXMgQVBJJ3MgZGVmYXVsdFxuICAgKiBzdGFnZS5cbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBndWVzdFJvdXRlSW52b2tlQXJuITogc3RyaW5nO1xuICAvKiogVGhlIEN1c3RvbWVyIFByb2ZpbGVzIGRvbWFpbiBuYW1lIHRoZSBvYmplY3QgdHlwZXMgYXJlIHJlZ2lzdGVyZWQgaW50by4gKi9cbiAgcHVibGljIHJlYWRvbmx5IGRvbWFpbk5hbWU6IHN0cmluZztcbiAgLyoqXG4gICAqIGB0cnVlYCB3aGVuIHRoaXMgY29uc3RydWN0IGNyZWF0ZWQgdGhlIEN1c3RvbWVyIFByb2ZpbGVzIGRvbWFpbiArIENvbm5lY3RcbiAgICogaW5zdGFuY2UgKGNyZWF0ZS1mcm9tLXNjcmF0Y2ggbW9kZSk7IGBmYWxzZWAgd2hlbiBpdCBhdHRhY2hlZCB0byBhbiBleGlzdGluZ1xuICAgKiBkb21haW4gbmFtZWQgYnkgYGRvbWFpbk5hbWVgLlxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IGNyZWF0ZXNSZXNvdXJjZXM6IGJvb2xlYW47XG4gIC8qKlxuICAgKiBJZCBvZiB0aGUgQW1hem9uIENvbm5lY3QgaW5zdGFuY2UgY3JlYXRlZCBpbiBjcmVhdGUtZnJvbS1zY3JhdGNoIG1vZGUuXG4gICAqIGB1bmRlZmluZWRgIGluIGF0dGFjaCBtb2RlLlxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IGNvbm5lY3RJbnN0YW5jZUlkPzogc3RyaW5nO1xuICAvKipcbiAgICogQVJOIG9mIHRoZSBBbWF6b24gQ29ubmVjdCBpbnN0YW5jZSBjcmVhdGVkIGluIGNyZWF0ZS1mcm9tLXNjcmF0Y2ggbW9kZS5cbiAgICogYHVuZGVmaW5lZGAgaW4gYXR0YWNoIG1vZGUuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgY29ubmVjdEluc3RhbmNlQXJuPzogc3RyaW5nO1xuICAvKipcbiAgICogQVJOIG9mIHRoZSBwdXNoLWRlbGl2ZXJ5IExhbWJkYSwgdG8gd2lyZSBhcyBhIENvbm5lY3QgSm91cm5leSBDdXN0b20tYWN0aW9uXG4gICAqIChJbnZva2UgTGFtYmRhKSB0YXJnZXQuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgcHVzaEZ1bmN0aW9uQXJuOiBzdHJpbmc7XG4gIC8qKlxuICAgKiBUaGUgQVdTIEVuZCBVc2VyIE1lc3NhZ2luZyAvIFBpbnBvaW50IGFwcGxpY2F0aW9uIGlkIHRoaXMgY29uc3RydWN0IGNyZWF0ZWRcbiAgICogYW5kIHRoZSBwdXNoIExhbWJkYSBjYWxscyBgU2VuZE1lc3NhZ2VzYCBhZ2FpbnN0LlxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IGV1bUFwcGxpY2F0aW9uSWQ6IHN0cmluZztcblxuICAvKipcbiAgICogUmVnaXN0ZXJzIHRoZSBBbXBsaWZ5UHJvZmlsZSAvIEFtcGxpZnlEZXZpY2Ugb2JqZWN0IHR5cGVzIGludG8gdGhlIEN1c3RvbWVyXG4gICAqIFByb2ZpbGVzIGRvbWFpbiAoY3JlYXRlZCBoZXJlIGluIGNyZWF0ZS1mcm9tLXNjcmF0Y2ggbW9kZSwgb3IgdGhlIGV4aXN0aW5nXG4gICAqIGBkb21haW5OYW1lYCBpbiBhdHRhY2ggbW9kZSksIHRoZSBpZGVudGlmeS11c2VyIExhbWJkYSArIEpXVC1hdXRob3JpemVkIEhUVFBcbiAgICogQVBJLCBhbmQgdGhlIHB1c2gtZGVsaXZlcnkgTGFtYmRhICsgQVdTIEVuZCBVc2VyIE1lc3NhZ2luZyBhcHBsaWNhdGlvbiBmb3JcbiAgICogdGhpcyBub3RpZmljYXRpb25zIGJhY2tlbmQuXG4gICAqL1xuICBjb25zdHJ1Y3RvcihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCBwcm9wczogQW1wbGlmeU5vdGlmaWNhdGlvbnNQcm9wcykge1xuICAgIHN1cGVyKHNjb3BlLCBpZCk7XG5cbiAgICBjb25zdCBzdGFjayA9IFN0YWNrLm9mKHRoaXMpO1xuICAgIHRoaXMuc3RhY2sgPSBzdGFjaztcbiAgICBjb25zdCBleHBpcmF0aW9uRGF5cyA9IHByb3BzLmV4cGlyYXRpb25EYXlzID8/IERFRkFVTFRfRVhQSVJBVElPTl9EQVlTO1xuXG4gICAgLy8gLS0tLSBNb2RlIHNlbGVjdGlvbjogY3JlYXRlLWZyb20tc2NyYXRjaCAoZGVmYXVsdCkgdnMgYXR0YWNoIC0tLS0tLS0tLS0tXG4gICAgLy8gSWYgYSBgZG9tYWluTmFtZWAgaXMgc3VwcGxpZWQsIEFUVEFDSCB0aGUgb2JqZWN0IHR5cGVzIHRvIHRoYXQgZXhpc3RpbmdcbiAgICAvLyBkb21haW4gKGNyZWF0ZSBub3RoaW5nKS4gT3RoZXJ3aXNlICh0aGUgemVyby1jb25maWcgZGVmYXVsdCkgQ1JFQVRFIGFcbiAgICAvLyBicmFuZC1uZXcgQ29ubmVjdCBpbnN0YW5jZSArIEN1c3RvbWVyIFByb2ZpbGVzIGRvbWFpbiB3aXRoIGdlbmVyYXRlZCxcbiAgICAvLyBzdGFibGUgbmFtZXMgYW5kIHJlZ2lzdGVyIHRoZSBvYmplY3QgdHlwZXMgaW50byB0aGUgbmV3IGRvbWFpbi5cbiAgICBjb25zdCBjcmVhdGVGcm9tU2NyYXRjaCA9ICFwcm9wcy5kb21haW5OYW1lO1xuICAgIHRoaXMuY3JlYXRlc1Jlc291cmNlcyA9IGNyZWF0ZUZyb21TY3JhdGNoO1xuXG4gICAgbGV0IGRvbWFpbk5hbWU6IHN0cmluZztcbiAgICBsZXQgcHJvZmlsZXNEb21haW46IENmbkRvbWFpbiB8IHVuZGVmaW5lZDtcbiAgICBsZXQgY29ubmVjdEluc3RhbmNlOiBDZm5JbnN0YW5jZSB8IHVuZGVmaW5lZDtcblxuICAgIGlmIChjcmVhdGVGcm9tU2NyYXRjaCkge1xuICAgICAgLy8gRGV0ZXJtaW5pc3RpYy15ZXQtdW5pcXVlIGJhc2UgbmFtZSBkZXJpdmVkIGZyb20gdGhlIGNvbnN0cnVjdCdzIHNjb3BlIHNvXG4gICAgICAvLyBpdCBpcyBTVEFCTEUgYWNyb3NzIGRlcGxveS9kZWxldGUgKHNhbWUgdHJlZSDihpIgc2FtZSBuYW1lKSBhbmQgdW5pcXVlIHBlclxuICAgICAgLy8gYXBwIC8gZW52aXJvbm1lbnQgKHRoZSByb290IHN0YWNrIG5hbWUgZW1iZWRzIHRoZSBBbXBsaWZ5IGFwcCArIGJyYW5jaCkuXG4gICAgICBjb25zdCBiYXNlTmFtZSA9IHRoaXMuZ2VuZXJhdGVSZXNvdXJjZU5hbWUoKTtcbiAgICAgIGRvbWFpbk5hbWUgPSBiYXNlTmFtZTtcblxuICAgICAgY29ubmVjdEluc3RhbmNlID0gbmV3IENmbkluc3RhbmNlKHRoaXMsICdDb25uZWN0SW5zdGFuY2UnLCB7XG4gICAgICAgIC8vIE1pbmltYWwgdGVsZXBob255IHN1cmZhY2U6IENvbm5lY3QgcmVxdWlyZXMgYXQgbGVhc3Qgb25lIG9mXG4gICAgICAgIC8vIGluYm91bmQvb3V0Ym91bmQ7IGVuYWJsZSBib3RoIHNvIHRoZSBpbnN0YW5jZSBpcyB1c2FibGUgZm9yIG91dGJvdW5kXG4gICAgICAgIC8vIGpvdXJuZXlzIGxhdGVyLiBEaXJlY3RvcnkgaXMgQ29ubmVjdC1tYW5hZ2VkIChubyBleHRlcm5hbCBpZGVudGl0eSkuXG4gICAgICAgIC8vXG4gICAgICAgIC8vIGhpZ2hWb2x1bWVPdXRCb3VuZCBlbmFibGVzIHRoZSBpbnN0YW5jZSdzIE91dGJvdW5kIENhbXBhaWducyBmZWF0dXJlLlxuICAgICAgICAvLyBUaGlzIGlzIHdoYXQgbWFrZXMgQW1hem9uIENvbm5lY3QgYXR0YWNoIHRoZVxuICAgICAgICAvLyBgSGlnaFZvbHVtZU91dGJvdW5kQ29tbXVuaWNhdGlvbkFjY2Vzc2AgaW5saW5lIHBvbGljeSB0byB0aGUgaW5zdGFuY2Unc1xuICAgICAgICAvLyBPV04gc2VydmljZS1saW5rZWQgcm9sZSDigJQgdGhlIHBvbGljeSBncmFudGluZyB0aGUgYGNvbm5lY3QtY2FtcGFpZ25zOipgXG4gICAgICAgIC8vIChDcmVhdGVDYW1wYWlnbiAvIExpc3RDYW1wYWlnbnMgLyAuLi4pIGFjdGlvbnMgdGhlIENvbm5lY3QgY29uc29sZVxuICAgICAgICAvLyBkcml2ZXMgSm91cm5leSArIGNhbXBhaWduIGF1dGhvcmluZyB0aHJvdWdoLiBPbmJvYXJkaW5nIHRvIE91dGJvdW5kXG4gICAgICAgIC8vIENhbXBhaWducyB2MiAodGhlIGNhbXBhaWduLWFzc29jaWF0aW9uIGN1c3RvbSByZXNvdXJjZSkgZG9lcyBOT1Qgc2V0XG4gICAgICAgIC8vIGl0LCBzbyB3aXRob3V0IHRoaXMgdGhlIGNvbnNvbGUncyBKb3VybmV5IC8gc2VnbWVudCBidWlsZGVyIGZhaWxzIHdpdGhcbiAgICAgICAgLy8gY29ubmVjdC1jYW1wYWlnbnMgQWNjZXNzRGVuaWVkIG9uIHRoZSBpbnN0YW5jZSBTTFIuXG4gICAgICAgIGF0dHJpYnV0ZXM6IHtcbiAgICAgICAgICBpbmJvdW5kQ2FsbHM6IHRydWUsXG4gICAgICAgICAgb3V0Ym91bmRDYWxsczogdHJ1ZSxcbiAgICAgICAgICBoaWdoVm9sdW1lT3V0Qm91bmQ6IHRydWUsXG4gICAgICAgIH0sXG4gICAgICAgIGlkZW50aXR5TWFuYWdlbWVudFR5cGU6ICdDT05ORUNUX01BTkFHRUQnLFxuICAgICAgICBpbnN0YW5jZUFsaWFzOiB0aGlzLnNhbml0aXplSW5zdGFuY2VBbGlhcyhcbiAgICAgICAgICBwcm9wcy5pbnN0YW5jZUFsaWFzID8/IGJhc2VOYW1lLFxuICAgICAgICApLFxuICAgICAgfSk7XG5cbiAgICAgIHByb2ZpbGVzRG9tYWluID0gbmV3IENmbkRvbWFpbih0aGlzLCAnUHJvZmlsZXNEb21haW4nLCB7XG4gICAgICAgIGRvbWFpbk5hbWUsXG4gICAgICAgIGRlZmF1bHRFeHBpcmF0aW9uRGF5czogZXhwaXJhdGlvbkRheXMsXG4gICAgICB9KTtcblxuICAgICAgdGhpcy5jb25uZWN0SW5zdGFuY2VJZCA9IGNvbm5lY3RJbnN0YW5jZS5hdHRySWQ7XG4gICAgICB0aGlzLmNvbm5lY3RJbnN0YW5jZUFybiA9IGNvbm5lY3RJbnN0YW5jZS5hdHRyQXJuO1xuXG4gICAgICAvLyBJbnN0YW5jZS1sZXZlbCBDdXN0b21lciBQcm9maWxlcyBmZWF0dXJlIGJpbmRpbmc6IHJlZ2lzdGVycyB0aGUgY3JlYXRlZFxuICAgICAgLy8gZG9tYWluIGFzIHRoZSBpbnN0YW5jZSdzIENUUiAoY29udGFjdC1yZWNvcmQpIHByb2ZpbGVzIHN0b3JlIOKAlCB0aGVcbiAgICAgIC8vIFwiQ3VzdG9tZXIgUHJvZmlsZXMgZW5hYmxlZFwiIGludGVncmF0aW9uIHRoZSBDb25uZWN0IGNvbnNvbGUgYW5kIEpvdXJuZXlcbiAgICAgIC8vIHNlZ21lbnQgYnVpbGRlciByZXF1aXJlLCBkaXN0aW5jdCBmcm9tIHRoZSBPdXRib3VuZCBDYW1wYWlnbnNcbiAgICAgIC8vIGludGVncmF0aW9uIHRoZSBhc3NvY2lhdGlvbiBjdXN0b20gcmVzb3VyY2Ugd2lyZXMgYmVsb3cuIFB1dEludGVncmF0aW9uXG4gICAgICAvLyBhdXRvLXJlc29sdmVzIHRoZSBDb25uZWN0IHNlcnZpY2UtbGlua2VkIHJvbGUgZm9yIGEgY29ubmVjdC1pbnN0YW5jZVxuICAgICAgLy8gVVJJOyB0aGF0IFNMUiBjYW4gb25seSByZWFjaCB0aGUgZG9tYWluIGJlY2F1c2UgaXQgaXMgbmFtZWRcbiAgICAgIC8vIGBhbWF6b24tY29ubmVjdC0qYCAoc2VlIGdlbmVyYXRlUmVzb3VyY2VOYW1lKS5cbiAgICAgIGNvbnN0IGN0ckludGVncmF0aW9uID0gbmV3IENmbkludGVncmF0aW9uKFxuICAgICAgICB0aGlzLFxuICAgICAgICAnQ29ubmVjdFByb2ZpbGVzSW50ZWdyYXRpb24nLFxuICAgICAgICB7XG4gICAgICAgICAgZG9tYWluTmFtZSxcbiAgICAgICAgICB1cmk6IGNvbm5lY3RJbnN0YW5jZS5hdHRyQXJuLFxuICAgICAgICAgIG9iamVjdFR5cGVOYW1lOiAnQ1RSJyxcbiAgICAgICAgfSxcbiAgICAgICk7XG4gICAgICBjdHJJbnRlZ3JhdGlvbi5hZGREZXBlbmRlbmN5KGNvbm5lY3RJbnN0YW5jZSk7XG4gICAgICBjdHJJbnRlZ3JhdGlvbi5hZGREZXBlbmRlbmN5KHByb2ZpbGVzRG9tYWluKTtcblxuICAgICAgLy8gTWVzc2FnZS10ZW1wbGF0ZXMga25vd2xlZGdlIGJhc2UgKyBpdHMgaW5zdGFuY2UgYXNzb2NpYXRpb24uIEJvdGggdGhlXG4gICAgICAvLyBDb25uZWN0IGNvbnNvbGUncyBtZXNzYWdlLXRlbXBsYXRlIGF1dGhvcmluZyBVSSBhbmQgdGhlIHB1c2gtZGVsaXZlcnlcbiAgICAgIC8vIExhbWJkYSdzIHJ1bnRpbWUgZGlzY292ZXJ5IChMaXN0SW50ZWdyYXRpb25Bc3NvY2lhdGlvbnMgZmlsdGVyZWQgdG9cbiAgICAgIC8vIFFfTUVTU0FHRV9URU1QTEFURVMg4oaSIHRoZSBLQiBpdCByZW5kZXJzIHRlbXBsYXRlcyBmcm9tKSByZXF1aXJlIGFcbiAgICAgIC8vIE1FU1NBR0VfVEVNUExBVEVTIGtub3dsZWRnZSBiYXNlIGxpbmtlZCB0byB0aGUgaW5zdGFuY2UuIFdlIHByb3Zpc2lvblxuICAgICAgLy8gdGhlIGVtcHR5IEtCICsgdGhlIFFfTUVTU0FHRV9URU1QTEFURVMgYXNzb2NpYXRpb24gb25seTsgdGhlIHRlbXBsYXRlc1xuICAgICAgLy8gdGhlbXNlbHZlcyBhcmUgdGhlIG1hcmtldGVyJ3Mgam9iIChhIHRlbXBsYXRlJ3MgbmFtZSBtdXN0IG1hdGNoIHRoZVxuICAgICAgLy8gam91cm5leSBDdXN0b20tYWN0aW9uIGlkLCBlLmcuIFwiUHVzaCBOb3RpZmljYXRpb25cIikuIEEgTUVTU0FHRV9URU1QTEFURVNcbiAgICAgIC8vIEtCIG5lZWRzIG5vIFEgYXNzaXN0YW50LiBUaGUgbmFtZSBpcyBkZXJpdmVkIGZyb20gdGhlIHNhbWUgZGV0ZXJtaW5pc3RpY1xuICAgICAgLy8gYmFzZSBhcyB0aGUgaW5zdGFuY2UvZG9tYWluIHNvIHJlZGVwbG95cyBzdGF5IHN0YWJsZSBhbmQgYXZvaWQgdGhlXG4gICAgICAvLyBDcmVhdGVLbm93bGVkZ2VCYXNlIENvbmZsaWN0RXhjZXB0aW9uIG9uIGR1cGxpY2F0ZSBuYW1lcy5cbiAgICAgIGNvbnN0IHRlbXBsYXRlc0tiID0gbmV3IENmbktub3dsZWRnZUJhc2UodGhpcywgJ01lc3NhZ2VUZW1wbGF0ZXNLYicsIHtcbiAgICAgICAgbmFtZTogYCR7YmFzZU5hbWV9LW1lc3NhZ2UtdGVtcGxhdGVzYCxcbiAgICAgICAga25vd2xlZGdlQmFzZVR5cGU6ICdNRVNTQUdFX1RFTVBMQVRFUycsXG4gICAgICB9KTtcblxuICAgICAgY29uc3QgdGVtcGxhdGVzQXNzb2NpYXRpb24gPSBuZXcgQ2ZuSW50ZWdyYXRpb25Bc3NvY2lhdGlvbihcbiAgICAgICAgdGhpcyxcbiAgICAgICAgJ01lc3NhZ2VUZW1wbGF0ZXNBc3NvY2lhdGlvbicsXG4gICAgICAgIHtcbiAgICAgICAgICBpbnN0YW5jZUlkOiBjb25uZWN0SW5zdGFuY2UuYXR0ckFybixcbiAgICAgICAgICBpbnRlZ3JhdGlvblR5cGU6ICdRX01FU1NBR0VfVEVNUExBVEVTJyxcbiAgICAgICAgICBpbnRlZ3JhdGlvbkFybjogdGVtcGxhdGVzS2IuYXR0cktub3dsZWRnZUJhc2VBcm4sXG4gICAgICAgIH0sXG4gICAgICApO1xuICAgICAgdGVtcGxhdGVzQXNzb2NpYXRpb24uYWRkRGVwZW5kZW5jeShjb25uZWN0SW5zdGFuY2UpO1xuICAgICAgdGVtcGxhdGVzQXNzb2NpYXRpb24uYWRkRGVwZW5kZW5jeSh0ZW1wbGF0ZXNLYik7XG4gICAgfSBlbHNlIHtcbiAgICAgIGRvbWFpbk5hbWUgPSBwcm9wcy5kb21haW5OYW1lIGFzIHN0cmluZztcbiAgICB9XG4gICAgdGhpcy5kb21haW5OYW1lID0gZG9tYWluTmFtZTtcblxuICAgIC8vIC0tLS0gT2JqZWN0IHR5cGVzIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgIC8vIFJlZ2lzdGVyZWQgSU5UTyBgZG9tYWluTmFtZWAuIEluIGF0dGFjaCBtb2RlIHRoaXMgaXMgcHVyZWx5IGFkZGl0aXZlIHRvIGFcbiAgICAvLyBwcmUtZXhpc3RpbmcgKGUuZy4gQ29ubmVjdC1tYW5hZ2VkKSBkb21haW4uIEluIGNyZWF0ZSBtb2RlIHRoZSBvYmplY3RcbiAgICAvLyB0eXBlcyBkZXBlbmQgb24gdGhlIGRvbWFpbiBjcmVhdGVkIGFib3ZlLCBzbyBDRk4gcHJvdmlzaW9ucyB0aGUgZG9tYWluXG4gICAgLy8gZmlyc3QgYW5kIOKAlCBvbiB0ZWFyZG93biDigJQgcmVtb3ZlcyB0aGUgb2JqZWN0IHR5cGVzIGJlZm9yZSB0aGUgZG9tYWluIChhXG4gICAgLy8gY2xlYW4sIGluLWNvbnN0cnVjdCBkZXBlbmRlbmN5OyBubyBjcm9zcy1zdGFjayBvcmRlcmluZyBoYWNrIG5lZWRlZCkuXG4gICAgY29uc3QgcHJvZmlsZVR5cGUgPSBuZXcgQ2ZuT2JqZWN0VHlwZSh0aGlzLCAnQW1wbGlmeVByb2ZpbGVUeXBlJywge1xuICAgICAgZG9tYWluTmFtZSxcbiAgICAgIG9iamVjdFR5cGVOYW1lOiBPQkpFQ1RfVFlQRV9OQU1FUy5wcm9maWxlLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdBbXBsaWZ5IGlkZW50aWZ5VXNlciBwZXJzb24gcHJvZmlsZSAoZmluZC1vci1jcmVhdGUgYnkgdmVyaWZpZWQgQ29nbml0byBzdWIpJyxcbiAgICAgIGFsbG93UHJvZmlsZUNyZWF0aW9uOiB0cnVlLFxuICAgICAgZmllbGRzOiBBTVBMSUZZX1BST0ZJTEVfRklFTERTLFxuICAgICAga2V5czogQU1QTElGWV9QUk9GSUxFX0tFWVMsXG4gICAgICBleHBpcmF0aW9uRGF5cyxcbiAgICB9KTtcblxuICAgIGNvbnN0IGRldmljZVR5cGUgPSBuZXcgQ2ZuT2JqZWN0VHlwZSh0aGlzLCAnQW1wbGlmeURldmljZVR5cGUnLCB7XG4gICAgICBkb21haW5OYW1lLFxuICAgICAgb2JqZWN0VHlwZU5hbWU6IE9CSkVDVF9UWVBFX05BTUVTLmRldmljZSxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnQW1wbGlmeSBpZGVudGlmeVVzZXIgZGV2aWNlICh1bmlxdWUgcGVyIHN0YWJsZSBkZXZpY2VJZDsgdG9rZW4gaXMgYSBtdXRhYmxlIGZpZWxkOyByZXNvbHZlcyB0byBwcm9maWxlIGJ5IGNvZ25pdG9Vc2VyS2V5KScsXG4gICAgICBhbGxvd1Byb2ZpbGVDcmVhdGlvbjogdHJ1ZSxcbiAgICAgIGZpZWxkczogQU1QTElGWV9ERVZJQ0VfRklFTERTLFxuICAgICAga2V5czogQU1QTElGWV9ERVZJQ0VfS0VZUyxcbiAgICAgIGV4cGlyYXRpb25EYXlzLFxuICAgIH0pO1xuXG4gICAgLy8gQSBkaXN0aW5jdCBvYmplY3QgdHlwZSBmb3IgR1VFU1QgcHJvZmlsZXMuIEN1c3RvbWVyXG4gICAgLy8gUHJvZmlsZXMgcGVybWl0cyBleGFjdGx5IG9uZSBVTklRVUUga2V5IHBlciBvYmplY3QgdHlwZSBhbmQgUHV0UHJvZmlsZU9iamVjdFxuICAgIC8vIHJlcXVpcmVzIHRoZSBpbmdlc3RlZCBvYmplY3QgdG8gY2FycnkgaXQ7IHRoZSBhdXRoZWQgQW1wbGlmeVByb2ZpbGUgcmVzZXJ2ZXNcbiAgICAvLyBpdHMgVU5JUVVFIGtleSBmb3IgY29nbml0b1N1Yiwgc28gZ3Vlc3QgcHJvZmlsZXMgKGtleWVkIG9uIHRoZSBJZGVudGl0eSBQb29sXG4gICAgLy8gY29nbml0b0lkZW50aXR5SWQpIGdldCB0aGVpciBvd24gdHlwZSB3aXRoIGNvZ25pdG9JZGVudGl0eUtleSBhcyBVTklRVUUuXG4gICAgY29uc3QgZ3Vlc3RQcm9maWxlVHlwZSA9IG5ldyBDZm5PYmplY3RUeXBlKFxuICAgICAgdGhpcyxcbiAgICAgICdBbXBsaWZ5R3Vlc3RQcm9maWxlVHlwZScsXG4gICAgICB7XG4gICAgICAgIGRvbWFpbk5hbWUsXG4gICAgICAgIG9iamVjdFR5cGVOYW1lOiBPQkpFQ1RfVFlQRV9OQU1FUy5ndWVzdFByb2ZpbGUsXG4gICAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAgICdBbXBsaWZ5IGlkZW50aWZ5VXNlciBHVUVTVCBwZXJzb24gcHJvZmlsZSAoZmluZC1vci1jcmVhdGUgYnkgdmVyaWZpZWQgQ29nbml0byBJZGVudGl0eSBQb29sIGlkZW50aXR5SWQpJyxcbiAgICAgICAgYWxsb3dQcm9maWxlQ3JlYXRpb246IHRydWUsXG4gICAgICAgIGZpZWxkczogQU1QTElGWV9HVUVTVF9QUk9GSUxFX0ZJRUxEUyxcbiAgICAgICAga2V5czogQU1QTElGWV9HVUVTVF9QUk9GSUxFX0tFWVMsXG4gICAgICAgIGV4cGlyYXRpb25EYXlzLFxuICAgICAgfSxcbiAgICApO1xuXG4gICAgaWYgKHByb2ZpbGVzRG9tYWluKSB7XG4gICAgICBwcm9maWxlVHlwZS5hZGREZXBlbmRlbmN5KHByb2ZpbGVzRG9tYWluKTtcbiAgICAgIGRldmljZVR5cGUuYWRkRGVwZW5kZW5jeShwcm9maWxlc0RvbWFpbik7XG4gICAgICBndWVzdFByb2ZpbGVUeXBlLmFkZERlcGVuZGVuY3kocHJvZmlsZXNEb21haW4pO1xuICAgIH1cblxuICAgIC8vIC0tLS0gT3V0Ym91bmQgQ2FtcGFpZ25zIGFzc29jaWF0aW9uIChjcmVhdGUtZnJvbS1zY3JhdGNoIE9OTFkpIC0tLS0tLS0tLS1cbiAgICAvLyBXaGVuIHRoaXMgY29uc3RydWN0IGNyZWF0ZWQgdGhlIGluc3RhbmNlICsgZG9tYWluLCBhIExhbWJkYS1iYWNrZWQgY3VzdG9tXG4gICAgLy8gcmVzb3VyY2UgYXNzb2NpYXRlcyB0aGUgbmV3IGRvbWFpbiB3aXRoIHRoZSBpbnN0YW5jZSdzIE91dGJvdW5kIENhbXBhaWduc1xuICAgIC8vIHYyIGF0IGRlcGxveSB0aW1lIOKAlCBzbyBDb25uZWN0IEpvdXJuZXlzIGNhbiB0YXJnZXQgdGhlIGRvbWFpbidzIHByb2ZpbGVzXG4gICAgLy8gd2l0aCBOTyBtYW51YWwgY29uc29sZSBzdGVwLiBJbiBhdHRhY2ggbW9kZSB0aGUgZXhpc3RpbmcgZG9tYWluJ3NcbiAgICAvLyBhc3NvY2lhdGlvbiBpcyB0aGUgdXNlcidzIHJlc3BvbnNpYmlsaXR5LCBzbyB0aGlzIHJlc291cmNlIGlzIE5PVCBhZGRlZC5cbiAgICBpZiAoY3JlYXRlRnJvbVNjcmF0Y2ggJiYgY29ubmVjdEluc3RhbmNlICYmIHByb2ZpbGVzRG9tYWluKSB7XG4gICAgICB0aGlzLmFkZENhbXBhaWduQXNzb2NpYXRpb24oXG4gICAgICAgIGNvbm5lY3RJbnN0YW5jZSxcbiAgICAgICAgcHJvZmlsZXNEb21haW4sXG4gICAgICAgIGRvbWFpbk5hbWUsXG4gICAgICAgIHByb3BzLmNhbXBhaWduQXNzb2NpYXRpb25MYW1iZGFDb2RlUGF0aCA/P1xuICAgICAgICAgIGRlZmF1bHRDYW1wYWlnbkFzc29jaWF0aW9uTGFtYmRhQ29kZVBhdGgsXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIC0tLS0gTGFtYmRhIGhhbmRsZXIgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgIC8vIFByZS1idW5kbGVkIGF0IGJ1aWxkIHRpbWUgKGVzYnVpbGQpIGludG8gYSBzZWxmLWNvbnRhaW5lZCBhc3NldCwgc28gdGhlXG4gICAgLy8gY29uc3RydWN0IHdvcmtzIHJlZ2FyZGxlc3Mgb2YgdGhlIGNvbnN1bWluZyBwcm9qZWN0J3Mgcm9vdCAoQW1wbGlmeSdzXG4gICAgLy8gTm9kZWpzRnVuY3Rpb24gZ3VhcmRyYWlsIGZvcmJpZHMgYW4gZW50cnkgb3V0c2lkZSB0aGUgYXBwIHJvb3QpLlxuICAgIGNvbnN0IGNvZGVQYXRoID0gcHJvcHMubGFtYmRhQ29kZVBhdGggPz8gZGVmYXVsdExhbWJkYUNvZGVQYXRoO1xuXG4gICAgY29uc3QgZm4gPSBuZXcgbGFtYmRhLkZ1bmN0aW9uKHRoaXMsICdJZGVudGlmeVVzZXJGbicsIHtcbiAgICAgIGNvZGU6IGxhbWJkYS5Db2RlLmZyb21Bc3NldChjb2RlUGF0aCksXG4gICAgICBoYW5kbGVyOiAnaW5kZXguaGFuZGxlcicsXG4gICAgICBydW50aW1lOiBsYW1iZGEuUnVudGltZS5OT0RFSlNfMjBfWCxcbiAgICAgIHRpbWVvdXQ6IER1cmF0aW9uLnNlY29uZHMoMTUpLFxuICAgICAgbWVtb3J5U2l6ZTogMjU2LFxuICAgICAgZW52aXJvbm1lbnQ6IHtcbiAgICAgICAgW0VOVl9ET01BSU5fTkFNRV06IGRvbWFpbk5hbWUsXG4gICAgICB9LFxuICAgIH0pO1xuXG4gICAgLy8gLS0tLSBMZWFzdC1wcml2aWxlZ2UgSUFNIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgICBjb25zdCBkb21haW5Bcm4gPSBBcm4uZm9ybWF0KFxuICAgICAge1xuICAgICAgICBzZXJ2aWNlOiAncHJvZmlsZScsXG4gICAgICAgIHJlc291cmNlOiAnZG9tYWlucycsXG4gICAgICAgIHJlc291cmNlTmFtZTogZG9tYWluTmFtZSxcbiAgICAgICAgYXJuRm9ybWF0OiBBcm5Gb3JtYXQuU0xBU0hfUkVTT1VSQ0VfTkFNRSxcbiAgICAgIH0sXG4gICAgICBzdGFjayxcbiAgICApO1xuICAgIGNvbnN0IG9iamVjdFR5cGVzQXJuID0gQXJuLmZvcm1hdChcbiAgICAgIHtcbiAgICAgICAgc2VydmljZTogJ3Byb2ZpbGUnLFxuICAgICAgICByZXNvdXJjZTogJ2RvbWFpbnMnLFxuICAgICAgICByZXNvdXJjZU5hbWU6IGAke2RvbWFpbk5hbWV9L29iamVjdC10eXBlcy8qYCxcbiAgICAgICAgYXJuRm9ybWF0OiBBcm5Gb3JtYXQuU0xBU0hfUkVTT1VSQ0VfTkFNRSxcbiAgICAgIH0sXG4gICAgICBzdGFjayxcbiAgICApO1xuICAgIGZuLmFkZFRvUm9sZVBvbGljeShcbiAgICAgIG5ldyBpYW0uUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgZWZmZWN0OiBpYW0uRWZmZWN0LkFMTE9XLFxuICAgICAgICBhY3Rpb25zOiBbXG4gICAgICAgICAgLy8gUHV0UHJvZmlsZU9iamVjdCBmaW5kLW9yLWNyZWF0ZSAoQW1wbGlmeVByb2ZpbGUpICsgcmVhZC1iYWNrLlxuICAgICAgICAgICdwcm9maWxlOlB1dFByb2ZpbGVPYmplY3QnLFxuICAgICAgICAgICdwcm9maWxlOlNlYXJjaFByb2ZpbGVzJyxcbiAgICAgICAgICAvLyBSZWFkIGJhY2sgdGhlIGV4aXN0aW5nIGRldmljZSBvYmplY3QgdG8gcHJlc2VydmUgaW1tdXRhYmxlIGNyZWF0ZWRBdC5cbiAgICAgICAgICAncHJvZmlsZTpMaXN0UHJvZmlsZU9iamVjdHMnLFxuICAgICAgICAgIC8vIFNldCB0YXJnZXRpbmcgLyBwZXJzb24gYXR0cmlidXRlcyBvbiB0aGUgcmVzb2x2ZWQgcHJvZmlsZS5cbiAgICAgICAgICAncHJvZmlsZTpVcGRhdGVQcm9maWxlJyxcbiAgICAgICAgXSxcbiAgICAgICAgcmVzb3VyY2VzOiBbZG9tYWluQXJuLCBvYmplY3RUeXBlc0Fybl0sXG4gICAgICB9KSxcbiAgICApO1xuXG4gICAgLy8gTWVyZ2Utb24tc2lnbi1pbiBmb2xkcyBhIHByaW9yIGd1ZXN0IHByb2ZpbGVcbiAgICAvLyAoKyBpdHMgZGV2aWNlIG9iamVjdHMpIGludG8gdGhlIGF1dGhlZCBwcm9maWxlIHZpYSBNZXJnZVByb2ZpbGVzLlxuICAgIC8vIE5PVEU6IHRoZSBTZXJ2aWNlIEF1dGhvcml6YXRpb24gUmVmZXJlbmNlIGxpc3RzIE1lcmdlUHJvZmlsZXMgdW5kZXIgdGhlXG4gICAgLy8gYGRvbWFpbnNgIHJlc291cmNlIHR5cGUsIGJ1dCB0aGUgc2VydmljZSBBQ1RVQUxMWSBhdXRob3JpemVzIGl0IGFnYWluc3RcbiAgICAvLyBhbiB1bmRvY3VtZW50ZWQsIGRpZmZlcmVudGx5LXNoYXBlZCByZXNvdXJjZSBBUk4gKG5vdGUgdGhlIGxlYWRpbmcgc2xhc2hcbiAgICAvLyBhbmQgdGhlIC9wcm9maWxlcy9vYmplY3RzL21lcmdlIHN1ZmZpeCk6XG4gICAgLy8gICBhcm46PHBhcnRpdGlvbj46cHJvZmlsZTo8cmVnaW9uPjo8YWNjb3VudD46L2RvbWFpbnMvPGRvbWFpbj4vcHJvZmlsZXMvb2JqZWN0cy9tZXJnZVxuICAgIC8vIEdyYW50aW5nIHRoZSBkb2N1bWVudGVkIGRvbWFpbiBBUk4gaXMgTk9UIHN1ZmZpY2llbnQuIFRoaXMgZGVkaWNhdGVkXG4gICAgLy8gc3RhdGVtZW50IHRhcmdldHMgdGhlIGVuZm9yY2VkIHJlc291cmNlLlxuICAgIGNvbnN0IG1lcmdlUHJvZmlsZXNBcm4gPSBgYXJuOiR7c3RhY2sucGFydGl0aW9ufTpwcm9maWxlOiR7c3RhY2sucmVnaW9ufToke3N0YWNrLmFjY291bnR9Oi9kb21haW5zLyR7ZG9tYWluTmFtZX0vcHJvZmlsZXMvb2JqZWN0cy9tZXJnZWA7XG4gICAgZm4uYWRkVG9Sb2xlUG9saWN5KFxuICAgICAgbmV3IGlhbS5Qb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICBlZmZlY3Q6IGlhbS5FZmZlY3QuQUxMT1csXG4gICAgICAgIGFjdGlvbnM6IFsncHJvZmlsZTpNZXJnZVByb2ZpbGVzJ10sXG4gICAgICAgIHJlc291cmNlczogW21lcmdlUHJvZmlsZXNBcm5dLFxuICAgICAgfSksXG4gICAgKTtcblxuICAgIC8vIC0tLS0gSFRUUCBBUEkgKyBKV1QgYXV0aG9yaXplciAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgY29uc3QgYXV0aG9yaXplciA9IG5ldyBIdHRwSnd0QXV0aG9yaXplcignSnd0QXV0aG9yaXplcicsIHByb3BzLmp3dElzc3Vlciwge1xuICAgICAgand0QXVkaWVuY2U6IHByb3BzLmp3dEF1ZGllbmNlLFxuICAgICAgaWRlbnRpdHlTb3VyY2U6IFsnJHJlcXVlc3QuaGVhZGVyLkF1dGhvcml6YXRpb24nXSxcbiAgICB9KTtcblxuICAgIGNvbnN0IGh0dHBBcGkgPSBuZXcgYXBpZ3d2Mi5IdHRwQXBpKHRoaXMsICdJZGVudGlmeVVzZXJBcGknLCB7XG4gICAgICBhcGlOYW1lOiAnaWRlbnRpZnktdXNlci1hcGknLFxuICAgICAgY3JlYXRlRGVmYXVsdFN0YWdlOiB0cnVlLFxuICAgIH0pO1xuXG4gICAgaHR0cEFwaS5hZGRSb3V0ZXMoe1xuICAgICAgcGF0aDogdGhpcy5pZGVudGlmeVVzZXJQYXRoLFxuICAgICAgbWV0aG9kczogW2FwaWd3djIuSHR0cE1ldGhvZC5QT1NUXSxcbiAgICAgIGludGVncmF0aW9uOiBuZXcgSHR0cExhbWJkYUludGVncmF0aW9uKCdJZGVudGlmeVVzZXJJbnRlZ3JhdGlvbicsIGZuKSxcbiAgICAgIGF1dGhvcml6ZXIsXG4gICAgfSk7XG5cbiAgICAvLyAtLS0tIEd1ZXN0ICh1bmF1dGhlbnRpY2F0ZWQpIHJvdXRlIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgIC8vIEEgc2Vjb25kIHJvdXRlIHRvIHRoZSBTQU1FIGlkZW50aWZ5IExhbWJkYSwgYnV0XG4gICAgLy8gYXV0aG9yaXplZCB3aXRoIElBTS9TaWdWNCBpbnN0ZWFkIG9mIGEgSldUIOKAlCBzbyBhbiBVTkFVVEhFTlRJQ0FURUQgQ29nbml0b1xuICAgIC8vIElkZW50aXR5IFBvb2wgY2FsbGVyIChndWVzdCBjcmVkZW50aWFscykgY2FuIHJlZ2lzdGVyIGEgZGV2aWNlIC8gc2VlZCBhXG4gICAgLy8gcHJvZmlsZSBCRUZPUkUgbG9naW4gKHRoZSBwcmUtbG9naW4gcHVzaC10b2tlbiBjYXNlKS5cbiAgICAvL1xuICAgIC8vIFRoZSBpbnRlZ3JhdGlvbiBNVVNUIHVzZSBwYXlsb2FkIGZvcm1hdCAxLjA6IEhUVFAgQVBJIHBheWxvYWQgZm9ybWF0IDIuMFxuICAgIC8vIGhhcyBOTyBgcmVxdWVzdENvbnRleHQuaWRlbnRpdHlgIGJsb2NrLCBzbyB0aGUgdmVyaWZpZWQgQ29nbml0b1xuICAgIC8vIGBjb2duaXRvSWRlbnRpdHlJZGAgKCsgYGNvZ25pdG9BdXRoZW50aWNhdGlvblR5cGVgKSB0aGUgTGFtYmRhIGtleXMgdGhlXG4gICAgLy8gZ3Vlc3QgcHJvZmlsZSBvbiBpcyBvbmx5IHByZXNlbnQgdW5kZXIgZm9ybWF0IDEuMC4gVGhlIExhbWJkYSBkZXJpdmVzIHRoZVxuICAgIC8vIGd1ZXN0IGlkZW50aXR5IFNPTEVMWSBmcm9tIHRoYXQgYXV0aG9yaXplci12ZXJpZmllZCBmaWVsZC5cbiAgICBjb25zdCBpYW1BdXRob3JpemVyID0gbmV3IEh0dHBJYW1BdXRob3JpemVyKCk7XG4gICAgaHR0cEFwaS5hZGRSb3V0ZXMoe1xuICAgICAgcGF0aDogdGhpcy5ndWVzdElkZW50aWZ5VXNlclBhdGgsXG4gICAgICBtZXRob2RzOiBbYXBpZ3d2Mi5IdHRwTWV0aG9kLlBPU1RdLFxuICAgICAgaW50ZWdyYXRpb246IG5ldyBIdHRwTGFtYmRhSW50ZWdyYXRpb24oJ0d1ZXN0SWRlbnRpZnlJbnRlZ3JhdGlvbicsIGZuLCB7XG4gICAgICAgIHBheWxvYWRGb3JtYXRWZXJzaW9uOiBhcGlnd3YyLlBheWxvYWRGb3JtYXRWZXJzaW9uLlZFUlNJT05fMV8wLFxuICAgICAgfSksXG4gICAgICBhdXRob3JpemVyOiBpYW1BdXRob3JpemVyLFxuICAgIH0pO1xuXG4gICAgLy8gYGV4ZWN1dGUtYXBpOkludm9rZWAgQVJOIGZvciB0aGUgZ3Vlc3Qgcm91dGUg4oCUIHRoZSBhcHAgZ3JhbnRzIHRoaXMgdG8gaXRzXG4gICAgLy8gSWRlbnRpdHkgUG9vbCBVTkFVVEhFTlRJQ0FURUQgcm9sZSBzbyBndWVzdHMgY2FuIGNhbGwgdGhlIHJvdXRlLiBTY29wZWQgYXNcbiAgICAvLyB0aWdodGx5IGFzIGV4ZWN1dGUtYXBpIGFsbG93czogYCRkZWZhdWx0L1BPU1QvaWRlbnRpZnktdXNlci1ndWVzdGAgcGlucyB0aGVcbiAgICAvLyBncmFudCB0byB0aGUgUE9TVCBtZXRob2Qgb24gdGhlIGd1ZXN0IHBhdGggb2YgdGhlIEFQSSdzIHNpbmdsZSBkZWZhdWx0XG4gICAgLy8gc3RhZ2UsIHNvIHRoZSB1bmF1dGggcm9sZSBjYW4gaW52b2tlIE5FSVRIRVIgb3RoZXIgbWV0aG9kcywgTk9SIG90aGVyXG4gICAgLy8gc3RhZ2VzLCBOT1IgdGhlIGF1dGhlZCBgL2lkZW50aWZ5LXVzZXJgIHJvdXRlLiAoSFRUUCBBUElzIGF1dG8tY3JlYXRlIHRoZVxuICAgIC8vIGAkZGVmYXVsdGAgc3RhZ2U7IHRoaXMgY29uc3RydWN0IG5ldmVyIGFkZHMgYW5vdGhlci4pXG4gICAgdGhpcy5ndWVzdFJvdXRlSW52b2tlQXJuID0gQXJuLmZvcm1hdChcbiAgICAgIHtcbiAgICAgICAgc2VydmljZTogJ2V4ZWN1dGUtYXBpJyxcbiAgICAgICAgcmVzb3VyY2U6IGh0dHBBcGkuYXBpSWQsXG4gICAgICAgIHJlc291cmNlTmFtZTogYCRkZWZhdWx0L1BPU1Qke3RoaXMuZ3Vlc3RJZGVudGlmeVVzZXJQYXRofWAsXG4gICAgICAgIGFybkZvcm1hdDogQXJuRm9ybWF0LlNMQVNIX1JFU09VUkNFX05BTUUsXG4gICAgICB9LFxuICAgICAgc3RhY2ssXG4gICAgKTtcblxuICAgIHRoaXMuYXBpRW5kcG9pbnQgPSBodHRwQXBpLmFwaUVuZHBvaW50O1xuXG4gICAgLy8gU2NvcGVkIHRvIHRoZSBzdGFjayAobm90IGB0aGlzYCkgc28gdGhlIG91dHB1dCBrZWVwcyBhIHN0YWJsZSwgcmVhZGFibGVcbiAgICAvLyBsb2dpY2FsIGlkIChgSWRlbnRpZnlVc2VyQXBpRW5kcG9pbnRgKSB0aGF0IGEgaHVtYW4gY2FuIGZpbmQgaW4gdGhlXG4gICAgLy8gQ2xvdWRGb3JtYXRpb24gY29uc29sZS4gVGhlIGNvbnN0cnVjdCBpcyBwcm92aXNpb25lZCBvbmNlIHBlciBzdGFjayAodGhlXG4gICAgLy8gR2VuMiBmYWN0b3J5IHBsYWNlcyBpdCBpbiBhIGRlZGljYXRlZCBuZXN0ZWQgc3RhY2spLCBzbyB0aGVyZSBpcyBub1xuICAgIC8vIGNvbGxpc2lvbiByaXNrIGZyb20gdGhlIHZlcmJhdGltIGlkLlxuICAgIG5ldyBDZm5PdXRwdXQoc3RhY2ssICdJZGVudGlmeVVzZXJBcGlFbmRwb2ludCcsIHtcbiAgICAgIHZhbHVlOiBodHRwQXBpLmFwaUVuZHBvaW50LFxuICAgICAgZGVzY3JpcHRpb246ICdQT1NUIHt2YWx1ZX0vaWRlbnRpZnktdXNlcicsXG4gICAgfSk7XG5cbiAgICAvLyBTdXJmYWNlIHRoZSBndWVzdCByb3V0ZSdzIGludm9rZSBBUk4gc28gYSBodW1hbiAvXG4gICAgLy8gdGhlIGFwcCBjYW4gZ3JhbnQgaXQgdG8gdGhlIElkZW50aXR5IFBvb2wgdW5hdXRoZW50aWNhdGVkIHJvbGUuXG4gICAgbmV3IENmbk91dHB1dChzdGFjaywgJ0d1ZXN0SWRlbnRpZnlSb3V0ZUludm9rZUFybicsIHtcbiAgICAgIHZhbHVlOiB0aGlzLmd1ZXN0Um91dGVJbnZva2VBcm4sXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0dyYW50IGV4ZWN1dGUtYXBpOkludm9rZSBvbiB0aGlzIEFSTiB0byB0aGUgQ29nbml0byBJZGVudGl0eSBQb29sIHVuYXV0aGVudGljYXRlZCByb2xlJyxcbiAgICB9KTtcblxuICAgIC8vIC0tLS0gUHVzaC1kZWxpdmVyeSBwYXRoIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgLy8gQW1hem9uIENvbm5lY3QgaGFzIG5vIG5hdGl2ZSBtb2JpbGUtcHVzaCBjaGFubmVsLCBzbyBhIExhbWJkYSBicmlkZ2VzIHRoZVxuICAgIC8vIGdhcDogQ29ubmVjdCBpbnZva2VzIGl0IHZpYSBhIEpvdXJuZXkgQ3VzdG9tLWFjdGlvbiB0byBkZWxpdmVyIHB1c2hcbiAgICAvLyB0aHJvdWdoIEFXUyBFbmQgVXNlciBNZXNzYWdpbmcgKFBpbnBvaW50IFNlbmRNZXNzYWdlcykuIEEgbWluaW1hbCBQaW5wb2ludFxuICAgIC8vIGFwcGxpY2F0aW9uIGlzIGFsd2F5cyBjcmVhdGVkIHNvIFNlbmRNZXNzYWdlcyBoYXMgYSB2YWxpZCBBcHBsaWNhdGlvbklkLlxuICAgIC8vIFRoZSBBUE5zIC8gR0NNIGNoYW5uZWxzIG9uIGl0IGFyZSBjb25maWd1cmVkIG9ubHkgd2hlbiB0aGUgY2FsbGVyIHN1cHBsaWVzXG4gICAgLy8gY3JlZGVudGlhbHMgKHNlZSBgYXBuc0NoYW5uZWxgIC8gYGZjbUNoYW5uZWxgKTsgb3RoZXJ3aXNlIHRoZSBhcHBsaWNhdGlvblxuICAgIC8vIGlzIGNyZWF0ZWQgd2l0aCBubyBjaGFubmVsIGVuYWJsZWQgKGRlbGl2ZXJ5IHdpbGwgNDA0IHVudGlsIGNvbmZpZ3VyZWQpLlxuICAgIGNvbnN0IHB1c2hBcHBsaWNhdGlvbiA9IG5ldyBDZm5BcHAodGhpcywgJ1B1c2hBcHAnLCB7XG4gICAgICBuYW1lOiBgJHtkb21haW5OYW1lfS1wdXNoYCxcbiAgICB9KTtcbiAgICBjb25zdCBldW1BcHBsaWNhdGlvbklkID0gcHVzaEFwcGxpY2F0aW9uLnJlZjtcbiAgICB0aGlzLmV1bUFwcGxpY2F0aW9uSWQgPSBldW1BcHBsaWNhdGlvbklkO1xuXG4gICAgLy8gLS0tLSBPcHRpb25hbCBwdXNoIGNoYW5uZWxzIChzZWNyZXQtZHJpdmVuKSAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgICAvLyBUaGUgQW1wbGlmeSBHZW4yIGZhY3RvcnkgcmVzb2x2ZXMgdGhlIEFQTnMgYC5wOGAga2V5IC8gRkNNIHNlcnZpY2UtYWNjb3VudFxuICAgIC8vIEpTT04gZnJvbSBBbXBsaWZ5IGBzZWNyZXQoKWBzIHRvIGRlcGxveS10aW1lIENGTiB0b2tlbnMgYW5kIHBhc3NlcyB0aGVtIGFzXG4gICAgLy8gcGxhaW4gc3RyaW5ncy4gQ2hhbm5lbCBjcmVkZW50aWFscyBmbG93IHRocm91Z2ggQ2xvdWRGb3JtYXRpb24gdGhlIHNhbWUgd2F5XG4gICAgLy8gQW1wbGlmeSdzIG93biBleHRlcm5hbC1hdXRoLXByb3ZpZGVyIHNlY3JldHMgZG8gKGRlZmluZUF1dGgpIOKAlCB2aWEgdGhlXG4gICAgLy8gc2VjcmV0IGN1c3RvbSByZXNvdXJjZSdzIHRva2VuLCBuZXZlciBhcyBsaXRlcmFsIHRlbXBsYXRlIHBsYWluIHRleHQuIFRoZVxuICAgIC8vIGNoYW5uZWxzIGF0dGFjaCB0byBUSElTIGNvbnN0cnVjdCdzIG93biBFVU0gYXBwLCBzbyB0aGV5IGFyZSBwcm92aXNpb25lZFxuICAgIC8vIGFmdGVyIGl0IGFuZCB0b3JuIGRvd24gd2l0aCB0aGUgc3RhY2suIFRoZSBgYXBwbGljYXRpb25JZGAgcHJvcCByZXNvbHZlcyB0b1xuICAgIC8vIGEgYFJlZmAgb24gdGhlIEVVTSBhcHAsIHNvIENsb3VkRm9ybWF0aW9uIGluZmVycyB0aGUgY3JlYXRlL2RlbGV0ZSBvcmRlcmluZ1xuICAgIC8vIOKAlCBubyBleHBsaWNpdCBgYWRkRGVwZW5kZW5jeWAgbmVlZGVkLlxuICAgIGNvbnN0IHsgYXBuc0NoYW5uZWw6IGFwbnNDb25maWcsIGZjbUNoYW5uZWw6IGZjbUNvbmZpZyB9ID0gcHJvcHM7XG5cbiAgICBsZXQgYXBuc0NoYW5uZWw6IENmbkFQTlNDaGFubmVsIHwgQ2ZuQVBOU1NhbmRib3hDaGFubmVsIHwgdW5kZWZpbmVkO1xuICAgIGlmIChhcG5zQ29uZmlnKSB7XG4gICAgICAvLyBUb2tlbiAoYC5wOGApIGF1dGhlbnRpY2F0aW9uOiB0aGUgQ0ZOIGBEZWZhdWx0QXV0aGVudGljYXRpb25NZXRob2RgXG4gICAgICAvLyBwcm9wZXJ0eSBhY2NlcHRzIGBUT0tFTmAgKHNpZ25pbmcta2V5IGF1dGgpIG9yIGBDRVJUSUZJQ0FURWA7IHRva2VuIGF1dGhcbiAgICAgIC8vIHVzZXMgdGhlIGAucDhgIHNpZ25pbmcga2V5LiBTYW5kYm94IHNlbGVjdHMgdGhlIGRldmVsb3BtZW50IEFQTnMgZW5kcG9pbnRcbiAgICAgIC8vIHVzZWQgYnkgZGV2ZWxvcG1lbnQtc2lnbmVkIGJ1aWxkcy5cbiAgICAgIGNvbnN0IGFwbnNQcm9wcyA9IHtcbiAgICAgICAgYXBwbGljYXRpb25JZDogZXVtQXBwbGljYXRpb25JZCxcbiAgICAgICAgZW5hYmxlZDogdHJ1ZSxcbiAgICAgICAgZGVmYXVsdEF1dGhlbnRpY2F0aW9uTWV0aG9kOiAnVE9LRU4nLFxuICAgICAgICB0b2tlbktleTogYXBuc0NvbmZpZy50b2tlbktleSxcbiAgICAgICAgdG9rZW5LZXlJZDogYXBuc0NvbmZpZy5rZXlJZCxcbiAgICAgICAgdGVhbUlkOiBhcG5zQ29uZmlnLnRlYW1JZCxcbiAgICAgICAgYnVuZGxlSWQ6IGFwbnNDb25maWcuYnVuZGxlSWQsXG4gICAgICB9O1xuICAgICAgYXBuc0NoYW5uZWwgPSBhcG5zQ29uZmlnLnNhbmRib3hcbiAgICAgICAgPyBuZXcgQ2ZuQVBOU1NhbmRib3hDaGFubmVsKHRoaXMsICdBcG5zU2FuZGJveENoYW5uZWwnLCBhcG5zUHJvcHMpXG4gICAgICAgIDogbmV3IENmbkFQTlNDaGFubmVsKHRoaXMsICdBcG5zQ2hhbm5lbCcsIGFwbnNQcm9wcyk7XG4gICAgfVxuXG4gICAgbGV0IGdjbUNoYW5uZWw6IENmbkdDTUNoYW5uZWwgfCB1bmRlZmluZWQ7XG4gICAgaWYgKGZjbUNvbmZpZykge1xuICAgICAgLy8gRkNNIEhUVFAgdjE6IGBUT0tFTmAgYXV0aCB3aXRoIGEgc2VydmljZS1hY2NvdW50IEpTT04gY3JlZGVudGlhbC4gR29vZ2xlXG4gICAgICAvLyBkZXByZWNhdGVkIHRoZSBsZWdhY3kgc2VydmVyLWtleSAoYEFwaUtleWAgLyBgS0VZYCkgQVBJLCBzbyBvbmx5IHRoZSB2MVxuICAgICAgLy8gYFNlcnZpY2VKc29uYCAoRkNNIHYxKSBwYXRoIGlzIHVzZWQuXG4gICAgICBnY21DaGFubmVsID0gbmV3IENmbkdDTUNoYW5uZWwodGhpcywgJ0djbUNoYW5uZWwnLCB7XG4gICAgICAgIGFwcGxpY2F0aW9uSWQ6IGV1bUFwcGxpY2F0aW9uSWQsXG4gICAgICAgIGVuYWJsZWQ6IHRydWUsXG4gICAgICAgIGRlZmF1bHRBdXRoZW50aWNhdGlvbk1ldGhvZDogJ1RPS0VOJyxcbiAgICAgICAgc2VydmljZUpzb246IGZjbUNvbmZpZy5zZXJ2aWNlSnNvbixcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGNvbnN0IHB1c2hDb2RlUGF0aCA9IHByb3BzLnB1c2hMYW1iZGFDb2RlUGF0aCA/PyBkZWZhdWx0UHVzaExhbWJkYUNvZGVQYXRoO1xuICAgIGNvbnN0IHB1c2hGbiA9IG5ldyBsYW1iZGEuRnVuY3Rpb24odGhpcywgJ1B1c2hIYW5kbGVyRm4nLCB7XG4gICAgICBjb2RlOiBsYW1iZGEuQ29kZS5mcm9tQXNzZXQocHVzaENvZGVQYXRoKSxcbiAgICAgIGhhbmRsZXI6ICdpbmRleC5oYW5kbGVyJyxcbiAgICAgIHJ1bnRpbWU6IGxhbWJkYS5SdW50aW1lLk5PREVKU18yMF9YLFxuICAgICAgdGltZW91dDogRHVyYXRpb24uc2Vjb25kcygzMCksXG4gICAgICBtZW1vcnlTaXplOiAyNTYsXG4gICAgICBlbnZpcm9ubWVudDoge1xuICAgICAgICBbRU5WX0RPTUFJTl9OQU1FXTogZG9tYWluTmFtZSxcbiAgICAgICAgW0VOVl9FVU1fQVBQTElDQVRJT05fSURdOiBldW1BcHBsaWNhdGlvbklkLFxuICAgICAgfSxcbiAgICB9KTtcblxuICAgIC8vIExlYXN0LXByaXZpbGVnZTogcmVhZCArIGRlbGV0ZSBkZXZpY2Ugb2JqZWN0cyBvbiBUSElTIGRvbWFpbiBvbmx5LCBhbmRcbiAgICAvLyBTZW5kTWVzc2FnZXMgc2NvcGVkIHRvIFRISVMgRVVNIGFwcGxpY2F0aW9uLlxuICAgIHB1c2hGbi5hZGRUb1JvbGVQb2xpY3koXG4gICAgICBuZXcgaWFtLlBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgIGVmZmVjdDogaWFtLkVmZmVjdC5BTExPVyxcbiAgICAgICAgYWN0aW9uczogW1xuICAgICAgICAgIC8vIFJlc29sdmUgYSBwcm9maWxlJ3MgcmVnaXN0ZXJlZCBkZXZpY2VzICh0b2tlbnMgKyBjaGFubmVscykuXG4gICAgICAgICAgJ3Byb2ZpbGU6TGlzdFByb2ZpbGVPYmplY3RzJyxcbiAgICAgICAgICAvLyBTdGFsZS10b2tlbiBjbGVhbnVwOiBkZWxldGUgYSBkZXZpY2Ugd2hvc2UgdG9rZW4gaXMgZGVhZC5cbiAgICAgICAgICAncHJvZmlsZTpEZWxldGVQcm9maWxlT2JqZWN0JyxcbiAgICAgICAgXSxcbiAgICAgICAgcmVzb3VyY2VzOiBbZG9tYWluQXJuLCBvYmplY3RUeXBlc0Fybl0sXG4gICAgICB9KSxcbiAgICApO1xuXG4gICAgY29uc3QgYXBwTWVzc2FnZXNBcm4gPSBBcm4uZm9ybWF0KFxuICAgICAge1xuICAgICAgICBzZXJ2aWNlOiAnbW9iaWxldGFyZ2V0aW5nJyxcbiAgICAgICAgcmVzb3VyY2U6ICdhcHBzJyxcbiAgICAgICAgcmVzb3VyY2VOYW1lOiBgJHtldW1BcHBsaWNhdGlvbklkfS9tZXNzYWdlc2AsXG4gICAgICAgIGFybkZvcm1hdDogQXJuRm9ybWF0LlNMQVNIX1JFU09VUkNFX05BTUUsXG4gICAgICB9LFxuICAgICAgc3RhY2ssXG4gICAgKTtcbiAgICBwdXNoRm4uYWRkVG9Sb2xlUG9saWN5KFxuICAgICAgbmV3IGlhbS5Qb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICBlZmZlY3Q6IGlhbS5FZmZlY3QuQUxMT1csXG4gICAgICAgIGFjdGlvbnM6IFsnbW9iaWxldGFyZ2V0aW5nOlNlbmRNZXNzYWdlcyddLFxuICAgICAgICByZXNvdXJjZXM6IFthcHBNZXNzYWdlc0Fybl0sXG4gICAgICB9KSxcbiAgICApO1xuXG4gICAgLy8gLS0tLSBSdW50aW1lIG1lc3NhZ2UtdGVtcGxhdGUgcmVzb2x1dGlvbiAoUSBpbiBDb25uZWN0KSAtLS0tLS0tLS0tLS0tLS1cbiAgICAvLyBUaGUgcHVzaCBMYW1iZGEgcmVzb2x2ZXMgcGVyLXByb2ZpbGUgY29weSBmcm9tIGEgUSBpbiBDb25uZWN0IChXaXNkb20pXG4gICAgLy8gUFVTSCBtZXNzYWdlIHRlbXBsYXRlIGF0IHJ1bnRpbWU6IGl0IGRpc2NvdmVycyB0aGUga25vd2xlZGdlIGJhc2UgZnJvbSB0aGVcbiAgICAvLyBqb3VybmV5J3MgY2FtcGFpZ24gKERlc2NyaWJlQ2FtcGFpZ24gLT4gY29ubmVjdEluc3RhbmNlSWQgLT5cbiAgICAvLyBMaXN0SW50ZWdyYXRpb25Bc3NvY2lhdGlvbnMpIGFuZCByZW5kZXJzIHRoZSB0ZW1wbGF0ZSB3aG9zZSBuYW1lIG1hdGNoZXNcbiAgICAvLyB0aGUgQ3VzdG9tLWFjdGlvbiBBY3Rpb25JZC4gTGVhc3QtcHJpdmlsZWdlLCBzY29wZWQgdG8gdGhpcyBhY2NvdW50IC9cbiAgICAvLyByZWdpb24uIElBTSBwcmVmaXhlcyBjb25maXJtZWQgZW1waXJpY2FsbHk6IGNhbXBhaWduIGFjdGlvbnMgdXNlXG4gICAgLy8gYGNvbm5lY3QtY2FtcGFpZ25zYCwgaW50ZWdyYXRpb24gbGlzdGluZyB1c2VzIGBjb25uZWN0YCwgYW5kIFEgaW4gQ29ubmVjdFxuICAgIC8vIG1lc3NhZ2UtdGVtcGxhdGUgYWN0aW9ucyB1c2UgdGhlIGB3aXNkb21gIHByZWZpeCAoUSBpbiBDb25uZWN0IGlzIHRoZVxuICAgIC8vIHJlYnJhbmQgb2YgQW1hem9uIENvbm5lY3QgV2lzZG9tOyB0aGUgU0RLIGNsaWVudCBpcyBgQGF3cy1zZGsvY2xpZW50LXFjb25uZWN0YFxuICAgIC8vIGJ1dCBJQU0vQVJOcyByZW1haW4gYHdpc2RvbWApLlxuICAgIHB1c2hGbi5hZGRUb1JvbGVQb2xpY3koXG4gICAgICBuZXcgaWFtLlBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgIGVmZmVjdDogaWFtLkVmZmVjdC5BTExPVyxcbiAgICAgICAgYWN0aW9uczogWydjb25uZWN0LWNhbXBhaWduczpEZXNjcmliZUNhbXBhaWduJ10sXG4gICAgICAgIHJlc291cmNlczogW1xuICAgICAgICAgIEFybi5mb3JtYXQoXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIHNlcnZpY2U6ICdjb25uZWN0LWNhbXBhaWducycsXG4gICAgICAgICAgICAgIHJlc291cmNlOiAnY2FtcGFpZ24nLFxuICAgICAgICAgICAgICByZXNvdXJjZU5hbWU6ICcqJyxcbiAgICAgICAgICAgICAgYXJuRm9ybWF0OiBBcm5Gb3JtYXQuU0xBU0hfUkVTT1VSQ0VfTkFNRSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBzdGFjayxcbiAgICAgICAgICApLFxuICAgICAgICBdLFxuICAgICAgfSksXG4gICAgKTtcbiAgICBwdXNoRm4uYWRkVG9Sb2xlUG9saWN5KFxuICAgICAgbmV3IGlhbS5Qb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICBlZmZlY3Q6IGlhbS5FZmZlY3QuQUxMT1csXG4gICAgICAgIGFjdGlvbnM6IFsnY29ubmVjdDpMaXN0SW50ZWdyYXRpb25Bc3NvY2lhdGlvbnMnXSxcbiAgICAgICAgcmVzb3VyY2VzOiBbXG4gICAgICAgICAgQXJuLmZvcm1hdChcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgc2VydmljZTogJ2Nvbm5lY3QnLFxuICAgICAgICAgICAgICByZXNvdXJjZTogJ2luc3RhbmNlJyxcbiAgICAgICAgICAgICAgcmVzb3VyY2VOYW1lOiAnKicsXG4gICAgICAgICAgICAgIGFybkZvcm1hdDogQXJuRm9ybWF0LlNMQVNIX1JFU09VUkNFX05BTUUsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgc3RhY2ssXG4gICAgICAgICAgKSxcbiAgICAgICAgXSxcbiAgICAgIH0pLFxuICAgICk7XG4gICAgcHVzaEZuLmFkZFRvUm9sZVBvbGljeShcbiAgICAgIG5ldyBpYW0uUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgZWZmZWN0OiBpYW0uRWZmZWN0LkFMTE9XLFxuICAgICAgICBhY3Rpb25zOiBbXG4gICAgICAgICAgJ3dpc2RvbTpMaXN0TWVzc2FnZVRlbXBsYXRlcycsXG4gICAgICAgICAgJ3dpc2RvbTpHZXRNZXNzYWdlVGVtcGxhdGUnLFxuICAgICAgICAgICd3aXNkb206UmVuZGVyTWVzc2FnZVRlbXBsYXRlJyxcbiAgICAgICAgXSxcbiAgICAgICAgcmVzb3VyY2VzOiBbXG4gICAgICAgICAgQXJuLmZvcm1hdChcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgc2VydmljZTogJ3dpc2RvbScsXG4gICAgICAgICAgICAgIHJlc291cmNlOiAna25vd2xlZGdlLWJhc2UnLFxuICAgICAgICAgICAgICByZXNvdXJjZU5hbWU6ICcqJyxcbiAgICAgICAgICAgICAgYXJuRm9ybWF0OiBBcm5Gb3JtYXQuU0xBU0hfUkVTT1VSQ0VfTkFNRSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBzdGFjayxcbiAgICAgICAgICApLFxuICAgICAgICAgIEFybi5mb3JtYXQoXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIHNlcnZpY2U6ICd3aXNkb20nLFxuICAgICAgICAgICAgICByZXNvdXJjZTogJ21lc3NhZ2UtdGVtcGxhdGUnLFxuICAgICAgICAgICAgICByZXNvdXJjZU5hbWU6ICcqJyxcbiAgICAgICAgICAgICAgYXJuRm9ybWF0OiBBcm5Gb3JtYXQuU0xBU0hfUkVTT1VSQ0VfTkFNRSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBzdGFjayxcbiAgICAgICAgICApLFxuICAgICAgICBdLFxuICAgICAgfSksXG4gICAgKTtcblxuICAgIC8vIC0tLS0gSW52b2tlIHJlc291cmNlIHBvbGljeSBmb3IgQW1hem9uIENvbm5lY3QgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgLy8gQSBDb25uZWN0IEpvdXJuZXkgQ3VzdG9tLWFjdGlvbiAoYW5kIE91dGJvdW5kIENhbXBhaWducyB2MikgaW52b2tlcyB0aGlzXG4gICAgLy8gTGFtYmRhIHRocm91Z2ggdGhlIGNvbm5lY3QgLyBjb25uZWN0LWNhbXBhaWducyBzZXJ2aWNlIHByaW5jaXBhbC4gR3JhbnRcbiAgICAvLyBsYW1iZGE6SW52b2tlRnVuY3Rpb24gdG8gYm90aCwgc2NvcGVkIHRvIFRISVMgYWNjb3VudCAoYHNvdXJjZUFjY291bnRgKSBzb1xuICAgIC8vIG9ubHkgQ29ubmVjdCBpbnN0YW5jZXMgaW4gdGhlIGRlcGxveWluZyBhY2NvdW50IOKAlCBub3QgYW55IENvbm5lY3QgaW5zdGFuY2VcbiAgICAvLyBhbnl3aGVyZSDigJQgY2FuIGludm9rZSBpdCAoY29uZnVzZWQtZGVwdXR5IGd1YXJkKS4gVGhlIENvbm5lY3QgaW5zdGFuY2UgQVJOXG4gICAgLy8gaXNuJ3Qga25vd24gYXQgc3ludGggdGltZSwgc28gYWNjb3VudCBzY29waW5nIGlzIHRoZSB0aWdodGVzdCBndWFyZCBoZXJlLlxuICAgIGZvciAoY29uc3Qgc2VydmljZVByaW5jaXBhbCBvZiBDT05ORUNUX0lOVk9LRV9TRVJWSUNFX1BSSU5DSVBBTFMpIHtcbiAgICAgIHB1c2hGbi5hZGRQZXJtaXNzaW9uKFxuICAgICAgICBgSW52b2tlLSR7c2VydmljZVByaW5jaXBhbC5yZXBsYWNlKC9bXmEtekEtWjAtOV0vZywgJy0nKX1gLFxuICAgICAgICB7XG4gICAgICAgICAgcHJpbmNpcGFsOiBuZXcgaWFtLlNlcnZpY2VQcmluY2lwYWwoc2VydmljZVByaW5jaXBhbCksXG4gICAgICAgICAgYWN0aW9uOiAnbGFtYmRhOkludm9rZUZ1bmN0aW9uJyxcbiAgICAgICAgICBzb3VyY2VBY2NvdW50OiBzdGFjay5hY2NvdW50LFxuICAgICAgICB9LFxuICAgICAgKTtcbiAgICB9XG5cbiAgICB0aGlzLnB1c2hGdW5jdGlvbkFybiA9IHB1c2hGbi5mdW5jdGlvbkFybjtcblxuICAgIC8vIFNjb3BlZCB0byB0aGUgc3RhY2sgKG5vdCBgdGhpc2ApIHNvIHRoZSBvdXRwdXQga2VlcHMgYSBzdGFibGUsIHJlYWRhYmxlXG4gICAgLy8gbG9naWNhbCBpZCAoYFB1c2hIYW5kbGVyRnVuY3Rpb25Bcm5gKSB0aGF0IGEgaHVtYW4gY2FuIGZpbmQgaW4gdGhlXG4gICAgLy8gQ2xvdWRGb3JtYXRpb24gY29uc29sZSBhbmQgY29weSB0byB3aXJlIHRoZSBKb3VybmV5IEN1c3RvbS1hY3Rpb24uXG4gICAgbmV3IENmbk91dHB1dChzdGFjaywgJ1B1c2hIYW5kbGVyRnVuY3Rpb25Bcm4nLCB7XG4gICAgICB2YWx1ZTogcHVzaEZuLmZ1bmN0aW9uQXJuLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdXaXJlIGFzIGEgQ29ubmVjdCBKb3VybmV5IEN1c3RvbS1hY3Rpb24gKEludm9rZSBMYW1iZGEpIHRhcmdldCcsXG4gICAgfSk7XG5cbiAgICAvLyAtLS0tIENyZWF0ZS1tb2RlIG91dHB1dHMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgIC8vIFN1cmZhY2UgdGhlIHJlc291cmNlcyB0aGlzIGNvbnN0cnVjdCBwcm92aXNpb25lZCBmcm9tIHNjcmF0Y2ggc28gYSBodW1hblxuICAgIC8vIGNhbiBmaW5kIHRoZSBuZXcgaW5zdGFuY2UgLyBkb21haW4gaW4gdGhlIGNvbnNvbGUuIFRoZWlyIE91dGJvdW5kXG4gICAgLy8gQ2FtcGFpZ25zIGFzc29jaWF0aW9uIGlzIGhhbmRsZWQgYXV0b21hdGljYWxseSBieSB0aGUgY3VzdG9tIHJlc291cmNlIGFib3ZlLlxuICAgIGlmIChjb25uZWN0SW5zdGFuY2UpIHtcbiAgICAgIG5ldyBDZm5PdXRwdXQoc3RhY2ssICdDb25uZWN0SW5zdGFuY2VJZCcsIHtcbiAgICAgICAgdmFsdWU6IGNvbm5lY3RJbnN0YW5jZS5hdHRySWQsXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnQW1hem9uIENvbm5lY3QgaW5zdGFuY2UgY3JlYXRlZCBmb3Igbm90aWZpY2F0aW9ucycsXG4gICAgICB9KTtcbiAgICAgIG5ldyBDZm5PdXRwdXQoc3RhY2ssICdDb25uZWN0SW5zdGFuY2VBcm4nLCB7XG4gICAgICAgIHZhbHVlOiBjb25uZWN0SW5zdGFuY2UuYXR0ckFybixcbiAgICAgICAgZGVzY3JpcHRpb246ICdBbWF6b24gQ29ubmVjdCBpbnN0YW5jZSBBUk4nLFxuICAgICAgfSk7XG4gICAgfVxuICAgIGlmIChwcm9maWxlc0RvbWFpbikge1xuICAgICAgbmV3IENmbk91dHB1dChzdGFjaywgJ1Byb2ZpbGVzRG9tYWluTmFtZScsIHtcbiAgICAgICAgdmFsdWU6IGRvbWFpbk5hbWUsXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnQ3VzdG9tZXIgUHJvZmlsZXMgZG9tYWluIGNyZWF0ZWQgZm9yIG5vdGlmaWNhdGlvbnMnLFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgdGhpcy5yZXNvdXJjZXMgPSB7XG4gICAgICBpZGVudGlmeVVzZXJGdW5jdGlvbjogZm4sXG4gICAgICBodHRwQXBpLFxuICAgICAgcHJvZmlsZU9iamVjdFR5cGU6IHByb2ZpbGVUeXBlLFxuICAgICAgZ3Vlc3RQcm9maWxlT2JqZWN0VHlwZTogZ3Vlc3RQcm9maWxlVHlwZSxcbiAgICAgIGRldmljZU9iamVjdFR5cGU6IGRldmljZVR5cGUsXG4gICAgICBwdXNoRnVuY3Rpb246IHB1c2hGbixcbiAgICAgIHB1c2hBcHBsaWNhdGlvbixcbiAgICAgIGFwbnNDaGFubmVsLFxuICAgICAgZ2NtQ2hhbm5lbCxcbiAgICAgIGNvbm5lY3RJbnN0YW5jZSxcbiAgICAgIHByb2ZpbGVzRG9tYWluLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlLWZyb20tc2NyYXRjaCBPTkxZOiBhIExhbWJkYS1iYWNrZWQgQ0RLIGN1c3RvbSByZXNvdXJjZSB0aGF0XG4gICAqIGFzc29jaWF0ZXMgdGhlIGNyZWF0ZWQgQ3VzdG9tZXIgUHJvZmlsZXMgZG9tYWluIHdpdGggdGhlIGNyZWF0ZWQgQW1hem9uXG4gICAqIENvbm5lY3QgaW5zdGFuY2UncyBPdXRib3VuZCBDYW1wYWlnbnMgdjIgYXQgZGVwbG95IHRpbWUsIHNvIENvbm5lY3QgSm91cm5leXNcbiAgICogY2FuIHRhcmdldCB0aGUgZG9tYWluJ3MgcHJvZmlsZXMgd2l0aCBubyBtYW51YWwgY29uc29sZSBzdGVwLlxuICAgKlxuICAgKiBBIGBjdXN0b20tcmVzb3VyY2VzLlByb3ZpZGVyYCBmcm9udHMgdGhlIGhhbmRsZXIgYmVjYXVzZSBvbmJvYXJkaW5nIGlzXG4gICAqIGFzeW5jaHJvbm91czogdGhlIGhhbmRsZXIgc3RhcnRzIHRoZSBpbnN0YW5jZS1vbmJvYXJkaW5nIGpvYiwgdGhlbiBQT0xMU1xuICAgKiBHZXRJbnN0YW5jZU9uYm9hcmRpbmdKb2JTdGF0dXMgdW50aWwgU1VDQ0VFREVEIChhbiBgQXdzQ3VzdG9tUmVzb3VyY2VgIGNhbid0XG4gICAqIHBvbGwpLiBvbkNyZWF0ZS9vblVwZGF0ZSBhcmUgaWRlbXBvdGVudDsgb25EZWxldGUgYmVzdC1lZmZvcnQgcmV2ZXJzZXMgdGhlXG4gICAqIGludGVncmF0aW9ucyArIG9mZmJvYXJkcywgbmV2ZXIgZmFpbGluZyB0ZWFyZG93bi4gVGhlIHJlc291cmNlIGRlcGVuZHMgb25cbiAgICogYm90aCB0aGUgaW5zdGFuY2UgYW5kIHRoZSBkb21haW4gc28gaXQgcnVucyBhZnRlciB0aGV5IGV4aXN0IGFuZCBpcyB0b3JuXG4gICAqIGRvd24gYmVmb3JlIHRoZW0uXG4gICAqL1xuICBwcml2YXRlIGFkZENhbXBhaWduQXNzb2NpYXRpb24oXG4gICAgY29ubmVjdEluc3RhbmNlOiBDZm5JbnN0YW5jZSxcbiAgICBwcm9maWxlc0RvbWFpbjogQ2ZuRG9tYWluLFxuICAgIGRvbWFpbk5hbWU6IHN0cmluZyxcbiAgICBjb2RlUGF0aDogc3RyaW5nLFxuICApOiB2b2lkIHtcbiAgICBjb25zdCBzdGFjayA9IHRoaXMuc3RhY2s7XG5cbiAgICBjb25zdCBhc3NvY2lhdGlvbkZuID0gbmV3IGxhbWJkYS5GdW5jdGlvbih0aGlzLCAnQ2FtcGFpZ25Bc3NvY2lhdGlvbkZuJywge1xuICAgICAgY29kZTogbGFtYmRhLkNvZGUuZnJvbUFzc2V0KGNvZGVQYXRoKSxcbiAgICAgIGhhbmRsZXI6ICdpbmRleC5oYW5kbGVyJyxcbiAgICAgIHJ1bnRpbWU6IGxhbWJkYS5SdW50aW1lLk5PREVKU18yMF9YLFxuICAgICAgLy8gT25ib2FyZGluZyBwb2xscyBHZXRJbnN0YW5jZU9uYm9hcmRpbmdKb2JTdGF0dXMgdW50aWwgU1VDQ0VFREVEICh+MjBzLFxuICAgICAgLy8gY2FwcGVkIH4ybWluKTsgYWxsb3cgZ2VuZXJvdXMgaGVhZHJvb20gZm9yIG9uYm9hcmRpbmcgKyBib3RoIGludGVncmF0aW9ucy5cbiAgICAgIHRpbWVvdXQ6IER1cmF0aW9uLm1pbnV0ZXMoMTApLFxuICAgICAgbWVtb3J5U2l6ZTogMjU2LFxuICAgIH0pO1xuXG4gICAgLy8gVGhlc2UgaW5zdGFuY2Utb25ib2FyZGluZyAvIGluc3RhbmNlLWludGVncmF0aW9uIGFjdGlvbnMgb3BlcmF0ZSBvbiB0aGVcbiAgICAvLyBDb25uZWN0IGluc3RhbmNlJ3MgT3V0Ym91bmQgQ2FtcGFpZ25zIGNvbmZpZ3VyYXRpb24sIG5vdCBvbiBhIGNhbXBhaWduXG4gICAgLy8gcmVzb3VyY2UuIGNvbm5lY3QtY2FtcGFpZ25zIGRvZXMgTk9UIHN1cHBvcnQgcmVzb3VyY2UtbGV2ZWwgcGVybWlzc2lvbnNcbiAgICAvLyBmb3IgdGhlbSAoSUFNIGV2YWx1YXRlcyB0aGVtIGFnYWluc3QgYGNhbXBhaWduLypgIGFuZCBkZW5pZXMgYW5cbiAgICAvLyBgaW5zdGFuY2UvKmAtc2NvcGVkIGdyYW50KSwgc28gdGhleSBtdXN0IGJlIGdyYW50ZWQgb24gYCpgLlxuICAgIGFzc29jaWF0aW9uRm4uYWRkVG9Sb2xlUG9saWN5KFxuICAgICAgbmV3IGlhbS5Qb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICBlZmZlY3Q6IGlhbS5FZmZlY3QuQUxMT1csXG4gICAgICAgIGFjdGlvbnM6IFtcbiAgICAgICAgICAnY29ubmVjdC1jYW1wYWlnbnM6U3RhcnRJbnN0YW5jZU9uYm9hcmRpbmdKb2InLFxuICAgICAgICAgICdjb25uZWN0LWNhbXBhaWduczpHZXRJbnN0YW5jZU9uYm9hcmRpbmdKb2JTdGF0dXMnLFxuICAgICAgICAgICdjb25uZWN0LWNhbXBhaWduczpEZWxldGVJbnN0YW5jZU9uYm9hcmRpbmdKb2InLFxuICAgICAgICAgICdjb25uZWN0LWNhbXBhaWduczpQdXRDb25uZWN0SW5zdGFuY2VJbnRlZ3JhdGlvbicsXG4gICAgICAgICAgJ2Nvbm5lY3QtY2FtcGFpZ25zOkRlbGV0ZUNvbm5lY3RJbnN0YW5jZUludGVncmF0aW9uJyxcbiAgICAgICAgXSxcbiAgICAgICAgcmVzb3VyY2VzOiBbJyonXSxcbiAgICAgIH0pLFxuICAgICk7XG5cbiAgICAvLyBjb25uZWN0LWNhbXBhaWducyBvbmJvYXJkaW5nICsgUHV0Q29ubmVjdEluc3RhbmNlSW50ZWdyYXRpb24gdmFsaWRhdGUgdGhlXG4gICAgLy8gdGFyZ2V0IENvbm5lY3QgaW5zdGFuY2Ugb24gdGhlIGNhbGxlcidzIGJlaGFsZiwgc28gdGhlIGhhbmRsZXIgcm9sZSBhbHNvXG4gICAgLy8gbmVlZHMgY29ubmVjdDpEZXNjcmliZUluc3RhbmNlIG9uIHRoZSAoY29uc3RydWN0LW93bmVkKSBpbnN0YW5jZS5cbiAgICBhc3NvY2lhdGlvbkZuLmFkZFRvUm9sZVBvbGljeShcbiAgICAgIG5ldyBpYW0uUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgZWZmZWN0OiBpYW0uRWZmZWN0LkFMTE9XLFxuICAgICAgICBhY3Rpb25zOiBbJ2Nvbm5lY3Q6RGVzY3JpYmVJbnN0YW5jZSddLFxuICAgICAgICByZXNvdXJjZXM6IFtjb25uZWN0SW5zdGFuY2UuYXR0ckFybl0sXG4gICAgICB9KSxcbiAgICApO1xuXG4gICAgLy8gUmVjaXByb2NhbCBDdXN0b21lciBQcm9maWxlcyBpbnRlZ3JhdGlvbiBvbiBUSElTIGRvbWFpbiBvbmx5IChJQU0gcHJlZml4XG4gICAgLy8gZm9yIEN1c3RvbWVyIFByb2ZpbGVzIGlzIGBwcm9maWxlYCkuIEdldERvbWFpbiBpcyByZWFkLW9ubHkgYW5kIHJlcXVpcmVkXG4gICAgLy8gYmVjYXVzZSBQdXRDb25uZWN0SW5zdGFuY2VJbnRlZ3JhdGlvbiB2YWxpZGF0ZXMgdGhlIEN1c3RvbWVyIFByb2ZpbGVzXG4gICAgLy8gZG9tYWluIGJlZm9yZSB3aXJpbmcgdGhlIGludGVncmF0aW9uLlxuICAgIGNvbnN0IGRvbWFpbkFybiA9IEFybi5mb3JtYXQoXG4gICAgICB7XG4gICAgICAgIHNlcnZpY2U6ICdwcm9maWxlJyxcbiAgICAgICAgcmVzb3VyY2U6ICdkb21haW5zJyxcbiAgICAgICAgcmVzb3VyY2VOYW1lOiBkb21haW5OYW1lLFxuICAgICAgICBhcm5Gb3JtYXQ6IEFybkZvcm1hdC5TTEFTSF9SRVNPVVJDRV9OQU1FLFxuICAgICAgfSxcbiAgICAgIHN0YWNrLFxuICAgICk7XG4gICAgYXNzb2NpYXRpb25Gbi5hZGRUb1JvbGVQb2xpY3koXG4gICAgICBuZXcgaWFtLlBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgIGVmZmVjdDogaWFtLkVmZmVjdC5BTExPVyxcbiAgICAgICAgYWN0aW9uczogW1xuICAgICAgICAgICdwcm9maWxlOlB1dEludGVncmF0aW9uJyxcbiAgICAgICAgICAncHJvZmlsZTpEZWxldGVJbnRlZ3JhdGlvbicsXG4gICAgICAgICAgJ3Byb2ZpbGU6R2V0RG9tYWluJyxcbiAgICAgICAgXSxcbiAgICAgICAgcmVzb3VyY2VzOiBbXG4gICAgICAgICAgZG9tYWluQXJuLFxuICAgICAgICAgIEFybi5mb3JtYXQoXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIHNlcnZpY2U6ICdwcm9maWxlJyxcbiAgICAgICAgICAgICAgcmVzb3VyY2U6ICdkb21haW5zJyxcbiAgICAgICAgICAgICAgcmVzb3VyY2VOYW1lOiBgJHtkb21haW5OYW1lfS9pbnRlZ3JhdGlvbnMvKmAsXG4gICAgICAgICAgICAgIGFybkZvcm1hdDogQXJuRm9ybWF0LlNMQVNIX1JFU09VUkNFX05BTUUsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgc3RhY2ssXG4gICAgICAgICAgKSxcbiAgICAgICAgXSxcbiAgICAgIH0pLFxuICAgICk7XG4gICAgLy8gUHV0Q29ubmVjdEluc3RhbmNlSW50ZWdyYXRpb24gdmFsaWRhdGVzIHRoZSBmb3VyIGJ1aWx0LWluIGNhbXBhaWduXG4gICAgLy8gb2JqZWN0LXR5cGUgVEVNUExBVEVTIHJlZmVyZW5jZWQgYnkgb2JqZWN0VHlwZU5hbWVzIChDYW1wYWlnbi1FbWFpbCxcbiAgICAvLyBDYW1wYWlnbi1TTVMsIENhbXBhaWduLVRlbGVwaG9ueSwgQ2FtcGFpZ24tT3JjaGVzdHJhdGlvbikgdmlhXG4gICAgLy8gcHJvZmlsZTpHZXRQcm9maWxlT2JqZWN0VHlwZVRlbXBsYXRlLCB1c2luZyB0aGUgQ0FMTEVSJ3MgY3JlZGVudGlhbHMuXG4gICAgLy8gVGVtcGxhdGVzIGFyZSBhY2NvdW50L3JlZ2lvbi1sZXZlbCByZXNvdXJjZXMgd2hvc2UgQVJOIGNhcnJpZXMgYSBsZWFkaW5nXG4gICAgLy8gc2xhc2ggKGA6L3RlbXBsYXRlcy88bmFtZT5gKSwgZGlzdGluY3QgZnJvbSB0aGUgZG9tYWluLCBzbyB0aGV5IG5lZWQgdGhlaXJcbiAgICAvLyBvd24gZ3JhbnQuXG4gICAgY29uc3QgcHJvZmlsZVRlbXBsYXRlc0FybiA9IGBhcm46JHtzdGFjay5wYXJ0aXRpb259OnByb2ZpbGU6JHtzdGFjay5yZWdpb259OiR7c3RhY2suYWNjb3VudH06L3RlbXBsYXRlcy8qYDtcbiAgICBhc3NvY2lhdGlvbkZuLmFkZFRvUm9sZVBvbGljeShcbiAgICAgIG5ldyBpYW0uUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgZWZmZWN0OiBpYW0uRWZmZWN0LkFMTE9XLFxuICAgICAgICBhY3Rpb25zOiBbXG4gICAgICAgICAgJ3Byb2ZpbGU6R2V0UHJvZmlsZU9iamVjdFR5cGVUZW1wbGF0ZScsXG4gICAgICAgICAgJ3Byb2ZpbGU6TGlzdFByb2ZpbGVPYmplY3RUeXBlVGVtcGxhdGVzJyxcbiAgICAgICAgXSxcbiAgICAgICAgcmVzb3VyY2VzOiBbcHJvZmlsZVRlbXBsYXRlc0Fybl0sXG4gICAgICB9KSxcbiAgICApO1xuICAgIC8vIE9uYm9hcmRpbmcgYXV0by1jcmVhdGVzIHRoZSBPdXRib3VuZCBDYW1wYWlnbnMgc2VydmljZS1saW5rZWQgcm9sZTsgdGhlXG4gICAgLy8gaGFuZGxlciB0aGVuIGxpc3RzIHJvbGVzIHRvIHJlc29sdmUgaXRzIEFSTi4gaWFtOkxpc3RSb2xlcyBoYXMgbm9cbiAgICAvLyByZXNvdXJjZS1sZXZlbCBzY29waW5nLCBzbyBpdCBtdXN0IHRhcmdldCBgKmAuXG4gICAgYXNzb2NpYXRpb25Gbi5hZGRUb1JvbGVQb2xpY3koXG4gICAgICBuZXcgaWFtLlBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgIGVmZmVjdDogaWFtLkVmZmVjdC5BTExPVyxcbiAgICAgICAgYWN0aW9uczogWydpYW06TGlzdFJvbGVzJ10sXG4gICAgICAgIHJlc291cmNlczogWycqJ10sXG4gICAgICB9KSxcbiAgICApO1xuICAgIC8vIEVhY2ggU3RhcnRJbnN0YW5jZU9uYm9hcmRpbmdKb2IgZm9yIGEgTkVXIENvbm5lY3QgaW5zdGFuY2UgY3JlYXRlcyBpdHMgb3duXG4gICAgLy8gY29ubmVjdC1jYW1wYWlnbnMgc2VydmljZS1saW5rZWQgcm9sZSAodGhlIHJvbGUgbmFtZSBjYXJyaWVzIGFcbiAgICAvLyBzZXJ2aWNlLWdlbmVyYXRlZCByYW5kb20gc3VmZml4KSwgc28gdGhlIGdyYW50IG11c3QgdXNlIGAqYCBmb3IgdGhlXG4gICAgLy8gcmVzb3VyY2UgYW5kIGlzIGluc3RlYWQgc2NvcGVkIHNhZmVseSBieSB0aGUgaWFtOkFXU1NlcnZpY2VOYW1lIGNvbmRpdGlvblxuICAgIC8vIHRvIE9OTFkgdGhlIGNvbm5lY3QtY2FtcGFpZ25zIFNMUi4gQSBwYXRoLXNjb3BlZCByZXNvdXJjZSBBUk4gaXMgZGVuaWVkIGJ5XG4gICAgLy8gSUFNIGhlcmUgKHN1cmZhY2VkIGFzIHRoZSBvbmJvYXJkaW5nIGpvYidzIElBTV9BQ0NFU1NfREVOSUVEIGZhaWx1cmVDb2RlKS5cbiAgICBjb25zdCBjYW1wYWlnbnNTbHJBcm4gPSBgYXJuOiR7c3RhY2sucGFydGl0aW9ufTppYW06OiR7c3RhY2suYWNjb3VudH06cm9sZS9hd3Mtc2VydmljZS1yb2xlLyR7Q09OTkVDVF9DQU1QQUlHTlNfU0VSVklDRV9OQU1FfS8qYDtcbiAgICBhc3NvY2lhdGlvbkZuLmFkZFRvUm9sZVBvbGljeShcbiAgICAgIG5ldyBpYW0uUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgZWZmZWN0OiBpYW0uRWZmZWN0LkFMTE9XLFxuICAgICAgICBhY3Rpb25zOiBbJ2lhbTpDcmVhdGVTZXJ2aWNlTGlua2VkUm9sZSddLFxuICAgICAgICByZXNvdXJjZXM6IFsnKiddLFxuICAgICAgICBjb25kaXRpb25zOiB7XG4gICAgICAgICAgU3RyaW5nRXF1YWxzOiB7XG4gICAgICAgICAgICAnaWFtOkFXU1NlcnZpY2VOYW1lJzogQ09OTkVDVF9DQU1QQUlHTlNfU0VSVklDRV9OQU1FLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICB9KSxcbiAgICApO1xuICAgIGFzc29jaWF0aW9uRm4uYWRkVG9Sb2xlUG9saWN5KFxuICAgICAgbmV3IGlhbS5Qb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICBlZmZlY3Q6IGlhbS5FZmZlY3QuQUxMT1csXG4gICAgICAgIGFjdGlvbnM6IFsnaWFtOlBhc3NSb2xlJ10sXG4gICAgICAgIHJlc291cmNlczogW2NhbXBhaWduc1NsckFybl0sXG4gICAgICB9KSxcbiAgICApO1xuICAgIC8vIER1cmluZyBvbmJvYXJkaW5nLCBjb25uZWN0LWNhbXBhaWducyBjdXN0b21pemVzIGl0cyBzZXJ2aWNlLWxpbmtlZCByb2xlXG4gICAgLy8gd2l0aCBpbnN0YW5jZS1zcGVjaWZpYyBpbmxpbmUgcGVybWlzc2lvbnMgKHRoZSBcImFkZGl0aW9uYWwgcGVybWlzc2lvbnNcbiAgICAvLyBhZGRlZCBmb3IgdGhlIHNlcnZpY2UtbGlua2VkIHJvbGUgdG8gYWNjZXNzIHRoZSByZXNvdXJjZXNcIiwgaW5jbC4gdGhlXG4gICAgLy8gQ3VzdG9tZXIgUHJvZmlsZXMgaW50ZWdyYXRpb24gYWNjZXNzKSB2aWEgaWFtOlB1dFJvbGVQb2xpY3kgL1xuICAgIC8vIGlhbTpBdHRhY2hSb2xlUG9saWN5LCBwZXJmb3JtZWQgd2l0aCB0aGUgQ0FMTEVSJ3MgY3JlZGVudGlhbHMuIFdpdGhvdXRcbiAgICAvLyB0aGVzZSB0aGUgb25ib2FyZGluZyBqb2IgZmFpbHMgd2l0aCBmYWlsdXJlQ29kZSBJQU1fQUNDRVNTX0RFTklFRC4gVGhlXG4gICAgLy8gcmV2ZXJzZSAoRGVsZXRlL0RldGFjaCkgbWlycm9ycyB0aGlzIHNvIHRoZSBiZXN0LWVmZm9ydCB0ZWFyZG93biBjYW5cbiAgICAvLyByZW1vdmUgdGhvc2UgaW5saW5lIHBlcm1pc3Npb25zIHdoZW4gZGlzYXNzb2NpYXRpbmcuIFNjb3BlZCB0byBPTkxZIHRoZVxuICAgIC8vIGNvbm5lY3QtY2FtcGFpZ25zIHNlcnZpY2UtbGlua2VkIHJvbGUuXG4gICAgYXNzb2NpYXRpb25Gbi5hZGRUb1JvbGVQb2xpY3koXG4gICAgICBuZXcgaWFtLlBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgIGVmZmVjdDogaWFtLkVmZmVjdC5BTExPVyxcbiAgICAgICAgYWN0aW9uczogW1xuICAgICAgICAgICdpYW06UHV0Um9sZVBvbGljeScsXG4gICAgICAgICAgJ2lhbTpBdHRhY2hSb2xlUG9saWN5JyxcbiAgICAgICAgICAnaWFtOkRlbGV0ZVJvbGVQb2xpY3knLFxuICAgICAgICAgICdpYW06RGV0YWNoUm9sZVBvbGljeScsXG4gICAgICAgIF0sXG4gICAgICAgIHJlc291cmNlczogW2NhbXBhaWduc1NsckFybl0sXG4gICAgICB9KSxcbiAgICApO1xuICAgIC8vIE9uYm9hcmRpbmcgYWxzbyBwcm92aXNpb25zIGEgbWFuYWdlZCBFdmVudEJyaWRnZSBydWxlIChuYW1lZFxuICAgIC8vIGBDb25uZWN0Q2FtcGFpZ25zUnVsZSpgKSB0aGF0IGRyaXZlcyBjYW1wYWlnbiBldmVudCBkZWxpdmVyeSwgY3JlYXRlZCB3aXRoXG4gICAgLy8gdGhlIENBTExFUidzIGNyZWRlbnRpYWxzLiBXaXRob3V0IHRoZXNlIHRoZSBvbmJvYXJkaW5nIGpvYiBmYWlscyB3aXRoXG4gICAgLy8gZmFpbHVyZUNvZGUgRVZFTlRfQlJJREdFX0FDQ0VTU19ERU5JRUQuIExpc3RSdWxlcyBoYXMgbm8gcmVzb3VyY2UtbGV2ZWxcbiAgICAvLyBzY29waW5nOyB0aGUgbXV0YXRpbmcgYWN0aW9ucyBhcmUgc2NvcGVkIHRvIHRoZSBDb25uZWN0Q2FtcGFpZ25zUnVsZSogbmFtZS5cbiAgICBjb25zdCBjb25uZWN0Q2FtcGFpZ25zUnVsZUFybiA9IGBhcm46JHtzdGFjay5wYXJ0aXRpb259OmV2ZW50czoke3N0YWNrLnJlZ2lvbn06JHtzdGFjay5hY2NvdW50fTpydWxlL0Nvbm5lY3RDYW1wYWlnbnNSdWxlKmA7XG4gICAgYXNzb2NpYXRpb25Gbi5hZGRUb1JvbGVQb2xpY3koXG4gICAgICBuZXcgaWFtLlBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgIGVmZmVjdDogaWFtLkVmZmVjdC5BTExPVyxcbiAgICAgICAgYWN0aW9uczogWydldmVudHM6TGlzdFJ1bGVzJ10sXG4gICAgICAgIHJlc291cmNlczogWycqJ10sXG4gICAgICB9KSxcbiAgICApO1xuICAgIGFzc29jaWF0aW9uRm4uYWRkVG9Sb2xlUG9saWN5KFxuICAgICAgbmV3IGlhbS5Qb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICBlZmZlY3Q6IGlhbS5FZmZlY3QuQUxMT1csXG4gICAgICAgIGFjdGlvbnM6IFtcbiAgICAgICAgICAnZXZlbnRzOlB1dFJ1bGUnLFxuICAgICAgICAgICdldmVudHM6UHV0VGFyZ2V0cycsXG4gICAgICAgICAgJ2V2ZW50czpEZWxldGVSdWxlJyxcbiAgICAgICAgICAnZXZlbnRzOlJlbW92ZVRhcmdldHMnLFxuICAgICAgICAgICdldmVudHM6TGlzdFRhcmdldHNCeVJ1bGUnLFxuICAgICAgICAgICdldmVudHM6RGVzY3JpYmVSdWxlJyxcbiAgICAgICAgXSxcbiAgICAgICAgcmVzb3VyY2VzOiBbY29ubmVjdENhbXBhaWduc1J1bGVBcm5dLFxuICAgICAgfSksXG4gICAgKTtcblxuICAgIGNvbnN0IHByb3ZpZGVyID0gbmV3IFByb3ZpZGVyKHRoaXMsICdDYW1wYWlnbkFzc29jaWF0aW9uUHJvdmlkZXInLCB7XG4gICAgICBvbkV2ZW50SGFuZGxlcjogYXNzb2NpYXRpb25GbixcbiAgICB9KTtcblxuICAgIGNvbnN0IGFzc29jaWF0aW9uID0gbmV3IEN1c3RvbVJlc291cmNlKHRoaXMsICdDYW1wYWlnbkFzc29jaWF0aW9uJywge1xuICAgICAgc2VydmljZVRva2VuOiBwcm92aWRlci5zZXJ2aWNlVG9rZW4sXG4gICAgICByZXNvdXJjZVR5cGU6ICdDdXN0b206Ok91dGJvdW5kQ2FtcGFpZ25zRG9tYWluQXNzb2NpYXRpb24nLFxuICAgICAgcHJvcGVydGllczoge1xuICAgICAgICBDb25uZWN0SW5zdGFuY2VJZDogY29ubmVjdEluc3RhbmNlLmF0dHJJZCxcbiAgICAgICAgRG9tYWluTmFtZTogZG9tYWluTmFtZSxcbiAgICAgICAgQWNjb3VudDogc3RhY2suYWNjb3VudCxcbiAgICAgICAgUmVnaW9uOiBzdGFjay5yZWdpb24sXG4gICAgICB9LFxuICAgIH0pO1xuXG4gICAgLy8gUHJvdmlzaW9uIGFmdGVyIOKAlCBhbmQgdGVhciBkb3duIGJlZm9yZSDigJQgdGhlIGluc3RhbmNlICsgZG9tYWluIGl0IGxpbmtzLlxuICAgIGFzc29jaWF0aW9uLm5vZGUuYWRkRGVwZW5kZW5jeShjb25uZWN0SW5zdGFuY2UpO1xuICAgIGFzc29jaWF0aW9uLm5vZGUuYWRkRGVwZW5kZW5jeShwcm9maWxlc0RvbWFpbik7XG4gIH1cblxuICAvKipcbiAgICogRGV0ZXJtaW5pc3RpYywgc3RhYmxlLCBwZXItYXBwIGJhc2UgbmFtZSBmb3IgdGhlIGNyZWF0ZWQgQ29ubmVjdCBpbnN0YW5jZVxuICAgKiBhbmQgQ3VzdG9tZXIgUHJvZmlsZXMgZG9tYWluIChjcmVhdGUtZnJvbS1zY3JhdGNoIG1vZGUpLlxuICAgKlxuICAgKiBUaGUgbmFtZSBtdXN0IGJlIFNUQUJMRSBhY3Jvc3MgZGVwbG95IGFuZCBkZWxldGUgKHNvIENGTiByZXNvbHZlcyB0aGUgc2FtZVxuICAgKiByZXNvdXJjZSBvbiB0ZWFyZG93bikgYW5kIFVOSVFVRSBwZXIgYXBwIC8gZW52aXJvbm1lbnQgKHNvIHR3byBhcHBzIGluIHRoZVxuICAgKiBzYW1lIGFjY291bnQgZG9uJ3QgY29sbGlkZSBvbiB0aGUgZ2xvYmFsbHktdW5pcXVlIENvbm5lY3QgYWxpYXMpLiBJdCBpc1xuICAgKiBkZXJpdmVkIGZyb20gYSBzaG9ydCBoYXNoIG9mIHRoZSByb290IHN0YWNrIG5hbWUgKHdoaWNoLCBpbiBBbXBsaWZ5IEdlbjIsXG4gICAqIGVtYmVkcyB0aGUgYXBwIG5hbWVzcGFjZSArIGJyYW5jaCkgcGx1cyB0aGlzIGNvbnN0cnVjdCdzIHBhdGgg4oCUIGJvdGggc3RhYmxlXG4gICAqIGlucHV0cy5cbiAgICpcbiAgICogVGhlIGBhbWF6b24tY29ubmVjdC1gIHByZWZpeCBpcyBSRVFVSVJFRCwgbm90IGNvc21ldGljOiBBbWF6b24gQ29ubmVjdCdzXG4gICAqIEFXUy1tYW5hZ2VkIHNlcnZpY2UtbGlua2VkLXJvbGUgcG9saWN5IChgQW1hem9uQ29ubmVjdFNlcnZpY2VMaW5rZWRSb2xlUG9saWN5YCxcbiAgICogc3RhdGVtZW50IGBBbGxvd0N1c3RvbWVyUHJvZmlsZXNGb3JDb25uZWN0RG9tYWluYCkgZ3JhbnRzIHRoZSBpbnN0YW5jZSdzXG4gICAqIHJvbGUgYHByb2ZpbGU6KmAgT05MWSBvbiBgYXJuOmF3czpwcm9maWxlOio6Kjpkb21haW5zL2FtYXpvbi1jb25uZWN0LSpgLiBBXG4gICAqIGRvbWFpbiBuYW1lZCBvdGhlcndpc2UgaXMgdW5yZWFjaGFibGUgYnkgdGhlIGluc3RhbmNlIOKAlCB0aGUgQ29ubmVjdCBjb25zb2xlXG4gICAqIGFuZCBKb3VybmV5IHNlZ21lbnQgYnVpbGRlciB0aGVuIHJlcG9ydCBcImRvZXMgbm90IGhhdmUgcGVybWlzc2lvbnMgdG8gYWNjZXNzXG4gICAqIEN1c3RvbWVyIFByb2ZpbGVzXCIuIFRoZSBTTFIgaXMgQVdTLXByb3RlY3RlZCAobm8gaW5saW5lIHBvbGljeSBjYW4gYmUgYWRkZWQpXG4gICAqIGFuZCB0aGUgbWFuYWdlZCBwb2xpY3kgaXMgbm90IGVkaXRhYmxlLCBzbyB0aGUgZG9tYWluIG5hbWUgaXMgdGhlIG9ubHkgbGV2ZXIuXG4gICAqL1xuICBwcml2YXRlIGdlbmVyYXRlUmVzb3VyY2VOYW1lKCk6IHN0cmluZyB7XG4gICAgbGV0IHJvb3Q6IFN0YWNrID0gdGhpcy5zdGFjaztcbiAgICB3aGlsZSAocm9vdC5uZXN0ZWRTdGFja1BhcmVudCkge1xuICAgICAgcm9vdCA9IHJvb3QubmVzdGVkU3RhY2tQYXJlbnQ7XG4gICAgfVxuICAgIGNvbnN0IHNlZWQgPSBgJHtyb290LnN0YWNrTmFtZX06OiR7dGhpcy5ub2RlLnBhdGh9YDtcbiAgICBjb25zdCBzdWZmaXggPSBjcmVhdGVIYXNoKCdzaGEyNTYnKS51cGRhdGUoc2VlZCkuZGlnZXN0KCdoZXgnKS5zbGljZSgwLCAxMik7XG4gICAgcmV0dXJuIGBhbWF6b24tY29ubmVjdC1ub3RpZmljYXRpb25zLSR7c3VmZml4fWA7XG4gIH1cblxuICAvKipcbiAgICogQ29lcmNlIGFuIGFyYml0cmFyeSBzdHJpbmcgaW50byBhIHZhbGlkIEFtYXpvbiBDb25uZWN0IGluc3RhbmNlIGFsaWFzOlxuICAgKiBsb3dlcmNhc2UgYWxwaGFudW1lcmljIGNoYXJhY3RlcnMgKyBzaW5nbGUgaHlwaGVucywgbm8gbGVhZGluZy90cmFpbGluZyBoeXBoZW4sIG5vdFxuICAgKiBzdGFydGluZyB3aXRoIHRoZSByZXNlcnZlZCBgZC1gIHByZWZpeCwgYW5kIHdpdGhpbiBDb25uZWN0J3MgMeKAkzYyIGNoYXJcbiAgICogYm91bmQuXG4gICAqL1xuICBwcml2YXRlIHNhbml0aXplSW5zdGFuY2VBbGlhcyhyYXc6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgbGV0IGFsaWFzID0gcmF3XG4gICAgICAudG9Mb3dlckNhc2UoKVxuICAgICAgLnJlcGxhY2UoL1teYS16MC05LV0vZywgJy0nKVxuICAgICAgLnJlcGxhY2UoLy0rL2csICctJylcbiAgICAgIC5yZXBsYWNlKC9eLSt8LSskL2csICcnKTtcbiAgICBpZiAoYWxpYXMuc3RhcnRzV2l0aCgnZC0nKSkge1xuICAgICAgYWxpYXMgPSBgYSR7YWxpYXN9YDtcbiAgICB9XG4gICAgaWYgKGFsaWFzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgYWxpYXMgPSAnYW1wbGlmeS1ub3RpZmljYXRpb25zJztcbiAgICB9XG4gICAgcmV0dXJuIGFsaWFzLnNsaWNlKDAsIDYyKS5yZXBsYWNlKC8tKyQvZywgJycpO1xuICB9XG59XG4iXX0=