@pipeline-builder/api-core 4.1.3 → 4.1.4

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 (75) hide show
  1. package/README.md +3 -3
  2. package/lib/errors/app-errors.d.ts +0 -4
  3. package/lib/errors/app-errors.js +1 -8
  4. package/lib/helpers/restore-helpers.d.ts +3 -3
  5. package/lib/helpers/restore-helpers.js +4 -4
  6. package/lib/helpers/sse-helpers.d.ts +8 -1
  7. package/lib/helpers/sse-helpers.js +11 -3
  8. package/lib/middleware/auth.d.ts +174 -43
  9. package/lib/middleware/auth.js +384 -179
  10. package/lib/middleware/index.d.ts +1 -0
  11. package/lib/middleware/index.js +2 -1
  12. package/lib/middleware/route-table.d.ts +104 -0
  13. package/lib/middleware/route-table.js +230 -0
  14. package/lib/middleware/step-up.d.ts +48 -16
  15. package/lib/middleware/step-up.js +74 -36
  16. package/lib/services/api-key-exchange.d.ts +25 -0
  17. package/lib/services/api-key-exchange.js +219 -0
  18. package/lib/services/cache-service.d.ts +11 -26
  19. package/lib/services/cache-service.js +20 -74
  20. package/lib/services/compliance-event-subscriber.d.ts +5 -4
  21. package/lib/services/compliance-event-subscriber.js +8 -6
  22. package/lib/services/durable-event-bus.d.ts +22 -39
  23. package/lib/services/durable-event-bus.js +95 -43
  24. package/lib/services/env-redis.d.ts +27 -0
  25. package/lib/services/env-redis.js +63 -1
  26. package/lib/services/http-client.d.ts +10 -15
  27. package/lib/services/http-client.js +32 -27
  28. package/lib/services/index.d.ts +3 -0
  29. package/lib/services/index.js +4 -1
  30. package/lib/services/jwks-cache.d.ts +102 -0
  31. package/lib/services/jwks-cache.js +222 -0
  32. package/lib/services/quota.js +12 -4
  33. package/lib/services/remote-audit-client.d.ts +1 -1
  34. package/lib/services/remote-audit-client.js +32 -1
  35. package/lib/services/scheduler.d.ts +2 -3
  36. package/lib/services/scheduler.js +2 -2
  37. package/lib/services/service-boot.d.ts +4 -2
  38. package/lib/services/service-boot.js +7 -3
  39. package/lib/services/service-keys.d.ts +83 -0
  40. package/lib/services/service-keys.js +354 -0
  41. package/lib/services/sse-ticket-store.d.ts +55 -22
  42. package/lib/services/sse-ticket-store.js +122 -79
  43. package/lib/services/token-revocation.js +30 -18
  44. package/lib/testing/route-coverage.d.ts +64 -0
  45. package/lib/testing/route-coverage.js +183 -0
  46. package/lib/testing/service-tokens.d.ts +66 -0
  47. package/lib/testing/service-tokens.js +137 -0
  48. package/lib/testing/tier-mock.d.ts +2 -2
  49. package/lib/testing/tier-mock.js +3 -3
  50. package/lib/testing/user-tokens.d.ts +75 -0
  51. package/lib/testing/user-tokens.js +115 -0
  52. package/lib/types/catalog-metadata.d.ts +0 -2
  53. package/lib/types/catalog-metadata.js +1 -3
  54. package/lib/types/common.d.ts +103 -4
  55. package/lib/types/common.js +11 -1
  56. package/lib/types/error-codes.d.ts +15 -0
  57. package/lib/types/error-codes.js +22 -1
  58. package/lib/types/permissions.d.ts +35 -1
  59. package/lib/types/permissions.js +70 -2
  60. package/lib/utils/api-key.d.ts +34 -0
  61. package/lib/utils/api-key.js +75 -0
  62. package/lib/utils/env.d.ts +0 -2
  63. package/lib/utils/env.js +1 -6
  64. package/lib/utils/index.d.ts +3 -0
  65. package/lib/utils/index.js +4 -1
  66. package/lib/utils/jwk.d.ts +98 -0
  67. package/lib/utils/jwk.js +139 -0
  68. package/lib/utils/logger.d.ts +4 -1
  69. package/lib/utils/logger.js +1 -22
  70. package/lib/utils/secret-encryption.d.ts +7 -2
  71. package/lib/utils/secret-encryption.js +47 -4
  72. package/lib/utils/secret-rotation.d.ts +17 -0
  73. package/lib/utils/secret-rotation.js +54 -0
  74. package/lib/validation/common-schemas.js +5 -4
  75. package/package.json +20 -1
@@ -2,135 +2,101 @@
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
  import { randomUUID } from 'crypto';
4
4
  import jwt from 'jsonwebtoken';
5
+ import { tagRouteGate } from './route-table.js';
5
6
  import { HttpStatus } from '../constants/http-status.js';
7
+ import { JwksUnavailableError, UnknownKidError, platformJwksCache } from '../services/jwks-cache.js';
8
+ import { SERVICE_SUBJECT_PREFIX, ServiceKeyError, isServiceKid, serviceIdentity, signServiceJwt, verifyServiceJwt, } from '../services/service-keys.js';
9
+ import { AUTH_METHODS, PRINCIPAL_TYPES, TOKEN_USES } from '../types/common.js';
6
10
  import { ErrorCode } from '../types/error-codes.js';
7
11
  import { hasPermission } from '../types/permissions.js';
12
+ import { isOpaqueApiKey } from '../utils/api-key.js';
8
13
  import { getHeaderString } from '../utils/headers.js';
9
14
  import { getIdentity } from '../utils/identity.js';
15
+ import { USER_TOKEN_ALGORITHM, decodeJwtHeader } from '../utils/jwk.js';
10
16
  import { createLogger } from '../utils/logger.js';
11
17
  import { emitCounter } from '../utils/metric-emitter.js';
12
18
  import { sendError } from '../utils/response.js';
13
19
  const logger = createLogger('auth-middleware');
14
- /** Cached JWT secret with periodic refresh from env var. */
15
- let _jwtSecret;
16
- let _jwtSecretRefreshedAt = 0;
17
- /** Cached PREVIOUS JWT secret (optional) — enables zero-downtime rotation. */
18
- let _jwtSecretPrevious;
19
- let _jwtSecretPreviousRefreshedAt = 0;
20
- const JWT_SECRET_REFRESH_INTERVAL_MS = 300_000; // 5 minutes
21
- function getJwtSecret() {
22
- const now = Date.now();
23
- if (!_jwtSecret || now - _jwtSecretRefreshedAt > JWT_SECRET_REFRESH_INTERVAL_MS) {
24
- const secret = process.env.JWT_SECRET;
25
- if (!secret) {
26
- logger.error('JWT_SECRET environment variable is not set');
27
- throw new Error('JWT_SECRET environment variable is required');
28
- }
29
- if (_jwtSecret && _jwtSecret !== secret) {
30
- logger.info('JWT secret rotated');
31
- }
32
- _jwtSecret = secret;
33
- _jwtSecretRefreshedAt = now;
34
- }
35
- return _jwtSecret;
20
+ /** Issuer/audience pinning, when the deployment configures them. Shared by both chains. */
21
+ function issuerAudienceOptions() {
22
+ return {
23
+ ...(process.env.JWT_ISSUER ? { issuer: process.env.JWT_ISSUER } : {}),
24
+ ...(process.env.JWT_AUDIENCE ? { audience: process.env.JWT_AUDIENCE } : {}),
25
+ };
36
26
  }
37
27
  /**
38
- * The optional PREVIOUS JWT secret (`JWT_SECRET_PREVIOUS`), cached with the same
39
- * TTL as the primary. Returns `undefined` when unset. During a `JWT_SECRET`
40
- * rotation, operators set `JWT_SECRET_PREVIOUS` to the old value so tokens signed
41
- * with EITHER secret keep verifying — closing the auth-outage window where
42
- * still-valid old-signed (or freshly new-signed) tokens would otherwise be
43
- * rejected. `undefined` is a valid cached value, so this refreshes purely on the
44
- * time interval (not on emptiness).
28
+ * Verify a token that speaks for a PERSON — access, step-up, and the token an
29
+ * opaque access key is exchanged for — against platform's published signing
30
+ * keys.
31
+ *
32
+ * ES256 and a `kid` are both mandatory: no `kid` means no way to pick the right
33
+ * key across a rotation, and any other algorithm is refused outright, which is
34
+ * what makes "no service accepts an HS256 user token" a property of the code
35
+ * rather than a convention. Key lookup goes through the shared JWKS cache
36
+ * (10-minute refresh, one refetch on an unknown `kid`, brief negative cache).
37
+ *
38
+ * @throws {UnknownKidError} the key set is current and has no such key → 401.
39
+ * @throws {JwksUnavailableError} the key set could not be obtained → 503; an
40
+ * unverifiable token is never treated as valid.
45
41
  */
46
- function getJwtSecretPrevious() {
47
- const now = Date.now();
48
- if (now - _jwtSecretPreviousRefreshedAt > JWT_SECRET_REFRESH_INTERVAL_MS) {
49
- _jwtSecretPrevious = process.env.JWT_SECRET_PREVIOUS || undefined;
50
- _jwtSecretPreviousRefreshedAt = now;
42
+ export async function verifyUserJwt(token) {
43
+ const header = decodeJwtHeader(token);
44
+ if (header?.alg !== USER_TOKEN_ALGORITHM || !header.kid) {
45
+ throw new jwt.JsonWebTokenError(`User tokens must be signed with ${USER_TOKEN_ALGORITHM} and carry a kid`);
51
46
  }
52
- return _jwtSecretPrevious;
47
+ const key = await platformJwksCache().getKey(header.kid);
48
+ return jwt.verify(token, key, { algorithms: [USER_TOKEN_ALGORITHM], ...issuerAudienceOptions() });
53
49
  }
54
50
  /**
55
- * Test-only: drop the cached JWT secrets so the next verify re-reads the env.
51
+ * Verify ANY bearer token and return its claims.
56
52
  *
57
- * Both secrets are cached for {@link JWT_SECRET_REFRESH_INTERVAL_MS}, so a test
58
- * that sets `JWT_SECRET`/`JWT_SECRET_PREVIOUS` mid-run would otherwise keep
59
- * verifying against the values read on first use. Don't call from production
60
- * code — rotation is picked up by the refresh interval.
61
- */
62
- export function _resetJwtSecretCacheForTests() {
63
- _jwtSecret = undefined;
64
- _jwtSecretRefreshedAt = 0;
65
- _jwtSecretPrevious = undefined;
66
- _jwtSecretPreviousRefreshedAt = 0;
67
- }
68
- /**
69
- * The JWT verify options every token check in the fleet must share: pinned
70
- * algorithm (blocks alg-confusion / `alg:none`) plus issuer/audience when the
71
- * deployment configures them.
53
+ * Since #14 there is no shared secret left: BOTH chains are ES256 with a `kid`,
54
+ * so the dispatch is by **who owns the `kid`** rather than by algorithm — and
55
+ * because a `kid` is an RFC 7638 thumbprint, ownership is a fact about the key,
56
+ * not a claim the token makes about itself:
72
57
  *
73
- * Centralized because it was built inline at each call site and `step-up.ts`
74
- * re-implemented it WITHOUT the issuer/audience pinning — so in a deployment
75
- * that sets `JWT_ISSUER`/`JWT_AUDIENCE`, a step-up token minted by any other
76
- * system sharing `JWT_SECRET` was accepted.
77
- */
78
- export function buildJwtVerifyOptions() {
79
- const verifyOptions = {
80
- algorithms: [(process.env.JWT_ALGORITHM || 'HS256')],
81
- };
82
- if (process.env.JWT_ISSUER)
83
- verifyOptions.issuer = process.env.JWT_ISSUER;
84
- if (process.env.JWT_AUDIENCE)
85
- verifyOptions.audience = process.env.JWT_AUDIENCE;
86
- return verifyOptions;
87
- }
88
- /**
89
- * Verify a JWT against the primary secret, falling back to the previous secret
90
- * (when `JWT_SECRET_PREVIOUS` is configured) ONLY on a signature/verification
91
- * failure. This makes token verification survive a secret rotation with zero
92
- * downtime: a token valid under EITHER secret passes.
58
+ * - a `kid` published in the per-service key bundle → an INTERNAL SERVICE token
59
+ * ({@link signServiceToken}), verified with that service's key; its `sub` must
60
+ * name the same service, so one service can never speak for another.
61
+ * - anything else → a platform-signed USER token, verified against platform's
62
+ * published JWKS. A token claiming `principalType: 'service'` is refused
63
+ * here: an internal identity may not ride the user signing key.
93
64
  *
94
- * jsonwebtoken's `verify` takes a single secret, so this is try-primary-then-
95
- * previous — NOT a secret array. No existing check is weakened:
96
- * - `verifyOptions` (algorithm pinning + optional issuer/audience) is applied
97
- * identically on BOTH attempts, so alg-confusion / `alg:none` stay blocked.
98
- * - Expiry / not-before from the PRIMARY attempt are authoritative and are
99
- * re-thrown without a previous-secret retry, so a `TokenExpiredError` is
100
- * never masked into an "invalid signature".
101
- * - When no previous secret is set, behaviour is byte-for-byte the original:
102
- * the primary error propagates unchanged.
65
+ * Anything that is not ES256 with a `kid` fails in both chains, which is what
66
+ * makes "no HS256 token is accepted anywhere" a property of the code.
103
67
  */
104
- export function verifyJwtWithRotation(token, verifyOptions) {
105
- try {
106
- return jwt.verify(token, getJwtSecret(), verifyOptions);
107
- }
108
- catch (err) {
109
- const previous = getJwtSecretPrevious();
110
- // Fall back to the previous secret only for a signature/verification failure
111
- // (a plain JsonWebTokenError). Expiry / not-before are enforced regardless of
112
- // which secret signed the token, so those errors must surface as-is.
113
- if (previous
114
- && err instanceof jwt.JsonWebTokenError
115
- && !(err instanceof jwt.TokenExpiredError)
116
- && !(err instanceof jwt.NotBeforeError)) {
117
- // A token signed by the previous secret verifies here; if it is instead
118
- // expired/invalid under the previous secret, that error propagates and is
119
- // handled by the caller exactly like a primary failure.
120
- return jwt.verify(token, previous, verifyOptions);
68
+ export async function verifyBearerToken(token) {
69
+ const header = decodeJwtHeader(token);
70
+ if (!header?.alg)
71
+ throw new jwt.JsonWebTokenError('Malformed token header');
72
+ if (header.kid && isServiceKid(header.kid)) {
73
+ const claims = verifyServiceJwt(token, { kid: header.kid, ...issuerAudienceOptions() });
74
+ if (claims.principalType !== 'service') {
75
+ emitCounter('service_key_non_service_token_rejected_total', { alg: header.alg });
76
+ throw new jwt.JsonWebTokenError('A service signing key may only mint a service principal');
121
77
  }
122
- throw err;
78
+ return claims;
79
+ }
80
+ const claims = await verifyUserJwt(token);
81
+ if (claims.principalType === 'service') {
82
+ throw new jwt.JsonWebTokenError('Service principals may not be signed with the user signing key');
123
83
  }
84
+ return claims;
124
85
  }
125
86
  export function requireAuth(reqOrOptions, res, next) {
126
87
  if (reqOrOptions && res && next && 'headers' in reqOrOptions) {
127
88
  return _requireAuth({}, reqOrOptions, res, next);
128
89
  }
129
90
  const options = reqOrOptions || {};
130
- return (req, resInner, nextInner) => {
91
+ const gate = tagRouteGate((req, resInner, nextInner) => {
131
92
  _requireAuth(options, req, resInner, nextInner);
132
- };
93
+ }, { kind: 'auth' });
94
+ if (options.minAssurance) {
95
+ tagRouteGate(gate, { kind: 'assurance', minAssurance: options.minAssurance, ...(options.maxAge !== undefined ? { maxAge: options.maxAge } : {}) });
96
+ }
97
+ return gate;
133
98
  }
99
+ tagRouteGate(requireAuth, { kind: 'auth' });
134
100
  let tokenRevocationStore;
135
101
  /**
136
102
  * Register (or clear, with `undefined`) the process-wide token-revocation store.
@@ -220,22 +186,55 @@ function _requireAuth(options, req, res, next) {
220
186
  if (parts.length !== 2 || parts[0] !== 'Bearer') {
221
187
  return sendError(res, HttpStatus.UNAUTHORIZED, 'Invalid authorization format. Use: Bearer <token>', ErrorCode.TOKEN_INVALID);
222
188
  }
189
+ // An OPAQUE ACCESS KEY (`pb_pat_…` / `pb_sa_…`) carries no claims and no
190
+ // signature, so it cannot be verified here. Trade it at platform for a
191
+ // short-lived JWT (cached in-process until it expires) and then verify that
192
+ // JWT on the normal path — services never read a key hash. See
193
+ // `services/api-key-exchange.ts`.
194
+ if (isOpaqueApiKey(parts[1])) {
195
+ void resolveApiKey(options, parts[1], req, res, next);
196
+ return;
197
+ }
198
+ // `.catch(next)` forwards a DOWNSTREAM synchronous throw from `next()` to
199
+ // Express's error middleware — verification itself never rejects (it maps
200
+ // every failure to a response).
201
+ void verifyAndAttach(options, parts[1], req, res, next).catch(next);
202
+ }
203
+ /**
204
+ * Exchange an opaque key for a JWT, then continue on the normal verification
205
+ * path. A refused key is a 401; an unreachable platform is a 503 (never a pass —
206
+ * an unverifiable credential is not an identity).
207
+ */
208
+ async function resolveApiKey(options, key, req, res, next) {
209
+ // Loaded LAZILY, on the first key ever presented. A static import would put
210
+ // the HTTP client (and platform's address) into the import graph of every
211
+ // module that merely uses `requireAuth`, which both widens the boot graph and
212
+ // breaks any test that mocks `http-client.js` with a partial module.
213
+ const { exchangeApiKey, ApiKeyExchangeUnavailableError } = await import('../services/api-key-exchange.js');
214
+ let token;
215
+ try {
216
+ token = await exchangeApiKey(key);
217
+ }
218
+ catch (error) {
219
+ if (error instanceof ApiKeyExchangeUnavailableError) {
220
+ return sendError(res, HttpStatus.SERVICE_UNAVAILABLE, 'Access-key verification is temporarily unavailable; please retry', ErrorCode.SERVICE_UNAVAILABLE);
221
+ }
222
+ return sendError(res, HttpStatus.UNAUTHORIZED, 'Invalid or revoked access key', ErrorCode.TOKEN_INVALID);
223
+ }
224
+ await verifyAndAttach(options, token, req, res, next);
225
+ }
226
+ async function verifyAndAttach(options, rawToken, req, res, next) {
223
227
  try {
224
- // Pass through optional issuer/audience verification when env-configured.
225
- // Without these, a JWT signed by any system that happens to share the
226
- // same JWT_SECRET would be accepted — defence-in-depth for shared-secret
227
- // misconfigurations across services / environments.
228
- // Pin the accepted algorithm to the configured HMAC alg (default HS256).
229
- // Without an allow-list, `jwt.verify` accepts any algorithm the key can
230
- // verify — the classic alg-confusion vector (and a hard guard against
231
- // `alg:none`). Env-driven so it stays in lockstep with how tokens are
232
- // signed (see signServiceToken + platform's config.auth.jwt.algorithm).
233
- const verifyOptions = buildJwtVerifyOptions();
234
- const decoded = verifyJwtWithRotation(parts[1], verifyOptions);
228
+ // Two chains, one entry point (see `verifyBearerToken`): a user token must
229
+ // be ES256 signed by platform and verified against its published JWKS; an
230
+ // internal service token stays on the shared secret and must declare itself
231
+ // a service principal. Both pin the algorithm (no alg-confusion, no
232
+ // `alg:none`) and both apply the optional issuer/audience binding.
233
+ const decoded = await verifyBearerToken(rawToken);
235
234
  if (decoded.type !== 'access') {
236
235
  return sendError(res, HttpStatus.UNAUTHORIZED, 'Only access tokens can be used for API requests', ErrorCode.TOKEN_INVALID);
237
236
  }
238
- if (!decoded.sub || !decoded.role) {
237
+ if (!decoded.sub || !decoded.role || !hasValidIdentityClaims(decoded)) {
239
238
  return sendError(res, HttpStatus.UNAUTHORIZED, 'Token missing required fields', ErrorCode.TOKEN_INVALID);
240
239
  }
241
240
  // Service-token kill-switch: reject a service principal whose service has
@@ -244,12 +243,28 @@ function _requireAuth(options, req, res, next) {
244
243
  // nukes EVERY service token fleet-wide. This lets one compromised/rogue
245
244
  // service be cut off surgically. O(1) Set lookup, zero cost when the denylist
246
245
  // is empty (the default), so it never taxes the S2S hot path unless armed.
247
- if (decoded.sub.startsWith('service:') && isServiceTokenDenied(decoded.sub)) {
248
- emitCounter('service_token_denied_total', { service: decoded.sub.slice('service:'.length) });
246
+ if (isServiceTokenDenied(decoded)) {
247
+ emitCounter('service_token_denied_total', { service: serviceNameOf(decoded) ?? 'unknown' });
249
248
  logger.warn('Rejected denylisted service token', { sub: decoded.sub });
250
249
  return sendError(res, HttpStatus.UNAUTHORIZED, 'Service token revoked', ErrorCode.TOKEN_REVOKED);
251
250
  }
252
251
  req.user = { ...decoded };
252
+ // BOOTSTRAP-ADMIN ENROLMENT SESSION (#8, revision 4). Such a token exists so
253
+ // the install's only admin can enrol a factor; it is `aal: 1` and must not
254
+ // reach anything else. Platform — which owns the exception and knows which
255
+ // of its own routes `init-platform.sh` calls — allows an explicit few before
256
+ // this point (see its own `requireAuth`); in EVERY other service the answer
257
+ // is simply no, so the reach restriction holds without a per-service
258
+ // allowlist to keep in sync.
259
+ if (decoded.mfaEnrollmentPending === true) {
260
+ emitCounter('mfa_enforcement_refused_total', { service: serviceIdentity(), reason: 'bootstrap_session' });
261
+ recordAuthzDenial(req, 'mfa-enrolment');
262
+ return sendError(res, HttpStatus.FORBIDDEN, 'Finish setting up two-factor authentication before using the rest of Pipeline Builder', ErrorCode.MFA_ENROLLMENT_REQUIRED);
263
+ }
264
+ // Session-level assurance (`requireAuth({ minAssurance, maxAge })`).
265
+ if (options.minAssurance
266
+ && refuseForAssurance({ minAssurance: options.minAssurance, ...(options.maxAge !== undefined ? { maxAge: options.maxAge } : {}) }, decoded, req, res))
267
+ return;
253
268
  // The x-org-id/x-org-name override lets a SYS-ADMIN act on a chosen org
254
269
  // (cross-org admin tooling). It is gated on the verified `isSuperAdmin` claim
255
270
  // here so that even a route which mistakenly enables `allowOrgHeaderOverride`
@@ -318,12 +333,113 @@ function _requireAuth(options, req, res, next) {
318
333
  if (error instanceof jwt.TokenExpiredError) {
319
334
  return sendError(res, HttpStatus.UNAUTHORIZED, 'Token has expired', ErrorCode.TOKEN_EXPIRED);
320
335
  }
321
- if (error instanceof jwt.JsonWebTokenError) {
336
+ // The signing keys couldn't be fetched, so the token's validity is UNKNOWN.
337
+ // Fail CLOSED with a retryable 503 — never a pass, and never a 401 that
338
+ // would send a legitimate client off to re-authenticate over our outage.
339
+ // Same reasoning for the SERVICE chain: no readable key bundle means no way
340
+ // to tell a peer's token from a forgery, so the request is refused with a
341
+ // retryable 503 rather than admitted or bounced to re-authenticate.
342
+ if (error instanceof JwksUnavailableError || error instanceof ServiceKeyError) {
343
+ logger.warn('Rejecting request: token signing keys unavailable', { error: error.message });
344
+ return sendError(res, HttpStatus.SERVICE_UNAVAILABLE, 'Token verification is temporarily unavailable; please retry', ErrorCode.SERVICE_UNAVAILABLE);
345
+ }
346
+ if (error instanceof UnknownKidError || error instanceof jwt.JsonWebTokenError) {
322
347
  return sendError(res, HttpStatus.UNAUTHORIZED, 'Invalid token', ErrorCode.TOKEN_INVALID);
323
348
  }
324
349
  return sendError(res, HttpStatus.UNAUTHORIZED, 'Authentication failed', ErrorCode.UNAUTHORIZED);
325
350
  }
326
351
  }
352
+ /**
353
+ * Whether a set of verified claims speaks for a PERSON's own session — the only
354
+ * kind of credential an assurance level can be asserted about.
355
+ *
356
+ * Excludes all three machine shapes: an internal service principal, an org
357
+ * service account, and any exchanged access key (`token_use: 'api_key'`, i.e. a
358
+ * PAT or a service-account key), each of which authenticates a program holding a
359
+ * secret rather than a person presenting factors.
360
+ */
361
+ export function isHumanPrincipal(claims) {
362
+ return claims?.principalType === 'user' && claims.token_use === 'access';
363
+ }
364
+ /**
365
+ * Standalone assurance gate, for a service whose own `requireAuth` is not
366
+ * api-core's (platform's is its own, because it reads Mongo). Compose it AFTER
367
+ * authentication: `router.get('/x', requireAuth, requireAssurance({ minAssurance: 2 }), h)`.
368
+ *
369
+ * Identical rules and identical refusals to `requireAuth({ minAssurance })` —
370
+ * that option simply calls the same check inline, so there is one implementation
371
+ * of "is this session MFA-grade" in the codebase.
372
+ */
373
+ export function requireAssurance(options) {
374
+ return tagRouteGate((req, res, next) => {
375
+ if (!req.user) {
376
+ return sendError(res, HttpStatus.UNAUTHORIZED, 'Authentication required', ErrorCode.UNAUTHORIZED);
377
+ }
378
+ if (refuseForAssurance(options, req.user, req, res))
379
+ return;
380
+ next();
381
+ }, { kind: 'assurance', minAssurance: options.minAssurance, ...(options.maxAge !== undefined ? { maxAge: options.maxAge } : {}) });
382
+ }
383
+ /**
384
+ * Enforce `minAssurance` / `maxAge` on a verified token. Returns true when the
385
+ * request was REFUSED (a response has been sent).
386
+ *
387
+ * Three distinct refusals, because the client's next move differs for each:
388
+ * a machine must stop (403), a weak session must gain a factor (401
389
+ * `MFA_REQUIRED` → enrolment, never a sign-out), and a stale one must simply
390
+ * authenticate again (401 `REAUTH_REQUIRED`).
391
+ */
392
+ function refuseForAssurance(options, decoded, req, res) {
393
+ const minAssurance = options.minAssurance;
394
+ const refuse = (reason, status, message, code) => {
395
+ emitCounter('mfa_enforcement_refused_total', { service: serviceIdentity(), reason });
396
+ recordAuthzDenial(req, `assurance:${minAssurance}`);
397
+ sendError(res, status, message, code);
398
+ return true;
399
+ };
400
+ if (!isHumanPrincipal(decoded)) {
401
+ return refuse('machine_principal', HttpStatus.FORBIDDEN, 'This action requires a person signed in with two-factor authentication — API keys and service accounts cannot perform it', ErrorCode.HUMAN_SESSION_REQUIRED);
402
+ }
403
+ if ((decoded.aal ?? 1) < minAssurance) {
404
+ return refuse('weak_session', HttpStatus.UNAUTHORIZED, 'This action requires two-factor authentication — sign in again with a passkey or an authenticator code', ErrorCode.MFA_REQUIRED);
405
+ }
406
+ if (options.maxAge !== undefined) {
407
+ const authTime = decoded.auth_time;
408
+ // No `auth_time` is not "recent enough by default" — `hasValidIdentityClaims`
409
+ // already requires it on a user token, so an absent one means a token this
410
+ // gate cannot reason about. Fail closed.
411
+ if (typeof authTime !== 'number' || Math.floor(Date.now() / 1000) - authTime > options.maxAge) {
412
+ return refuse('stale_session', HttpStatus.UNAUTHORIZED, 'This action requires a recent sign-in — please authenticate again', ErrorCode.REAUTH_REQUIRED);
413
+ }
414
+ }
415
+ return false;
416
+ }
417
+ /**
418
+ * Whether a verified token carries a well-formed identity: a known
419
+ * `principalType` and `token_use`, and the claims that kind of principal must
420
+ * have. Fails closed — a token minted before these claims existed, or one with a
421
+ * contradictory combination, is not an identity any gate should reason about.
422
+ *
423
+ * - `service`: `token_use: 'access'` and a `service:<name>` subject (the name
424
+ * feeds the denylist and audit attribution).
425
+ * - `user` / `service_account`: `amr` (known methods), `aal` and `auth_time`.
426
+ */
427
+ export function hasValidIdentityClaims(decoded) {
428
+ if (!decoded.principalType || !PRINCIPAL_TYPES.includes(decoded.principalType))
429
+ return false;
430
+ if (!decoded.token_use || !TOKEN_USES.includes(decoded.token_use))
431
+ return false;
432
+ if (decoded.principalType === 'service') {
433
+ return decoded.token_use === 'access'
434
+ && typeof decoded.sub === 'string'
435
+ && decoded.sub.startsWith(SERVICE_SUBJECT_PREFIX)
436
+ && decoded.sub.length > SERVICE_SUBJECT_PREFIX.length;
437
+ }
438
+ return Array.isArray(decoded.amr)
439
+ && decoded.amr.every((m) => AUTH_METHODS.includes(m))
440
+ && (decoded.aal === 1 || decoded.aal === 2)
441
+ && typeof decoded.auth_time === 'number';
442
+ }
327
443
  /**
328
444
  * Whether the request's user holds `permission`. Superadmins implicitly hold
329
445
  * every permission. Reads the resolved `permissions` claim (set at token issue,
@@ -352,8 +468,12 @@ export function setAuthzDenialAuditor(fn) {
352
468
  * Emit a denial event, best-effort. Only fires for state-changing (non-GET,
353
469
  * non-HEAD/OPTIONS) requests — a rejected GET is low-signal probing noise and
354
470
  * would amplify audit volume under a scan. Never throws.
471
+ *
472
+ * The permission gates here call it themselves. Export it for data-driven checks
473
+ * a route makes inline (cross-org access, service-only endpoints), so those 403s
474
+ * reach the same `authz.denied` trail. `required` names what was missing.
355
475
  */
356
- function auditAuthzDenial(req, required) {
476
+ export function recordAuthzDenial(req, required) {
357
477
  const auditor = authzDenialAuditor;
358
478
  if (!auditor)
359
479
  return;
@@ -383,7 +503,7 @@ function auditAuthzDenial(req, required) {
383
503
  * them should grant access.
384
504
  */
385
505
  export function requirePermission(...permissions) {
386
- return (req, res, next) => {
506
+ return tagRouteGate((req, res, next) => {
387
507
  if (!req.user) {
388
508
  return sendError(res, HttpStatus.UNAUTHORIZED, 'Authentication required', ErrorCode.UNAUTHORIZED);
389
509
  }
@@ -392,9 +512,9 @@ export function requirePermission(...permissions) {
392
512
  // the any-of membership test without re-inlining either.
393
513
  if (permissions.some((p) => userHasPermission(req, p)))
394
514
  return next();
395
- auditAuthzDenial(req, permissions.join(' or '));
515
+ recordAuthzDenial(req, permissions.join(' or '));
396
516
  return sendError(res, HttpStatus.FORBIDDEN, `Missing required permission: ${permissions.join(' or ')}`, ErrorCode.INSUFFICIENT_PERMISSIONS);
397
- };
517
+ }, { kind: 'permission', mode: 'any', permissions });
398
518
  }
399
519
  /**
400
520
  * Requires that the user hold EVERY one of the given permissions (or be a
@@ -405,20 +525,20 @@ export function requirePermission(...permissions) {
405
525
  * (they implicitly hold every permission).
406
526
  */
407
527
  export function requireAllPermissions(...permissions) {
408
- return (req, res, next) => {
528
+ return tagRouteGate((req, res, next) => {
409
529
  if (!req.user) {
410
530
  return sendError(res, HttpStatus.UNAUTHORIZED, 'Authentication required', ErrorCode.UNAUTHORIZED);
411
531
  }
412
532
  const missing = permissions.filter((p) => !userHasPermission(req, p));
413
533
  if (missing.length === 0)
414
534
  return next();
415
- auditAuthzDenial(req, permissions.join(' and '));
535
+ recordAuthzDenial(req, permissions.join(' and '));
416
536
  return sendError(res, HttpStatus.FORBIDDEN, `Missing required permission: ${missing.join(' and ')}`, ErrorCode.INSUFFICIENT_PERMISSIONS);
417
- };
537
+ }, { kind: 'permission', mode: 'all', permissions });
418
538
  }
419
539
  /**
420
540
  * Like {@link requirePermission} (any-of) but ALSO admits an internal service
421
- * principal (a `service:*` machine token). For READ endpoints that BOTH
541
+ * principal (`principalType: 'service'`). For READ endpoints that BOTH
422
542
  * interactive users — who must hold one of the `:read` capabilities — AND
423
543
  * service-to-service callers legitimately hit; service tokens carry no
424
544
  * permission claims (they're least-privilege `role:member`), so a plain
@@ -428,19 +548,19 @@ export function requireAllPermissions(...permissions) {
428
548
  * `requirePermission` for purely user-facing reads.
429
549
  */
430
550
  export function requirePermissionOrService(...permissions) {
431
- return (req, res, next) => {
551
+ return tagRouteGate((req, res, next) => {
432
552
  if (!req.user) {
433
553
  return sendError(res, HttpStatus.UNAUTHORIZED, 'Authentication required', ErrorCode.UNAUTHORIZED);
434
554
  }
435
555
  if (isServicePrincipal(req) || permissions.some((p) => userHasPermission(req, p)))
436
556
  return next();
437
- auditAuthzDenial(req, permissions.join(' or '));
557
+ recordAuthzDenial(req, permissions.join(' or '));
438
558
  return sendError(res, HttpStatus.FORBIDDEN, `Missing required permission: ${permissions.join(' or ')}`, ErrorCode.INSUFFICIENT_PERMISSIONS);
439
- };
559
+ }, { kind: 'permission', mode: 'any', permissions, allowService: true });
440
560
  }
441
561
  /**
442
- * Gate an endpoint to internal service-to-service callers only (a `service:*`
443
- * machine principal minted via {@link signServiceToken} / `getServiceAuthHeader`).
562
+ * Gate an endpoint to internal service-to-service callers only (a
563
+ * `principalType: 'service'` principal minted via {@link signServiceToken} / `getServiceAuthHeader`).
444
564
  * Rejects any user token. For NON-user-facing endpoints — entity-event ingest,
445
565
  * auto-subscribe, and similar peer-service hooks — that a browser must never
446
566
  * reach. Compose after `requireAuth` so `req.user` is populated.
@@ -453,6 +573,59 @@ export function requireServicePrincipal(req, res, next) {
453
573
  }
454
574
  next();
455
575
  }
576
+ tagRouteGate(requireServicePrincipal, { kind: 'servicePrincipal' });
577
+ /**
578
+ * THE gate for an INTERNAL route (#14) — the one every `/internal/*` path, the
579
+ * quota usage counters, the entity-event ingest and the audit ingest go through.
580
+ *
581
+ * Two rules, both fail-closed:
582
+ *
583
+ * 1. **No user token, ever.** Not a member's, not a superadmin's, not a
584
+ * service-account key's. An internal route is a peer-service API surface, so
585
+ * "a sufficiently privileged human" is not an acceptable caller — that
586
+ * equivalence is exactly how a browser-reachable path becomes a tenant
587
+ * boundary bug. `requireServicePrincipal` already refused users; this also
588
+ * closes the `|| isSystemAdmin(req)` escape hatches that had grown around
589
+ * the individual internal routes.
590
+ * 2. **Only the NAMED callers.** `callers` lists the services that legitimately
591
+ * call this route, and the name is cryptographically bound to the signing
592
+ * key (`services/service-keys.ts`), so this is an identity check rather than
593
+ * a claim check. It is the same allow-list the mesh policy names, at the
594
+ * layer that also holds in docker compose, where there is no mesh at all —
595
+ * the Istio `AuthorizationPolicy` is defence in depth on top, never the
596
+ * enforcement.
597
+ *
598
+ * Compose after `requireAuth` so `req.user` is populated. Refusals are counted
599
+ * (`internal_route_refused_total`) and audited through the shared `authz.denied`
600
+ * sink.
601
+ */
602
+ export function requireInternalService(options) {
603
+ const allowed = new Set(options.callers);
604
+ return tagRouteGate((req, res, next) => {
605
+ const refuse = (reason) => {
606
+ emitCounter('internal_route_refused_total', {
607
+ service: serviceIdentity(),
608
+ route: req.route?.path ? `${req.method} ${req.baseUrl}${req.route.path}` : `${req.method} ${(req.originalUrl || req.url).split('?')[0]}`,
609
+ reason,
610
+ caller: serviceNameOf(req.user) ?? 'none',
611
+ });
612
+ recordAuthzDenial(req, `internal-service (${options.callers.join(', ')})`);
613
+ if (reason === 'unauthenticated') {
614
+ return sendError(res, HttpStatus.UNAUTHORIZED, 'Authentication required', ErrorCode.UNAUTHORIZED);
615
+ }
616
+ logger.warn('Refused an internal route', { reason, path: (req.originalUrl || req.url).split('?')[0], caller: serviceNameOf(req.user) });
617
+ return sendError(res, HttpStatus.FORBIDDEN, 'Internal service calls only', ErrorCode.INSUFFICIENT_PERMISSIONS);
618
+ };
619
+ if (!req.user)
620
+ return refuse('unauthenticated');
621
+ if (!isServicePrincipal(req))
622
+ return refuse('user_token');
623
+ const caller = serviceNameOf(req.user);
624
+ if (!caller || !allowed.has(caller))
625
+ return refuse('wrong_caller');
626
+ next();
627
+ }, { kind: 'servicePrincipal' }, { kind: 'internalService', callers: [...options.callers] });
628
+ }
456
629
  /**
457
630
  * The system tenant's canonical org **id** — a fixed, well-known ObjectId (NOT
458
631
  * the string 'system'). This is the single knob every service resolves the
@@ -498,18 +671,19 @@ export function hasScope(req, scope) {
498
671
  * (the org-membership path was removed). Use after requireAuth. */
499
672
  export function requireSystemAdmin(req, res, next) {
500
673
  if (!isSystemAdmin(req)) {
501
- auditAuthzDenial(req, 'system-admin');
674
+ recordAuthzDenial(req, 'system-admin');
502
675
  return sendError(res, HttpStatus.FORBIDDEN, 'Access denied. Only system administrators can perform this action.', ErrorCode.INSUFFICIENT_PERMISSIONS);
503
676
  }
504
677
  next();
505
678
  }
679
+ tagRouteGate(requireSystemAdmin, { kind: 'systemAdmin' });
506
680
  /**
507
681
  * Require a specific feature flag. Use after requireAuth.
508
682
  * Checks the `features` array in the JWT payload (set at token issuance).
509
683
  * Sysadmins (isSuperAdmin) bypass — they always have every feature.
510
684
  */
511
685
  export function requireFeature(feature) {
512
- return (req, res, next) => {
686
+ return tagRouteGate((req, res, next) => {
513
687
  if (!req.user) {
514
688
  return sendError(res, HttpStatus.UNAUTHORIZED, 'Authentication required', ErrorCode.UNAUTHORIZED);
515
689
  }
@@ -523,19 +697,22 @@ export function requireFeature(feature) {
523
697
  // Route feature-gate denials through the same audit sink as
524
698
  // requirePermission / requireSystemAdmin so a probe for an
525
699
  // unentitled capability leaves a trail (state-changing methods only).
526
- auditAuthzDenial(req, `feature:${feature}`);
700
+ recordAuthzDenial(req, `feature:${feature}`);
527
701
  return sendError(res, HttpStatus.FORBIDDEN, `This feature requires a higher plan (${feature})`, ErrorCode.INSUFFICIENT_PERMISSIONS);
528
702
  }
529
703
  next();
530
- };
704
+ }, { kind: 'feature', feature });
531
705
  }
532
706
  // ---------------------------------------------------------------------------
533
707
  // Service-to-service tokens
534
708
  //
535
709
  // Inter-service HTTP calls (billing → message, platform → compliance, etc.)
536
710
  // need to satisfy the same `requireAuth` middleware as user requests.
537
- // `signServiceToken` mints a short-lived JWT signed with the shared
538
- // JWT_SECRET, identifying the calling service via `sub: 'service:<name>'`.
711
+ // `signServiceToken` mints a short-lived ES256 JWT signed with THIS service's
712
+ // OWN key (see `services/service-keys.ts`), carrying `principalType: 'service'`
713
+ // and naming the calling service via `sub: 'service:<name>'`. Gates branch on
714
+ // the claim; the subject names — and since #14 the name is cryptographically
715
+ // bound to the signing key, so it can also be trusted.
539
716
  // `requireAuth` accepts these tokens transparently — they pass `decoded.sub`
540
717
  // and `decoded.role` checks, and downstream `requireOrganization` /
541
718
  // `requireSystemAdmin` rely on the org/role embedded in the token.
@@ -546,102 +723,130 @@ export function requireFeature(feature) {
546
723
  const DEFAULT_SERVICE_TOKEN_TTL_SECONDS = 300;
547
724
  /**
548
725
  * Denylist of service NAMES (the `<name>` in `sub: service:<name>`) whose tokens
549
- * `requireAuth` must reject. Seeded from `SERVICE_TOKEN_DENYLIST` (comma-separated)
550
- * at module load; a service can push live updates (e.g. from a Redis-subscribed
551
- * kill-switch) via {@link setServiceTokenDenylist} so a compromised service can be
552
- * cut off WITHOUT rotating the shared JWT secret (which invalidates all of them).
726
+ * `requireAuth` must reject. Read from `SERVICE_TOKEN_DENYLIST` (comma-separated)
727
+ * at process start, so arming it is a config change + rollout — it cuts off a
728
+ * compromised service WITHOUT rotating any key, and (unlike the pre-#14 shared
729
+ * secret) without invalidating every other service's tokens as collateral.
553
730
  */
554
- let serviceTokenDenylist = new Set((process.env.SERVICE_TOKEN_DENYLIST || '')
731
+ const serviceTokenDenylist = new Set((process.env.SERVICE_TOKEN_DENYLIST || '')
555
732
  .split(',')
556
733
  .map((s) => s.trim())
557
734
  .filter(Boolean));
558
- /** Replace the service-token denylist (service names). Empty ⇒ kill-switch off. */
559
- export function setServiceTokenDenylist(names) {
560
- serviceTokenDenylist = new Set([...names].map((s) => s.trim()).filter(Boolean));
735
+ /**
736
+ * The calling service's name for a SERVICE principal (`principalType: 'service'`),
737
+ * else `undefined`. A user token never yields a name, whatever its `sub` says.
738
+ */
739
+ export function serviceNameOf(claims) {
740
+ if (claims?.principalType !== 'service' || typeof claims.sub !== 'string')
741
+ return undefined;
742
+ if (!claims.sub.startsWith(SERVICE_SUBJECT_PREFIX))
743
+ return undefined;
744
+ return claims.sub.slice(SERVICE_SUBJECT_PREFIX.length) || undefined;
561
745
  }
562
- /** True when `sub` is `service:<name>` and `<name>` is on the denylist. */
563
- export function isServiceTokenDenied(sub) {
746
+ /** True when the claims are a service principal whose service is on the denylist. */
747
+ export function isServiceTokenDenied(claims) {
564
748
  if (serviceTokenDenylist.size === 0)
565
749
  return false;
566
- if (!sub.startsWith('service:'))
567
- return false;
568
- return serviceTokenDenylist.has(sub.slice('service:'.length));
750
+ const name = serviceNameOf(claims);
751
+ return name !== undefined && serviceTokenDenylist.has(name);
569
752
  }
570
753
  /**
571
754
  * Mint a JWT identifying the calling service. Used for inter-service HTTP calls.
572
755
  * The token satisfies `requireAuth` and (when orgId is present) `requireOrganization`.
573
756
  * Scope it with `opts.role` — least privilege keeps a leaked token low-value.
757
+ *
758
+ * `opts.serviceName` must be THIS process's own identity (`SERVICE_NAME`): a
759
+ * service holds only its own signing key, so minting a token that names another
760
+ * service throws rather than producing one every peer would reject. That is the
761
+ * one behaviour change #14 forces on callers — see `services/service-keys.ts`.
574
762
  */
575
763
  export function signServiceToken(opts) {
576
764
  const role = opts.role;
577
765
  const payload = {
578
- sub: `service:${opts.serviceName}`,
579
766
  username: `${opts.serviceName}-service`,
580
767
  email: `${opts.serviceName}@internal`,
768
+ principalType: 'service',
769
+ token_use: 'access',
581
770
  role,
582
771
  isAdmin: role === 'owner' || role === 'admin',
583
772
  type: 'access',
584
773
  organizationId: opts.orgId,
585
774
  organizationName: opts.orgName ?? opts.orgId,
775
+ // Unique token id on every mint. Combined with the short (300s default) TTL
776
+ // this gives each service token a distinct identity — the correlation handle
777
+ // for tracing which mint performed a cross-service action, and the building
778
+ // block for replay detection (a verifier can track seen jtis). It does NOT
779
+ // by itself prevent replay within the TTL window.
780
+ jti: randomUUID(),
586
781
  // Least-privilege capability claim (optional) — lets a member-role token
587
782
  // satisfy a specific permission gate without carrying isAdmin.
588
783
  ...(opts.permissions && opts.permissions.length > 0 ? { permissions: opts.permissions } : {}),
589
784
  };
590
- // Match the optional issuer/audience that requireAuth verifies, when
591
- // configured. Without these, a service token signed here would fail
592
- // requireAuth in a deployment that has set JWT_ISSUER/JWT_AUDIENCE.
593
- const signOptions = {
594
- expiresIn: opts.ttlSeconds ?? DEFAULT_SERVICE_TOKEN_TTL_SECONDS,
595
- // Sign with the same configured alg requireAuth pins on verify, so service
596
- // tokens stay valid under a non-default JWT_ALGORITHM.
597
- algorithm: (process.env.JWT_ALGORITHM || 'HS256'),
598
- // Unique token id on every mint. Combined with the short (300s default) TTL
599
- // this gives each service token a distinct identity — the building block for
600
- // replay detection (a verifier can track seen jtis) and the correlation
601
- // handle for tracing which mint performed a cross-service action. It does
602
- // NOT by itself prevent replay within the TTL window; true replay defence
603
- // needs the asymmetric-key work tracked separately.
604
- jwtid: randomUUID(),
605
- };
606
- if (process.env.JWT_ISSUER)
607
- signOptions.issuer = process.env.JWT_ISSUER;
608
- if (process.env.JWT_AUDIENCE)
609
- signOptions.audience = process.env.JWT_AUDIENCE;
610
- return jwt.sign(payload, getJwtSecret(), signOptions);
785
+ // `sub`, `iat`/`exp` and the optional issuer/audience that requireAuth
786
+ // verifies are stamped by the signer, so there is exactly one place that
787
+ // decides what a service token says.
788
+ return signServiceJwt(payload, {
789
+ serviceName: opts.serviceName,
790
+ expiresInSeconds: opts.ttlSeconds ?? DEFAULT_SERVICE_TOKEN_TTL_SECONDS,
791
+ ...issuerAudienceOptions(),
792
+ });
611
793
  }
612
794
  /** Convenience: returns a `Bearer <token>` header value for fetch/axios calls. */
613
795
  export function getServiceAuthHeader(opts) {
614
796
  return `Bearer ${signServiceToken(opts)}`;
615
797
  }
616
- /** True when `req.user.sub` was issued by `signServiceToken` (i.e. starts with `service:`). */
798
+ /** True when `req.user` is a service principal (`principalType: 'service'`, minted by `signServiceToken`). */
617
799
  export function isServicePrincipal(req) {
618
- return req.user?.sub?.startsWith('service:') ?? false;
800
+ return req.user?.principalType === 'service';
801
+ }
802
+ /**
803
+ * True when `req.user` is an ORG SERVICE ACCOUNT (`principalType:
804
+ * 'service_account'`) — a non-human principal owned by one org, authenticating
805
+ * with a `pb_sa_…` key exchanged at platform.
806
+ *
807
+ * A service account is NOT an internal service principal: it holds org Roles and
808
+ * is subject to every permission gate a member is. What it can never do is
809
+ * satisfy a HUMAN-presence requirement — step-up (and any later assurance gate)
810
+ * refuses it outright, because there is no person behind it to re-verify.
811
+ */
812
+ export function isServiceAccountPrincipal(req) {
813
+ return req.user?.principalType === 'service_account';
814
+ }
815
+ /** True when `req.user` is the named internal service (e.g. `'billing'`). */
816
+ export function isServicePrincipalNamed(req, serviceName) {
817
+ return serviceNameOf(req.user) === serviceName;
619
818
  }
620
819
  /**
621
820
  * PRE-auth check: cryptographically verify the request carries a valid, signed
622
- * SERVICE token (`sub` starts with `service:`). Unlike {@link isServicePrincipal}
821
+ * SERVICE token (`principalType: 'service'`). Unlike {@link isServicePrincipal}
623
822
  * (which reads the already-populated `req.user`), this verifies the bearer token
624
823
  * itself, so it is safe to call BEFORE `requireAuth` runs — e.g. the global rate
625
824
  * limiter's `skip`, which must not trust the spoofable `x-internal-service`
626
- * header. Mirrors `requireAuth`'s verification (algorithm pinning + optional
627
- * issuer/audience) and returns `false` on any missing/invalid/non-service token.
825
+ * header. Mirrors `requireAuth`'s SERVICE chain exactly (the signer's own key,
826
+ * resolved by `kid`, with the `sub`/signer agreement check and the optional
827
+ * issuer/audience) and returns `false` on any missing/invalid/non-service token
828
+ * — including any platform-signed USER token, whose `kid` is not in the service
829
+ * bundle at all. Stays SYNCHRONOUS, which is why the per-service public keys are
830
+ * distributed as a mounted bundle rather than fetched over HTTP.
628
831
  */
629
832
  export function verifyServicePrincipal(req) {
630
833
  const parts = req.headers.authorization?.split(' ');
631
834
  if (!parts || parts.length !== 2 || parts[0] !== 'Bearer')
632
835
  return false;
633
836
  try {
634
- const verifyOptions = buildJwtVerifyOptions();
635
- const decoded = verifyJwtWithRotation(parts[1], verifyOptions);
636
- if (decoded.type !== 'access' || typeof decoded.sub !== 'string' || !decoded.sub.startsWith('service:'))
837
+ const header = decodeJwtHeader(parts[1]);
838
+ if (!header?.kid || !isServiceKid(header.kid))
839
+ return false;
840
+ const decoded = verifyServiceJwt(parts[1], { kid: header.kid, ...issuerAudienceOptions() });
841
+ if (decoded.type !== 'access' || decoded.principalType !== 'service' || !hasValidIdentityClaims(decoded))
637
842
  return false;
638
843
  // A denylisted (killed) service must NOT be treated as a trusted principal —
639
844
  // otherwise it keeps the rate-limiter exemption even though requireAuth rejects
640
845
  // it on real routes. Fold the kill-switch into the pre-auth check too.
641
- return !isServiceTokenDenied(decoded.sub);
846
+ return !isServiceTokenDenied(decoded);
642
847
  }
643
848
  catch {
644
849
  return false;
645
850
  }
646
851
  }
647
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0aC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9taWRkbGV3YXJlL2F1dGgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQUV0QyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sUUFBUSxDQUFDO0FBRXBDLE9BQU8sR0FBRyxNQUFNLGNBQWMsQ0FBQztBQUMvQixPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFFekQsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBRXBELE9BQU8sRUFBbUIsYUFBYSxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDekUsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ3RELE9BQU8sRUFBRSxXQUFXLEVBQXdCLE1BQU0sc0JBQXNCLENBQUM7QUFDekUsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ2xELE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUN6RCxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFFakQsTUFBTSxNQUFNLEdBQUcsWUFBWSxDQUFDLGlCQUFpQixDQUFDLENBQUM7QUFFL0MsNERBQTREO0FBQzVELElBQUksVUFBOEIsQ0FBQztBQUNuQyxJQUFJLHFCQUFxQixHQUFHLENBQUMsQ0FBQztBQUM5Qiw4RUFBOEU7QUFDOUUsSUFBSSxrQkFBc0MsQ0FBQztBQUMzQyxJQUFJLDZCQUE2QixHQUFHLENBQUMsQ0FBQztBQUN0QyxNQUFNLDhCQUE4QixHQUFHLE9BQU8sQ0FBQyxDQUFDLFlBQVk7QUFFNUQsU0FBUyxZQUFZO0lBQ25CLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztJQUN2QixJQUFJLENBQUMsVUFBVSxJQUFJLEdBQUcsR0FBRyxxQkFBcUIsR0FBRyw4QkFBOEIsRUFBRSxDQUFDO1FBQ2hGLE1BQU0sTUFBTSxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDO1FBQ3RDLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztZQUNaLE1BQU0sQ0FBQyxLQUFLLENBQUMsNENBQTRDLENBQUMsQ0FBQztZQUMzRCxNQUFNLElBQUksS0FBSyxDQUFDLDZDQUE2QyxDQUFDLENBQUM7UUFDakUsQ0FBQztRQUNELElBQUksVUFBVSxJQUFJLFVBQVUsS0FBSyxNQUFNLEVBQUUsQ0FBQztZQUN4QyxNQUFNLENBQUMsSUFBSSxDQUFDLG9CQUFvQixDQUFDLENBQUM7UUFDcEMsQ0FBQztRQUNELFVBQVUsR0FBRyxNQUFNLENBQUM7UUFDcEIscUJBQXFCLEdBQUcsR0FBRyxDQUFDO0lBQzlCLENBQUM7SUFDRCxPQUFPLFVBQVUsQ0FBQztBQUNwQixDQUFDO0FBRUQ7Ozs7Ozs7O0dBUUc7QUFDSCxTQUFTLG9CQUFvQjtJQUMzQixNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7SUFDdkIsSUFBSSxHQUFHLEdBQUcsNkJBQTZCLEdBQUcsOEJBQThCLEVBQUUsQ0FBQztRQUN6RSxrQkFBa0IsR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDLG1CQUFtQixJQUFJLFNBQVMsQ0FBQztRQUNsRSw2QkFBNkIsR0FBRyxHQUFHLENBQUM7SUFDdEMsQ0FBQztJQUNELE9BQU8sa0JBQWtCLENBQUM7QUFDNUIsQ0FBQztBQUVEOzs7Ozs7O0dBT0c7QUFDSCxNQUFNLFVBQVUsNEJBQTRCO0lBQzFDLFVBQVUsR0FBRyxTQUFTLENBQUM7SUFDdkIscUJBQXFCLEdBQUcsQ0FBQyxDQUFDO0lBQzFCLGtCQUFrQixHQUFHLFNBQVMsQ0FBQztJQUMvQiw2QkFBNkIsR0FBRyxDQUFDLENBQUM7QUFDcEMsQ0FBQztBQUVEOzs7Ozs7Ozs7R0FTRztBQUNILE1BQU0sVUFBVSxxQkFBcUI7SUFDbkMsTUFBTSxhQUFhLEdBQXNCO1FBQ3ZDLFVBQVUsRUFBRSxDQUFDLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxhQUFhLElBQUksT0FBTyxDQUFrQixDQUFDO0tBQ3RFLENBQUM7SUFDRixJQUFJLE9BQU8sQ0FBQyxHQUFHLENBQUMsVUFBVTtRQUFFLGFBQWEsQ0FBQyxNQUFNLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUM7SUFDMUUsSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLFlBQVk7UUFBRSxhQUFhLENBQUMsUUFBUSxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsWUFBWSxDQUFDO0lBQ2hGLE9BQU8sYUFBYSxDQUFDO0FBQ3ZCLENBQUM7QUFFRDs7Ozs7Ozs7Ozs7Ozs7O0dBZUc7QUFDSCxNQUFNLFVBQVUscUJBQXFCLENBQUMsS0FBYSxFQUFFLGFBQWdDO0lBQ25GLElBQUksQ0FBQztRQUNILE9BQU8sR0FBRyxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUUsWUFBWSxFQUFFLEVBQUUsYUFBYSxDQUFlLENBQUM7SUFDeEUsQ0FBQztJQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7UUFDYixNQUFNLFFBQVEsR0FBRyxvQkFBb0IsRUFBRSxDQUFDO1FBQ3hDLDZFQUE2RTtRQUM3RSw4RUFBOEU7UUFDOUUscUVBQXFFO1FBQ3JFLElBQ0UsUUFBUTtlQUNMLEdBQUcsWUFBWSxHQUFHLENBQUMsaUJBQWlCO2VBQ3BDLENBQUMsQ0FBQyxHQUFHLFlBQVksR0FBRyxDQUFDLGlCQUFpQixDQUFDO2VBQ3ZDLENBQUMsQ0FBQyxHQUFHLFlBQVksR0FBRyxDQUFDLGNBQWMsQ0FBQyxFQUN2QyxDQUFDO1lBQ0Qsd0VBQXdFO1lBQ3hFLDBFQUEwRTtZQUMxRSx3REFBd0Q7WUFDeEQsT0FBTyxHQUFHLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRSxRQUFRLEVBQUUsYUFBYSxDQUFlLENBQUM7UUFDbEUsQ0FBQztRQUNELE1BQU0sR0FBRyxDQUFDO0lBQ1osQ0FBQztBQUNILENBQUM7QUF3QkQsTUFBTSxVQUFVLFdBQVcsQ0FDekIsWUFBMkMsRUFDM0MsR0FBYyxFQUNkLElBQW1CO0lBRW5CLElBQUksWUFBWSxJQUFJLEdBQUcsSUFBSSxJQUFJLElBQUksU0FBUyxJQUFJLFlBQVksRUFBRSxDQUFDO1FBQzdELE9BQU8sWUFBWSxDQUFDLEVBQUUsRUFBRSxZQUF1QixFQUFFLEdBQUcsRUFBRSxJQUFJLENBQUMsQ0FBQztJQUM5RCxDQUFDO0lBRUQsTUFBTSxPQUFPLEdBQUksWUFBbUMsSUFBSSxFQUFFLENBQUM7SUFDM0QsT0FBTyxDQUFDLEdBQVksRUFBRSxRQUFrQixFQUFFLFNBQXVCLEVBQUUsRUFBRTtRQUNuRSxZQUFZLENBQUMsT0FBTyxFQUFFLEdBQUcsRUFBRSxRQUFRLEVBQUUsU0FBUyxDQUFDLENBQUM7SUFDbEQsQ0FBQyxDQUFDO0FBQ0osQ0FBQztBQW1DRCxJQUFJLG9CQUFzRCxDQUFDO0FBRTNEOzs7OztHQUtHO0FBQ0gsTUFBTSxVQUFVLHVCQUF1QixDQUFDLEtBQXVDO0lBQzdFLG9CQUFvQixHQUFHLEtBQUssQ0FBQztJQUM3QixJQUFJLEtBQUs7UUFBRSw0QkFBNEIsR0FBRyxLQUFLLENBQUMsQ0FBQyxzQ0FBc0M7QUFDekYsQ0FBQztBQUVELGtGQUFrRjtBQUNsRixJQUFJLDRCQUE0QixHQUFHLEtBQUssQ0FBQztBQUV6Qzs7Ozs7R0FLRztBQUNILEtBQUssVUFBVSxjQUFjLENBQUMsT0FBbUI7SUFDL0MsTUFBTSxLQUFLLEdBQUcsb0JBQW9CLENBQUM7SUFDbkMsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQ1gsOEVBQThFO1FBQzlFLDhFQUE4RTtRQUM5RSw4RUFBOEU7UUFDOUUsK0RBQStEO1FBQy9ELElBQUksQ0FBQyw0QkFBNEIsSUFBSSxPQUFPLENBQUMsR0FBRyxJQUFJLE9BQU8sT0FBTyxDQUFDLFlBQVksS0FBSyxRQUFRLEVBQUUsQ0FBQztZQUM3Riw0QkFBNEIsR0FBRyxJQUFJLENBQUM7WUFDcEMsTUFBTSxDQUFDLElBQUksQ0FBQyw4S0FBOEssQ0FBQyxDQUFDO1FBQzlMLENBQUM7UUFDRCxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFDRCxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsSUFBSSxPQUFPLE9BQU8sQ0FBQyxZQUFZLEtBQUssUUFBUTtRQUFFLE9BQU8sS0FBSyxDQUFDO0lBQzNFLElBQUksQ0FBQztRQUNILE1BQU0sT0FBTyxHQUFHLE1BQU0sS0FBSyxDQUFDLGlCQUFpQixDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUMzRCxPQUFPLE9BQU8sS0FBSyxJQUFJLElBQUksT0FBTyxDQUFDLFlBQVksR0FBRyxPQUFPLENBQUM7SUFDNUQsQ0FBQztJQUFDLE1BQU0sQ0FBQztRQUNQLHFFQUFxRTtRQUNyRSxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7QUFDSCxDQUFDO0FBRUQ7Ozs7R0FJRztBQUNILEtBQUssVUFBVSxzQkFBc0IsQ0FBQyxHQUFXO0lBQy9DLE1BQU0sS0FBSyxHQUFHLG9CQUFvQixDQUFDO0lBQ25DLElBQUksQ0FBQyxLQUFLLEVBQUUsb0JBQW9CO1FBQUUsT0FBTyxhQUFhLENBQUM7SUFDdkQsSUFBSSxDQUFDO1FBQ0gsT0FBTyxNQUFNLEtBQUssQ0FBQyxvQkFBb0IsQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUMvQyxDQUFDO0lBQUMsTUFBTSxDQUFDO1FBQ1AsT0FBTyxhQUFhLENBQUM7SUFDdkIsQ0FBQztBQUNILENBQUM7QUFFRCw0RkFBNEY7QUFDNUYsU0FBUyxzQkFBc0IsQ0FBQyxPQUFvRDtJQUNsRixPQUFPLE9BQU8sT0FBTyxDQUFDLGNBQWMsS0FBSyxRQUFRLElBQUksT0FBTyxPQUFPLENBQUMsR0FBRyxLQUFLLFFBQVEsSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUM7QUFDakgsQ0FBQztBQUVEOzs7Ozs7O0dBT0c7QUFDSCxNQUFNLENBQUMsS0FBSyxVQUFVLG9CQUFvQixDQUN4QyxNQUFzRjtJQUV0Riw4RUFBOEU7SUFDOUUsNEVBQTRFO0lBQzVFLG1CQUFtQjtJQUNuQixJQUFJLHNCQUFzQixDQUFDLE1BQU0sQ0FBQyxJQUFJLE1BQU0sc0JBQXNCLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxLQUFLLE1BQU07UUFBRSxPQUFPLElBQUksQ0FBQztJQUN2RyxPQUFPLGNBQWMsQ0FBQyxNQUFvQixDQUFDLENBQUM7QUFDOUMsQ0FBQztBQUVELFNBQVMsWUFBWSxDQUNuQixPQUEyQixFQUMzQixHQUFZLEVBQ1osR0FBYSxFQUNiLElBQWtCO0lBRWxCLE1BQU0sVUFBVSxHQUFHLEdBQUcsQ0FBQyxPQUFPLENBQUMsYUFBYSxDQUFDO0lBRTdDLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQztRQUNoQixPQUFPLFNBQVMsQ0FBQyxHQUFHLEVBQUUsVUFBVSxDQUFDLFlBQVksRUFBRSwrQkFBK0IsRUFBRSxTQUFTLENBQUMsYUFBYSxDQUFDLENBQUM7SUFDM0csQ0FBQztJQUVELE1BQU0sS0FBSyxHQUFHLFVBQVUsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDcEMsSUFBSSxLQUFLLENBQUMsTUFBTSxLQUFLLENBQUMsSUFBSSxLQUFLLENBQUMsQ0FBQyxDQUFDLEtBQUssUUFBUSxFQUFFLENBQUM7UUFDaEQsT0FBTyxTQUFTLENBQUMsR0FBRyxFQUFFLFVBQVUsQ0FBQyxZQUFZLEVBQUUsbURBQW1ELEVBQUUsU0FBUyxDQUFDLGFBQWEsQ0FBQyxDQUFDO0lBQy9ILENBQUM7SUFFRCxJQUFJLENBQUM7UUFDSCwwRUFBMEU7UUFDMUUsc0VBQXNFO1FBQ3RFLHlFQUF5RTtRQUN6RSxvREFBb0Q7UUFDcEQseUVBQXlFO1FBQ3pFLHdFQUF3RTtRQUN4RSxzRUFBc0U7UUFDdEUsc0VBQXNFO1FBQ3RFLHdFQUF3RTtRQUN4RSxNQUFNLGFBQWEsR0FBRyxxQkFBcUIsRUFBRSxDQUFDO1FBQzlDLE1BQU0sT0FBTyxHQUFHLHFCQUFxQixDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsRUFBRSxhQUFhLENBQUMsQ0FBQztRQUUvRCxJQUFJLE9BQU8sQ0FBQyxJQUFJLEtBQUssUUFBUSxFQUFFLENBQUM7WUFDOUIsT0FBTyxTQUFTLENBQUMsR0FBRyxFQUFFLFVBQVUsQ0FBQyxZQUFZLEVBQUUsaURBQWlELEVBQUUsU0FBUyxDQUFDLGFBQWEsQ0FBQyxDQUFDO1FBQzdILENBQUM7UUFFRCxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUNsQyxPQUFPLFNBQVMsQ0FBQyxHQUFHLEVBQUUsVUFBVSxDQUFDLFlBQVksRUFBRSwrQkFBK0IsRUFBRSxTQUFTLENBQUMsYUFBYSxDQUFDLENBQUM7UUFDM0csQ0FBQztRQUVELDBFQUEwRTtRQUMxRSx5RUFBeUU7UUFDekUsNEVBQTRFO1FBQzVFLHdFQUF3RTtRQUN4RSw4RUFBOEU7UUFDOUUsMkVBQTJFO1FBQzNFLElBQUksT0FBTyxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsVUFBVSxDQUFDLElBQUksb0JBQW9CLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDNUUsV0FBVyxDQUFDLDRCQUE0QixFQUFFLEVBQUUsT0FBTyxFQUFFLE9BQU8sQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLENBQUM7WUFDN0YsTUFBTSxDQUFDLElBQUksQ0FBQyxtQ0FBbUMsRUFBRSxFQUFFLEdBQUcsRUFBRSxPQUFPLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQztZQUN2RSxPQUFPLFNBQVMsQ0FBQyxHQUFHLEVBQUUsVUFBVSxDQUFDLFlBQVksRUFBRSx1QkFBdUIsRUFBRSxTQUFTLENBQUMsYUFBYSxDQUFDLENBQUM7UUFDbkcsQ0FBQztRQUVELEdBQUcsQ0FBQyxJQUFJLEdBQUcsRUFBRSxHQUFHLE9BQU8sRUFBRSxDQUFDO1FBRTFCLHdFQUF3RTtRQUN4RSw4RUFBOEU7UUFDOUUsOEVBQThFO1FBQzlFLDhFQUE4RTtRQUM5RSw0RUFBNEU7UUFDNUUsSUFBSSxPQUFPLENBQUMsc0JBQXNCLElBQUksT0FBTyxDQUFDLFlBQVksS0FBSyxJQUFJLEVBQUUsQ0FBQztZQUNwRSxNQUFNLFdBQVcsR0FBRyxlQUFlLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDO1lBQzdELE1BQU0sYUFBYSxHQUFHLGVBQWUsQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLFlBQVksQ0FBQyxDQUFDLENBQUM7WUFDakUsSUFBSSxXQUFXO2dCQUFFLEdBQUcsQ0FBQyxJQUFJLENBQUMsY0FBYyxHQUFHLFdBQVcsQ0FBQztZQUN2RCxJQUFJLGFBQWE7Z0JBQUUsR0FBRyxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxhQUFhLENBQUM7UUFDL0QsQ0FBQztRQUVELHFFQUFxRTtRQUNyRSxFQUFFO1FBQ0YsMkVBQTJFO1FBQzNFLDRFQUE0RTtRQUM1RSx3RUFBd0U7UUFDeEUsMkVBQTJFO1FBQzNFLCtFQUErRTtRQUMvRSw2RUFBNkU7UUFDN0UsNEVBQTRFO1FBQzVFLDhFQUE4RTtRQUM5RSw4RUFBOEU7UUFDOUUsMkVBQTJFO1FBQzNFLDBFQUEwRTtRQUMxRSxvRUFBb0U7UUFDcEUsTUFBTSxNQUFNLEdBQUksR0FBNkQsQ0FBQyxPQUFPLENBQUM7UUFDdEYsSUFBSSxNQUFNLEVBQUUsQ0FBQztZQUNYLE1BQU0sQ0FBQyxRQUFRLEdBQUcsV0FBVyxDQUFDLEdBQTZCLENBQUMsQ0FBQztRQUMvRCxDQUFDO1FBRUQsd0VBQXdFO1FBQ3hFLHlFQUF5RTtRQUN6RSw0RUFBNEU7UUFDNUUsMkVBQTJFO1FBQzNFLDRFQUE0RTtRQUM1RSx5RUFBeUU7UUFDekUsMEVBQTBFO1FBQzFFLDZEQUE2RDtRQUM3RCxNQUFNLGFBQWEsR0FBRyxzQkFBc0IsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUN0RCxJQUFJLGFBQWEsSUFBSSxDQUFDLG9CQUFvQixJQUFJLE9BQU8sQ0FBQyxHQUFHLElBQUksT0FBTyxPQUFPLENBQUMsWUFBWSxLQUFLLFFBQVEsQ0FBQyxFQUFFLENBQUM7WUFDdkcsMEVBQTBFO1lBQzFFLDBFQUEwRTtZQUMxRSxzRUFBc0U7WUFDdEUsc0VBQXNFO1lBQ3RFLDJFQUEyRTtZQUMzRSxDQUFDLEtBQUssSUFBSSxFQUFFO2dCQUNWLElBQUksYUFBYSxFQUFFLENBQUM7b0JBQ2xCLE1BQU0sS0FBSyxHQUFHLE1BQU0sc0JBQXNCLENBQUMsT0FBTyxDQUFDLEdBQWEsQ0FBQyxDQUFDO29CQUNsRSxJQUFJLEtBQUssS0FBSyxNQUFNLEVBQUUsQ0FBQzt3QkFDckIsT0FBTyxTQUFTLENBQ2QsR0FBRyxFQUNILFVBQVUsQ0FBQyxZQUFZLEVBQ3ZCLEtBQUssS0FBSyxTQUFTOzRCQUNqQixDQUFDLENBQUMsMkNBQTJDOzRCQUM3QyxDQUFDLENBQUMsa0RBQWtELEVBQ3RELFNBQVMsQ0FBQyxhQUFhLENBQ3hCLENBQUM7b0JBQ0osQ0FBQztnQkFDSCxDQUFDO2dCQUNELElBQUksb0JBQW9CLElBQUksT0FBTyxDQUFDLEdBQUcsSUFBSSxPQUFPLE9BQU8sQ0FBQyxZQUFZLEtBQUssUUFBUSxJQUFJLE1BQU0sY0FBYyxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7b0JBQ3JILE9BQU8sU0FBUyxDQUFDLEdBQUcsRUFBRSxVQUFVLENBQUMsWUFBWSxFQUFFLGdEQUFnRCxFQUFFLFNBQVMsQ0FBQyxhQUFhLENBQUMsQ0FBQztnQkFDNUgsQ0FBQztnQkFDRCxJQUFJLEVBQUUsQ0FBQztZQUNULENBQUMsQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQ2pCLE9BQU87UUFDVCxDQUFDO1FBRUQsSUFBSSxFQUFFLENBQUM7SUFDVCxDQUFDO0lBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztRQUNmLElBQUksS0FBSyxZQUFZLEdBQUcsQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1lBQzNDLE9BQU8sU0FBUyxDQUFDLEdBQUcsRUFBRSxVQUFVLENBQUMsWUFBWSxFQUFFLG1CQUFtQixFQUFFLFNBQVMsQ0FBQyxhQUFhLENBQUMsQ0FBQztRQUMvRixDQUFDO1FBRUQsSUFBSSxLQUFLLFlBQVksR0FBRyxDQUFDLGlCQUFpQixFQUFFLENBQUM7WUFDM0MsT0FBTyxTQUFTLENBQUMsR0FBRyxFQUFFLFVBQVUsQ0FBQyxZQUFZLEVBQUUsZUFBZSxFQUFFLFNBQVMsQ0FBQyxhQUFhLENBQUMsQ0FBQztRQUMzRixDQUFDO1FBRUQsT0FBTyxTQUFTLENBQUMsR0FBRyxFQUFFLFVBQVUsQ0FBQyxZQUFZLEVBQUUsdUJBQXVCLEVBQUUsU0FBUyxDQUFDLFlBQVksQ0FBQyxDQUFDO0lBQ2xHLENBQUM7QUFDSCxDQUFDO0FBRUQ7Ozs7R0FJRztBQUNILE1BQU0sVUFBVSxpQkFBaUIsQ0FBQyxHQUFZLEVBQUUsVUFBc0I7SUFDcEUsT0FBTyxhQUFhLENBQUMsR0FBRyxDQUFDLElBQUksRUFBRSxXQUFXLEVBQUUsVUFBVSxFQUFFLEdBQUcsQ0FBQyxJQUFJLEVBQUUsWUFBWSxDQUFDLENBQUM7QUFDbEYsQ0FBQztBQW9CRDs7Ozs7OztHQU9HO0FBQ0gsSUFBSSxrQkFBaUUsQ0FBQztBQUV0RTs7O0dBR0c7QUFDSCxNQUFNLFVBQVUscUJBQXFCLENBQUMsRUFBaUQ7SUFDckYsa0JBQWtCLEdBQUcsRUFBRSxDQUFDO0FBQzFCLENBQUM7QUFFRDs7OztHQUlHO0FBQ0gsU0FBUyxnQkFBZ0IsQ0FBQyxHQUFZLEVBQUUsUUFBZ0I7SUFDdEQsTUFBTSxPQUFPLEdBQUcsa0JBQWtCLENBQUM7SUFDbkMsSUFBSSxDQUFDLE9BQU87UUFBRSxPQUFPO0lBQ3JCLE1BQU0sTUFBTSxHQUFHLEdBQUcsQ0FBQyxNQUFNLENBQUMsV0FBVyxFQUFFLENBQUM7SUFDeEMsSUFBSSxNQUFNLEtBQUssS0FBSyxJQUFJLE1BQU0sS0FBSyxNQUFNLElBQUksTUFBTSxLQUFLLFNBQVM7UUFBRSxPQUFPO0lBQzFFLElBQUksQ0FBQztRQUNILE9BQU8sQ0FBQztZQUNOLE9BQU8sRUFBRSxHQUFHLENBQUMsSUFBSSxFQUFFLEdBQUc7WUFDdEIsVUFBVSxFQUFFLEdBQUcsQ0FBQyxJQUFJLEVBQUUsS0FBSztZQUMzQixLQUFLLEVBQUUsR0FBRyxDQUFDLElBQUksRUFBRSxjQUFjO1lBQy9CLE1BQU07WUFDTiwwRUFBMEU7WUFDMUUsdUVBQXVFO1lBQ3ZFLElBQUksRUFBRSxDQUFDLEdBQUcsQ0FBQyxXQUFXLElBQUksR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDaEQsUUFBUTtTQUNULENBQUMsQ0FBQztJQUNMLENBQUM7SUFBQyxNQUFNLENBQUM7UUFDUCxpRUFBaUU7SUFDbkUsQ0FBQztBQUNILENBQUM7QUFFRDs7Ozs7R0FLRztBQUNILE1BQU0sVUFBVSxpQkFBaUIsQ0FBQyxHQUFHLFdBQXlCO0lBQzVELE9BQU8sQ0FBQyxHQUFZLEVBQUUsR0FBYSxFQUFFLElBQWtCLEVBQVEsRUFBRTtRQUMvRCxJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksRUFBRSxDQUFDO1lBQ2QsT0FBTyxTQUFTLENBQUMsR0FBRyxFQUFFLFVBQVUsQ0FBQyxZQUFZLEVBQUUseUJBQXlCLEVBQUUsU0FBUyxDQUFDLFlBQVksQ0FBQyxDQUFDO1FBQ3BHLENBQUM7UUFDRCxxRUFBcUU7UUFDckUseUVBQXlFO1FBQ3pFLHlEQUF5RDtRQUN6RCxJQUFJLFdBQVcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLGlCQUFpQixDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUMsQ0FBQztZQUFFLE9BQU8sSUFBSSxFQUFFLENBQUM7UUFDdEUsZ0JBQWdCLENBQUMsR0FBRyxFQUFFLFdBQVcsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQztRQUNoRCxPQUFPLFNBQVMsQ0FDZCxHQUFHLEVBQUUsVUFBVSxDQUFDLFNBQVMsRUFDekIsZ0NBQWdDLFdBQVcsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLEVBQUUsRUFDMUQsU0FBUyxDQUFDLHdCQUF3QixDQUNuQyxDQUFDO0lBQ0osQ0FBQyxDQUFDO0FBQ0osQ0FBQztBQUVEOzs7Ozs7O0dBT0c7QUFDSCxNQUFNLFVBQVUscUJBQXFCLENBQUMsR0FBRyxXQUF5QjtJQUNoRSxPQUFPLENBQUMsR0FBWSxFQUFFLEdBQWEsRUFBRSxJQUFrQixFQUFRLEVBQUU7UUFDL0QsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUNkLE9BQU8sU0FBUyxDQUFDLEdBQUcsRUFBRSxVQUFVLENBQUMsWUFBWSxFQUFFLHlCQUF5QixFQUFFLFNBQVMsQ0FBQyxZQUFZLENBQUMsQ0FBQztRQUNwRyxDQUFDO1FBQ0QsTUFBTSxPQUFPLEdBQUcsV0FBVyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxpQkFBaUIsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUN0RSxJQUFJLE9BQU8sQ0FBQyxNQUFNLEtBQUssQ0FBQztZQUFFLE9BQU8sSUFBSSxFQUFFLENBQUM7UUFDeEMsZ0JBQWdCLENBQUMsR0FBRyxFQUFFLFdBQVcsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQztRQUNqRCxPQUFPLFNBQVMsQ0FDZCxHQUFHLEVBQUUsVUFBVSxDQUFDLFNBQVMsRUFDekIsZ0NBQWdDLE9BQU8sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLEVBQUUsRUFDdkQsU0FBUyxDQUFDLHdCQUF3QixDQUNuQyxDQUFDO0lBQ0osQ0FBQyxDQUFDO0FBQ0osQ0FBQztBQUVEOzs7Ozs7Ozs7O0dBVUc7QUFDSCxNQUFNLFVBQVUsMEJBQTBCLENBQUMsR0FBRyxXQUF5QjtJQUNyRSxPQUFPLENBQUMsR0FBWSxFQUFFLEdBQWEsRUFBRSxJQUFrQixFQUFRLEVBQUU7UUFDL0QsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUNkLE9BQU8sU0FBUyxDQUFDLEdBQUcsRUFBRSxVQUFVLENBQUMsWUFBWSxFQUFFLHlCQUF5QixFQUFFLFNBQVMsQ0FBQyxZQUFZLENBQUMsQ0FBQztRQUNwRyxDQUFDO1FBQ0QsSUFBSSxrQkFBa0IsQ0FBQyxHQUFHLENBQUMsSUFBSSxXQUFXLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxpQkFBaUIsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDLENBQUM7WUFBRSxPQUFPLElBQUksRUFBRSxDQUFDO1FBQ2pHLGdCQUFnQixDQUFDLEdBQUcsRUFBRSxXQUFXLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUM7UUFDaEQsT0FBTyxTQUFTLENBQ2QsR0FBRyxFQUFFLFVBQVUsQ0FBQyxTQUFTLEVBQ3pCLGdDQUFnQyxXQUFXLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxFQUFFLEVBQzFELFNBQVMsQ0FBQyx3QkFBd0IsQ0FDbkMsQ0FBQztJQUNKLENBQUMsQ0FBQztBQUNKLENBQUM7QUFFRDs7Ozs7O0dBTUc7QUFDSCxNQUFNLFVBQVUsdUJBQXVCLENBQUMsR0FBWSxFQUFFLEdBQWEsRUFBRSxJQUFrQjtJQUNyRixJQUFJLENBQUMsa0JBQWtCLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUM3QiwwRUFBMEU7UUFDMUUsaUZBQWlGO1FBQ2pGLE9BQU8sU0FBUyxDQUFDLEdBQUcsRUFBRSxVQUFVLENBQUMsU0FBUyxFQUFFLDZCQUE2QixFQUFFLFNBQVMsQ0FBQyx3QkFBd0IsQ0FBQyxDQUFDO0lBQ2pILENBQUM7SUFDRCxJQUFJLEVBQUUsQ0FBQztBQUNULENBQUM7QUFFRDs7Ozs7O0dBTUc7QUFDSCxNQUFNLENBQUMsTUFBTSxhQUFhLEdBQUcsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLGFBQWEsSUFBSSwwQkFBMEIsQ0FBQyxDQUFDLFdBQVcsRUFBRSxDQUFDO0FBRXJHLHdHQUF3RztBQUN4RyxNQUFNLENBQUMsTUFBTSxlQUFlLEdBQUcsUUFBUSxDQUFDO0FBRXhDOzs7OztHQUtHO0FBQ0gsTUFBTSxVQUFVLGFBQWEsQ0FBQyxLQUFjLEVBQUUsT0FBZ0I7SUFDNUQsT0FBTyxLQUFLLEVBQUUsV0FBVyxFQUFFLEtBQUssYUFBYSxJQUFJLE9BQU8sRUFBRSxXQUFXLEVBQUUsS0FBSyxlQUFlLENBQUM7QUFDOUYsQ0FBQztBQUVEOzs7Ozs7Ozs7O0dBVUc7QUFDSCxNQUFNLFVBQVUsYUFBYSxDQUFDLEdBQVk7SUFDeEMsT0FBTyxHQUFHLENBQUMsSUFBSSxFQUFFLFlBQVksS0FBSyxJQUFJLENBQUM7QUFDekMsQ0FBQztBQUVEOzs7O0dBSUc7QUFDSCxNQUFNLFVBQVUsUUFBUSxDQUFDLEdBQVksRUFBRSxLQUFhO0lBQ2xELE9BQU8sR0FBRyxDQUFDLElBQUksRUFBRSxLQUFLLEtBQUssS0FBSyxDQUFDO0FBQ25DLENBQUM7QUFFRDtvRUFDb0U7QUFDcEUsTUFBTSxVQUFVLGtCQUFrQixDQUNoQyxHQUFZLEVBQ1osR0FBYSxFQUNiLElBQWtCO0lBRWxCLElBQUksQ0FBQyxhQUFhLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUN4QixnQkFBZ0IsQ0FBQyxHQUFHLEVBQUUsY0FBYyxDQUFDLENBQUM7UUFDdEMsT0FBTyxTQUFTLENBQ2QsR0FBRyxFQUFFLFVBQVUsQ0FBQyxTQUFTLEVBQ3pCLG9FQUFvRSxFQUNwRSxTQUFTLENBQUMsd0JBQXdCLENBQ25DLENBQUM7SUFDSixDQUFDO0lBQ0QsSUFBSSxFQUFFLENBQUM7QUFDVCxDQUFDO0FBRUQ7Ozs7R0FJRztBQUNILE1BQU0sVUFBVSxjQUFjLENBQUMsT0FBZTtJQUM1QyxPQUFPLENBQUMsR0FBWSxFQUFFLEdBQWEsRUFBRSxJQUFrQixFQUFRLEVBQUU7UUFDL0QsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUNkLE9BQU8sU0FBUyxDQUFDLEdBQUcsRUFBRSxVQUFVLENBQUMsWUFBWSxFQUFFLHlCQUF5QixFQUFFLFNBQVMsQ0FBQyxZQUFZLENBQUMsQ0FBQztRQUNwRyxDQUFDO1FBRUQscUVBQXFFO1FBQ3JFLHVFQUF1RTtRQUN2RSxxRUFBcUU7UUFDckUsa0JBQWtCO1FBQ2xCLElBQUksR0FBRyxDQUFDLElBQUksQ0FBQyxZQUFZLEtBQUssSUFBSTtZQUFFLE9BQU8sSUFBSSxFQUFFLENBQUM7UUFFbEQsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLFFBQVEsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDO1lBQzFDLDREQUE0RDtZQUM1RCwyREFBMkQ7WUFDM0Qsc0VBQXNFO1lBQ3RFLGdCQUFnQixDQUFDLEdBQUcsRUFBRSxXQUFXLE9BQU8sRUFBRSxDQUFDLENBQUM7WUFDNUMsT0FBTyxTQUFTLENBQ2QsR0FBRyxFQUFFLFVBQVUsQ0FBQyxTQUFTLEVBQ3pCLHdDQUF3QyxPQUFPLEdBQUcsRUFDbEQsU0FBUyxDQUFDLHdCQUF3QixDQUNuQyxDQUFDO1FBQ0osQ0FBQztRQUVELElBQUksRUFBRSxDQUFDO0lBQ1QsQ0FBQyxDQUFDO0FBQ0osQ0FBQztBQUVELDhFQUE4RTtBQUM5RSw0QkFBNEI7QUFDNUIsRUFBRTtBQUNGLDRFQUE0RTtBQUM1RSxzRUFBc0U7QUFDdEUsb0VBQW9FO0FBQ3BFLDJFQUEyRTtBQUMzRSw2RUFBNkU7QUFDN0Usb0VBQW9FO0FBQ3BFLG1FQUFtRTtBQUNuRSxFQUFFO0FBQ0YseUVBQXlFO0FBQ3pFLGlEQUFpRDtBQUNqRCw4RUFBOEU7QUFFOUUsTUFBTSxpQ0FBaUMsR0FBRyxHQUFHLENBQUM7QUFFOUM7Ozs7OztHQU1HO0FBQ0gsSUFBSSxvQkFBb0IsR0FBRyxJQUFJLEdBQUcsQ0FDaEMsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLHNCQUFzQixJQUFJLEVBQUUsQ0FBQztLQUN2QyxLQUFLLENBQUMsR0FBRyxDQUFDO0tBQ1YsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUM7S0FDcEIsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUNuQixDQUFDO0FBRUYsbUZBQW1GO0FBQ25GLE1BQU0sVUFBVSx1QkFBdUIsQ0FBQyxLQUF1QjtJQUM3RCxvQkFBb0IsR0FBRyxJQUFJLEdBQUcsQ0FBQyxDQUFDLEdBQUcsS0FBSyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQztBQUNsRixDQUFDO0FBRUQsMkVBQTJFO0FBQzNFLE1BQU0sVUFBVSxvQkFBb0IsQ0FBQyxHQUFXO0lBQzlDLElBQUksb0JBQW9CLENBQUMsSUFBSSxLQUFLLENBQUM7UUFBRSxPQUFPLEtBQUssQ0FBQztJQUNsRCxJQUFJLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxVQUFVLENBQUM7UUFBRSxPQUFPLEtBQUssQ0FBQztJQUM5QyxPQUFPLG9CQUFvQixDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDO0FBQ2hFLENBQUM7QUE2QkQ7Ozs7R0FJRztBQUNILE1BQU0sVUFBVSxnQkFBZ0IsQ0FBQyxJQUF5QjtJQUN4RCxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDO0lBQ3ZCLE1BQU0sT0FBTyxHQUFlO1FBQzFCLEdBQUcsRUFBRSxXQUFXLElBQUksQ0FBQyxXQUFXLEVBQUU7UUFDbEMsUUFBUSxFQUFFLEdBQUcsSUFBSSxDQUFDLFdBQVcsVUFBVTtRQUN2QyxLQUFLLEVBQUUsR0FBRyxJQUFJLENBQUMsV0FBVyxXQUFXO1FBQ3JDLElBQUk7UUFDSixPQUFPLEVBQUUsSUFBSSxLQUFLLE9BQU8sSUFBSSxJQUFJLEtBQUssT0FBTztRQUM3QyxJQUFJLEVBQUUsUUFBUTtRQUNkLGNBQWMsRUFBRSxJQUFJLENBQUMsS0FBSztRQUMxQixnQkFBZ0IsRUFBRSxJQUFJLENBQUMsT0FBTyxJQUFJLElBQUksQ0FBQyxLQUFLO1FBQzVDLHlFQUF5RTtRQUN6RSwrREFBK0Q7UUFDL0QsR0FBRyxDQUFDLElBQUksQ0FBQyxXQUFXLElBQUksSUFBSSxDQUFDLFdBQVcsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLFdBQVcsRUFBRSxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztLQUM5RixDQUFDO0lBQ0YscUVBQXFFO0lBQ3JFLG9FQUFvRTtJQUNwRSxvRUFBb0U7SUFDcEUsTUFBTSxXQUFXLEdBQW9CO1FBQ25DLFNBQVMsRUFBRSxJQUFJLENBQUMsVUFBVSxJQUFJLGlDQUFpQztRQUMvRCwyRUFBMkU7UUFDM0UsdURBQXVEO1FBQ3ZELFNBQVMsRUFBRSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsYUFBYSxJQUFJLE9BQU8sQ0FBa0I7UUFDbEUsNEVBQTRFO1FBQzVFLDZFQUE2RTtRQUM3RSx3RUFBd0U7UUFDeEUsMEVBQTBFO1FBQzFFLDBFQUEwRTtRQUMxRSxvREFBb0Q7UUFDcEQsS0FBSyxFQUFFLFVBQVUsRUFBRTtLQUNwQixDQUFDO0lBQ0YsSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLFVBQVU7UUFBRSxXQUFXLENBQUMsTUFBTSxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDO0lBQ3hFLElBQUksT0FBTyxDQUFDLEdBQUcsQ0FBQyxZQUFZO1FBQUUsV0FBVyxDQUFDLFFBQVEsR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDLFlBQVksQ0FBQztJQUM5RSxPQUFPLEdBQUcsQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLFlBQVksRUFBRSxFQUFFLFdBQVcsQ0FBQyxDQUFDO0FBQ3hELENBQUM7QUFFRCxrRkFBa0Y7QUFDbEYsTUFBTSxVQUFVLG9CQUFvQixDQUFDLElBQXlCO0lBQzVELE9BQU8sVUFBVSxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO0FBQzVDLENBQUM7QUFFRCwrRkFBK0Y7QUFDL0YsTUFBTSxVQUFVLGtCQUFrQixDQUFDLEdBQVk7SUFDN0MsT0FBTyxHQUFHLENBQUMsSUFBSSxFQUFFLEdBQUcsRUFBRSxVQUFVLENBQUMsVUFBVSxDQUFDLElBQUksS0FBSyxDQUFDO0FBQ3hELENBQUM7QUFFRDs7Ozs7Ozs7R0FRRztBQUNILE1BQU0sVUFBVSxzQkFBc0IsQ0FBQyxHQUFZO0lBQ2pELE1BQU0sS0FBSyxHQUFHLEdBQUcsQ0FBQyxPQUFPLENBQUMsYUFBYSxFQUFFLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUNwRCxJQUFJLENBQUMsS0FBSyxJQUFJLEtBQUssQ0FBQyxNQUFNLEtBQUssQ0FBQyxJQUFJLEtBQUssQ0FBQyxDQUFDLENBQUMsS0FBSyxRQUFRO1FBQUUsT0FBTyxLQUFLLENBQUM7SUFDeEUsSUFBSSxDQUFDO1FBQ0gsTUFBTSxhQUFhLEdBQUcscUJBQXFCLEVBQUUsQ0FBQztRQUM5QyxNQUFNLE9BQU8sR0FBRyxxQkFBcUIsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUUsYUFBYSxDQUFDLENBQUM7UUFDL0QsSUFBSSxPQUFPLENBQUMsSUFBSSxLQUFLLFFBQVEsSUFBSSxPQUFPLE9BQU8sQ0FBQyxHQUFHLEtBQUssUUFBUSxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsVUFBVSxDQUFDO1lBQUUsT0FBTyxLQUFLLENBQUM7UUFDdEgsNkVBQTZFO1FBQzdFLGdGQUFnRjtRQUNoRix1RUFBdUU7UUFDdkUsT0FBTyxDQUFDLG9CQUFvQixDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUM1QyxDQUFDO0lBQUMsTUFBTSxDQUFDO1FBQ1AsT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDO0FBQ0gsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG5pbXBvcnQgeyByYW5kb21VVUlEIH0gZnJvbSAnY3J5cHRvJztcbmltcG9ydCB0eXBlIHsgUmVxdWVzdCwgUmVzcG9uc2UsIE5leHRGdW5jdGlvbiB9IGZyb20gJ2V4cHJlc3MnO1xuaW1wb3J0IGp3dCBmcm9tICdqc29ud2VidG9rZW4nO1xuaW1wb3J0IHsgSHR0cFN0YXR1cyB9IGZyb20gJy4uL2NvbnN0YW50cy9odHRwLXN0YXR1cy5qcyc7XG5pbXBvcnQgdHlwZSB7IEp3dFBheWxvYWQgfSBmcm9tICcuLi90eXBlcy9jb21tb24uanMnO1xuaW1wb3J0IHsgRXJyb3JDb2RlIH0gZnJvbSAnLi4vdHlwZXMvZXJyb3ItY29kZXMuanMnO1xuaW1wb3J0IHR5cGUgeyBIdHRwUmVxdWVzdCB9IGZyb20gJy4uL3R5cGVzL2h0dHAuanMnO1xuaW1wb3J0IHsgdHlwZSBQZXJtaXNzaW9uLCBoYXNQZXJtaXNzaW9uIH0gZnJvbSAnLi4vdHlwZXMvcGVybWlzc2lvbnMuanMnO1xuaW1wb3J0IHsgZ2V0SGVhZGVyU3RyaW5nIH0gZnJvbSAnLi4vdXRpbHMvaGVhZGVycy5qcyc7XG5pbXBvcnQgeyBnZXRJZGVudGl0eSwgdHlwZSBSZXF1ZXN0SWRlbnRpdHkgfSBmcm9tICcuLi91dGlscy9pZGVudGl0eS5qcyc7XG5pbXBvcnQgeyBjcmVhdGVMb2dnZXIgfSBmcm9tICcuLi91dGlscy9sb2dnZXIuanMnO1xuaW1wb3J0IHsgZW1pdENvdW50ZXIgfSBmcm9tICcuLi91dGlscy9tZXRyaWMtZW1pdHRlci5qcyc7XG5pbXBvcnQgeyBzZW5kRXJyb3IgfSBmcm9tICcuLi91dGlscy9yZXNwb25zZS5qcyc7XG5cbmNvbnN0IGxvZ2dlciA9IGNyZWF0ZUxvZ2dlcignYXV0aC1taWRkbGV3YXJlJyk7XG5cbi8qKiBDYWNoZWQgSldUIHNlY3JldCB3aXRoIHBlcmlvZGljIHJlZnJlc2ggZnJvbSBlbnYgdmFyLiAqL1xubGV0IF9qd3RTZWNyZXQ6IHN0cmluZyB8IHVuZGVmaW5lZDtcbmxldCBfand0U2VjcmV0UmVmcmVzaGVkQXQgPSAwO1xuLyoqIENhY2hlZCBQUkVWSU9VUyBKV1Qgc2VjcmV0IChvcHRpb25hbCkg4oCUIGVuYWJsZXMgemVyby1kb3dudGltZSByb3RhdGlvbi4gKi9cbmxldCBfand0U2VjcmV0UHJldmlvdXM6IHN0cmluZyB8IHVuZGVmaW5lZDtcbmxldCBfand0U2VjcmV0UHJldmlvdXNSZWZyZXNoZWRBdCA9IDA7XG5jb25zdCBKV1RfU0VDUkVUX1JFRlJFU0hfSU5URVJWQUxfTVMgPSAzMDBfMDAwOyAvLyA1IG1pbnV0ZXNcblxuZnVuY3Rpb24gZ2V0Snd0U2VjcmV0KCk6IHN0cmluZyB7XG4gIGNvbnN0IG5vdyA9IERhdGUubm93KCk7XG4gIGlmICghX2p3dFNlY3JldCB8fCBub3cgLSBfand0U2VjcmV0UmVmcmVzaGVkQXQgPiBKV1RfU0VDUkVUX1JFRlJFU0hfSU5URVJWQUxfTVMpIHtcbiAgICBjb25zdCBzZWNyZXQgPSBwcm9jZXNzLmVudi5KV1RfU0VDUkVUO1xuICAgIGlmICghc2VjcmV0KSB7XG4gICAgICBsb2dnZXIuZXJyb3IoJ0pXVF9TRUNSRVQgZW52aXJvbm1lbnQgdmFyaWFibGUgaXMgbm90IHNldCcpO1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdKV1RfU0VDUkVUIGVudmlyb25tZW50IHZhcmlhYmxlIGlzIHJlcXVpcmVkJyk7XG4gICAgfVxuICAgIGlmIChfand0U2VjcmV0ICYmIF9qd3RTZWNyZXQgIT09IHNlY3JldCkge1xuICAgICAgbG9nZ2VyLmluZm8oJ0pXVCBzZWNyZXQgcm90YXRlZCcpO1xuICAgIH1cbiAgICBfand0U2VjcmV0ID0gc2VjcmV0O1xuICAgIF9qd3RTZWNyZXRSZWZyZXNoZWRBdCA9IG5vdztcbiAgfVxuICByZXR1cm4gX2p3dFNlY3JldDtcbn1cblxuLyoqXG4gKiBUaGUgb3B0aW9uYWwgUFJFVklPVVMgSldUIHNlY3JldCAoYEpXVF9TRUNSRVRfUFJFVklPVVNgKSwgY2FjaGVkIHdpdGggdGhlIHNhbWVcbiAqIFRUTCBhcyB0aGUgcHJpbWFyeS4gUmV0dXJucyBgdW5kZWZpbmVkYCB3aGVuIHVuc2V0LiBEdXJpbmcgYSBgSldUX1NFQ1JFVGBcbiAqIHJvdGF0aW9uLCBvcGVyYXRvcnMgc2V0IGBKV1RfU0VDUkVUX1BSRVZJT1VTYCB0byB0aGUgb2xkIHZhbHVlIHNvIHRva2VucyBzaWduZWRcbiAqIHdpdGggRUlUSEVSIHNlY3JldCBrZWVwIHZlcmlmeWluZyDigJQgY2xvc2luZyB0aGUgYXV0aC1vdXRhZ2Ugd2luZG93IHdoZXJlXG4gKiBzdGlsbC12YWxpZCBvbGQtc2lnbmVkIChvciBmcmVzaGx5IG5ldy1zaWduZWQpIHRva2VucyB3b3VsZCBvdGhlcndpc2UgYmVcbiAqIHJlamVjdGVkLiBgdW5kZWZpbmVkYCBpcyBhIHZhbGlkIGNhY2hlZCB2YWx1ZSwgc28gdGhpcyByZWZyZXNoZXMgcHVyZWx5IG9uIHRoZVxuICogdGltZSBpbnRlcnZhbCAobm90IG9uIGVtcHRpbmVzcykuXG4gKi9cbmZ1bmN0aW9uIGdldEp3dFNlY3JldFByZXZpb3VzKCk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IG5vdyA9IERhdGUubm93KCk7XG4gIGlmIChub3cgLSBfand0U2VjcmV0UHJldmlvdXNSZWZyZXNoZWRBdCA+IEpXVF9TRUNSRVRfUkVGUkVTSF9JTlRFUlZBTF9NUykge1xuICAgIF9qd3RTZWNyZXRQcmV2aW91cyA9IHByb2Nlc3MuZW52LkpXVF9TRUNSRVRfUFJFVklPVVMgfHwgdW5kZWZpbmVkO1xuICAgIF9qd3RTZWNyZXRQcmV2aW91c1JlZnJlc2hlZEF0ID0gbm93O1xuICB9XG4gIHJldHVybiBfand0U2VjcmV0UHJldmlvdXM7XG59XG5cbi8qKlxuICogVGVzdC1vbmx5OiBkcm9wIHRoZSBjYWNoZWQgSldUIHNlY3JldHMgc28gdGhlIG5leHQgdmVyaWZ5IHJlLXJlYWRzIHRoZSBlbnYuXG4gKlxuICogQm90aCBzZWNyZXRzIGFyZSBjYWNoZWQgZm9yIHtAbGluayBKV1RfU0VDUkVUX1JFRlJFU0hfSU5URVJWQUxfTVN9LCBzbyBhIHRlc3RcbiAqIHRoYXQgc2V0cyBgSldUX1NFQ1JFVGAvYEpXVF9TRUNSRVRfUFJFVklPVVNgIG1pZC1ydW4gd291bGQgb3RoZXJ3aXNlIGtlZXBcbiAqIHZlcmlmeWluZyBhZ2FpbnN0IHRoZSB2YWx1ZXMgcmVhZCBvbiBmaXJzdCB1c2UuIERvbid0IGNhbGwgZnJvbSBwcm9kdWN0aW9uXG4gKiBjb2RlIOKAlCByb3RhdGlvbiBpcyBwaWNrZWQgdXAgYnkgdGhlIHJlZnJlc2ggaW50ZXJ2YWwuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBfcmVzZXRKd3RTZWNyZXRDYWNoZUZvclRlc3RzKCk6IHZvaWQge1xuICBfand0U2VjcmV0ID0gdW5kZWZpbmVkO1xuICBfand0U2VjcmV0UmVmcmVzaGVkQXQgPSAwO1xuICBfand0U2VjcmV0UHJldmlvdXMgPSB1bmRlZmluZWQ7XG4gIF9qd3RTZWNyZXRQcmV2aW91c1JlZnJlc2hlZEF0ID0gMDtcbn1cblxuLyoqXG4gKiBUaGUgSldUIHZlcmlmeSBvcHRpb25zIGV2ZXJ5IHRva2VuIGNoZWNrIGluIHRoZSBmbGVldCBtdXN0IHNoYXJlOiBwaW5uZWRcbiAqIGFsZ29yaXRobSAoYmxvY2tzIGFsZy1jb25mdXNpb24gLyBgYWxnOm5vbmVgKSBwbHVzIGlzc3Vlci9hdWRpZW5jZSB3aGVuIHRoZVxuICogZGVwbG95bWVudCBjb25maWd1cmVzIHRoZW0uXG4gKlxuICogQ2VudHJhbGl6ZWQgYmVjYXVzZSBpdCB3YXMgYnVpbHQgaW5saW5lIGF0IGVhY2ggY2FsbCBzaXRlIGFuZCBgc3RlcC11cC50c2BcbiAqIHJlLWltcGxlbWVudGVkIGl0IFdJVEhPVVQgdGhlIGlzc3Vlci9hdWRpZW5jZSBwaW5uaW5nIOKAlCBzbyBpbiBhIGRlcGxveW1lbnRcbiAqIHRoYXQgc2V0cyBgSldUX0lTU1VFUmAvYEpXVF9BVURJRU5DRWAsIGEgc3RlcC11cCB0b2tlbiBtaW50ZWQgYnkgYW55IG90aGVyXG4gKiBzeXN0ZW0gc2hhcmluZyBgSldUX1NFQ1JFVGAgd2FzIGFjY2VwdGVkLlxuICovXG5leHBvcnQgZnVuY3Rpb24gYnVpbGRKd3RWZXJpZnlPcHRpb25zKCk6IGp3dC5WZXJpZnlPcHRpb25zIHtcbiAgY29uc3QgdmVyaWZ5T3B0aW9uczogand0LlZlcmlmeU9wdGlvbnMgPSB7XG4gICAgYWxnb3JpdGhtczogWyhwcm9jZXNzLmVudi5KV1RfQUxHT1JJVEhNIHx8ICdIUzI1NicpIGFzIGp3dC5BbGdvcml0aG1dLFxuICB9O1xuICBpZiAocHJvY2Vzcy5lbnYuSldUX0lTU1VFUikgdmVyaWZ5T3B0aW9ucy5pc3N1ZXIgPSBwcm9jZXNzLmVudi5KV1RfSVNTVUVSO1xuICBpZiAocHJvY2Vzcy5lbnYuSldUX0FVRElFTkNFKSB2ZXJpZnlPcHRpb25zLmF1ZGllbmNlID0gcHJvY2Vzcy5lbnYuSldUX0FVRElFTkNFO1xuICByZXR1cm4gdmVyaWZ5T3B0aW9ucztcbn1cblxuLyoqXG4gKiBWZXJpZnkgYSBKV1QgYWdhaW5zdCB0aGUgcHJpbWFyeSBzZWNyZXQsIGZhbGxpbmcgYmFjayB0byB0aGUgcHJldmlvdXMgc2VjcmV0XG4gKiAod2hlbiBgSldUX1NFQ1JFVF9QUkVWSU9VU2AgaXMgY29uZmlndXJlZCkgT05MWSBvbiBhIHNpZ25hdHVyZS92ZXJpZmljYXRpb25cbiAqIGZhaWx1cmUuIFRoaXMgbWFrZXMgdG9rZW4gdmVyaWZpY2F0aW9uIHN1cnZpdmUgYSBzZWNyZXQgcm90YXRpb24gd2l0aCB6ZXJvXG4gKiBkb3dudGltZTogYSB0b2tlbiB2YWxpZCB1bmRlciBFSVRIRVIgc2VjcmV0IHBhc3Nlcy5cbiAqXG4gKiBqc29ud2VidG9rZW4ncyBgdmVyaWZ5YCB0YWtlcyBhIHNpbmdsZSBzZWNyZXQsIHNvIHRoaXMgaXMgdHJ5LXByaW1hcnktdGhlbi1cbiAqIHByZXZpb3VzIOKAlCBOT1QgYSBzZWNyZXQgYXJyYXkuIE5vIGV4aXN0aW5nIGNoZWNrIGlzIHdlYWtlbmVkOlxuICogICAtIGB2ZXJpZnlPcHRpb25zYCAoYWxnb3JpdGhtIHBpbm5pbmcgKyBvcHRpb25hbCBpc3N1ZXIvYXVkaWVuY2UpIGlzIGFwcGxpZWRcbiAqICAgICBpZGVudGljYWxseSBvbiBCT1RIIGF0dGVtcHRzLCBzbyBhbGctY29uZnVzaW9uIC8gYGFsZzpub25lYCBzdGF5IGJsb2NrZWQuXG4gKiAgIC0gRXhwaXJ5IC8gbm90LWJlZm9yZSBmcm9tIHRoZSBQUklNQVJZIGF0dGVtcHQgYXJlIGF1dGhvcml0YXRpdmUgYW5kIGFyZVxuICogICAgIHJlLXRocm93biB3aXRob3V0IGEgcHJldmlvdXMtc2VjcmV0IHJldHJ5LCBzbyBhIGBUb2tlbkV4cGlyZWRFcnJvcmAgaXNcbiAqICAgICBuZXZlciBtYXNrZWQgaW50byBhbiBcImludmFsaWQgc2lnbmF0dXJlXCIuXG4gKiAgIC0gV2hlbiBubyBwcmV2aW91cyBzZWNyZXQgaXMgc2V0LCBiZWhhdmlvdXIgaXMgYnl0ZS1mb3ItYnl0ZSB0aGUgb3JpZ2luYWw6XG4gKiAgICAgdGhlIHByaW1hcnkgZXJyb3IgcHJvcGFnYXRlcyB1bmNoYW5nZWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB2ZXJpZnlKd3RXaXRoUm90YXRpb24odG9rZW46IHN0cmluZywgdmVyaWZ5T3B0aW9uczogand0LlZlcmlmeU9wdGlvbnMpOiBKd3RQYXlsb2FkIHtcbiAgdHJ5IHtcbiAgICByZXR1cm4gand0LnZlcmlmeSh0b2tlbiwgZ2V0Snd0U2VjcmV0KCksIHZlcmlmeU9wdGlvbnMpIGFzIEp3dFBheWxvYWQ7XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIGNvbnN0IHByZXZpb3VzID0gZ2V0Snd0U2VjcmV0UHJldmlvdXMoKTtcbiAgICAvLyBGYWxsIGJhY2sgdG8gdGhlIHByZXZpb3VzIHNlY3JldCBvbmx5IGZvciBhIHNpZ25hdHVyZS92ZXJpZmljYXRpb24gZmFpbHVyZVxuICAgIC8vIChhIHBsYWluIEpzb25XZWJUb2tlbkVycm9yKS4gRXhwaXJ5IC8gbm90LWJlZm9yZSBhcmUgZW5mb3JjZWQgcmVnYXJkbGVzcyBvZlxuICAgIC8vIHdoaWNoIHNlY3JldCBzaWduZWQgdGhlIHRva2VuLCBzbyB0aG9zZSBlcnJvcnMgbXVzdCBzdXJmYWNlIGFzLWlzLlxuICAgIGlmIChcbiAgICAgIHByZXZpb3VzXG4gICAgICAmJiBlcnIgaW5zdGFuY2VvZiBqd3QuSnNvbldlYlRva2VuRXJyb3JcbiAgICAgICYmICEoZXJyIGluc3RhbmNlb2Ygand0LlRva2VuRXhwaXJlZEVycm9yKVxuICAgICAgJiYgIShlcnIgaW5zdGFuY2VvZiBqd3QuTm90QmVmb3JlRXJyb3IpXG4gICAgKSB7XG4gICAgICAvLyBBIHRva2VuIHNpZ25lZCBieSB0aGUgcHJldmlvdXMgc2VjcmV0IHZlcmlmaWVzIGhlcmU7IGlmIGl0IGlzIGluc3RlYWRcbiAgICAgIC8vIGV4cGlyZWQvaW52YWxpZCB1bmRlciB0aGUgcHJldmlvdXMgc2VjcmV0LCB0aGF0IGVycm9yIHByb3BhZ2F0ZXMgYW5kIGlzXG4gICAgICAvLyBoYW5kbGVkIGJ5IHRoZSBjYWxsZXIgZXhhY3RseSBsaWtlIGEgcHJpbWFyeSBmYWlsdXJlLlxuICAgICAgcmV0dXJuIGp3dC52ZXJpZnkodG9rZW4sIHByZXZpb3VzLCB2ZXJpZnlPcHRpb25zKSBhcyBKd3RQYXlsb2FkO1xuICAgIH1cbiAgICB0aHJvdyBlcnI7XG4gIH1cbn1cblxuZXhwb3J0IGludGVyZmFjZSBSZXF1aXJlQXV0aE9wdGlvbnMge1xuICAvKipcbiAgICogQWxsb3cgeC1vcmctaWQveC1vcmctbmFtZSBoZWFkZXJzIHRvIG92ZXJyaWRlIHRoZSBKV1QncyBvcmdhbml6YXRpb24gZmllbGRzLlxuICAgKlxuICAgKiBXaGVuIGVuYWJsZWQsIHRoZSBgeC1vcmctaWRgL2B4LW9yZy1uYW1lYCBoZWFkZXJzIG92ZXJyaWRlIHRoZSBjYWxsZXIncyBvcmdcbiAgICog4oCUIGJ1dCBPTkxZIGZvciBhIHZlcmlmaWVkIFNZUy1BRE1JTiAoYGlzU3VwZXJBZG1pbmAgY2xhaW0pLiBGb3IgYW55IG9yZGluYXJ5XG4gICAqIGF1dGhlbnRpY2F0ZWQgdXNlciB0aGUgaGVhZGVycyBhcmUgaWdub3JlZCwgc28gZW5hYmxpbmcgdGhpcyBjYW4gbmV2ZXIgbGV0IGFcbiAgICogbm9ybWFsIHVzZXIgaW1wZXJzb25hdGUgYW5vdGhlciB0ZW5hbnQncyBvcmcuIFVzZSBmb3IgY3Jvc3Mtb3JnIGFkbWluIHRvb2xpbmdcbiAgICogKGUuZy4gYSBzeXNhZG1pbiBtYW5hZ2luZyBhIGdpdmVuIG9yZydzIGJpbGxpbmcpLiBJZiB1bnN1cmUsIGxlYXZlIGl0IGRpc2FibGVkLlxuICAgKi9cbiAgYWxsb3dPcmdIZWFkZXJPdmVycmlkZT86IGJvb2xlYW47XG59XG5cbi8qKiBKV1QgYXV0aCBtaWRkbGV3YXJlLiBVc2UgZGlyZWN0bHkgb3IgY2FsbCB3aXRoIG9wdGlvbnMuICovXG5leHBvcnQgZnVuY3Rpb24gcmVxdWlyZUF1dGgoXG4gIHJlcTogUmVxdWVzdCxcbiAgcmVzOiBSZXNwb25zZSxcbiAgbmV4dDogTmV4dEZ1bmN0aW9uLFxuKTogdm9pZDtcbmV4cG9ydCBmdW5jdGlvbiByZXF1aXJlQXV0aChcbiAgb3B0aW9ucz86IFJlcXVpcmVBdXRoT3B0aW9ucyxcbik6IChyZXE6IFJlcXVlc3QsIHJlczogUmVzcG9uc2UsIG5leHQ6IE5leHRGdW5jdGlvbikgPT4gdm9pZDtcbmV4cG9ydCBmdW5jdGlvbiByZXF1aXJlQXV0aChcbiAgcmVxT3JPcHRpb25zPzogUmVxdWVzdCB8IFJlcXVpcmVBdXRoT3B0aW9ucyxcbiAgcmVzPzogUmVzcG9uc2UsXG4gIG5leHQ/OiBOZXh0RnVuY3Rpb24sXG4pOiB2b2lkIHwgKChyZXE6IFJlcXVlc3QsIHJlczogUmVzcG9uc2UsIG5leHQ6IE5leHRGdW5jdGlvbikgPT4gdm9pZCkge1xuICBpZiAocmVxT3JPcHRpb25zICYmIHJlcyAmJiBuZXh0ICYmICdoZWFkZXJzJyBpbiByZXFPck9wdGlvbnMpIHtcbiAgICByZXR1cm4gX3JlcXVpcmVBdXRoKHt9LCByZXFPck9wdGlvbnMgYXMgUmVxdWVzdCwgcmVzLCBuZXh0KTtcbiAgfVxuXG4gIGNvbnN0IG9wdGlvbnMgPSAocmVxT3JPcHRpb25zIGFzIFJlcXVpcmVBdXRoT3B0aW9ucykgfHwge307XG4gIHJldHVybiAocmVxOiBSZXF1ZXN0LCByZXNJbm5lcjogUmVzcG9uc2UsIG5leHRJbm5lcjogTmV4dEZ1bmN0aW9uKSA9PiB7XG4gICAgX3JlcXVpcmVBdXRoKG9wdGlvbnMsIHJlcSwgcmVzSW5uZXIsIG5leHRJbm5lcik7XG4gIH07XG59XG5cbi8qKlxuICogQSBzb3VyY2Ugb2YgdGhlIENVUlJFTlQgYHRva2VuVmVyc2lvbmAgZm9yIGEgdXNlciwgYmFja2VkIGJ5IGEgc3RvcmUgdGhlXG4gKiBzdGF0ZWxlc3Mgc2VydmljZXMgY2FuIHJlYWQgKGluIHByYWN0aWNlIGEgUmVkaXMga2V5IHRoZSBwbGF0Zm9ybSBwdWJsaXNoZXNcbiAqIHRvIG9uIGV2ZXJ5IHByaXZpbGVnZSBjaGFuZ2UpLiBSZWdpc3RlcmVkIHZpYSB7QGxpbmsgc2V0VG9rZW5SZXZvY2F0aW9uU3RvcmV9LlxuICpcbiAqIGBnZXRDdXJyZW50VmVyc2lvbmAgcmV0dXJucyB0aGUgdXNlcidzIGN1cnJlbnQgdmVyc2lvbiwgb3IgYG51bGxgIHdoZW4gdGhlXG4gKiBzdG9yZSBoYXMgbm8gZW50cnkg4oCUIGEgbWlzcyBpcyB0cmVhdGVkIGFzIFwibm8ga25vd24gcmV2b2NhdGlvblwiIChmYWlsLW9wZW4pOlxuICogcmV2b2NhdGlvbiBlbnRyaWVzIGFyZSBwdWJsaXNoZWQgd2l0aCBhIFRUTCBtYXRjaGluZyB0aGUgYWNjZXNzLXRva2VuXG4gKiBsaWZldGltZSwgc28gYSBtaXNzaW5nIGVudHJ5IG1lYW5zIGFueSB0b2tlbiBvbGQgZW5vdWdoIHRvIHByZWRhdGUgaXQgaGFzXG4gKiBhbHJlYWR5IGV4cGlyZWQgb24gaXRzIG93bi5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBUb2tlblJldm9jYXRpb25TdG9yZSB7XG4gIGdldEN1cnJlbnRWZXJzaW9uKHVzZXJJZDogc3RyaW5nKTogUHJvbWlzZTxudW1iZXIgfCBudWxsPjtcbiAgLyoqXG4gICAqIFdoZXRoZXIgb25lIElNUEVSU09OQVRJT04gc2Vzc2lvbiAoYnkgdG9rZW4gYGp0aWApIGhhcyBiZWVuIGVuZGVkIGVhcmx5LlxuICAgKlxuICAgKiBPcHRpb25hbCBzbyBhIHN0b3JlIHRoYXQgcHJlZGF0ZXMgaXQgc3RpbGwgbGlua3Mg4oCUIGJ1dCBhIHN0b3JlIFdJVEhPVVQgaXRcbiAgICogY2Fubm90IGFuc3dlciwgYW5kIGFuIGltcGVyc29uYXRpb24gdG9rZW4gaXMgdGhlbiBSRUpFQ1RFRC4gVW5saWtlXG4gICAqIGBnZXRDdXJyZW50VmVyc2lvbmAsIHRoaXMgaXMgZGVsaWJlcmF0ZWx5IG5vdCBmYWlsLW9wZW46IHRoZSBwbGF0Zm9ybSBlbmRzIGFcbiAgICogc2Vzc2lvbiB3aGVuIHNvbWVvbmUgd2l0aGRyYXdzIGNvbnNlbnQsIGFuZCBhIHdpdGhkcmF3biBjb25zZW50IHRoYXQga2VlcHNcbiAgICogd29ya2luZyBpbiBldmVyeSBvdGhlciBzZXJ2aWNlIGlzIG5vdCB3aXRoZHJhd24uXG4gICAqL1xuICBnZXRTZXNzaW9uUmV2b2NhdGlvbj8oanRpOiBzdHJpbmcpOiBQcm9taXNlPFNlc3Npb25SZXZvY2F0aW9uU3RhdGU+O1xufVxuXG4vKipcbiAqIGByZXZva2VkYCAgICAg4oCUIHRoZSBzZXNzaW9uIHdhcyBlbmRlZDsgcmVqZWN0LlxuICogYGxpdmVgICAgICAgICDigJQgbm8gcmV2b2NhdGlvbiByZWNvcmRlZDsgYWxsb3cuXG4gKiBgdW5hdmFpbGFibGVgIOKAlCB0aGUgc3RvcmUgY291bGRuJ3QgYmUgcmVhZCBvciBjYW4ndCBhbnN3ZXI7IFJFSkVDVC4gRGlzdGluY3RcbiAqICAgICAgICAgICAgICAgICBmcm9tIGBsaXZlYCBwcmVjaXNlbHkgc28gYW4gb3V0YWdlIGNhbid0IHJlYWQgYXMgXCJub3QgcmV2b2tlZFwiLlxuICovXG5leHBvcnQgdHlwZSBTZXNzaW9uUmV2b2NhdGlvblN0YXRlID0gJ3Jldm9rZWQnIHwgJ2xpdmUnIHwgJ3VuYXZhaWxhYmxlJztcblxubGV0IHRva2VuUmV2b2NhdGlvblN0b3JlOiBUb2tlblJldm9jYXRpb25TdG9yZSB8IHVuZGVmaW5lZDtcblxuLyoqXG4gKiBSZWdpc3RlciAob3IgY2xlYXIsIHdpdGggYHVuZGVmaW5lZGApIHRoZSBwcm9jZXNzLXdpZGUgdG9rZW4tcmV2b2NhdGlvbiBzdG9yZS5cbiAqIFdoZW4gdW5zZXQgKHRoZSBkZWZhdWx0KSwgYHJlcXVpcmVBdXRoYCBwZXJmb3JtcyBOTyByZXZvY2F0aW9uIGNoZWNrIChpdCByZWxpZXNcbiAqIG9uIHRoZSBzaG9ydCBhY2Nlc3MtdG9rZW4gVFRMKTsgc2VydmljZXMgb3B0IGluIGF0IGJvb3QgYnkgd2lyaW5nIHRoZWlyIFJlZGlzXG4gKiBjbGllbnQuIFBsYXRmb3JtIGtlZXBzIGl0cyBvd24gTW9uZ28tYmFja2VkIGNoZWNrIGFuZCBuZWVkIG5vdCByZWdpc3RlciBvbmUuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzZXRUb2tlblJldm9jYXRpb25TdG9yZShzdG9yZTogVG9rZW5SZXZvY2F0aW9uU3RvcmUgfCB1bmRlZmluZWQpOiB2b2lkIHtcbiAgdG9rZW5SZXZvY2F0aW9uU3RvcmUgPSBzdG9yZTtcbiAgaWYgKHN0b3JlKSByZXZvY2F0aW9uU3RvcmVNaXNzaW5nV2FybmVkID0gZmFsc2U7IC8vIHJlLWFybSBpZiBhIHN0b3JlIGlzIChyZSlyZWdpc3RlcmVkXG59XG5cbi8qKiBPbmUtc2hvdCBndWFyZCBzbyB0aGUgXCJyZXZvY2F0aW9uIGluYWN0aXZlXCIgd2FybmluZyBkb2Vzbid0IGZsb29kIHRoZSBsb2dzLiAqL1xubGV0IHJldm9jYXRpb25TdG9yZU1pc3NpbmdXYXJuZWQgPSBmYWxzZTtcblxuLyoqXG4gKiBSZXR1cm5zIHRydWUgd2hlbiBgZGVjb2RlZGAgaGFzIGJlZW4gcmV2b2tlZCBwZXIgdGhlIHJlZ2lzdGVyZWQgc3RvcmU6IGl0c1xuICogZW1iZWRkZWQgYHRva2VuVmVyc2lvbmAgaXMgc3RyaWN0bHkgYmVoaW5kIHRoZSBzdG9yZSdzIGN1cnJlbnQgdmVyc2lvbi5cbiAqIEZhaWwtb3BlbiDigJQgYW55IHN0b3JlIGVycm9yLCBhIG1pc3NpbmcgZW50cnksIG9yIGEgdG9rZW4vc3RvcmUgd2l0aG91dCBhXG4gKiB1c2FibGUgdmVyc2lvbiB5aWVsZHMgYGZhbHNlYCAoYWxsb3cpLiBOZXZlciB0aHJvd3MuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGlzVG9rZW5SZXZva2VkKGRlY29kZWQ6IEp3dFBheWxvYWQpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgY29uc3Qgc3RvcmUgPSB0b2tlblJldm9jYXRpb25TdG9yZTtcbiAgaWYgKCFzdG9yZSkge1xuICAgIC8vIE1ha2UgdGhlIFwicmV2b2NhdGlvbiBpcyBPRkZcIiBzdGF0ZSBPQlNFUlZBQkxFOiBhIHNlcnZpY2UgdGhhdCB2ZXJpZmllcyB1c2VyXG4gICAgLy8gdG9rZW5zIGJ1dCBmb3Jnb3QgYHNldFRva2VuUmV2b2NhdGlvblN0b3JlKClgIHNpbGVudGx5IGRpc2FibGVzIHRoZSBzZXNzaW9uXG4gICAgLy8ga2lsbC1zd2l0Y2guIFdhcm4gT05DRSAob25seSBmb3IgYSByZXZvY2FibGUgdXNlciB0b2tlbikgc28gYSBtaXNjb25maWd1cmVkXG4gICAgLy8gYm9vdCBzdXJmYWNlcyBpbiB0aGUgbG9ncyBpbnN0ZWFkIG9mIGZhaWxpbmcgb3BlbiBpbnZpc2libHkuXG4gICAgaWYgKCFyZXZvY2F0aW9uU3RvcmVNaXNzaW5nV2FybmVkICYmIGRlY29kZWQuc3ViICYmIHR5cGVvZiBkZWNvZGVkLnRva2VuVmVyc2lvbiA9PT0gJ251bWJlcicpIHtcbiAgICAgIHJldm9jYXRpb25TdG9yZU1pc3NpbmdXYXJuZWQgPSB0cnVlO1xuICAgICAgbG9nZ2VyLndhcm4oJ1Rva2VuIHJldm9jYXRpb24gc3RvcmUgTk9UIHJlZ2lzdGVyZWQg4oCUIHJldm9jYXRpb24gY2hlY2tzIGFyZSBJTkFDVElWRSAoc2V0VG9rZW5SZXZvY2F0aW9uU3RvcmUgd2FzIG5ldmVyIGNhbGxlZCk7IHJldm9rZWQvY29tcHJvbWlzZWQgc2Vzc2lvbnMgc3RheSB2YWxpZCB1bnRpbCBuYXR1cmFsIFRUTCcpO1xuICAgIH1cbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbiAgaWYgKCFkZWNvZGVkLnN1YiB8fCB0eXBlb2YgZGVjb2RlZC50b2tlblZlcnNpb24gIT09ICdudW1iZXInKSByZXR1cm4gZmFsc2U7XG4gIHRyeSB7XG4gICAgY29uc3QgY3VycmVudCA9IGF3YWl0IHN0b3JlLmdldEN1cnJlbnRWZXJzaW9uKGRlY29kZWQuc3ViKTtcbiAgICByZXR1cm4gY3VycmVudCAhPT0gbnVsbCAmJiBkZWNvZGVkLnRva2VuVmVyc2lvbiA8IGN1cnJlbnQ7XG4gIH0gY2F0Y2gge1xuICAgIC8vIEZhaWwtb3BlbjogYSByZXZvY2F0aW9uLXN0b3JlIG91dGFnZSBtdXN0IG5vdCBsb2NrIGV2ZXJ5IHVzZXIgb3V0LlxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxufVxuXG4vKipcbiAqIFJlc29sdmUgYW4gaW1wZXJzb25hdGlvbiBzZXNzaW9uJ3MgcmV2b2NhdGlvbiBzdGF0ZS4gTmV2ZXIgdGhyb3dzOiBhbnkgZmFpbHVyZVxuICog4oCUIG5vIHN0b3JlLCBhIHN0b3JlIHRoYXQgY2FuJ3QgYW5zd2VyLCBhIHJlYWQgZXJyb3Ig4oCUIGlzIGB1bmF2YWlsYWJsZWAsIHdoaWNoXG4gKiBjYWxsZXJzIHRyZWF0IGFzIHJldm9rZWQuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHNlc3Npb25SZXZvY2F0aW9uU3RhdGUoanRpOiBzdHJpbmcpOiBQcm9taXNlPFNlc3Npb25SZXZvY2F0aW9uU3RhdGU+IHtcbiAgY29uc3Qgc3RvcmUgPSB0b2tlblJldm9jYXRpb25TdG9yZTtcbiAgaWYgKCFzdG9yZT8uZ2V0U2Vzc2lvblJldm9jYXRpb24pIHJldHVybiAndW5hdmFpbGFibGUnO1xuICB0cnkge1xuICAgIHJldHVybiBhd2FpdCBzdG9yZS5nZXRTZXNzaW9uUmV2b2NhdGlvbihqdGkpO1xuICB9IGNhdGNoIHtcbiAgICByZXR1cm4gJ3VuYXZhaWxhYmxlJztcbiAgfVxufVxuXG4vKiogQW4gaW1wZXJzb25hdGlvbiBzZXNzaW9uIHRva2VuOiBpdCBuYW1lcyB0aGUgb3BlcmF0b3IgQU5EIGNhcnJpZXMgaXRzIG93biBzZXNzaW9uIGlkLiAqL1xuZnVuY3Rpb24gaXNJbXBlcnNvbmF0aW9uU2Vzc2lvbihkZWNvZGVkOiB7IGltcGVyc29uYXRvcklkPzogdW5rbm93bjsganRpPzogdW5rbm93biB9KTogZGVjb2RlZCBpcyB7IGltcGVyc29uYXRvcklkOiBzdHJpbmc7IGp0aTogc3RyaW5nIH0ge1xuICByZXR1cm4gdHlwZW9mIGRlY29kZWQuaW1wZXJzb25hdG9ySWQgPT09ICdzdHJpbmcnICYmIHR5cGVvZiBkZWNvZGVkLmp0aSA9PT0gJ3N0cmluZycgJiYgZGVjb2RlZC5qdGkubGVuZ3RoID4gMDtcbn1cblxuLyoqXG4gKiBQdWJsaWMgcmV2b2NhdGlvbiBjaGVjayBmb3Igcm91dGVzIHRoYXQgdmVyaWZ5IGEgcGxhdGZvcm0gSldUIE9VVFNJREVcbiAqIGByZXF1aXJlQXV0aGAgKGUuZy4gdGhlIGltYWdlLXJlZ2lzdHJ5IGAvdG9rZW5gIG1pbnQgcGF0aCwgd2hpY2ggcmVzb2x2ZXNcbiAqIGlkZW50aXR5IGl0c2VsZikuIFJldHVybnMgdHJ1ZSB3aGVuIHRoZSB0b2tlbidzIGB0b2tlblZlcnNpb25gIGlzIHN0cmljdGx5XG4gKiBiZWhpbmQgdGhlIHN0b3JlJ3MgY3VycmVudCB2ZXJzaW9uLiBGYWlsLW9wZW4gKG5ldmVyIHRocm93cykg4oCUIGEgc3RvcmUgb3V0YWdlXG4gKiBvciBhIHRva2VuL3N0b3JlIHdpdGhvdXQgYSB1c2FibGUgdmVyc2lvbiB5aWVsZHMgZmFsc2UgKGFsbG93KSwgbWF0Y2hpbmdcbiAqIGByZXF1aXJlQXV0aGAuIFBhc3MgdGhlIHZlcmlmaWVkIEpXVCBjbGFpbXMgKGBzdWJgLCBgdG9rZW5WZXJzaW9uYCkuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBpc0FjY2Vzc1Rva2VuUmV2b2tlZChcbiAgY2xhaW1zOiB7IHN1Yj86IHN0cmluZzsgdG9rZW5WZXJzaW9uPzogbnVtYmVyOyBqdGk/OiBzdHJpbmc7IGltcGVyc29uYXRvcklkPzogc3RyaW5nIH0sXG4pOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgLy8gQW4gaW1wZXJzb25hdGlvbiBzZXNzaW9uIGlzIHJldm9rZWQgdW5sZXNzIHRoZSBzdG9yZSBwb3NpdGl2ZWx5IHNheXMgbGl2ZSDigJRcbiAgLy8gaW5jbHVkaW5nIG9uIHRoaXMgb3V0LW9mLWJhbmQgcGF0aCwgb3IgYSByZXZva2VkIHNlc3Npb24gY291bGQgc3RpbGwgbWludFxuICAvLyByZWdpc3RyeSB0b2tlbnMuXG4gIGlmIChpc0ltcGVyc29uYXRpb25TZXNzaW9uKGNsYWltcykgJiYgYXdhaXQgc2Vzc2lvblJldm9jYXRpb25TdGF0ZShjbGFpbXMuanRpKSAhPT0gJ2xpdmUnKSByZXR1cm4gdHJ1ZTtcbiAgcmV0dXJuIGlzVG9rZW5SZXZva2VkKGNsYWltcyBhcyBKd3RQYXlsb2FkKTtcbn1cblxuZnVuY3Rpb24gX3JlcXVpcmVBdXRoKFxuICBvcHRpb25zOiBSZXF1aXJlQXV0aE9wdGlvbnMsXG4gIHJlcTogUmVxdWVzdCxcbiAgcmVzOiBSZXNwb25zZSxcbiAgbmV4dDogTmV4dEZ1bmN0aW9uLFxuKTogdm9pZCB7XG4gIGNvbnN0IGF1dGhIZWFkZXIgPSByZXEuaGVhZGVycy5hdXRob3JpemF0aW9uO1xuXG4gIGlmICghYXV0aEhlYWRlcikge1xuICAgIHJldHVybiBzZW5kRXJyb3IocmVzLCBIdHRwU3RhdHVzLlVOQVVUSE9SSVpFRCwgJ0F1dGhvcml6YXRpb24gaGVhZGVyIHJlcXVpcmVkJywgRXJyb3JDb2RlLlRPS0VOX01JU1NJTkcpO1xuICB9XG5cbiAgY29uc3QgcGFydHMgPSBhdXRoSGVhZGVyLnNwbGl0KCcgJyk7XG4gIGlmIChwYXJ0cy5sZW5ndGggIT09IDIgfHwgcGFydHNbMF0gIT09ICdCZWFyZXInKSB7XG4gICAgcmV0dXJuIHNlbmRFcnJvcihyZXMsIEh0dHBTdGF0dXMuVU5BVVRIT1JJWkVELCAnSW52YWxpZCBhdXRob3JpemF0aW9uIGZvcm1hdC4gVXNlOiBCZWFyZXIgPHRva2VuPicsIEVycm9yQ29kZS5UT0tFTl9JTlZBTElEKTtcbiAgfVxuXG4gIHRyeSB7XG4gICAgLy8gUGFzcyB0aHJvdWdoIG9wdGlvbmFsIGlzc3Vlci9hdWRpZW5jZSB2ZXJpZmljYXRpb24gd2hlbiBlbnYtY29uZmlndXJlZC5cbiAgICAvLyBXaXRob3V0IHRoZXNlLCBhIEpXVCBzaWduZWQgYnkgYW55IHN5c3RlbSB0aGF0IGhhcHBlbnMgdG8gc2hhcmUgdGhlXG4gICAgLy8gc2FtZSBKV1RfU0VDUkVUIHdvdWxkIGJlIGFjY2VwdGVkIOKAlCBkZWZlbmNlLWluLWRlcHRoIGZvciBzaGFyZWQtc2VjcmV0XG4gICAgLy8gbWlzY29uZmlndXJhdGlvbnMgYWNyb3NzIHNlcnZpY2VzIC8gZW52aXJvbm1lbnRzLlxuICAgIC8vIFBpbiB0aGUgYWNjZXB0ZWQgYWxnb3JpdGhtIHRvIHRoZSBjb25maWd1cmVkIEhNQUMgYWxnIChkZWZhdWx0IEhTMjU2KS5cbiAgICAvLyBXaXRob3V0IGFuIGFsbG93LWxpc3QsIGBqd3QudmVyaWZ5YCBhY2NlcHRzIGFueSBhbGdvcml0aG0gdGhlIGtleSBjYW5cbiAgICAvLyB2ZXJpZnkg4oCUIHRoZSBjbGFzc2ljIGFsZy1jb25mdXNpb24gdmVjdG9yIChhbmQgYSBoYXJkIGd1YXJkIGFnYWluc3RcbiAgICAvLyBgYWxnOm5vbmVgKS4gRW52LWRyaXZlbiBzbyBpdCBzdGF5cyBpbiBsb2Nrc3RlcCB3aXRoIGhvdyB0b2tlbnMgYXJlXG4gICAgLy8gc2lnbmVkIChzZWUgc2lnblNlcnZpY2VUb2tlbiArIHBsYXRmb3JtJ3MgY29uZmlnLmF1dGguand0LmFsZ29yaXRobSkuXG4gICAgY29uc3QgdmVyaWZ5T3B0aW9ucyA9IGJ1aWxkSnd0VmVyaWZ5T3B0aW9ucygpO1xuICAgIGNvbnN0IGRlY29kZWQgPSB2ZXJpZnlKd3RXaXRoUm90YXRpb24ocGFydHNbMV0sIHZlcmlmeU9wdGlvbnMpO1xuXG4gICAgaWYgKGRlY29kZWQudHlwZSAhPT0gJ2FjY2VzcycpIHtcbiAgICAgIHJldHVybiBzZW5kRXJyb3IocmVzLCBIdHRwU3RhdHVzLlVOQVVUSE9SSVpFRCwgJ09ubHkgYWNjZXNzIHRva2VucyBjYW4gYmUgdXNlZCBmb3IgQVBJIHJlcXVlc3RzJywgRXJyb3JDb2RlLlRPS0VOX0lOVkFMSUQpO1xuICAgIH1cblxuICAgIGlmICghZGVjb2RlZC5zdWIgfHwgIWRlY29kZWQucm9sZSkge1xuICAgICAgcmV0dXJuIHNlbmRFcnJvcihyZXMsIEh0dHBTdGF0dXMuVU5BVVRIT1JJWkVELCAnVG9rZW4gbWlzc2luZyByZXF1aXJlZCBmaWVsZHMnLCBFcnJvckNvZGUuVE9LRU5fSU5WQUxJRCk7XG4gICAgfVxuXG4gICAgLy8gU2VydmljZS10b2tlbiBraWxsLXN3aXRjaDogcmVqZWN0IGEgc2VydmljZSBwcmluY2lwYWwgd2hvc2Ugc2VydmljZSBoYXNcbiAgICAvLyBiZWVuIGFkZGVkIHRvIHRoZSBkZW55bGlzdC4gUm90YXRpbmcgdGhlIHNoYXJlZCBKV1Qgc2VjcmV0IGlzIHRoZSBvbmx5XG4gICAgLy8gb3RoZXIgd2F5IHRvIGludmFsaWRhdGUgYSBzZXJ2aWNlIHRva2VuIGJlZm9yZSBpdHMgKHNob3J0KSBUVEwg4oCUIGJ1dCB0aGF0XG4gICAgLy8gbnVrZXMgRVZFUlkgc2VydmljZSB0b2tlbiBmbGVldC13aWRlLiBUaGlzIGxldHMgb25lIGNvbXByb21pc2VkL3JvZ3VlXG4gICAgLy8gc2VydmljZSBiZSBjdXQgb2ZmIHN1cmdpY2FsbHkuIE8oMSkgU2V0IGxvb2t1cCwgemVybyBjb3N0IHdoZW4gdGhlIGRlbnlsaXN0XG4gICAgLy8gaXMgZW1wdHkgKHRoZSBkZWZhdWx0KSwgc28gaXQgbmV2ZXIgdGF4ZXMgdGhlIFMyUyBob3QgcGF0aCB1bmxlc3MgYXJtZWQuXG4gICAgaWYgKGRlY29kZWQuc3ViLnN0YXJ0c1dpdGgoJ3NlcnZpY2U6JykgJiYgaXNTZXJ2aWNlVG9rZW5EZW5pZWQoZGVjb2RlZC5zdWIpKSB7XG4gICAgICBlbWl0Q291bnRlcignc2VydmljZV90b2tlbl9kZW5pZWRfdG90YWwnLCB7IHNlcnZpY2U6IGRlY29kZWQuc3ViLnNsaWNlKCdzZXJ2aWNlOicubGVuZ3RoKSB9KTtcbiAgICAgIGxvZ2dlci53YXJuKCdSZWplY3RlZCBkZW55bGlzdGVkIHNlcnZpY2UgdG9rZW4nLCB7IHN1YjogZGVjb2RlZC5zdWIgfSk7XG4gICAgICByZXR1cm4gc2VuZEVycm9yKHJlcywgSHR0cFN0YXR1cy5VTkFVVEhPUklaRUQsICdTZXJ2aWNlIHRva2VuIHJldm9rZWQnLCBFcnJvckNvZGUuVE9LRU5fUkVWT0tFRCk7XG4gICAgfVxuXG4gICAgcmVxLnVzZXIgPSB7IC4uLmRlY29kZWQgfTtcblxuICAgIC8vIFRoZSB4LW9yZy1pZC94LW9yZy1uYW1lIG92ZXJyaWRlIGxldHMgYSBTWVMtQURNSU4gYWN0IG9uIGEgY2hvc2VuIG9yZ1xuICAgIC8vIChjcm9zcy1vcmcgYWRtaW4gdG9vbGluZykuIEl0IGlzIGdhdGVkIG9uIHRoZSB2ZXJpZmllZCBgaXNTdXBlckFkbWluYCBjbGFpbVxuICAgIC8vIGhlcmUgc28gdGhhdCBldmVuIGEgcm91dGUgd2hpY2ggbWlzdGFrZW5seSBlbmFibGVzIGBhbGxvd09yZ0hlYWRlck92ZXJyaWRlYFxuICAgIC8vIGNhbiBORVZFUiBsZXQgYW4gb3JkaW5hcnkgYXV0aGVudGljYXRlZCB1c2VyIHNwb29mIGFub3RoZXIgdGVuYW50J3Mgb3JnIHZpYVxuICAgIC8vIHRoZSBoZWFkZXIg4oCUIGRlZmVuY2UtaW4tZGVwdGggYWdhaW5zdCB0aGUgY3Jvc3MtdGVuYW50IGJyZWFrIHRoaXMgY2F1c2VkLlxuICAgIGlmIChvcHRpb25zLmFsbG93T3JnSGVhZGVyT3ZlcnJpZGUgJiYgZGVjb2RlZC5pc1N1cGVyQWRtaW4gPT09IHRydWUpIHtcbiAgICAgIGNvbnN0IGhlYWRlck9yZ0lkID0gZ2V0SGVhZGVyU3RyaW5nKHJlcS5oZWFkZXJzWyd4LW9yZy1pZCddKTtcbiAgICAgIGNvbnN0IGhlYWRlck9yZ05hbWUgPSBnZXRIZWFkZXJTdHJpbmcocmVxLmhlYWRlcnNbJ3gtb3JnLW5hbWUnXSk7XG4gICAgICBpZiAoaGVhZGVyT3JnSWQpIHJlcS51c2VyLm9yZ2FuaXphdGlvbklkID0gaGVhZGVyT3JnSWQ7XG4gICAgICBpZiAoaGVhZGVyT3JnTmFtZSkgcmVxLnVzZXIub3JnYW5pemF0aW9uTmFtZSA9IGhlYWRlck9yZ05hbWU7XG4gICAgfVxuXG4gICAgLy8gUmUtZGVyaXZlIHRoZSByZXF1ZXN0J3MgdGVuYW50IGlkZW50aXR5IGZyb20gdGhlIE5PVy12ZXJpZmllZCBKV1QuXG4gICAgLy9cbiAgICAvLyBgYXR0YWNoUmVxdWVzdENvbnRleHRgIHJ1bnMgYXMgYSBnbG9iYWwgbWlkZGxld2FyZSBCRUZPUkUgdGhpcyBwZXItcm91dGVcbiAgICAvLyBgcmVxdWlyZUF1dGhgLCBzbyBpdCBjYXB0dXJlZCBgcmVxLmNvbnRleHQuaWRlbnRpdHlgIHdoaWxlIGByZXEudXNlcmAgd2FzXG4gICAgLy8gc3RpbGwgdW5kZWZpbmVkIOKAlCBhdCB3aGljaCBwb2ludCBgZ2V0SWRlbnRpdHlgIGZhbGxzIGJhY2sgdG8gdGhlIHJhdyxcbiAgICAvLyBjbGllbnQtc2V0dGFibGUgYHgtb3JnLWlkYC9geC11c2VyLWlkYCBoZWFkZXJzLiBFdmVyeSBkb3duc3RyZWFtIHRlbmFudC1cbiAgICAvLyBhdXRob3JpdHkgY29uc3VtZXIgKHJlcXVpcmVPcmdJZCwgd2l0aFRlbmFudENvbnRleHQncyBSTFMgc2NvcGUsIGNoZWNrUXVvdGEsXG4gICAgLy8gd2l0aFJvdXRlLCBhbmQgdGhlIGlkZW1wb3RlbmN5IG5hbWVzcGFjZSkgcmVhZHMgYHJlcS5jb250ZXh0LmlkZW50aXR5YCwgc29cbiAgICAvLyB0aGF0IGZyb3plbiBoZWFkZXItZGVyaXZlZCB2YWx1ZSDigJQgbm90IHRoZSBKV1Qg4oCUIHdhcyBnb3Zlcm5pbmcgdGVuYW5jeSBvblxuICAgIC8vIGFueSBub24tbmdpbnggcGF0aC4gUmVjb21wdXRpbmcgaGVyZSwgYXQgdGhlIHNpbmdsZSBwb3N0LXZlcmlmaWNhdGlvbiBjaG9rZVxuICAgIC8vIHBvaW50LCBtYWtlcyBgZ2V0SWRlbnRpdHlgIHByZWZlciB0aGUgdmVyaWZpZWQgYHJlcS51c2VyYCAoc2VlIGlkZW50aXR5LnRzKVxuICAgIC8vIHNvIHRlbmFuY3kgaXMgSldULWF1dGhvcml0YXRpdmUuIFRoZSBuZ2lueCBgeC1vcmctaWRgIG92ZXJ3cml0ZSBzdGF5cyBhc1xuICAgIC8vIGRlZmVuY2UtaW4tZGVwdGguIEd1YXJkZWQgb24gYHJlcS5jb250ZXh0YCBzbyBzZXJ2aWNlcy9wYXRocyB0aGF0IG5ldmVyXG4gICAgLy8gYXR0YWNoIGEgY29udGV4dCAob3IgcnVuIHJlcXVpcmVBdXRoIHByZS1jb250ZXh0KSBhcmUgdW5hZmZlY3RlZC5cbiAgICBjb25zdCByZXFDdHggPSAocmVxIGFzIFJlcXVlc3QgJiB7IGNvbnRleHQ/OiB7IGlkZW50aXR5OiBSZXF1ZXN0SWRlbnRpdHkgfSB9KS5jb250ZXh0O1xuICAgIGlmIChyZXFDdHgpIHtcbiAgICAgIHJlcUN0eC5pZGVudGl0eSA9IGdldElkZW50aXR5KHJlcSBhcyB1bmtub3duIGFzIEh0dHBSZXF1ZXN0KTtcbiAgICB9XG5cbiAgICAvLyBTZXNzaW9uLWludmFsaWRhdGlvbiBjaGVjayBmb3IgdGhlIHN0YXRlbGVzcyBzZXJ2aWNlczogcmVqZWN0IGEgdG9rZW5cbiAgICAvLyB3aG9zZSBgdG9rZW5WZXJzaW9uYCBpcyBiZWhpbmQgdGhlIHJldm9jYXRpb24gc3RvcmUncyBjdXJyZW50IHZhbHVlIChhXG4gICAgLy8gcHJpdmlsZWdlIGNoYW5nZSB0aGUgcGxhdGZvcm0gcHVibGlzaGVkKS4gTm8gc3RvcmUgcmVnaXN0ZXJlZCDih5IgdGhpcyBpcyBhXG4gICAgLy8gbm8tb3AgYW5kIGNvbnRyb2wgcGFzc2VzIHN0cmFpZ2h0IHRocm91Z2guIEZhaWwtb3BlbiBvbiBhbnkgc3RvcmUgZXJyb3IuXG4gICAgLy8gQW4gaW1wZXJzb25hdGlvbiBzZXNzaW9uIGlzIGNoZWNrZWQgZXZlbiB3aGVuIE5PIHN0b3JlIGlzIHJlZ2lzdGVyZWQ6IHRoZVxuICAgIC8vIHRva2VuVmVyc2lvbiBjaGVjayBiZWxvdyBpcyBhIG5vLW9wIHdpdGhvdXQgYSBzdG9yZSwgYnV0IGZvciBhIHNlc3Npb25cbiAgICAvLyB0aGF0IHdvdWxkIHNpbGVudGx5IG1lYW4gXCJuZXZlciByZXZva2VkXCIuIEhlcmUgbm8gc3RvcmUg4oeSIHVuYXZhaWxhYmxlIOKHklxuICAgIC8vIHJlamVjdGVkLiBTZWUgYFRva2VuUmV2b2NhdGlvblN0b3JlLmdldFNlc3Npb25SZXZvY2F0aW9uYC5cbiAgICBjb25zdCBpbXBlcnNvbmF0aW9uID0gaXNJbXBlcnNvbmF0aW9uU2Vzc2lvbihkZWNvZGVkKTtcbiAgICBpZiAoaW1wZXJzb25hdGlvbiB8fCAodG9rZW5SZXZvY2F0aW9uU3RvcmUgJiYgZGVjb2RlZC5zdWIgJiYgdHlwZW9mIGRlY29kZWQudG9rZW5WZXJzaW9uID09PSAnbnVtYmVyJykpIHtcbiAgICAgIC8vIGAuY2F0Y2gobmV4dClgIGZvcndhcmRzIGEgRE9XTlNUUkVBTSBzeW5jaHJvbm91cyB0aHJvdyBmcm9tIGBuZXh0KClgIHRvXG4gICAgICAvLyBFeHByZXNzJ3MgZXJyb3IgbWlkZGxld2FyZSDigJQgd2l0aG91dCBpdCwgdGhhdCB0aHJvdyB3b3VsZCBzdXJmYWNlIGFzIGFuXG4gICAgICAvLyB1bmhhbmRsZWQgcmVqZWN0aW9uICh0aGlzIGBuZXh0KClgIHJ1bnMgaW4gYSBtaWNyb3Rhc2ssIG91dHNpZGUgdGhlXG4gICAgICAvLyBzdXJyb3VuZGluZyB0cnkvY2F0Y2ggYW5kIEV4cHJlc3MncyBwZXItbGF5ZXIgZGlzcGF0Y2gpLiBUaGUgY2hlY2tzXG4gICAgICAvLyB0aGVtc2VsdmVzIG5ldmVyIHJlamVjdCwgc28gdGhlIGNhdGNoIG9ubHkgZXZlciBzZWVzIGEgZG93bnN0cmVhbSBlcnJvci5cbiAgICAgIChhc3luYyAoKSA9PiB7XG4gICAgICAgIGlmIChpbXBlcnNvbmF0aW9uKSB7XG4gICAgICAgICAgY29uc3Qgc3RhdGUgPSBhd2FpdCBzZXNzaW9uUmV2b2NhdGlvblN0YXRlKGRlY29kZWQuanRpIGFzIHN0cmluZyk7XG4gICAgICAgICAgaWYgKHN0YXRlICE9PSAnbGl2ZScpIHtcbiAgICAgICAgICAgIHJldHVybiBzZW5kRXJyb3IoXG4gICAgICAgICAgICAgIHJlcyxcbiAgICAgICAgICAgICAgSHR0cFN0YXR1cy5VTkFVVEhPUklaRUQsXG4gICAgICAgICAgICAgIHN0YXRlID09PSAncmV2b2tlZCdcbiAgICAgICAgICAgICAgICA/ICdUaGlzIGltcGVyc29uYXRpb24gc2Vzc2lvbiBoYXMgYmVlbiBlbmRlZCdcbiAgICAgICAgICAgICAgICA6ICdUaGlzIGltcGVyc29uYXRpb24gc2Vzc2lvbiBjb3VsZCBub3QgYmUgdmVyaWZpZWQnLFxuICAgICAgICAgICAgICBFcnJvckNvZGUuVE9LRU5fUkVWT0tFRCxcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGlmICh0b2tlblJldm9jYXRpb25TdG9yZSAmJiBkZWNvZGVkLnN1YiAmJiB0eXBlb2YgZGVjb2RlZC50b2tlblZlcnNpb24gPT09ICdudW1iZXInICYmIGF3YWl0IGlzVG9rZW5SZXZva2VkKGRlY29kZWQpKSB7XG4gICAgICAgICAgcmV0dXJuIHNlbmRFcnJvcihyZXMsIEh0dHBTdGF0dXMuVU5BVVRIT1JJWkVELCAnU2Vzc2lvbiBoYXMgYmVlbiByZXZva2VkOyBwbGVhc2Ugc2lnbiBpbiBhZ2FpbicsIEVycm9yQ29kZS5UT0tFTl9SRVZPS0VEKTtcbiAgICAgICAgfVxuICAgICAgICBuZXh0KCk7XG4gICAgICB9KSgpLmNhdGNoKG5leHQpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIG5leHQoKTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBqd3QuVG9rZW5FeHBpcmVkRXJyb3IpIHtcbiAgICAgIHJldHVybiBzZW5kRXJyb3IocmVzLCBIdHRwU3RhdHVzLlVOQVVUSE9SSVpFRCwgJ1Rva2VuIGhhcyBleHBpcmVkJywgRXJyb3JDb2RlLlRPS0VOX0VYUElSRUQpO1xuICAgIH1cblxuICAgIGlmIChlcnJvciBpbnN0YW5jZW9mIGp3dC5Kc29uV2ViVG9rZW5FcnJvcikge1xuICAgICAgcmV0dXJuIHNlbmRFcnJvcihyZXMsIEh0dHBTdGF0dXMuVU5BVVRIT1JJWkVELCAnSW52YWxpZCB0b2tlbicsIEVycm9yQ29kZS5UT0tFTl9JTlZBTElEKTtcbiAgICB9XG5cbiAgICByZXR1cm4gc2VuZEVycm9yKHJlcywgSHR0cFN0YXR1cy5VTkFVVEhPUklaRUQsICdBdXRoZW50aWNhdGlvbiBmYWlsZWQnLCBFcnJvckNvZGUuVU5BVVRIT1JJWkVEKTtcbiAgfVxufVxuXG4vKipcbiAqIFdoZXRoZXIgdGhlIHJlcXVlc3QncyB1c2VyIGhvbGRzIGBwZXJtaXNzaW9uYC4gU3VwZXJhZG1pbnMgaW1wbGljaXRseSBob2xkXG4gKiBldmVyeSBwZXJtaXNzaW9uLiBSZWFkcyB0aGUgcmVzb2x2ZWQgYHBlcm1pc3Npb25zYCBjbGFpbSAoc2V0IGF0IHRva2VuIGlzc3VlLFxuICogb3IgcmUtZGVyaXZlZCBwZXIgcmVxdWVzdCBieSB0aGUgcGxhdGZvcm0pLlxuICovXG5leHBvcnQgZnVuY3Rpb24gdXNlckhhc1Blcm1pc3Npb24ocmVxOiBSZXF1ZXN0LCBwZXJtaXNzaW9uOiBQZXJtaXNzaW9uKTogYm9vbGVhbiB7XG4gIHJldHVybiBoYXNQZXJtaXNzaW9uKHJlcS51c2VyPy5wZXJtaXNzaW9ucywgcGVybWlzc2lvbiwgcmVxLnVzZXI/LmlzU3VwZXJBZG1pbik7XG59XG5cbi8qKlxuICogQ29udGV4dCBwYXNzZWQgdG8gYSByZWdpc3RlcmVkIGF1dGhvcml6YXRpb24tZGVuaWFsIGF1ZGl0b3Igd2hlbiBhXG4gKiBzdGF0ZS1jaGFuZ2luZyByZXF1ZXN0IGlzIHJlamVjdGVkIGJ5IGByZXF1aXJlUGVybWlzc2lvbmAgL1xuICogYHJlcXVpcmVTeXN0ZW1BZG1pbmAuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQXV0aHpEZW5pYWxJbmZvIHtcbiAgLyoqIFRoZSBkZW5pZWQgdXNlcidzIGlkIChgc3ViYCksIGlmIGF1dGhlbnRpY2F0ZWQuICovXG4gIGFjdG9ySWQ/OiBzdHJpbmc7XG4gIGFjdG9yRW1haWw/OiBzdHJpbmc7XG4gIC8qKiBUaGUgdXNlcidzIGFjdGl2ZSBvcmcgYXQgZGVuaWFsIHRpbWUuICovXG4gIG9yZ0lkPzogc3RyaW5nO1xuICAvKiogSFRUUCBtZXRob2QgKyBwYXRoIG9mIHRoZSByZWplY3RlZCByZXF1ZXN0LiAqL1xuICBtZXRob2Q6IHN0cmluZztcbiAgcGF0aDogc3RyaW5nO1xuICAvKiogV2hhdCB3YXMgcmVxdWlyZWQ6IHRoZSBtaXNzaW5nIHBlcm1pc3Npb24ocyksIG9yICdzeXN0ZW0tYWRtaW4nLiAqL1xuICByZXF1aXJlZDogc3RyaW5nO1xufVxuXG4vKipcbiAqIE9wdGlvbmFsIHNpbmsgZm9yIGRlbmllZC1hdXRob3JpemF0aW9uIGV2ZW50cy4gTGVmdCB1bnNldCBieSBkZWZhdWx0IHNvXG4gKiBhcGktY29yZSBzdGF5cyBkZWNvdXBsZWQgZnJvbSBhbnkgYXVkaXQgdHJhbnNwb3J0IOKAlCBhIHNlcnZpY2UgcmVnaXN0ZXJzIG9uZVxuICogYXQgYm9vdCAodHlwaWNhbGx5IGZvcndhcmRpbmcgdG8gaXRzIGBSZW1vdGVBdWRpdENsaWVudGAgYXMgYW5cbiAqIGBhdXRoei5kZW5pZWRgIGV2ZW50LCBvciwgb24gcGxhdGZvcm0sIHRvIHRoZSBsb2NhbCBgYXVkaXQoKWAgaGVscGVyKS5cbiAqIE1VU1QgYmUgYmVzdC1lZmZvcnQ6IGl0IGlzIGludm9rZWQgaW5zaWRlIHRoZSByZXF1ZXN0IHBhdGgsIHNvIGl0IG11c3QgbmV2ZXJcbiAqIHRocm93IG9yIGJsb2NrICh0aGUgZ2F0ZSB3cmFwcyB0aGUgY2FsbCBpbiB0cnkvY2F0Y2ggcmVnYXJkbGVzcykuXG4gKi9cbmxldCBhdXRoekRlbmlhbEF1ZGl0b3I6ICgoaW5mbzogQXV0aHpEZW5pYWxJbmZvKSA9PiB2b2lkKSB8IHVuZGVmaW5lZDtcblxuLyoqXG4gKiBSZWdpc3RlciAob3IgY2xlYXIsIHdpdGggYHVuZGVmaW5lZGApIHRoZSBwcm9jZXNzLXdpZGUgYXV0aG9yaXphdGlvbi1kZW5pYWxcbiAqIGF1ZGl0b3IuIElkZW1wb3RlbnQ7IHRoZSBsYXN0IHJlZ2lzdHJhdGlvbiB3aW5zLlxuICovXG5leHBvcnQgZnVuY3Rpb24gc2V0QXV0aHpEZW5pYWxBdWRpdG9yKGZuOiAoKGluZm86IEF1dGh6RGVuaWFsSW5mbykgPT4gdm9pZCkgfCB1bmRlZmluZWQpOiB2b2lkIHtcbiAgYXV0aHpEZW5pYWxBdWRpdG9yID0gZm47XG59XG5cbi8qKlxuICogRW1pdCBhIGRlbmlhbCBldmVudCwgYmVzdC1lZmZvcnQuIE9ubHkgZmlyZXMgZm9yIHN0YXRlLWNoYW5naW5nIChub24tR0VULFxuICogbm9uLUhFQUQvT1BUSU9OUykgcmVxdWVzdHMg4oCUIGEgcmVqZWN0ZWQgR0VUIGlzIGxvdy1zaWduYWwgcHJvYmluZyBub2lzZSBhbmRcbiAqIHdvdWxkIGFtcGxpZnkgYXVkaXQgdm9sdW1lIHVuZGVyIGEgc2Nhbi4gTmV2ZXIgdGhyb3dzLlxuICovXG5mdW5jdGlvbiBhdWRpdEF1dGh6RGVuaWFsKHJlcTogUmVxdWVzdCwgcmVxdWlyZWQ6IHN0cmluZyk6IHZvaWQge1xuICBjb25zdCBhdWRpdG9yID0gYXV0aHpEZW5pYWxBdWRpdG9yO1xuICBpZiAoIWF1ZGl0b3IpIHJldHVybjtcbiAgY29uc3QgbWV0aG9kID0gcmVxLm1ldGhvZC50b1VwcGVyQ2FzZSgpO1xuICBpZiAobWV0aG9kID09PSAnR0VUJyB8fCBtZXRob2QgPT09ICdIRUFEJyB8fCBtZXRob2QgPT09ICdPUFRJT05TJykgcmV0dXJuO1xuICB0cnkge1xuICAgIGF1ZGl0b3Ioe1xuICAgICAgYWN0b3JJZDogcmVxLnVzZXI/LnN1YixcbiAgICAgIGFjdG9yRW1haWw6IHJlcS51c2VyPy5lbWFpbCxcbiAgICAgIG9yZ0lkOiByZXEudXNlcj8ub3JnYW5pemF0aW9uSWQsXG4gICAgICBtZXRob2QsXG4gICAgICAvLyBTdHJpcCB0aGUgcXVlcnkgc3RyaW5nIOKAlCBhIGRlbmllZCByZXF1ZXN0IG1heSBjYXJyeSBhIHRva2VuL3NlY3JldCBhcyBhXG4gICAgICAvLyBxdWVyeSBwYXJhbSwgYW5kIHRoaXMgcGF0aCBpcyBwZXJzaXN0ZWQgdmVyYmF0aW0gaW50byB0aGUgYXVkaXQgbG9nLlxuICAgICAgcGF0aDogKHJlcS5vcmlnaW5hbFVybCB8fCByZXEudXJsKS5zcGxpdCgnPycpWzBdLFxuICAgICAgcmVxdWlyZWQsXG4gICAgfSk7XG4gIH0gY2F0Y2gge1xuICAgIC8vIEJlc3QtZWZmb3J0IOKAlCBhIGJyb2tlbiBhdWRpdG9yIG11c3QgbmV2ZXIgYnJlYWsgdGhlIGF1dGggZ2F0ZS5cbiAgfVxufVxuXG4vKipcbiAqIFJlcXVpcmVzIHRoYXQgdGhlIHVzZXIgaG9sZCBBVCBMRUFTVCBPTkUgb2YgdGhlIGdpdmVuIHBlcm1pc3Npb25zIChvciBiZSBhXG4gKiBzdXBlcmFkbWluKS4gVXNlIGFmdGVyIHJlcXVpcmVBdXRoLiBNaXJyb3JzIGByZXF1aXJlUm9sZWAncyBhbnktb2Ygc2VtYW50aWNzO1xuICogcGFzcyBhIHNpbmdsZSBwZXJtaXNzaW9uIGZvciBhIHNwZWNpZmljIGFjdGlvbiwgb3Igc2V2ZXJhbCB3aGVuIGFueSBvbmUgb2ZcbiAqIHRoZW0gc2hvdWxkIGdyYW50IGFjY2Vzcy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlcXVpcmVQZXJtaXNzaW9uKC4uLnBlcm1pc3Npb25zOiBQZXJtaXNzaW9uW10pIHtcbiAgcmV0dXJuIChyZXE6IFJlcXVlc3QsIHJlczogUmVzcG9uc2UsIG5leHQ6IE5leHRGdW5jdGlvbik6IHZvaWQgPT4ge1xuICAgIGlmICghcmVxLnVzZXIpIHtcbiAgICAgIHJldHVybiBzZW5kRXJyb3IocmVzLCBIdHRwU3RhdHVzLlVOQVVUSE9SSVpFRCwgJ0F1dGhlbnRpY2F0aW9uIHJlcXVpcmVkJywgRXJyb3JDb2RlLlVOQVVUSE9SSVpFRCk7XG4gICAgfVxuICAgIC8vIHVzZXJIYXNQZXJtaXNzaW9uIOKGkiBoYXNQZXJtaXNzaW9uIGFscmVhZHkgZ3JhbnRzIHN1cGVyYWRtaW5zIGV2ZXJ5XG4gICAgLy8gcGVybWlzc2lvbiwgc28gdGhpcyBzaW5nbGUgY2hlY2sgY292ZXJzIGJvdGggdGhlIHN1cGVyYWRtaW4gYnlwYXNzIGFuZFxuICAgIC8vIHRoZSBhbnktb2YgbWVtYmVyc2hpcCB0ZXN0IHdpdGhvdXQgcmUtaW5saW5pbmcgZWl0aGVyLlxuICAgIGlmIChwZXJtaXNzaW9ucy5zb21lKChwKSA9PiB1c2VySGFzUGVybWlzc2lvbihyZXEsIHApKSkgcmV0dXJuIG5leHQoKTtcbiAgICBhdWRpdEF1dGh6RGVuaWFsKHJlcSwgcGVybWlzc2lvbnMuam9pbignIG9yICcpKTtcbiAgICByZXR1cm4gc2VuZEVycm9yKFxuICAgICAgcmVzLCBIdHRwU3RhdHVzLkZPUkJJRERFTixcbiAgICAgIGBNaXNzaW5nIHJlcXVpcmVkIHBlcm1pc3Npb246ICR7cGVybWlzc2lvbnMuam9pbignIG9yICcpfWAsXG4gICAgICBFcnJvckNvZGUuSU5TVUZGSUNJRU5UX1BFUk1JU1NJT05TLFxuICAgICk7XG4gIH07XG59XG5cbi8qKlxuICogUmVxdWlyZXMgdGhhdCB0aGUgdXNlciBob2xkIEVWRVJZIG9uZSBvZiB0aGUgZ2l2ZW4gcGVybWlzc2lvbnMgKG9yIGJlIGFcbiAqIHN1cGVyYWRtaW4pIOKAlCB0aGUgQU5EIGNvdW50ZXJwYXJ0IHRvIGByZXF1aXJlUGVybWlzc2lvbmAncyBhbnktb2YuIFVzZSBmb3IgYVxuICogc2Vuc2l0aXZlIGFjdGlvbiB0aGF0IGxlZ2l0aW1hdGVseSBkZW1hbmRzIHR3byBkaXN0aW5jdCBjYXBhYmlsaXRpZXMgYXQgb25jZVxuICogKGUuZy4gYSBjcm9zcy1zdXJmYWNlIG9wZXJhdGlvbiksIHNvIHRoZSBndWFyYW50ZWUgaXMgZXhwbGljaXQgcmF0aGVyIHRoYW5cbiAqIGFwcHJveGltYXRlZCBieSBjaGFpbmluZyB0d28gYHJlcXVpcmVQZXJtaXNzaW9uYCBnYXRlcy4gU3VwZXJhZG1pbnMgYnlwYXNzXG4gKiAodGhleSBpbXBsaWNpdGx5IGhvbGQgZXZlcnkgcGVybWlzc2lvbikuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXF1aXJlQWxsUGVybWlzc2lvbnMoLi4ucGVybWlzc2lvbnM6IFBlcm1pc3Npb25bXSkge1xuICByZXR1cm4gKHJlcTogUmVxdWVzdCwgcmVzOiBSZXNwb25zZSwgbmV4dDogTmV4dEZ1bmN0aW9uKTogdm9pZCA9PiB7XG4gICAgaWYgKCFyZXEudXNlcikge1xuICAgICAgcmV0dXJuIHNlbmRFcnJvcihyZXMsIEh0dHBTdGF0dXMuVU5BVVRIT1JJWkVELCAnQXV0aGVudGljYXRpb24gcmVxdWlyZWQnLCBFcnJvckNvZGUuVU5BVVRIT1JJWkVEKTtcbiAgICB9XG4gICAgY29uc3QgbWlzc2luZyA9IHBlcm1pc3Npb25zLmZpbHRlcigocCkgPT4gIXVzZXJIYXNQZXJtaXNzaW9uKHJlcSwgcCkpO1xuICAgIGlmIChtaXNzaW5nLmxlbmd0aCA9PT0gMCkgcmV0dXJuIG5leHQoKTtcbiAgICBhdWRpdEF1dGh6RGVuaWFsKHJlcSwgcGVybWlzc2lvbnMuam9pbignIGFuZCAnKSk7XG4gICAgcmV0dXJuIHNlbmRFcnJvcihcbiAgICAgIHJlcywgSHR0cFN0YXR1cy5GT1JCSURERU4sXG4gICAgICBgTWlzc2luZyByZXF1aXJlZCBwZXJtaXNzaW9uOiAke21pc3Npbmcuam9pbignIGFuZCAnKX1gLFxuICAgICAgRXJyb3JDb2RlLklOU1VGRklDSUVOVF9QRVJNSVNTSU9OUyxcbiAgICApO1xuICB9O1xufVxuXG4vKipcbiAqIExpa2Uge0BsaW5rIHJlcXVpcmVQZXJtaXNzaW9ufSAoYW55LW9mKSBidXQgQUxTTyBhZG1pdHMgYW4gaW50ZXJuYWwgc2VydmljZVxuICogcHJpbmNpcGFsIChhIGBzZXJ2aWNlOipgIG1hY2hpbmUgdG9rZW4pLiBGb3IgUkVBRCBlbmRwb2ludHMgdGhhdCBCT1RIXG4gKiBpbnRlcmFjdGl2ZSB1c2VycyDigJQgd2hvIG11c3QgaG9sZCBvbmUgb2YgdGhlIGA6cmVhZGAgY2FwYWJpbGl0aWVzIOKAlCBBTkRcbiAqIHNlcnZpY2UtdG8tc2VydmljZSBjYWxsZXJzIGxlZ2l0aW1hdGVseSBoaXQ7IHNlcnZpY2UgdG9rZW5zIGNhcnJ5IG5vXG4gKiBwZXJtaXNzaW9uIGNsYWltcyAodGhleSdyZSBsZWFzdC1wcml2aWxlZ2UgYHJvbGU6bWVtYmVyYCksIHNvIGEgcGxhaW5cbiAqIGByZXF1aXJlUGVybWlzc2lvbmAgd291bGQgd3JvbmdseSA0MDMgdGhlbS4gU3VwZXJhZG1pbnMgcGFzcyB2aWFcbiAqIGB1c2VySGFzUGVybWlzc2lvbmAncyBpbXBsaWNpdC1hbGwuIFVzZSBvbmx5IHdoZXJlIGEgc2VydmljZSBjYWxsZXIgaXMgYSBrbm93bixcbiAqIGludGVuZGVkIGNvbnN1bWVyIG9mIHRoZSByb3V0ZSAodmVyaWZ5IHRoZSBjYWxsZXJzKTsgcHJlZmVyIHBsYWluXG4gKiBgcmVxdWlyZVBlcm1pc3Npb25gIGZvciBwdXJlbHkgdXNlci1mYWNpbmcgcmVhZHMuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXF1aXJlUGVybWlzc2lvbk9yU2VydmljZSguLi5wZXJtaXNzaW9uczogUGVybWlzc2lvbltdKSB7XG4gIHJldHVybiAocmVxOiBSZXF1ZXN0LCByZXM6IFJlc3BvbnNlLCBuZXh0OiBOZXh0RnVuY3Rpb24pOiB2b2lkID0+IHtcbiAgICBpZiAoIXJlcS51c2VyKSB7XG4gICAgICByZXR1cm4gc2VuZEVycm9yKHJlcywgSHR0cFN0YXR1cy5VTkFVVEhPUklaRUQsICdBdXRoZW50aWNhdGlvbiByZXF1aXJlZCcsIEVycm9yQ29kZS5VTkFVVEhPUklaRUQpO1xuICAgIH1cbiAgICBpZiAoaXNTZXJ2aWNlUHJpbmNpcGFsKHJlcSkgfHwgcGVybWlzc2lvbnMuc29tZSgocCkgPT4gdXNlckhhc1Blcm1pc3Npb24ocmVxLCBwKSkpIHJldHVybiBuZXh0KCk7XG4gICAgYXVkaXRBdXRoekRlbmlhbChyZXEsIHBlcm1pc3Npb25zLmpvaW4oJyBvciAnKSk7XG4gICAgcmV0dXJuIHNlbmRFcnJvcihcbiAgICAgIHJlcywgSHR0cFN0YXR1cy5GT1JCSURERU4sXG4gICAgICBgTWlzc2luZyByZXF1aXJlZCBwZXJtaXNzaW9uOiAke3Blcm1pc3Npb25zLmpvaW4oJyBvciAnKX1gLFxuICAgICAgRXJyb3JDb2RlLklOU1VGRklDSUVOVF9QRVJNSVNTSU9OUyxcbiAgICApO1xuICB9O1xufVxuXG4vKipcbiAqIEdhdGUgYW4gZW5kcG9pbnQgdG8gaW50ZXJuYWwgc2VydmljZS10by1zZXJ2aWNlIGNhbGxlcnMgb25seSAoYSBgc2VydmljZToqYFxuICogbWFjaGluZSBwcmluY2lwYWwgbWludGVkIHZpYSB7QGxpbmsgc2lnblNlcnZpY2VUb2tlbn0gLyBgZ2V0U2VydmljZUF1dGhIZWFkZXJgKS5cbiAqIFJlamVjdHMgYW55IHVzZXIgdG9rZW4uIEZvciBOT04tdXNlci1mYWNpbmcgZW5kcG9pbnRzIOKAlCBlbnRpdHktZXZlbnQgaW5nZXN0LFxuICogYXV0by1zdWJzY3JpYmUsIGFuZCBzaW1pbGFyIHBlZXItc2VydmljZSBob29rcyDigJQgdGhhdCBhIGJyb3dzZXIgbXVzdCBuZXZlclxuICogcmVhY2guIENvbXBvc2UgYWZ0ZXIgYHJlcXVpcmVBdXRoYCBzbyBgcmVxLnVzZXJgIGlzIHBvcHVsYXRlZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlcXVpcmVTZXJ2aWNlUHJpbmNpcGFsKHJlcTogUmVxdWVzdCwgcmVzOiBSZXNwb25zZSwgbmV4dDogTmV4dEZ1bmN0aW9uKTogdm9pZCB7XG4gIGlmICghaXNTZXJ2aWNlUHJpbmNpcGFsKHJlcSkpIHtcbiAgICAvLyA0MDMgKG5vdCA0MDApIOKAlCB0aGlzIGlzIGFuIGF1dGhvcml6YXRpb24gcmVmdXNhbDsgc3RhdHVzIG11c3QgbWF0Y2ggdGhlXG4gICAgLy8gSU5TVUZGSUNJRU5UX1BFUk1JU1NJT05TIGNvZGUgYW5kIHRoZSBzaWJsaW5nIGdhdGVzIChyZXF1aXJlUGVybWlzc2lvbiwgZXRjLikuXG4gICAgcmV0dXJuIHNlbmRFcnJvcihyZXMsIEh0dHBTdGF0dXMuRk9SQklEREVOLCAnSW50ZXJuYWwgc2VydmljZSBjYWxscyBvbmx5JywgRXJyb3JDb2RlLklOU1VGRklDSUVOVF9QRVJNSVNTSU9OUyk7XG4gIH1cbiAgbmV4dCgpO1xufVxuXG4vKipcbiAqIFRoZSBzeXN0ZW0gdGVuYW50J3MgY2Fub25pY2FsIG9yZyAqKmlkKiog4oCUIGEgZml4ZWQsIHdlbGwta25vd24gT2JqZWN0SWQgKE5PVFxuICogdGhlIHN0cmluZyAnc3lzdGVtJykuIFRoaXMgaXMgdGhlIHNpbmdsZSBrbm9iIGV2ZXJ5IHNlcnZpY2UgcmVzb2x2ZXMgdGhlXG4gKiBzeXN0ZW0gdGVuYW50IHRocm91Z2g7IG92ZXJyaWRlIHZpYSB0aGUgYFNZU1RFTV9PUkdfSURgIGVudiBmb3IgYWx0ZXJuYXRlXG4gKiBpbnN0YWxscy4gVGhlIHN5c3RlbSBvcmcncyBodW1hbiBpZGVudGlmaWVyIHN0YXlzIHRoZSBzbHVnL25hbWUgJ3N5c3RlbSdcbiAqIChzZWUge0BsaW5rIFNZU1RFTV9PUkdfU0xVR30pOyBvbmx5IGl0cyBgX2lkYCBpcyB0aGlzIE9iamVjdElkLlxuICovXG5leHBvcnQgY29uc3QgU1lTVEVNX09SR19JRCA9IChwcm9jZXNzLmVudi5TWVNURU1fT1JHX0lEIHx8ICcwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDEnKS50b0xvd2VyQ2FzZSgpO1xuXG4vKiogVGhlIHN5c3RlbSBvcmcncyB3ZWxsLWtub3duIHNsdWcvbmFtZSAodGhlIGh1bWFuIGlkZW50aWZpZXI7IGl0cyBgX2lkYCBpcyB7QGxpbmsgU1lTVEVNX09SR19JRH0pLiAqL1xuZXhwb3J0IGNvbnN0IFNZU1RFTV9PUkdfU0xVRyA9ICdzeXN0ZW0nO1xuXG4vKipcbiAqIENoZWNrIGlmIGFuIG9yZ0lkIG9yIG9yZ05hbWUvc2x1ZyBtYXRjaGVzIHRoZSBzeXN0ZW0gb3JnLiBVc2UgdGhpcyBpbnN0ZWFkIG9mXG4gKiBjb21wYXJpbmcgZGlyZWN0bHk6IHRoZSBpZCBpcyBub3cgYW4gT2JqZWN0SWQgKHtAbGluayBTWVNURU1fT1JHX0lEfSkgd2hpbGUgdGhlXG4gKiBuYW1lL3NsdWcgaXMgJ3N5c3RlbScgKHtAbGluayBTWVNURU1fT1JHX1NMVUd9KSwgc28gdGhlIHR3byBhcmUgY29tcGFyZWQgYWdhaW5zdFxuICogdGhlaXIgcmVzcGVjdGl2ZSBjYW5vbmljYWwgdmFsdWVzLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNTeXN0ZW1PcmdJZChvcmdJZD86IHN0cmluZywgb3JnTmFtZT86IHN0cmluZyk6IGJvb2xlYW4ge1xuICByZXR1cm4gb3JnSWQ/LnRvTG93ZXJDYXNlKCkgPT09IFNZU1RFTV9PUkdfSUQgfHwgb3JnTmFtZT8udG9Mb3dlckNhc2UoKSA9PT0gU1lTVEVNX09SR19TTFVHO1xufVxuXG4vKipcbiAqIENoZWNrIGlmIHRoZSByZXF1ZXN0IGlzIGZyb20gYSBzeXN0ZW0gYWRtaW4uXG4gKlxuICogQXV0aG9yaXR5IGlzIGdyYW50ZWQgc29sZWx5IGJ5IHRoZSB1c2VyLWxldmVsIGBpc1N1cGVyQWRtaW5gIGZsYWcgY2FycmllZFxuICogaW4gdGhlIEpXVC4gVGhlIFwibWVtYmVyc2hpcCBpbiB0aGUgd2VsbC1rbm93biAnc3lzdGVtJyBvcmcgd2l0aCByb2xlXG4gKiBhZG1pbi9vd25lclwiIHBhdGggd2FzIHJlbW92ZWQg4oCUIGl0IGNvbmZsYXRlZCBhIFBpcGVsaW5lIEJ1aWxkZXIgb3BlcmF0b3JcbiAqIHdpdGggYSByZWFsIGN1c3RvbWVyIHRlbmFudCBpbiB0aGUgZGF0YSBtb2RlbCwgYW5kIG1lYW50IGFueSB1bmludGVuZGVkXG4gKiB3cml0ZSB0aGF0IGNyZWF0ZWQgYSAnc3lzdGVtJy1uYW1lZCBvcmcgY291bGQgcXVpZXRseSBncmFudCBjcm9zcy1vcmdcbiAqIGF1dGhvcml0eS4gVGhlIGBzeXN0ZW1gIG9yZyBzdGlsbCBleGlzdHMgYXMgYSAqY29udGVudCBob2xkZXIqIGZvciBzaGFyZWRcbiAqIHNhbXBsZSBkYXRhOyBpdCBqdXN0IG5vIGxvbmdlciBjb25mZXJzIHByaXZpbGVnZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzU3lzdGVtQWRtaW4ocmVxOiBSZXF1ZXN0KTogYm9vbGVhbiB7XG4gIHJldHVybiByZXEudXNlcj8uaXNTdXBlckFkbWluID09PSB0cnVlO1xufVxuXG4vKipcbiAqIFdoZXRoZXIgdGhlIHJlcXVlc3QncyB0b2tlbiBjYXJyaWVzIGEgc3BlY2lmaWMgY2FwYWJpbGl0eSBgc2NvcGVgIChlLmcuXG4gKiBgJ3JlcG9ydGluZzppbmdlc3QnYCkuIFVzZWQgdG8gZ2F0ZSBlbmRwb2ludHMgdGhhdCBhY2NlcHQgYSBuYXJyb3cgbWFjaGluZVxuICogaWRlbnRpdHkg4oCUIGEgbm9ybWFsIGludGVyYWN0aXZlIHVzZXIgdG9rZW4gaGFzIG5vIGBzY29wZWAgYW5kIHJldHVybnMgZmFsc2UuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBoYXNTY29wZShyZXE6IFJlcXVlc3QsIHNjb3BlOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgcmV0dXJuIHJlcS51c2VyPy5zY29wZSA9PT0gc2NvcGU7XG59XG5cbi8qKiBSZXF1aXJlcyBhIHN5c3RlbSBhZG1pbiDigJQgZ3JhbnRlZCBzb2xlbHkgYnkgdGhlIGBpc1N1cGVyQWRtaW5gIHRva2VuIGNsYWltXG4gKiAgKHRoZSBvcmctbWVtYmVyc2hpcCBwYXRoIHdhcyByZW1vdmVkKS4gVXNlIGFmdGVyIHJlcXVpcmVBdXRoLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlcXVpcmVTeXN0ZW1BZG1pbihcbiAgcmVxOiBSZXF1ZXN0LFxuICByZXM6IFJlc3BvbnNlLFxuICBuZXh0OiBOZXh0RnVuY3Rpb24sXG4pOiB2b2lkIHtcbiAgaWYgKCFpc1N5c3RlbUFkbWluKHJlcSkpIHtcbiAgICBhdWRpdEF1dGh6RGVuaWFsKHJlcSwgJ3N5c3RlbS1hZG1pbicpO1xuICAgIHJldHVybiBzZW5kRXJyb3IoXG4gICAgICByZXMsIEh0dHBTdGF0dXMuRk9SQklEREVOLFxuICAgICAgJ0FjY2VzcyBkZW5pZWQuIE9ubHkgc3lzdGVtIGFkbWluaXN0cmF0b3JzIGNhbiBwZXJmb3JtIHRoaXMgYWN0aW9uLicsXG4gICAgICBFcnJvckNvZGUuSU5TVUZGSUNJRU5UX1BFUk1JU1NJT05TLFxuICAgICk7XG4gIH1cbiAgbmV4dCgpO1xufVxuXG4vKipcbiAqIFJlcXVpcmUgYSBzcGVjaWZpYyBmZWF0dXJlIGZsYWcuIFVzZSBhZnRlciByZXF1aXJlQXV0aC5cbiAqIENoZWNrcyB0aGUgYGZlYXR1cmVzYCBhcnJheSBpbiB0aGUgSldUIHBheWxvYWQgKHNldCBhdCB0b2tlbiBpc3N1YW5jZSkuXG4gKiBTeXNhZG1pbnMgKGlzU3VwZXJBZG1pbikgYnlwYXNzIOKAlCB0aGV5IGFsd2F5cyBoYXZlIGV2ZXJ5IGZlYXR1cmUuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXF1aXJlRmVhdHVyZShmZWF0dXJlOiBzdHJpbmcpIHtcbiAgcmV0dXJuIChyZXE6IFJlcXVlc3QsIHJlczogUmVzcG9uc2UsIG5leHQ6IE5leHRGdW5jdGlvbik6IHZvaWQgPT4ge1xuICAgIGlmICghcmVxLnVzZXIpIHtcbiAgICAgIHJldHVybiBzZW5kRXJyb3IocmVzLCBIdHRwU3RhdHVzLlVOQVVUSE9SSVpFRCwgJ0F1dGhlbnRpY2F0aW9uIHJlcXVpcmVkJywgRXJyb3JDb2RlLlVOQVVUSE9SSVpFRCk7XG4gICAgfVxuXG4gICAgLy8gU3lzYWRtaW5zIGdldCBhbGwgZmVhdHVyZXM7IHRoZSBgZmVhdHVyZXNgIGFycmF5IG9uIHRoZWlyIHRva2VuIGlzXG4gICAgLy8gcG9wdWxhdGVkIHdpdGggZXZlcnkgZmxhZyBhdCBpc3N1YW5jZSB0aW1lIGJ1dCB0aGUgYnlwYXNzIGhlcmUga2VlcHNcbiAgICAvLyB0aGUgcnVsZSBleHBsaWNpdCBhbmQgc3Vydml2ZXMgYSB0b2tlbiBpc3N1ZWQgYmVmb3JlIGEgbmV3IGZlYXR1cmVcbiAgICAvLyBmbGFnIHdhcyBhZGRlZC5cbiAgICBpZiAocmVxLnVzZXIuaXNTdXBlckFkbWluID09PSB0cnVlKSByZXR1cm4gbmV4dCgpO1xuXG4gICAgaWYgKCFyZXEudXNlci5mZWF0dXJlcz8uaW5jbHVkZXMoZmVhdHVyZSkpIHtcbiAgICAgIC8vIFJvdXRlIGZlYXR1cmUtZ2F0ZSBkZW5pYWxzIHRocm91Z2ggdGhlIHNhbWUgYXVkaXQgc2luayBhc1xuICAgICAgLy8gcmVxdWlyZVBlcm1pc3Npb24gLyByZXF1aXJlU3lzdGVtQWRtaW4gc28gYSBwcm9iZSBmb3IgYW5cbiAgICAgIC8vIHVuZW50aXRsZWQgY2FwYWJpbGl0eSBsZWF2ZXMgYSB0cmFpbCAoc3RhdGUtY2hhbmdpbmcgbWV0aG9kcyBvbmx5KS5cbiAgICAgIGF1ZGl0QXV0aHpEZW5pYWwocmVxLCBgZmVhdHVyZToke2ZlYXR1cmV9YCk7XG4gICAgICByZXR1cm4gc2VuZEVycm9yKFxuICAgICAgICByZXMsIEh0dHBTdGF0dXMuRk9SQklEREVOLFxuICAgICAgICBgVGhpcyBmZWF0dXJlIHJlcXVpcmVzIGEgaGlnaGVyIHBsYW4gKCR7ZmVhdHVyZX0pYCxcbiAgICAgICAgRXJyb3JDb2RlLklOU1VGRklDSUVOVF9QRVJNSVNTSU9OUyxcbiAgICAgICk7XG4gICAgfVxuXG4gICAgbmV4dCgpO1xuICB9O1xufVxuXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIFNlcnZpY2UtdG8tc2VydmljZSB0b2tlbnNcbi8vXG4vLyBJbnRlci1zZXJ2aWNlIEhUVFAgY2FsbHMgKGJpbGxpbmcg4oaSIG1lc3NhZ2UsIHBsYXRmb3JtIOKGkiBjb21wbGlhbmNlLCBldGMuKVxuLy8gbmVlZCB0byBzYXRpc2Z5IHRoZSBzYW1lIGByZXF1aXJlQXV0aGAgbWlkZGxld2FyZSBhcyB1c2VyIHJlcXVlc3RzLlxuLy8gYHNpZ25TZXJ2aWNlVG9rZW5gIG1pbnRzIGEgc2hvcnQtbGl2ZWQgSldUIHNpZ25lZCB3aXRoIHRoZSBzaGFyZWRcbi8vIEpXVF9TRUNSRVQsIGlkZW50aWZ5aW5nIHRoZSBjYWxsaW5nIHNlcnZpY2UgdmlhIGBzdWI6ICdzZXJ2aWNlOjxuYW1lPidgLlxuLy8gYHJlcXVpcmVBdXRoYCBhY2NlcHRzIHRoZXNlIHRva2VucyB0cmFuc3BhcmVudGx5IOKAlCB0aGV5IHBhc3MgYGRlY29kZWQuc3ViYFxuLy8gYW5kIGBkZWNvZGVkLnJvbGVgIGNoZWNrcywgYW5kIGRvd25zdHJlYW0gYHJlcXVpcmVPcmdhbml6YXRpb25gIC9cbi8vIGByZXF1aXJlU3lzdGVtQWRtaW5gIHJlbHkgb24gdGhlIG9yZy9yb2xlIGVtYmVkZGVkIGluIHRoZSB0b2tlbi5cbi8vXG4vLyBUb2tlbnMgZGVmYXVsdCB0byA1LW1pbnV0ZSBUVEwg4oCUIGxvbmcgZW5vdWdoIHRvIHN1cnZpdmUgYSBiYWNrZW5kIGhvcCxcbi8vIHNob3J0IGVub3VnaCB0aGF0IGEgbGVha2VkIHRva2VuIGlzIGxvdy12YWx1ZS5cbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5jb25zdCBERUZBVUxUX1NFUlZJQ0VfVE9LRU5fVFRMX1NFQ09ORFMgPSAzMDA7XG5cbi8qKlxuICogRGVueWxpc3Qgb2Ygc2VydmljZSBOQU1FUyAodGhlIGA8bmFtZT5gIGluIGBzdWI6IHNlcnZpY2U6PG5hbWU+YCkgd2hvc2UgdG9rZW5zXG4gKiBgcmVxdWlyZUF1dGhgIG11c3QgcmVqZWN0LiBTZWVkZWQgZnJvbSBgU0VSVklDRV9UT0tFTl9ERU5ZTElTVGAgKGNvbW1hLXNlcGFyYXRlZClcbiAqIGF0IG1vZHVsZSBsb2FkOyBhIHNlcnZpY2UgY2FuIHB1c2ggbGl2ZSB1cGRhdGVzIChlLmcuIGZyb20gYSBSZWRpcy1zdWJzY3JpYmVkXG4gKiBraWxsLXN3aXRjaCkgdmlhIHtAbGluayBzZXRTZXJ2aWNlVG9rZW5EZW55bGlzdH0gc28gYSBjb21wcm9taXNlZCBzZXJ2aWNlIGNhbiBiZVxuICogY3V0IG9mZiBXSVRIT1VUIHJvdGF0aW5nIHRoZSBzaGFyZWQgSldUIHNlY3JldCAod2hpY2ggaW52YWxpZGF0ZXMgYWxsIG9mIHRoZW0pLlxuICovXG5sZXQgc2VydmljZVRva2VuRGVueWxpc3QgPSBuZXcgU2V0KFxuICAocHJvY2Vzcy5lbnYuU0VSVklDRV9UT0tFTl9ERU5ZTElTVCB8fCAnJylcbiAgICAuc3BsaXQoJywnKVxuICAgIC5tYXAoKHMpID0+IHMudHJpbSgpKVxuICAgIC5maWx0ZXIoQm9vbGVhbiksXG4pO1xuXG4vKiogUmVwbGFjZSB0aGUgc2VydmljZS10b2tlbiBkZW55bGlzdCAoc2VydmljZSBuYW1lcykuIEVtcHR5IOKHkiBraWxsLXN3aXRjaCBvZmYuICovXG5leHBvcnQgZnVuY3Rpb24gc2V0U2VydmljZVRva2VuRGVueWxpc3QobmFtZXM6IEl0ZXJhYmxlPHN0cmluZz4pOiB2b2lkIHtcbiAgc2VydmljZVRva2VuRGVueWxpc3QgPSBuZXcgU2V0KFsuLi5uYW1lc10ubWFwKChzKSA9PiBzLnRyaW0oKSkuZmlsdGVyKEJvb2xlYW4pKTtcbn1cblxuLyoqIFRydWUgd2hlbiBgc3ViYCBpcyBgc2VydmljZTo8bmFtZT5gIGFuZCBgPG5hbWU+YCBpcyBvbiB0aGUgZGVueWxpc3QuICovXG5leHBvcnQgZnVuY3Rpb24gaXNTZXJ2aWNlVG9rZW5EZW5pZWQoc3ViOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgaWYgKHNlcnZpY2VUb2tlbkRlbnlsaXN0LnNpemUgPT09IDApIHJldHVybiBmYWxzZTtcbiAgaWYgKCFzdWIuc3RhcnRzV2l0aCgnc2VydmljZTonKSkgcmV0dXJuIGZhbHNlO1xuICByZXR1cm4gc2VydmljZVRva2VuRGVueWxpc3QuaGFzKHN1Yi5zbGljZSgnc2VydmljZTonLmxlbmd0aCkpO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFNlcnZpY2VUb2tlbk9wdGlvbnMge1xuICAvKiogQ2FsbGluZyBzZXJ2aWNlIGlkZW50aWZpZXIgKGUuZy4gJ2JpbGxpbmcnLCAncGxhdGZvcm0nKS4gRW1iZWRkZWQgYXMgYHN1Yjogc2VydmljZTo8bmFtZT5gLiAqL1xuICBzZXJ2aWNlTmFtZTogc3RyaW5nO1xuICAvKiogQWN0aXZlIG9yZyBjb250ZXh0IGZvciB0aGUgY2FsbC4gVXNlIHRoZSB0YXJnZXQgdGVuYW50J3Mgb3JnIGlkLCBvciB0aGVcbiAgICogIHdlbGwta25vd24gYFNZU1RFTV9PUkdfSURgIChhbiBPYmplY3RJZCkgZm9yIHN5c3RlbS13aWRlIG9wcyDigJQgTk9UIHRoZSBzdHJpbmdcbiAgICogICdzeXN0ZW0nLCB3aGljaCBpZC1iYXNlZCBzeXN0ZW0tb3JnIGNoZWNrcyB3b24ndCByZWNvZ25pemUuICovXG4gIG9yZ0lkPzogc3RyaW5nO1xuICAvKiogQWN0aXZlIG9yZyBuYW1lLiBEZWZhdWx0cyB0byBvcmdJZC4gKi9cbiAgb3JnTmFtZT86IHN0cmluZztcbiAgLyoqIFRUTCBpbiBzZWNvbmRzIChkZWZhdWx0IDMwMCkuICovXG4gIHR0bFNlY29uZHM/OiBudW1iZXI7XG4gIC8qKlxuICAgKiBSb2xlIHRoZSB0b2tlbiBjYXJyaWVzIChyZXF1aXJlZCDigJQgbm8gaW1wbGljaXQgZGVmYXVsdCkuICoqUGFzcyB0aGUgTE9XRVNUXG4gICAqIHJvbGUgdGhlIGNhbGwgYWN0dWFsbHkgbmVlZHMqKiAoYCdtZW1iZXInYCBmb3IgcmVhZCAvIGRhdGEtcGxhbmUgY2FsbHMpIHNvIGFcbiAgICogbGVha2VkIHNlcnZpY2UgdG9rZW4gY2FuJ3QgcGVyZm9ybSBhZG1pbiBhY3Rpb25zIGluIHRoZSB0YXJnZXQgb3JnLlxuICAgKiBgaXNBZG1pbmAgaXMgZGVyaXZlZCBmcm9tIHRoaXMgKGFkbWlufG93bmVyIOKGkiB0cnVlKS5cbiAgICovXG4gIHJvbGU6ICdvd25lcicgfCAnYWRtaW4nIHwgJ21lbWJlcic7XG4gIC8qKlxuICAgKiBPcHRpb25hbCBmaW5lLWdyYWluZWQgcGVybWlzc2lvbiBjbGFpbS4gUHJlZmVyIHRoaXMgKyBgcm9sZTogJ21lbWJlcidgIG92ZXIgYVxuICAgKiBoaWdoIHJvbGUgd2hlbiBhIGNhbGwgbmVlZHMgT05FIHNwZWNpZmljIGNhcGFiaWxpdHkgKGUuZy4gYFsncGx1Z2luczp3cml0ZSddYFxuICAgKiB0byBwdXNoIGEgcGx1Z2luIGltYWdlKSDigJQgdGhlIHRva2VuIHRoZW4gc2F0aXNmaWVzIHRoYXQgcGVybWlzc2lvbiBnYXRlXG4gICAqIFdJVEhPVVQgY2FycnlpbmcgYGlzQWRtaW5gLCBzbyBhIGxlYWtlZCB0b2tlbiBjYW4ndCBwZXJmb3JtIGFkbWluIGFjdGlvbnMuXG4gICAqL1xuICBwZXJtaXNzaW9ucz86IFBlcm1pc3Npb25bXTtcbn1cblxuLyoqXG4gKiBNaW50IGEgSldUIGlkZW50aWZ5aW5nIHRoZSBjYWxsaW5nIHNlcnZpY2UuIFVzZWQgZm9yIGludGVyLXNlcnZpY2UgSFRUUCBjYWxscy5cbiAqIFRoZSB0b2tlbiBzYXRpc2ZpZXMgYHJlcXVpcmVBdXRoYCBhbmQgKHdoZW4gb3JnSWQgaXMgcHJlc2VudCkgYHJlcXVpcmVPcmdhbml6YXRpb25gLlxuICogU2NvcGUgaXQgd2l0aCBgb3B0cy5yb2xlYCDigJQgbGVhc3QgcHJpdmlsZWdlIGtlZXBzIGEgbGVha2VkIHRva2VuIGxvdy12YWx1ZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNpZ25TZXJ2aWNlVG9rZW4ob3B0czogU2VydmljZVRva2VuT3B0aW9ucyk6IHN0cmluZyB7XG4gIGNvbnN0IHJvbGUgPSBvcHRzLnJvbGU7XG4gIGNvbnN0IHBheWxvYWQ6IEp3dFBheWxvYWQgPSB7XG4gICAgc3ViOiBgc2VydmljZToke29wdHMuc2VydmljZU5hbWV9YCxcbiAgICB1c2VybmFtZTogYCR7b3B0cy5zZXJ2aWNlTmFtZX0tc2VydmljZWAsXG4gICAgZW1haWw6IGAke29wdHMuc2VydmljZU5hbWV9QGludGVybmFsYCxcbiAgICByb2xlLFxuICAgIGlzQWRtaW46IHJvbGUgPT09ICdvd25lcicgfHwgcm9sZSA9PT0gJ2FkbWluJyxcbiAgICB0eXBlOiAnYWNjZXNzJyxcbiAgICBvcmdhbml6YXRpb25JZDogb3B0cy5vcmdJZCxcbiAgICBvcmdhbml6YXRpb25OYW1lOiBvcHRzLm9yZ05hbWUgPz8gb3B0cy5vcmdJZCxcbiAgICAvLyBMZWFzdC1wcml2aWxlZ2UgY2FwYWJpbGl0eSBjbGFpbSAob3B0aW9uYWwpIOKAlCBsZXRzIGEgbWVtYmVyLXJvbGUgdG9rZW5cbiAgICAvLyBzYXRpc2Z5IGEgc3BlY2lmaWMgcGVybWlzc2lvbiBnYXRlIHdpdGhvdXQgY2FycnlpbmcgaXNBZG1pbi5cbiAgICAuLi4ob3B0cy5wZXJtaXNzaW9ucyAmJiBvcHRzLnBlcm1pc3Npb25zLmxlbmd0aCA+IDAgPyB7IHBlcm1pc3Npb25zOiBvcHRzLnBlcm1pc3Npb25zIH0gOiB7fSksXG4gIH07XG4gIC8vIE1hdGNoIHRoZSBvcHRpb25hbCBpc3N1ZXIvYXVkaWVuY2UgdGhhdCByZXF1aXJlQXV0aCB2ZXJpZmllcywgd2hlblxuICAvLyBjb25maWd1cmVkLiBXaXRob3V0IHRoZXNlLCBhIHNlcnZpY2UgdG9rZW4gc2lnbmVkIGhlcmUgd291bGQgZmFpbFxuICAvLyByZXF1aXJlQXV0aCBpbiBhIGRlcGxveW1lbnQgdGhhdCBoYXMgc2V0IEpXVF9JU1NVRVIvSldUX0FVRElFTkNFLlxuICBjb25zdCBzaWduT3B0aW9uczogand0LlNpZ25PcHRpb25zID0ge1xuICAgIGV4cGlyZXNJbjogb3B0cy50dGxTZWNvbmRzID8/IERFRkFVTFRfU0VSVklDRV9UT0tFTl9UVExfU0VDT05EUyxcbiAgICAvLyBTaWduIHdpdGggdGhlIHNhbWUgY29uZmlndXJlZCBhbGcgcmVxdWlyZUF1dGggcGlucyBvbiB2ZXJpZnksIHNvIHNlcnZpY2VcbiAgICAvLyB0b2tlbnMgc3RheSB2YWxpZCB1bmRlciBhIG5vbi1kZWZhdWx0IEpXVF9BTEdPUklUSE0uXG4gICAgYWxnb3JpdGhtOiAocHJvY2Vzcy5lbnYuSldUX0FMR09SSVRITSB8fCAnSFMyNTYnKSBhcyBqd3QuQWxnb3JpdGhtLFxuICAgIC8vIFVuaXF1ZSB0b2tlbiBpZCBvbiBldmVyeSBtaW50LiBDb21iaW5lZCB3aXRoIHRoZSBzaG9ydCAoMzAwcyBkZWZhdWx0KSBUVExcbiAgICAvLyB0aGlzIGdpdmVzIGVhY2ggc2VydmljZSB0b2tlbiBhIGRpc3RpbmN0IGlkZW50aXR5IOKAlCB0aGUgYnVpbGRpbmcgYmxvY2sgZm9yXG4gICAgLy8gcmVwbGF5IGRldGVjdGlvbiAoYSB2ZXJpZmllciBjYW4gdHJhY2sgc2VlbiBqdGlzKSBhbmQgdGhlIGNvcnJlbGF0aW9uXG4gICAgLy8gaGFuZGxlIGZvciB0cmFjaW5nIHdoaWNoIG1pbnQgcGVyZm9ybWVkIGEgY3Jvc3Mtc2VydmljZSBhY3Rpb24uIEl0IGRvZXNcbiAgICAvLyBOT1QgYnkgaXRzZWxmIHByZXZlbnQgcmVwbGF5IHdpdGhpbiB0aGUgVFRMIHdpbmRvdzsgdHJ1ZSByZXBsYXkgZGVmZW5jZVxuICAgIC8vIG5lZWRzIHRoZSBhc3ltbWV0cmljLWtleSB3b3JrIHRyYWNrZWQgc2VwYXJhdGVseS5cbiAgICBqd3RpZDogcmFuZG9tVVVJRCgpLFxuICB9O1xuICBpZiAocHJvY2Vzcy5lbnYuSldUX0lTU1VFUikgc2lnbk9wdGlvbnMuaXNzdWVyID0gcHJvY2Vzcy5lbnYuSldUX0lTU1VFUjtcbiAgaWYgKHByb2Nlc3MuZW52LkpXVF9BVURJRU5DRSkgc2lnbk9wdGlvbnMuYXVkaWVuY2UgPSBwcm9jZXNzLmVudi5KV1RfQVVESUVOQ0U7XG4gIHJldHVybiBqd3Quc2lnbihwYXlsb2FkLCBnZXRKd3RTZWNyZXQoKSwgc2lnbk9wdGlvbnMpO1xufVxuXG4vKiogQ29udmVuaWVuY2U6IHJldHVybnMgYSBgQmVhcmVyIDx0b2tlbj5gIGhlYWRlciB2YWx1ZSBmb3IgZmV0Y2gvYXhpb3MgY2FsbHMuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0U2VydmljZUF1dGhIZWFkZXIob3B0czogU2VydmljZVRva2VuT3B0aW9ucyk6IHN0cmluZyB7XG4gIHJldHVybiBgQmVhcmVyICR7c2lnblNlcnZpY2VUb2tlbihvcHRzKX1gO1xufVxuXG4vKiogVHJ1ZSB3aGVuIGByZXEudXNlci5zdWJgIHdhcyBpc3N1ZWQgYnkgYHNpZ25TZXJ2aWNlVG9rZW5gIChpLmUuIHN0YXJ0cyB3aXRoIGBzZXJ2aWNlOmApLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzU2VydmljZVByaW5jaXBhbChyZXE6IFJlcXVlc3QpOiBib29sZWFuIHtcbiAgcmV0dXJuIHJlcS51c2VyPy5zdWI/LnN0YXJ0c1dpdGgoJ3NlcnZpY2U6JykgPz8gZmFsc2U7XG59XG5cbi8qKlxuICogUFJFLWF1dGggY2hlY2s6IGNyeXB0b2dyYXBoaWNhbGx5IHZlcmlmeSB0aGUgcmVxdWVzdCBjYXJyaWVzIGEgdmFsaWQsIHNpZ25lZFxuICogU0VSVklDRSB0b2tlbiAoYHN1YmAgc3RhcnRzIHdpdGggYHNlcnZpY2U6YCkuIFVubGlrZSB7QGxpbmsgaXNTZXJ2aWNlUHJpbmNpcGFsfVxuICogKHdoaWNoIHJlYWRzIHRoZSBhbHJlYWR5LXBvcHVsYXRlZCBgcmVxLnVzZXJgKSwgdGhpcyB2ZXJpZmllcyB0aGUgYmVhcmVyIHRva2VuXG4gKiBpdHNlbGYsIHNvIGl0IGlzIHNhZmUgdG8gY2FsbCBCRUZPUkUgYHJlcXVpcmVBdXRoYCBydW5zIOKAlCBlLmcuIHRoZSBnbG9iYWwgcmF0ZVxuICogbGltaXRlcidzIGBza2lwYCwgd2hpY2ggbXVzdCBub3QgdHJ1c3QgdGhlIHNwb29mYWJsZSBgeC1pbnRlcm5hbC1zZXJ2aWNlYFxuICogaGVhZGVyLiBNaXJyb3JzIGByZXF1aXJlQXV0aGAncyB2ZXJpZmljYXRpb24gKGFsZ29yaXRobSBwaW5uaW5nICsgb3B0aW9uYWxcbiAqIGlzc3Vlci9hdWRpZW5jZSkgYW5kIHJldHVybnMgYGZhbHNlYCBvbiBhbnkgbWlzc2luZy9pbnZhbGlkL25vbi1zZXJ2aWNlIHRva2VuLlxuICovXG5leHBvcnQgZnVuY3Rpb24gdmVyaWZ5U2VydmljZVByaW5jaXBhbChyZXE6IFJlcXVlc3QpOiBib29sZWFuIHtcbiAgY29uc3QgcGFydHMgPSByZXEuaGVhZGVycy5hdXRob3JpemF0aW9uPy5zcGxpdCgnICcpO1xuICBpZiAoIXBhcnRzIHx8IHBhcnRzLmxlbmd0aCAhPT0gMiB8fCBwYXJ0c1swXSAhPT0gJ0JlYXJlcicpIHJldHVybiBmYWxzZTtcbiAgdHJ5IHtcbiAgICBjb25zdCB2ZXJpZnlPcHRpb25zID0gYnVpbGRKd3RWZXJpZnlPcHRpb25zKCk7XG4gICAgY29uc3QgZGVjb2RlZCA9IHZlcmlmeUp3dFdpdGhSb3RhdGlvbihwYXJ0c1sxXSwgdmVyaWZ5T3B0aW9ucyk7XG4gICAgaWYgKGRlY29kZWQudHlwZSAhPT0gJ2FjY2VzcycgfHwgdHlwZW9mIGRlY29kZWQuc3ViICE9PSAnc3RyaW5nJyB8fCAhZGVjb2RlZC5zdWIuc3RhcnRzV2l0aCgnc2VydmljZTonKSkgcmV0dXJuIGZhbHNlO1xuICAgIC8vIEEgZGVueWxpc3RlZCAoa2lsbGVkKSBzZXJ2aWNlIG11c3QgTk9UIGJlIHRyZWF0ZWQgYXMgYSB0cnVzdGVkIHByaW5jaXBhbCDigJRcbiAgICAvLyBvdGhlcndpc2UgaXQga2VlcHMgdGhlIHJhdGUtbGltaXRlciBleGVtcHRpb24gZXZlbiB0aG91Z2ggcmVxdWlyZUF1dGggcmVqZWN0c1xuICAgIC8vIGl0IG9uIHJlYWwgcm91dGVzLiBGb2xkIHRoZSBraWxsLXN3aXRjaCBpbnRvIHRoZSBwcmUtYXV0aCBjaGVjayB0b28uXG4gICAgcmV0dXJuICFpc1NlcnZpY2VUb2tlbkRlbmllZChkZWNvZGVkLnN1Yik7XG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxufVxuIl19
852
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0aC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9taWRkbGV3YXJlL2F1dGgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQUV0QyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sUUFBUSxDQUFDO0FBRXBDLE9BQU8sR0FBRyxNQUFNLGNBQWMsQ0FBQztBQUMvQixPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDaEQsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBQ3pELE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxlQUFlLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUNyRyxPQUFPLEVBQ0wsc0JBQXNCLEVBQ3RCLGVBQWUsRUFDZixZQUFZLEVBQ1osZUFBZSxFQUNmLGNBQWMsRUFDZCxnQkFBZ0IsR0FDakIsTUFBTSw2QkFBNkIsQ0FBQztBQUNyQyxPQUFPLEVBQUUsWUFBWSxFQUFFLGVBQWUsRUFBRSxVQUFVLEVBQXdDLE1BQU0sb0JBQW9CLENBQUM7QUFDckgsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBRXBELE9BQU8sRUFBbUIsYUFBYSxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDekUsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ3JELE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUN0RCxPQUFPLEVBQUUsV0FBVyxFQUF3QixNQUFNLHNCQUFzQixDQUFDO0FBQ3pFLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxlQUFlLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUN4RSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDbEQsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQ3pELE9BQU8sRUFBRSxT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RUFBRSxFQUFFLEdBQUcsRUFBRSxNQUFNLENBQUMsR0FBRyxFQUFFLEdBQUcscUJBQXFCLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFDeEcsSUFBSSxPQUFPLENBQUMsSUFBSSxLQUFLLFFBQVEsSUFBSSxPQUFPLENBQUMsYUFBYSxLQUFLLFNBQVMsSUFBSSxDQUFDLHNCQUFzQixDQUFDLE9BQU8sQ0FBQztZQUFFLE9BQU8sS0FBSyxDQUFDO1FBQ3ZILDZFQUE2RTtRQUM3RSxnRkFBZ0Y7UUFDaEYsdUVBQXVFO1FBQ3ZFLE9BQU8sQ0FBQyxvQkFBb0IsQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUN4QyxDQUFDO0lBQUMsTUFBTSxDQUFDO1FBQ1AsT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDO0FBQ0gsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG5pbXBvcnQgeyByYW5kb21VVUlEIH0gZnJvbSAnY3J5cHRvJztcbmltcG9ydCB0eXBlIHsgUmVxdWVzdCwgUmVzcG9uc2UsIE5leHRGdW5jdGlvbiB9IGZyb20gJ2V4cHJlc3MnO1xuaW1wb3J0IGp3dCBmcm9tICdqc29ud2VidG9rZW4nO1xuaW1wb3J0IHsgdGFnUm91dGVHYXRlIH0gZnJvbSAnLi9yb3V0ZS10YWJsZS5qcyc7XG5pbXBvcnQgeyBIdHRwU3RhdHVzIH0gZnJvbSAnLi4vY29uc3RhbnRzL2h0dHAtc3RhdHVzLmpzJztcbmltcG9ydCB7IEp3a3NVbmF2YWlsYWJsZUVycm9yLCBVbmtub3duS2lkRXJyb3IsIHBsYXRmb3JtSndrc0NhY2hlIH0gZnJvbSAnLi4vc2VydmljZXMvandrcy1jYWNoZS5qcyc7XG5pbXBvcnQge1xuICBTRVJWSUNFX1NVQkpFQ1RfUFJFRklYLFxuICBTZXJ2aWNlS2V5RXJyb3IsXG4gIGlzU2VydmljZUtpZCxcbiAgc2VydmljZUlkZW50aXR5LFxuICBzaWduU2VydmljZUp3dCxcbiAgdmVyaWZ5U2VydmljZUp3dCxcbn0gZnJvbSAnLi4vc2VydmljZXMvc2VydmljZS1rZXlzLmpzJztcbmltcG9ydCB7IEFVVEhfTUVUSE9EUywgUFJJTkNJUEFMX1RZUEVTLCBUT0tFTl9VU0VTLCB0eXBlIEFzc3VyYW5jZUxldmVsLCB0eXBlIEp3dFBheWxvYWQgfSBmcm9tICcuLi90eXBlcy9jb21tb24uanMnO1xuaW1wb3J0IHsgRXJyb3JDb2RlIH0gZnJvbSAnLi4vdHlwZXMvZXJyb3ItY29kZXMuanMnO1xuaW1wb3J0IHR5cGUgeyBIdHRwUmVxdWVzdCB9IGZyb20gJy4uL3R5cGVzL2h0dHAuanMnO1xuaW1wb3J0IHsgdHlwZSBQZXJtaXNzaW9uLCBoYXNQZXJtaXNzaW9uIH0gZnJvbSAnLi4vdHlwZXMvcGVybWlzc2lvbnMuanMnO1xuaW1wb3J0IHsgaXNPcGFxdWVBcGlLZXkgfSBmcm9tICcuLi91dGlscy9hcGkta2V5LmpzJztcbmltcG9ydCB7IGdldEhlYWRlclN0cmluZyB9IGZyb20gJy4uL3V0aWxzL2hlYWRlcnMuanMnO1xuaW1wb3J0IHsgZ2V0SWRlbnRpdHksIHR5cGUgUmVxdWVzdElkZW50aXR5IH0gZnJvbSAnLi4vdXRpbHMvaWRlbnRpdHkuanMnO1xuaW1wb3J0IHsgVVNFUl9UT0tFTl9BTEdPUklUSE0sIGRlY29kZUp3dEhlYWRlciB9IGZyb20gJy4uL3V0aWxzL2p3ay5qcyc7XG5pbXBvcnQgeyBjcmVhdGVMb2dnZXIgfSBmcm9tICcuLi91dGlscy9sb2dnZXIuanMnO1xuaW1wb3J0IHsgZW1pdENvdW50ZXIgfSBmcm9tICcuLi91dGlscy9tZXRyaWMtZW1pdHRlci5qcyc7XG5pbXBvcnQgeyBzZW5kRXJyb3IgfSBmcm9tICcuLi91dGlscy9yZXNwb25zZS5qcyc7XG5cbmNvbnN0IGxvZ2dlciA9IGNyZWF0ZUxvZ2dlcignYXV0aC1taWRkbGV3YXJlJyk7XG5cbi8qKiBJc3N1ZXIvYXVkaWVuY2UgcGlubmluZywgd2hlbiB0aGUgZGVwbG95bWVudCBjb25maWd1cmVzIHRoZW0uIFNoYXJlZCBieSBib3RoIGNoYWlucy4gKi9cbmZ1bmN0aW9uIGlzc3VlckF1ZGllbmNlT3B0aW9ucygpOiB7IGlzc3Vlcj86IHN0cmluZzsgYXVkaWVuY2U/OiBzdHJpbmcgfSB7XG4gIHJldHVybiB7XG4gICAgLi4uKHByb2Nlc3MuZW52LkpXVF9JU1NVRVIgPyB7IGlzc3VlcjogcHJvY2Vzcy5lbnYuSldUX0lTU1VFUiB9IDoge30pLFxuICAgIC4uLihwcm9jZXNzLmVudi5KV1RfQVVESUVOQ0UgPyB7IGF1ZGllbmNlOiBwcm9jZXNzLmVudi5KV1RfQVVESUVOQ0UgfSA6IHt9KSxcbiAgfTtcbn1cblxuLyoqXG4gKiBWZXJpZnkgYSB0b2tlbiB0aGF0IHNwZWFrcyBmb3IgYSBQRVJTT04g4oCUIGFjY2Vzcywgc3RlcC11cCwgYW5kIHRoZSB0b2tlbiBhblxuICogb3BhcXVlIGFjY2VzcyBrZXkgaXMgZXhjaGFuZ2VkIGZvciDigJQgYWdhaW5zdCBwbGF0Zm9ybSdzIHB1Ymxpc2hlZCBzaWduaW5nXG4gKiBrZXlzLlxuICpcbiAqIEVTMjU2IGFuZCBhIGBraWRgIGFyZSBib3RoIG1hbmRhdG9yeTogbm8gYGtpZGAgbWVhbnMgbm8gd2F5IHRvIHBpY2sgdGhlIHJpZ2h0XG4gKiBrZXkgYWNyb3NzIGEgcm90YXRpb24sIGFuZCBhbnkgb3RoZXIgYWxnb3JpdGhtIGlzIHJlZnVzZWQgb3V0cmlnaHQsIHdoaWNoIGlzXG4gKiB3aGF0IG1ha2VzIFwibm8gc2VydmljZSBhY2NlcHRzIGFuIEhTMjU2IHVzZXIgdG9rZW5cIiBhIHByb3BlcnR5IG9mIHRoZSBjb2RlXG4gKiByYXRoZXIgdGhhbiBhIGNvbnZlbnRpb24uIEtleSBsb29rdXAgZ29lcyB0aHJvdWdoIHRoZSBzaGFyZWQgSldLUyBjYWNoZVxuICogKDEwLW1pbnV0ZSByZWZyZXNoLCBvbmUgcmVmZXRjaCBvbiBhbiB1bmtub3duIGBraWRgLCBicmllZiBuZWdhdGl2ZSBjYWNoZSkuXG4gKlxuICogQHRocm93cyB7VW5rbm93bktpZEVycm9yfSB0aGUga2V5IHNldCBpcyBjdXJyZW50IGFuZCBoYXMgbm8gc3VjaCBrZXkg4oaSIDQwMS5cbiAqIEB0aHJvd3Mge0p3a3NVbmF2YWlsYWJsZUVycm9yfSB0aGUga2V5IHNldCBjb3VsZCBub3QgYmUgb2J0YWluZWQg4oaSIDUwMzsgYW5cbiAqICAgICAgICAgdW52ZXJpZmlhYmxlIHRva2VuIGlzIG5ldmVyIHRyZWF0ZWQgYXMgdmFsaWQuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiB2ZXJpZnlVc2VySnd0PFQgPSBKd3RQYXlsb2FkPih0b2tlbjogc3RyaW5nKTogUHJvbWlzZTxUPiB7XG4gIGNvbnN0IGhlYWRlciA9IGRlY29kZUp3dEhlYWRlcih0b2tlbik7XG4gIGlmIChoZWFkZXI/LmFsZyAhPT0gVVNFUl9UT0tFTl9BTEdPUklUSE0gfHwgIWhlYWRlci5raWQpIHtcbiAgICB0aHJvdyBuZXcgand0Lkpzb25XZWJUb2tlbkVycm9yKGBVc2VyIHRva2VucyBtdXN0IGJlIHNpZ25lZCB3aXRoICR7VVNFUl9UT0tFTl9BTEdPUklUSE19IGFuZCBjYXJyeSBhIGtpZGApO1xuICB9XG4gIGNvbnN0IGtleSA9IGF3YWl0IHBsYXRmb3JtSndrc0NhY2hlKCkuZ2V0S2V5KGhlYWRlci5raWQpO1xuICByZXR1cm4gand0LnZlcmlmeSh0b2tlbiwga2V5LCB7IGFsZ29yaXRobXM6IFtVU0VSX1RPS0VOX0FMR09SSVRITV0sIC4uLmlzc3VlckF1ZGllbmNlT3B0aW9ucygpIH0pIGFzIFQ7XG59XG5cbi8qKlxuICogVmVyaWZ5IEFOWSBiZWFyZXIgdG9rZW4gYW5kIHJldHVybiBpdHMgY2xhaW1zLlxuICpcbiAqIFNpbmNlICMxNCB0aGVyZSBpcyBubyBzaGFyZWQgc2VjcmV0IGxlZnQ6IEJPVEggY2hhaW5zIGFyZSBFUzI1NiB3aXRoIGEgYGtpZGAsXG4gKiBzbyB0aGUgZGlzcGF0Y2ggaXMgYnkgKip3aG8gb3ducyB0aGUgYGtpZGAqKiByYXRoZXIgdGhhbiBieSBhbGdvcml0aG0g4oCUIGFuZFxuICogYmVjYXVzZSBhIGBraWRgIGlzIGFuIFJGQyA3NjM4IHRodW1icHJpbnQsIG93bmVyc2hpcCBpcyBhIGZhY3QgYWJvdXQgdGhlIGtleSxcbiAqIG5vdCBhIGNsYWltIHRoZSB0b2tlbiBtYWtlcyBhYm91dCBpdHNlbGY6XG4gKlxuICogLSBhIGBraWRgIHB1Ymxpc2hlZCBpbiB0aGUgcGVyLXNlcnZpY2Uga2V5IGJ1bmRsZSDihpIgYW4gSU5URVJOQUwgU0VSVklDRSB0b2tlblxuICogICAoe0BsaW5rIHNpZ25TZXJ2aWNlVG9rZW59KSwgdmVyaWZpZWQgd2l0aCB0aGF0IHNlcnZpY2UncyBrZXk7IGl0cyBgc3ViYCBtdXN0XG4gKiAgIG5hbWUgdGhlIHNhbWUgc2VydmljZSwgc28gb25lIHNlcnZpY2UgY2FuIG5ldmVyIHNwZWFrIGZvciBhbm90aGVyLlxuICogLSBhbnl0aGluZyBlbHNlIOKGkiBhIHBsYXRmb3JtLXNpZ25lZCBVU0VSIHRva2VuLCB2ZXJpZmllZCBhZ2FpbnN0IHBsYXRmb3JtJ3NcbiAqICAgcHVibGlzaGVkIEpXS1MuIEEgdG9rZW4gY2xhaW1pbmcgYHByaW5jaXBhbFR5cGU6ICdzZXJ2aWNlJ2AgaXMgcmVmdXNlZFxuICogICBoZXJlOiBhbiBpbnRlcm5hbCBpZGVudGl0eSBtYXkgbm90IHJpZGUgdGhlIHVzZXIgc2lnbmluZyBrZXkuXG4gKlxuICogQW55dGhpbmcgdGhhdCBpcyBub3QgRVMyNTYgd2l0aCBhIGBraWRgIGZhaWxzIGluIGJvdGggY2hhaW5zLCB3aGljaCBpcyB3aGF0XG4gKiBtYWtlcyBcIm5vIEhTMjU2IHRva2VuIGlzIGFjY2VwdGVkIGFueXdoZXJlXCIgYSBwcm9wZXJ0eSBvZiB0aGUgY29kZS5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHZlcmlmeUJlYXJlclRva2VuKHRva2VuOiBzdHJpbmcpOiBQcm9taXNlPEp3dFBheWxvYWQ+IHtcbiAgY29uc3QgaGVhZGVyID0gZGVjb2RlSnd0SGVhZGVyKHRva2VuKTtcbiAgaWYgKCFoZWFkZXI/LmFsZykgdGhyb3cgbmV3IGp3dC5Kc29uV2ViVG9rZW5FcnJvcignTWFsZm9ybWVkIHRva2VuIGhlYWRlcicpO1xuXG4gIGlmIChoZWFkZXIua2lkICYmIGlzU2VydmljZUtpZChoZWFkZXIua2lkKSkge1xuICAgIGNvbnN0IGNsYWltcyA9IHZlcmlmeVNlcnZpY2VKd3Q8Snd0UGF5bG9hZD4odG9rZW4sIHsga2lkOiBoZWFkZXIua2lkLCAuLi5pc3N1ZXJBdWRpZW5jZU9wdGlvbnMoKSB9KTtcbiAgICBpZiAoY2xhaW1zLnByaW5jaXBhbFR5cGUgIT09ICdzZXJ2aWNlJykge1xuICAgICAgZW1pdENvdW50ZXIoJ3NlcnZpY2Vfa2V5X25vbl9zZXJ2aWNlX3Rva2VuX3JlamVjdGVkX3RvdGFsJywgeyBhbGc6IGhlYWRlci5hbGcgfSk7XG4gICAgICB0aHJvdyBuZXcgand0Lkpzb25XZWJUb2tlbkVycm9yKCdBIHNlcnZpY2Ugc2lnbmluZyBrZXkgbWF5IG9ubHkgbWludCBhIHNlcnZpY2UgcHJpbmNpcGFsJyk7XG4gICAgfVxuICAgIHJldHVybiBjbGFpbXM7XG4gIH1cblxuICBjb25zdCBjbGFpbXMgPSBhd2FpdCB2ZXJpZnlVc2VySnd0KHRva2VuKTtcbiAgaWYgKGNsYWltcy5wcmluY2lwYWxUeXBlID09PSAnc2VydmljZScpIHtcbiAgICB0aHJvdyBuZXcgand0Lkpzb25XZWJUb2tlbkVycm9yKCdTZXJ2aWNlIHByaW5jaXBhbHMgbWF5IG5vdCBiZSBzaWduZWQgd2l0aCB0aGUgdXNlciBzaWduaW5nIGtleScpO1xuICB9XG4gIHJldHVybiBjbGFpbXM7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUmVxdWlyZUF1dGhPcHRpb25zIHtcbiAgLyoqXG4gICAqIEFsbG93IHgtb3JnLWlkL3gtb3JnLW5hbWUgaGVhZGVycyB0byBvdmVycmlkZSB0aGUgSldUJ3Mgb3JnYW5pemF0aW9uIGZpZWxkcy5cbiAgICpcbiAgICogV2hlbiBlbmFibGVkLCB0aGUgYHgtb3JnLWlkYC9geC1vcmctbmFtZWAgaGVhZGVycyBvdmVycmlkZSB0aGUgY2FsbGVyJ3Mgb3JnXG4gICAqIOKAlCBidXQgT05MWSBmb3IgYSB2ZXJpZmllZCBTWVMtQURNSU4gKGBpc1N1cGVyQWRtaW5gIGNsYWltKS4gRm9yIGFueSBvcmRpbmFyeVxuICAgKiBhdXRoZW50aWNhdGVkIHVzZXIgdGhlIGhlYWRlcnMgYXJlIGlnbm9yZWQsIHNvIGVuYWJsaW5nIHRoaXMgY2FuIG5ldmVyIGxldCBhXG4gICAqIG5vcm1hbCB1c2VyIGltcGVyc29uYXRlIGFub3RoZXIgdGVuYW50J3Mgb3JnLiBVc2UgZm9yIGNyb3NzLW9yZyBhZG1pbiB0b29saW5nXG4gICAqIChlLmcuIGEgc3lzYWRtaW4gbWFuYWdpbmcgYSBnaXZlbiBvcmcncyBiaWxsaW5nKS4gSWYgdW5zdXJlLCBsZWF2ZSBpdCBkaXNhYmxlZC5cbiAgICovXG4gIGFsbG93T3JnSGVhZGVyT3ZlcnJpZGU/OiBib29sZWFuO1xuICAvKipcbiAgICogRGVtYW5kIHRoYXQgdGhlIHdob2xlIFNFU1NJT04gYmUgYXQgbGVhc3QgdGhpcyBhc3N1cmFuY2UgbGV2ZWwgKCM4KS5cbiAgICpcbiAgICogYG1pbkFzc3VyYW5jZTogMmAgbWVhbnMgdGhlIHBlcnNvbiBhdXRoZW50aWNhdGVkIHdpdGggYSBzZWNvbmQgZmFjdG9yIOKAlCBhXG4gICAqIHBhc3NrZXkgd2l0aCB1c2VyIHZlcmlmaWNhdGlvbiwgYSBwYXNzd29yZCBwbHVzIGFuIGF1dGhlbnRpY2F0b3IgY29kZSwgb3JcbiAgICogU1NPIHRocm91Z2ggYW4gSWRQIHRoZSBvcmcgbWFya2VkIGFzIGVuZm9yY2luZyBNRkEuIEEgd2Vha2VyIHRva2VuIGdldHNcbiAgICogKio0MDEgYE1GQV9SRVFVSVJFRGAqKiwgd2hpY2ggdGhlIGNsaWVudCBhbnN3ZXJzIGJ5IHNlbmRpbmcgdGhlIHBlcnNvbiB0b1xuICAgKiBlbnJvbG1lbnQgb3IgdG8gYSBzdHJvbmdlciBzaWduLWluOyByZWZyZXNoaW5nIGNhbm5vdCBoZWxwLCBiZWNhdXNlIGBhYWxgXG4gICAqIGxpdmVzIG9uIHRoZSBzZXNzaW9uIHNsb3QgYW5kIGEgcmVmcmVzaCBuZXZlciByYWlzZXMgaXQuXG4gICAqXG4gICAqIFRoaXMgaXMgdGhlIFNFU1NJT04tbGV2ZWwgY291bnRlcnBhcnQgdG8ge0BsaW5rIHJlcXVpcmVTdGVwVXB9LCB3aGljaCBzdGF5c1xuICAgKiBhIGZyZXNoLCBwZXItYWN0aW9uIGNvbmZpcm1hdGlvbi4gVXNlIGJvdGggb24gdGhlIG1vc3QgZGFuZ2Vyb3VzIHJvdXRlcy5cbiAgICpcbiAgICogTUFDSElORVMgTkVWRVIgU0FUSVNGWSBJVC4gQSBzZXJ2aWNlIHByaW5jaXBhbCwgYW4gb3JnIHNlcnZpY2UgYWNjb3VudCBhbmRcbiAgICogYW4gZXhjaGFuZ2VkIGFjY2VzcyBrZXkgYWxsIGdldCAqKjQwMyBgSFVNQU5fU0VTU0lPTl9SRVFVSVJFRGAqKiDigJQgdGhlcmUgaXNcbiAgICogbm8gcGVyc29uIGJlaGluZCB0aGVtIHRvIGhhdmUgcHJlc2VudGVkIGEgZmFjdG9yLCBzbyBcImFzc3VyYW5jZVwiIGlzIG5vdCBhXG4gICAqIHF1ZXN0aW9uIHRoZWlyIGNyZWRlbnRpYWwgY2FuIGFuc3dlci4gVGhhdCBpcyBkZWxpYmVyYXRlbHkgbm90IGEgc2lsZW50XG4gICAqIHBhc3MtdGhyb3VnaCBmb3IgaW50ZXJuYWwgc2VydmljZXM6IGEgcm91dGUgdGhhdCBkZW1hbmRzIE1GQSBpcyBhIHJvdXRlIGFcbiAgICogaHVtYW4gaXMgZG9pbmcgc29tZXRoaW5nIGRhbmdlcm91cyBvbi5cbiAgICovXG4gIG1pbkFzc3VyYW5jZT86IEFzc3VyYW5jZUxldmVsO1xuICAvKipcbiAgICogV2l0aCB7QGxpbmsgbWluQXNzdXJhbmNlfSwgYWRkaXRpb25hbGx5IGJvdW5kIGhvdyBsb25nIGFnbyB0aGF0IHNpZ24taW5cbiAgICogaGFwcGVuZWQgKHNlY29uZHMsIGNvbXBhcmVkIGFnYWluc3QgdGhlIHRva2VuJ3MgYGF1dGhfdGltZWApLiBBIHNlc3Npb24gdGhhdFxuICAgKiBpcyBNRkEtZ3JhZGUgYnV0IG9sZGVyIHRoYW4gdGhpcyBnZXRzICoqNDAxIGBSRUFVVEhfUkVRVUlSRURgKiouIElnbm9yZWRcbiAgICogd2l0aG91dCBgbWluQXNzdXJhbmNlYCDigJQgXCJob3cgcmVjZW50XCIgaXMgb25seSBtZWFuaW5nZnVsIG9uY2UgXCJob3cgc3Ryb25nXCJcbiAgICogaXMgYmVpbmcgYXNrZWQuXG4gICAqL1xuICBtYXhBZ2U/OiBudW1iZXI7XG59XG5cbi8qKiBKV1QgYXV0aCBtaWRkbGV3YXJlLiBVc2UgZGlyZWN0bHkgb3IgY2FsbCB3aXRoIG9wdGlvbnMuICovXG5leHBvcnQgZnVuY3Rpb24gcmVxdWlyZUF1dGgoXG4gIHJlcTogUmVxdWVzdCxcbiAgcmVzOiBSZXNwb25zZSxcbiAgbmV4dDogTmV4dEZ1bmN0aW9uLFxuKTogdm9pZDtcbmV4cG9ydCBmdW5jdGlvbiByZXF1aXJlQXV0aChcbiAgb3B0aW9ucz86IFJlcXVpcmVBdXRoT3B0aW9ucyxcbik6IChyZXE6IFJlcXVlc3QsIHJlczogUmVzcG9uc2UsIG5leHQ6IE5leHRGdW5jdGlvbikgPT4gdm9pZDtcbmV4cG9ydCBmdW5jdGlvbiByZXF1aXJlQXV0aChcbiAgcmVxT3JPcHRpb25zPzogUmVxdWVzdCB8IFJlcXVpcmVBdXRoT3B0aW9ucyxcbiAgcmVzPzogUmVzcG9uc2UsXG4gIG5leHQ/OiBOZXh0RnVuY3Rpb24sXG4pOiB2b2lkIHwgKChyZXE6IFJlcXVlc3QsIHJlczogUmVzcG9uc2UsIG5leHQ6IE5leHRGdW5jdGlvbikgPT4gdm9pZCkge1xuICBpZiAocmVxT3JPcHRpb25zICYmIHJlcyAmJiBuZXh0ICYmICdoZWFkZXJzJyBpbiByZXFPck9wdGlvbnMpIHtcbiAgICByZXR1cm4gX3JlcXVpcmVBdXRoKHt9LCByZXFPck9wdGlvbnMgYXMgUmVxdWVzdCwgcmVzLCBuZXh0KTtcbiAgfVxuXG4gIGNvbnN0IG9wdGlvbnMgPSAocmVxT3JPcHRpb25zIGFzIFJlcXVpcmVBdXRoT3B0aW9ucykgfHwge307XG4gIGNvbnN0IGdhdGUgPSB0YWdSb3V0ZUdhdGUoKHJlcTogUmVxdWVzdCwgcmVzSW5uZXI6IFJlc3BvbnNlLCBuZXh0SW5uZXI6IE5leHRGdW5jdGlvbikgPT4ge1xuICAgIF9yZXF1aXJlQXV0aChvcHRpb25zLCByZXEsIHJlc0lubmVyLCBuZXh0SW5uZXIpO1xuICB9LCB7IGtpbmQ6ICdhdXRoJyB9KTtcbiAgaWYgKG9wdGlvbnMubWluQXNzdXJhbmNlKSB7XG4gICAgdGFnUm91dGVHYXRlKGdhdGUsIHsga2luZDogJ2Fzc3VyYW5jZScsIG1pbkFzc3VyYW5jZTogb3B0aW9ucy5taW5Bc3N1cmFuY2UsIC4uLihvcHRpb25zLm1heEFnZSAhPT0gdW5kZWZpbmVkID8geyBtYXhBZ2U6IG9wdGlvbnMubWF4QWdlIH0gOiB7fSkgfSk7XG4gIH1cbiAgcmV0dXJuIGdhdGU7XG59XG50YWdSb3V0ZUdhdGUocmVxdWlyZUF1dGgsIHsga2luZDogJ2F1dGgnIH0pO1xuXG4vKipcbiAqIEEgc291cmNlIG9mIHRoZSBDVVJSRU5UIGB0b2tlblZlcnNpb25gIGZvciBhIHVzZXIsIGJhY2tlZCBieSBhIHN0b3JlIHRoZVxuICogc3RhdGVsZXNzIHNlcnZpY2VzIGNhbiByZWFkIChpbiBwcmFjdGljZSBhIFJlZGlzIGtleSB0aGUgcGxhdGZvcm0gcHVibGlzaGVzXG4gKiB0byBvbiBldmVyeSBwcml2aWxlZ2UgY2hhbmdlKS4gUmVnaXN0ZXJlZCB2aWEge0BsaW5rIHNldFRva2VuUmV2b2NhdGlvblN0b3JlfS5cbiAqXG4gKiBgZ2V0Q3VycmVudFZlcnNpb25gIHJldHVybnMgdGhlIHVzZXIncyBjdXJyZW50IHZlcnNpb24sIG9yIGBudWxsYCB3aGVuIHRoZVxuICogc3RvcmUgaGFzIG5vIGVudHJ5IOKAlCBhIG1pc3MgaXMgdHJlYXRlZCBhcyBcIm5vIGtub3duIHJldm9jYXRpb25cIiAoZmFpbC1vcGVuKTpcbiAqIHJldm9jYXRpb24gZW50cmllcyBhcmUgcHVibGlzaGVkIHdpdGggYSBUVEwgbWF0Y2hpbmcgdGhlIGFjY2Vzcy10b2tlblxuICogbGlmZXRpbWUsIHNvIGEgbWlzc2luZyBlbnRyeSBtZWFucyBhbnkgdG9rZW4gb2xkIGVub3VnaCB0byBwcmVkYXRlIGl0IGhhc1xuICogYWxyZWFkeSBleHBpcmVkIG9uIGl0cyBvd24uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgVG9rZW5SZXZvY2F0aW9uU3RvcmUge1xuICBnZXRDdXJyZW50VmVyc2lvbih1c2VySWQ6IHN0cmluZyk6IFByb21pc2U8bnVtYmVyIHwgbnVsbD47XG4gIC8qKlxuICAgKiBXaGV0aGVyIG9uZSBJTVBFUlNPTkFUSU9OIHNlc3Npb24gKGJ5IHRva2VuIGBqdGlgKSBoYXMgYmVlbiBlbmRlZCBlYXJseS5cbiAgICpcbiAgICogT3B0aW9uYWwgc28gYSBzdG9yZSB0aGF0IHByZWRhdGVzIGl0IHN0aWxsIGxpbmtzIOKAlCBidXQgYSBzdG9yZSBXSVRIT1VUIGl0XG4gICAqIGNhbm5vdCBhbnN3ZXIsIGFuZCBhbiBpbXBlcnNvbmF0aW9uIHRva2VuIGlzIHRoZW4gUkVKRUNURUQuIFVubGlrZVxuICAgKiBgZ2V0Q3VycmVudFZlcnNpb25gLCB0aGlzIGlzIGRlbGliZXJhdGVseSBub3QgZmFpbC1vcGVuOiB0aGUgcGxhdGZvcm0gZW5kcyBhXG4gICAqIHNlc3Npb24gd2hlbiBzb21lb25lIHdpdGhkcmF3cyBjb25zZW50LCBhbmQgYSB3aXRoZHJhd24gY29uc2VudCB0aGF0IGtlZXBzXG4gICAqIHdvcmtpbmcgaW4gZXZlcnkgb3RoZXIgc2VydmljZSBpcyBub3Qgd2l0aGRyYXduLlxuICAgKi9cbiAgZ2V0U2Vzc2lvblJldm9jYXRpb24/KGp0aTogc3RyaW5nKTogUHJvbWlzZTxTZXNzaW9uUmV2b2NhdGlvblN0YXRlPjtcbn1cblxuLyoqXG4gKiBgcmV2b2tlZGAgICAgIOKAlCB0aGUgc2Vzc2lvbiB3YXMgZW5kZWQ7IHJlamVjdC5cbiAqIGBsaXZlYCAgICAgICAg4oCUIG5vIHJldm9jYXRpb24gcmVjb3JkZWQ7IGFsbG93LlxuICogYHVuYXZhaWxhYmxlYCDigJQgdGhlIHN0b3JlIGNvdWxkbid0IGJlIHJlYWQgb3IgY2FuJ3QgYW5zd2VyOyBSRUpFQ1QuIERpc3RpbmN0XG4gKiAgICAgICAgICAgICAgICAgZnJvbSBgbGl2ZWAgcHJlY2lzZWx5IHNvIGFuIG91dGFnZSBjYW4ndCByZWFkIGFzIFwibm90IHJldm9rZWRcIi5cbiAqL1xuZXhwb3J0IHR5cGUgU2Vzc2lvblJldm9jYXRpb25TdGF0ZSA9ICdyZXZva2VkJyB8ICdsaXZlJyB8ICd1bmF2YWlsYWJsZSc7XG5cbmxldCB0b2tlblJldm9jYXRpb25TdG9yZTogVG9rZW5SZXZvY2F0aW9uU3RvcmUgfCB1bmRlZmluZWQ7XG5cbi8qKlxuICogUmVnaXN0ZXIgKG9yIGNsZWFyLCB3aXRoIGB1bmRlZmluZWRgKSB0aGUgcHJvY2Vzcy13aWRlIHRva2VuLXJldm9jYXRpb24gc3RvcmUuXG4gKiBXaGVuIHVuc2V0ICh0aGUgZGVmYXVsdCksIGByZXF1aXJlQXV0aGAgcGVyZm9ybXMgTk8gcmV2b2NhdGlvbiBjaGVjayAoaXQgcmVsaWVzXG4gKiBvbiB0aGUgc2hvcnQgYWNjZXNzLXRva2VuIFRUTCk7IHNlcnZpY2VzIG9wdCBpbiBhdCBib290IGJ5IHdpcmluZyB0aGVpciBSZWRpc1xuICogY2xpZW50LiBQbGF0Zm9ybSBrZWVwcyBpdHMgb3duIE1vbmdvLWJhY2tlZCBjaGVjayBhbmQgbmVlZCBub3QgcmVnaXN0ZXIgb25lLlxuICovXG5leHBvcnQgZnVuY3Rpb24gc2V0VG9rZW5SZXZvY2F0aW9uU3RvcmUoc3RvcmU6IFRva2VuUmV2b2NhdGlvblN0b3JlIHwgdW5kZWZpbmVkKTogdm9pZCB7XG4gIHRva2VuUmV2b2NhdGlvblN0b3JlID0gc3RvcmU7XG4gIGlmIChzdG9yZSkgcmV2b2NhdGlvblN0b3JlTWlzc2luZ1dhcm5lZCA9IGZhbHNlOyAvLyByZS1hcm0gaWYgYSBzdG9yZSBpcyAocmUpcmVnaXN0ZXJlZFxufVxuXG4vKiogT25lLXNob3QgZ3VhcmQgc28gdGhlIFwicmV2b2NhdGlvbiBpbmFjdGl2ZVwiIHdhcm5pbmcgZG9lc24ndCBmbG9vZCB0aGUgbG9ncy4gKi9cbmxldCByZXZvY2F0aW9uU3RvcmVNaXNzaW5nV2FybmVkID0gZmFsc2U7XG5cbi8qKlxuICogUmV0dXJucyB0cnVlIHdoZW4gYGRlY29kZWRgIGhhcyBiZWVuIHJldm9rZWQgcGVyIHRoZSByZWdpc3RlcmVkIHN0b3JlOiBpdHNcbiAqIGVtYmVkZGVkIGB0b2tlblZlcnNpb25gIGlzIHN0cmljdGx5IGJlaGluZCB0aGUgc3RvcmUncyBjdXJyZW50IHZlcnNpb24uXG4gKiBGYWlsLW9wZW4g4oCUIGFueSBzdG9yZSBlcnJvciwgYSBtaXNzaW5nIGVudHJ5LCBvciBhIHRva2VuL3N0b3JlIHdpdGhvdXQgYVxuICogdXNhYmxlIHZlcnNpb24geWllbGRzIGBmYWxzZWAgKGFsbG93KS4gTmV2ZXIgdGhyb3dzLlxuICovXG5hc3luYyBmdW5jdGlvbiBpc1Rva2VuUmV2b2tlZChkZWNvZGVkOiBKd3RQYXlsb2FkKTogUHJvbWlzZTxib29sZWFuPiB7XG4gIGNvbnN0IHN0b3JlID0gdG9rZW5SZXZvY2F0aW9uU3RvcmU7XG4gIGlmICghc3RvcmUpIHtcbiAgICAvLyBNYWtlIHRoZSBcInJldm9jYXRpb24gaXMgT0ZGXCIgc3RhdGUgT0JTRVJWQUJMRTogYSBzZXJ2aWNlIHRoYXQgdmVyaWZpZXMgdXNlclxuICAgIC8vIHRva2VucyBidXQgZm9yZ290IGBzZXRUb2tlblJldm9jYXRpb25TdG9yZSgpYCBzaWxlbnRseSBkaXNhYmxlcyB0aGUgc2Vzc2lvblxuICAgIC8vIGtpbGwtc3dpdGNoLiBXYXJuIE9OQ0UgKG9ubHkgZm9yIGEgcmV2b2NhYmxlIHVzZXIgdG9rZW4pIHNvIGEgbWlzY29uZmlndXJlZFxuICAgIC8vIGJvb3Qgc3VyZmFjZXMgaW4gdGhlIGxvZ3MgaW5zdGVhZCBvZiBmYWlsaW5nIG9wZW4gaW52aXNpYmx5LlxuICAgIGlmICghcmV2b2NhdGlvblN0b3JlTWlzc2luZ1dhcm5lZCAmJiBkZWNvZGVkLnN1YiAmJiB0eXBlb2YgZGVjb2RlZC50b2tlblZlcnNpb24gPT09ICdudW1iZXInKSB7XG4gICAgICByZXZvY2F0aW9uU3RvcmVNaXNzaW5nV2FybmVkID0gdHJ1ZTtcbiAgICAgIGxvZ2dlci53YXJuKCdUb2tlbiByZXZvY2F0aW9uIHN0b3JlIE5PVCByZWdpc3RlcmVkIOKAlCByZXZvY2F0aW9uIGNoZWNrcyBhcmUgSU5BQ1RJVkUgKHNldFRva2VuUmV2b2NhdGlvblN0b3JlIHdhcyBuZXZlciBjYWxsZWQpOyByZXZva2VkL2NvbXByb21pc2VkIHNlc3Npb25zIHN0YXkgdmFsaWQgdW50aWwgbmF0dXJhbCBUVEwnKTtcbiAgICB9XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG4gIGlmICghZGVjb2RlZC5zdWIgfHwgdHlwZW9mIGRlY29kZWQudG9rZW5WZXJzaW9uICE9PSAnbnVtYmVyJykgcmV0dXJuIGZhbHNlO1xuICB0cnkge1xuICAgIGNvbnN0IGN1cnJlbnQgPSBhd2FpdCBzdG9yZS5nZXRDdXJyZW50VmVyc2lvbihkZWNvZGVkLnN1Yik7XG4gICAgcmV0dXJuIGN1cnJlbnQgIT09IG51bGwgJiYgZGVjb2RlZC50b2tlblZlcnNpb24gPCBjdXJyZW50O1xuICB9IGNhdGNoIHtcbiAgICAvLyBGYWlsLW9wZW46IGEgcmV2b2NhdGlvbi1zdG9yZSBvdXRhZ2UgbXVzdCBub3QgbG9jayBldmVyeSB1c2VyIG91dC5cbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbn1cblxuLyoqXG4gKiBSZXNvbHZlIGFuIGltcGVyc29uYXRpb24gc2Vzc2lvbidzIHJldm9jYXRpb24gc3RhdGUuIE5ldmVyIHRocm93czogYW55IGZhaWx1cmVcbiAqIOKAlCBubyBzdG9yZSwgYSBzdG9yZSB0aGF0IGNhbid0IGFuc3dlciwgYSByZWFkIGVycm9yIOKAlCBpcyBgdW5hdmFpbGFibGVgLCB3aGljaFxuICogY2FsbGVycyB0cmVhdCBhcyByZXZva2VkLlxuICovXG5hc3luYyBmdW5jdGlvbiBzZXNzaW9uUmV2b2NhdGlvblN0YXRlKGp0aTogc3RyaW5nKTogUHJvbWlzZTxTZXNzaW9uUmV2b2NhdGlvblN0YXRlPiB7XG4gIGNvbnN0IHN0b3JlID0gdG9rZW5SZXZvY2F0aW9uU3RvcmU7XG4gIGlmICghc3RvcmU/LmdldFNlc3Npb25SZXZvY2F0aW9uKSByZXR1cm4gJ3VuYXZhaWxhYmxlJztcbiAgdHJ5IHtcbiAgICByZXR1cm4gYXdhaXQgc3RvcmUuZ2V0U2Vzc2lvblJldm9jYXRpb24oanRpKTtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuICd1bmF2YWlsYWJsZSc7XG4gIH1cbn1cblxuLyoqIEFuIGltcGVyc29uYXRpb24gc2Vzc2lvbiB0b2tlbjogaXQgbmFtZXMgdGhlIG9wZXJhdG9yIEFORCBjYXJyaWVzIGl0cyBvd24gc2Vzc2lvbiBpZC4gKi9cbmZ1bmN0aW9uIGlzSW1wZXJzb25hdGlvblNlc3Npb24oZGVjb2RlZDogeyBpbXBlcnNvbmF0b3JJZD86IHVua25vd247IGp0aT86IHVua25vd24gfSk6IGRlY29kZWQgaXMgeyBpbXBlcnNvbmF0b3JJZDogc3RyaW5nOyBqdGk6IHN0cmluZyB9IHtcbiAgcmV0dXJuIHR5cGVvZiBkZWNvZGVkLmltcGVyc29uYXRvcklkID09PSAnc3RyaW5nJyAmJiB0eXBlb2YgZGVjb2RlZC5qdGkgPT09ICdzdHJpbmcnICYmIGRlY29kZWQuanRpLmxlbmd0aCA+IDA7XG59XG5cbi8qKlxuICogUHVibGljIHJldm9jYXRpb24gY2hlY2sgZm9yIHJvdXRlcyB0aGF0IHZlcmlmeSBhIHBsYXRmb3JtIEpXVCBPVVRTSURFXG4gKiBgcmVxdWlyZUF1dGhgIChlLmcuIHRoZSBpbWFnZS1yZWdpc3RyeSBgL3Rva2VuYCBtaW50IHBhdGgsIHdoaWNoIHJlc29sdmVzXG4gKiBpZGVudGl0eSBpdHNlbGYpLiBSZXR1cm5zIHRydWUgd2hlbiB0aGUgdG9rZW4ncyBgdG9rZW5WZXJzaW9uYCBpcyBzdHJpY3RseVxuICogYmVoaW5kIHRoZSBzdG9yZSdzIGN1cnJlbnQgdmVyc2lvbi4gRmFpbC1vcGVuIChuZXZlciB0aHJvd3MpIOKAlCBhIHN0b3JlIG91dGFnZVxuICogb3IgYSB0b2tlbi9zdG9yZSB3aXRob3V0IGEgdXNhYmxlIHZlcnNpb24geWllbGRzIGZhbHNlIChhbGxvdyksIG1hdGNoaW5nXG4gKiBgcmVxdWlyZUF1dGhgLiBQYXNzIHRoZSB2ZXJpZmllZCBKV1QgY2xhaW1zIChgc3ViYCwgYHRva2VuVmVyc2lvbmApLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gaXNBY2Nlc3NUb2tlblJldm9rZWQoXG4gIGNsYWltczogeyBzdWI/OiBzdHJpbmc7IHRva2VuVmVyc2lvbj86IG51bWJlcjsganRpPzogc3RyaW5nOyBpbXBlcnNvbmF0b3JJZD86IHN0cmluZyB9LFxuKTogUHJvbWlzZTxib29sZWFuPiB7XG4gIC8vIEFuIGltcGVyc29uYXRpb24gc2Vzc2lvbiBpcyByZXZva2VkIHVubGVzcyB0aGUgc3RvcmUgcG9zaXRpdmVseSBzYXlzIGxpdmUg4oCUXG4gIC8vIGluY2x1ZGluZyBvbiB0aGlzIG91dC1vZi1iYW5kIHBhdGgsIG9yIGEgcmV2b2tlZCBzZXNzaW9uIGNvdWxkIHN0aWxsIG1pbnRcbiAgLy8gcmVnaXN0cnkgdG9rZW5zLlxuICBpZiAoaXNJbXBlcnNvbmF0aW9uU2Vzc2lvbihjbGFpbXMpICYmIGF3YWl0IHNlc3Npb25SZXZvY2F0aW9uU3RhdGUoY2xhaW1zLmp0aSkgIT09ICdsaXZlJykgcmV0dXJuIHRydWU7XG4gIHJldHVybiBpc1Rva2VuUmV2b2tlZChjbGFpbXMgYXMgSnd0UGF5bG9hZCk7XG59XG5cbmZ1bmN0aW9uIF9yZXF1aXJlQXV0aChcbiAgb3B0aW9uczogUmVxdWlyZUF1dGhPcHRpb25zLFxuICByZXE6IFJlcXVlc3QsXG4gIHJlczogUmVzcG9uc2UsXG4gIG5leHQ6IE5leHRGdW5jdGlvbixcbik6IHZvaWQge1xuICBjb25zdCBhdXRoSGVhZGVyID0gcmVxLmhlYWRlcnMuYXV0aG9yaXphdGlvbjtcblxuICBpZiAoIWF1dGhIZWFkZXIpIHtcbiAgICByZXR1cm4gc2VuZEVycm9yKHJlcywgSHR0cFN0YXR1cy5VTkFVVEhPUklaRUQsICdBdXRob3JpemF0aW9uIGhlYWRlciByZXF1aXJlZCcsIEVycm9yQ29kZS5UT0tFTl9NSVNTSU5HKTtcbiAgfVxuXG4gIGNvbnN0IHBhcnRzID0gYXV0aEhlYWRlci5zcGxpdCgnICcpO1xuICBpZiAocGFydHMubGVuZ3RoICE9PSAyIHx8IHBhcnRzWzBdICE9PSAnQmVhcmVyJykge1xuICAgIHJldHVybiBzZW5kRXJyb3IocmVzLCBIdHRwU3RhdHVzLlVOQVVUSE9SSVpFRCwgJ0ludmFsaWQgYXV0aG9yaXphdGlvbiBmb3JtYXQuIFVzZTogQmVhcmVyIDx0b2tlbj4nLCBFcnJvckNvZGUuVE9LRU5fSU5WQUxJRCk7XG4gIH1cblxuICAvLyBBbiBPUEFRVUUgQUNDRVNTIEtFWSAoYHBiX3BhdF/igKZgIC8gYHBiX3NhX+KApmApIGNhcnJpZXMgbm8gY2xhaW1zIGFuZCBub1xuICAvLyBzaWduYXR1cmUsIHNvIGl0IGNhbm5vdCBiZSB2ZXJpZmllZCBoZXJlLiBUcmFkZSBpdCBhdCBwbGF0Zm9ybSBmb3IgYVxuICAvLyBzaG9ydC1saXZlZCBKV1QgKGNhY2hlZCBpbi1wcm9jZXNzIHVudGlsIGl0IGV4cGlyZXMpIGFuZCB0aGVuIHZlcmlmeSB0aGF0XG4gIC8vIEpXVCBvbiB0aGUgbm9ybWFsIHBhdGgg4oCUIHNlcnZpY2VzIG5ldmVyIHJlYWQgYSBrZXkgaGFzaC4gU2VlXG4gIC8vIGBzZXJ2aWNlcy9hcGkta2V5LWV4Y2hhbmdlLnRzYC5cbiAgaWYgKGlzT3BhcXVlQXBpS2V5KHBhcnRzWzFdKSkge1xuICAgIHZvaWQgcmVzb2x2ZUFwaUtleShvcHRpb25zLCBwYXJ0c1sxXSwgcmVxLCByZXMsIG5leHQpO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIC8vIGAuY2F0Y2gobmV4dClgIGZvcndhcmRzIGEgRE9XTlNUUkVBTSBzeW5jaHJvbm91cyB0aHJvdyBmcm9tIGBuZXh0KClgIHRvXG4gIC8vIEV4cHJlc3MncyBlcnJvciBtaWRkbGV3YXJlIOKAlCB2ZXJpZmljYXRpb24gaXRzZWxmIG5ldmVyIHJlamVjdHMgKGl0IG1hcHNcbiAgLy8gZXZlcnkgZmFpbHVyZSB0byBhIHJlc3BvbnNlKS5cbiAgdm9pZCB2ZXJpZnlBbmRBdHRhY2gob3B0aW9ucywgcGFydHNbMV0sIHJlcSwgcmVzLCBuZXh0KS5jYXRjaChuZXh0KTtcbn1cblxuLyoqXG4gKiBFeGNoYW5nZSBhbiBvcGFxdWUga2V5IGZvciBhIEpXVCwgdGhlbiBjb250aW51ZSBvbiB0aGUgbm9ybWFsIHZlcmlmaWNhdGlvblxuICogcGF0aC4gQSByZWZ1c2VkIGtleSBpcyBhIDQwMTsgYW4gdW5yZWFjaGFibGUgcGxhdGZvcm0gaXMgYSA1MDMgKG5ldmVyIGEgcGFzcyDigJRcbiAqIGFuIHVudmVyaWZpYWJsZSBjcmVkZW50aWFsIGlzIG5vdCBhbiBpZGVudGl0eSkuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHJlc29sdmVBcGlLZXkoXG4gIG9wdGlvbnM6IFJlcXVpcmVBdXRoT3B0aW9ucyxcbiAga2V5OiBzdHJpbmcsXG4gIHJlcTogUmVxdWVzdCxcbiAgcmVzOiBSZXNwb25zZSxcbiAgbmV4dDogTmV4dEZ1bmN0aW9uLFxuKTogUHJvbWlzZTx2b2lkPiB7XG4gIC8vIExvYWRlZCBMQVpJTFksIG9uIHRoZSBmaXJzdCBrZXkgZXZlciBwcmVzZW50ZWQuIEEgc3RhdGljIGltcG9ydCB3b3VsZCBwdXRcbiAgLy8gdGhlIEhUVFAgY2xpZW50IChhbmQgcGxhdGZvcm0ncyBhZGRyZXNzKSBpbnRvIHRoZSBpbXBvcnQgZ3JhcGggb2YgZXZlcnlcbiAgLy8gbW9kdWxlIHRoYXQgbWVyZWx5IHVzZXMgYHJlcXVpcmVBdXRoYCwgd2hpY2ggYm90aCB3aWRlbnMgdGhlIGJvb3QgZ3JhcGggYW5kXG4gIC8vIGJyZWFrcyBhbnkgdGVzdCB0aGF0IG1vY2tzIGBodHRwLWNsaWVudC5qc2Agd2l0aCBhIHBhcnRpYWwgbW9kdWxlLlxuICBjb25zdCB7IGV4Y2hhbmdlQXBpS2V5LCBBcGlLZXlFeGNoYW5nZVVuYXZhaWxhYmxlRXJyb3IgfSA9IGF3YWl0IGltcG9ydCgnLi4vc2VydmljZXMvYXBpLWtleS1leGNoYW5nZS5qcycpO1xuICBsZXQgdG9rZW46IHN0cmluZztcbiAgdHJ5IHtcbiAgICB0b2tlbiA9IGF3YWl0IGV4Y2hhbmdlQXBpS2V5KGtleSk7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgaWYgKGVycm9yIGluc3RhbmNlb2YgQXBpS2V5RXhjaGFuZ2VVbmF2YWlsYWJsZUVycm9yKSB7XG4gICAgICByZXR1cm4gc2VuZEVycm9yKFxuICAgICAgICByZXMsIEh0dHBTdGF0dXMuU0VSVklDRV9VTkFWQUlMQUJMRSxcbiAgICAgICAgJ0FjY2Vzcy1rZXkgdmVyaWZpY2F0aW9uIGlzIHRlbXBvcmFyaWx5IHVuYXZhaWxhYmxlOyBwbGVhc2UgcmV0cnknLFxuICAgICAgICBFcnJvckNvZGUuU0VSVklDRV9VTkFWQUlMQUJMRSxcbiAgICAgICk7XG4gICAgfVxuICAgIHJldHVybiBzZW5kRXJyb3IocmVzLCBIdHRwU3RhdHVzLlVOQVVUSE9SSVpFRCwgJ0ludmFsaWQgb3IgcmV2b2tlZCBhY2Nlc3Mga2V5JywgRXJyb3JDb2RlLlRPS0VOX0lOVkFMSUQpO1xuICB9XG4gIGF3YWl0IHZlcmlmeUFuZEF0dGFjaChvcHRpb25zLCB0b2tlbiwgcmVxLCByZXMsIG5leHQpO1xufVxuXG5hc3luYyBmdW5jdGlvbiB2ZXJpZnlBbmRBdHRhY2goXG4gIG9wdGlvbnM6IFJlcXVpcmVBdXRoT3B0aW9ucyxcbiAgcmF3VG9rZW46IHN0cmluZyxcbiAgcmVxOiBSZXF1ZXN0LFxuICByZXM6IFJlc3BvbnNlLFxuICBuZXh0OiBOZXh0RnVuY3Rpb24sXG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgdHJ5IHtcbiAgICAvLyBUd28gY2hhaW5zLCBvbmUgZW50cnkgcG9pbnQgKHNlZSBgdmVyaWZ5QmVhcmVyVG9rZW5gKTogYSB1c2VyIHRva2VuIG11c3RcbiAgICAvLyBiZSBFUzI1NiBzaWduZWQgYnkgcGxhdGZvcm0gYW5kIHZlcmlmaWVkIGFnYWluc3QgaXRzIHB1Ymxpc2hlZCBKV0tTOyBhblxuICAgIC8vIGludGVybmFsIHNlcnZpY2UgdG9rZW4gc3RheXMgb24gdGhlIHNoYXJlZCBzZWNyZXQgYW5kIG11c3QgZGVjbGFyZSBpdHNlbGZcbiAgICAvLyBhIHNlcnZpY2UgcHJpbmNpcGFsLiBCb3RoIHBpbiB0aGUgYWxnb3JpdGhtIChubyBhbGctY29uZnVzaW9uLCBub1xuICAgIC8vIGBhbGc6bm9uZWApIGFuZCBib3RoIGFwcGx5IHRoZSBvcHRpb25hbCBpc3N1ZXIvYXVkaWVuY2UgYmluZGluZy5cbiAgICBjb25zdCBkZWNvZGVkID0gYXdhaXQgdmVyaWZ5QmVhcmVyVG9rZW4ocmF3VG9rZW4pO1xuXG4gICAgaWYgKGRlY29kZWQudHlwZSAhPT0gJ2FjY2VzcycpIHtcbiAgICAgIHJldHVybiBzZW5kRXJyb3IocmVzLCBIdHRwU3RhdHVzLlVOQVVUSE9SSVpFRCwgJ09ubHkgYWNjZXNzIHRva2VucyBjYW4gYmUgdXNlZCBmb3IgQVBJIHJlcXVlc3RzJywgRXJyb3JDb2RlLlRPS0VOX0lOVkFMSUQpO1xuICAgIH1cblxuICAgIGlmICghZGVjb2RlZC5zdWIgfHwgIWRlY29kZWQucm9sZSB8fCAhaGFzVmFsaWRJZGVudGl0eUNsYWltcyhkZWNvZGVkKSkge1xuICAgICAgcmV0dXJuIHNlbmRFcnJvcihyZXMsIEh0dHBTdGF0dXMuVU5BVVRIT1JJWkVELCAnVG9rZW4gbWlzc2luZyByZXF1aXJlZCBmaWVsZHMnLCBFcnJvckNvZGUuVE9LRU5fSU5WQUxJRCk7XG4gICAgfVxuXG4gICAgLy8gU2VydmljZS10b2tlbiBraWxsLXN3aXRjaDogcmVqZWN0IGEgc2VydmljZSBwcmluY2lwYWwgd2hvc2Ugc2VydmljZSBoYXNcbiAgICAvLyBiZWVuIGFkZGVkIHRvIHRoZSBkZW55bGlzdC4gUm90YXRpbmcgdGhlIHNoYXJlZCBKV1Qgc2VjcmV0IGlzIHRoZSBvbmx5XG4gICAgLy8gb3RoZXIgd2F5IHRvIGludmFsaWRhdGUgYSBzZXJ2aWNlIHRva2VuIGJlZm9yZSBpdHMgKHNob3J0KSBUVEwg4oCUIGJ1dCB0aGF0XG4gICAgLy8gbnVrZXMgRVZFUlkgc2VydmljZSB0b2tlbiBmbGVldC13aWRlLiBUaGlzIGxldHMgb25lIGNvbXByb21pc2VkL3JvZ3VlXG4gICAgLy8gc2VydmljZSBiZSBjdXQgb2ZmIHN1cmdpY2FsbHkuIE8oMSkgU2V0IGxvb2t1cCwgemVybyBjb3N0IHdoZW4gdGhlIGRlbnlsaXN0XG4gICAgLy8gaXMgZW1wdHkgKHRoZSBkZWZhdWx0KSwgc28gaXQgbmV2ZXIgdGF4ZXMgdGhlIFMyUyBob3QgcGF0aCB1bmxlc3MgYXJtZWQuXG4gICAgaWYgKGlzU2VydmljZVRva2VuRGVuaWVkKGRlY29kZWQpKSB7XG4gICAgICBlbWl0Q291bnRlcignc2VydmljZV90b2tlbl9kZW5pZWRfdG90YWwnLCB7IHNlcnZpY2U6IHNlcnZpY2VOYW1lT2YoZGVjb2RlZCkgPz8gJ3Vua25vd24nIH0pO1xuICAgICAgbG9nZ2VyLndhcm4oJ1JlamVjdGVkIGRlbnlsaXN0ZWQgc2VydmljZSB0b2tlbicsIHsgc3ViOiBkZWNvZGVkLnN1YiB9KTtcbiAgICAgIHJldHVybiBzZW5kRXJyb3IocmVzLCBIdHRwU3RhdHVzLlVOQVVUSE9SSVpFRCwgJ1NlcnZpY2UgdG9rZW4gcmV2b2tlZCcsIEVycm9yQ29kZS5UT0tFTl9SRVZPS0VEKTtcbiAgICB9XG5cbiAgICByZXEudXNlciA9IHsgLi4uZGVjb2RlZCB9O1xuXG4gICAgLy8gQk9PVFNUUkFQLUFETUlOIEVOUk9MTUVOVCBTRVNTSU9OICgjOCwgcmV2aXNpb24gNCkuIFN1Y2ggYSB0b2tlbiBleGlzdHMgc29cbiAgICAvLyB0aGUgaW5zdGFsbCdzIG9ubHkgYWRtaW4gY2FuIGVucm9sIGEgZmFjdG9yOyBpdCBpcyBgYWFsOiAxYCBhbmQgbXVzdCBub3RcbiAgICAvLyByZWFjaCBhbnl0aGluZyBlbHNlLiBQbGF0Zm9ybSDigJQgd2hpY2ggb3ducyB0aGUgZXhjZXB0aW9uIGFuZCBrbm93cyB3aGljaFxuICAgIC8vIG9mIGl0cyBvd24gcm91dGVzIGBpbml0LXBsYXRmb3JtLnNoYCBjYWxscyDigJQgYWxsb3dzIGFuIGV4cGxpY2l0IGZldyBiZWZvcmVcbiAgICAvLyB0aGlzIHBvaW50IChzZWUgaXRzIG93biBgcmVxdWlyZUF1dGhgKTsgaW4gRVZFUlkgb3RoZXIgc2VydmljZSB0aGUgYW5zd2VyXG4gICAgLy8gaXMgc2ltcGx5IG5vLCBzbyB0aGUgcmVhY2ggcmVzdHJpY3Rpb24gaG9sZHMgd2l0aG91dCBhIHBlci1zZXJ2aWNlXG4gICAgLy8gYWxsb3dsaXN0IHRvIGtlZXAgaW4gc3luYy5cbiAgICBpZiAoZGVjb2RlZC5tZmFFbnJvbGxtZW50UGVuZGluZyA9PT0gdHJ1ZSkge1xuICAgICAgZW1pdENvdW50ZXIoJ21mYV9lbmZvcmNlbWVudF9yZWZ1c2VkX3RvdGFsJywgeyBzZXJ2aWNlOiBzZXJ2aWNlSWRlbnRpdHkoKSwgcmVhc29uOiAnYm9vdHN0cmFwX3Nlc3Npb24nIH0pO1xuICAgICAgcmVjb3JkQXV0aHpEZW5pYWwocmVxLCAnbWZhLWVucm9sbWVudCcpO1xuICAgICAgcmV0dXJuIHNlbmRFcnJvcihcbiAgICAgICAgcmVzLCBIdHRwU3RhdHVzLkZPUkJJRERFTixcbiAgICAgICAgJ0ZpbmlzaCBzZXR0aW5nIHVwIHR3by1mYWN0b3IgYXV0aGVudGljYXRpb24gYmVmb3JlIHVzaW5nIHRoZSByZXN0IG9mIFBpcGVsaW5lIEJ1aWxkZXInLFxuICAgICAgICBFcnJvckNvZGUuTUZBX0VOUk9MTE1FTlRfUkVRVUlSRUQsXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIFNlc3Npb24tbGV2ZWwgYXNzdXJhbmNlIChgcmVxdWlyZUF1dGgoeyBtaW5Bc3N1cmFuY2UsIG1heEFnZSB9KWApLlxuICAgIGlmIChvcHRpb25zLm1pbkFzc3VyYW5jZVxuICAgICAgJiYgcmVmdXNlRm9yQXNzdXJhbmNlKHsgbWluQXNzdXJhbmNlOiBvcHRpb25zLm1pbkFzc3VyYW5jZSwgLi4uKG9wdGlvbnMubWF4QWdlICE9PSB1bmRlZmluZWQgPyB7IG1heEFnZTogb3B0aW9ucy5tYXhBZ2UgfSA6IHt9KSB9LCBkZWNvZGVkLCByZXEsIHJlcykpIHJldHVybjtcblxuICAgIC8vIFRoZSB4LW9yZy1pZC94LW9yZy1uYW1lIG92ZXJyaWRlIGxldHMgYSBTWVMtQURNSU4gYWN0IG9uIGEgY2hvc2VuIG9yZ1xuICAgIC8vIChjcm9zcy1vcmcgYWRtaW4gdG9vbGluZykuIEl0IGlzIGdhdGVkIG9uIHRoZSB2ZXJpZmllZCBgaXNTdXBlckFkbWluYCBjbGFpbVxuICAgIC8vIGhlcmUgc28gdGhhdCBldmVuIGEgcm91dGUgd2hpY2ggbWlzdGFrZW5seSBlbmFibGVzIGBhbGxvd09yZ0hlYWRlck92ZXJyaWRlYFxuICAgIC8vIGNhbiBORVZFUiBsZXQgYW4gb3JkaW5hcnkgYXV0aGVudGljYXRlZCB1c2VyIHNwb29mIGFub3RoZXIgdGVuYW50J3Mgb3JnIHZpYVxuICAgIC8vIHRoZSBoZWFkZXIg4oCUIGRlZmVuY2UtaW4tZGVwdGggYWdhaW5zdCB0aGUgY3Jvc3MtdGVuYW50IGJyZWFrIHRoaXMgY2F1c2VkLlxuICAgIGlmIChvcHRpb25zLmFsbG93T3JnSGVhZGVyT3ZlcnJpZGUgJiYgZGVjb2RlZC5pc1N1cGVyQWRtaW4gPT09IHRydWUpIHtcbiAgICAgIGNvbnN0IGhlYWRlck9yZ0lkID0gZ2V0SGVhZGVyU3RyaW5nKHJlcS5oZWFkZXJzWyd4LW9yZy1pZCddKTtcbiAgICAgIGNvbnN0IGhlYWRlck9yZ05hbWUgPSBnZXRIZWFkZXJTdHJpbmcocmVxLmhlYWRlcnNbJ3gtb3JnLW5hbWUnXSk7XG4gICAgICBpZiAoaGVhZGVyT3JnSWQpIHJlcS51c2VyLm9yZ2FuaXphdGlvbklkID0gaGVhZGVyT3JnSWQ7XG4gICAgICBpZiAoaGVhZGVyT3JnTmFtZSkgcmVxLnVzZXIub3JnYW5pemF0aW9uTmFtZSA9IGhlYWRlck9yZ05hbWU7XG4gICAgfVxuXG4gICAgLy8gUmUtZGVyaXZlIHRoZSByZXF1ZXN0J3MgdGVuYW50IGlkZW50aXR5IGZyb20gdGhlIE5PVy12ZXJpZmllZCBKV1QuXG4gICAgLy9cbiAgICAvLyBgYXR0YWNoUmVxdWVzdENvbnRleHRgIHJ1bnMgYXMgYSBnbG9iYWwgbWlkZGxld2FyZSBCRUZPUkUgdGhpcyBwZXItcm91dGVcbiAgICAvLyBgcmVxdWlyZUF1dGhgLCBzbyBpdCBjYXB0dXJlZCBgcmVxLmNvbnRleHQuaWRlbnRpdHlgIHdoaWxlIGByZXEudXNlcmAgd2FzXG4gICAgLy8gc3RpbGwgdW5kZWZpbmVkIOKAlCBhdCB3aGljaCBwb2ludCBgZ2V0SWRlbnRpdHlgIGZhbGxzIGJhY2sgdG8gdGhlIHJhdyxcbiAgICAvLyBjbGllbnQtc2V0dGFibGUgYHgtb3JnLWlkYC9geC11c2VyLWlkYCBoZWFkZXJzLiBFdmVyeSBkb3duc3RyZWFtIHRlbmFudC1cbiAgICAvLyBhdXRob3JpdHkgY29uc3VtZXIgKHJlcXVpcmVPcmdJZCwgd2l0aFRlbmFudENvbnRleHQncyBSTFMgc2NvcGUsIGNoZWNrUXVvdGEsXG4gICAgLy8gd2l0aFJvdXRlLCBhbmQgdGhlIGlkZW1wb3RlbmN5IG5hbWVzcGFjZSkgcmVhZHMgYHJlcS5jb250ZXh0LmlkZW50aXR5YCwgc29cbiAgICAvLyB0aGF0IGZyb3plbiBoZWFkZXItZGVyaXZlZCB2YWx1ZSDigJQgbm90IHRoZSBKV1Qg4oCUIHdhcyBnb3Zlcm5pbmcgdGVuYW5jeSBvblxuICAgIC8vIGFueSBub24tbmdpbnggcGF0aC4gUmVjb21wdXRpbmcgaGVyZSwgYXQgdGhlIHNpbmdsZSBwb3N0LXZlcmlmaWNhdGlvbiBjaG9rZVxuICAgIC8vIHBvaW50LCBtYWtlcyBgZ2V0SWRlbnRpdHlgIHByZWZlciB0aGUgdmVyaWZpZWQgYHJlcS51c2VyYCAoc2VlIGlkZW50aXR5LnRzKVxuICAgIC8vIHNvIHRlbmFuY3kgaXMgSldULWF1dGhvcml0YXRpdmUuIFRoZSBuZ2lueCBgeC1vcmctaWRgIG92ZXJ3cml0ZSBzdGF5cyBhc1xuICAgIC8vIGRlZmVuY2UtaW4tZGVwdGguIEd1YXJkZWQgb24gYHJlcS5jb250ZXh0YCBzbyBzZXJ2aWNlcy9wYXRocyB0aGF0IG5ldmVyXG4gICAgLy8gYXR0YWNoIGEgY29udGV4dCAob3IgcnVuIHJlcXVpcmVBdXRoIHByZS1jb250ZXh0KSBhcmUgdW5hZmZlY3RlZC5cbiAgICBjb25zdCByZXFDdHggPSAocmVxIGFzIFJlcXVlc3QgJiB7IGNvbnRleHQ/OiB7IGlkZW50aXR5OiBSZXF1ZXN0SWRlbnRpdHkgfSB9KS5jb250ZXh0O1xuICAgIGlmIChyZXFDdHgpIHtcbiAgICAgIHJlcUN0eC5pZGVudGl0eSA9IGdldElkZW50aXR5KHJlcSBhcyB1bmtub3duIGFzIEh0dHBSZXF1ZXN0KTtcbiAgICB9XG5cbiAgICAvLyBTZXNzaW9uLWludmFsaWRhdGlvbiBjaGVjayBmb3IgdGhlIHN0YXRlbGVzcyBzZXJ2aWNlczogcmVqZWN0IGEgdG9rZW5cbiAgICAvLyB3aG9zZSBgdG9rZW5WZXJzaW9uYCBpcyBiZWhpbmQgdGhlIHJldm9jYXRpb24gc3RvcmUncyBjdXJyZW50IHZhbHVlIChhXG4gICAgLy8gcHJpdmlsZWdlIGNoYW5nZSB0aGUgcGxhdGZvcm0gcHVibGlzaGVkKS4gTm8gc3RvcmUgcmVnaXN0ZXJlZCDih5IgdGhpcyBpcyBhXG4gICAgLy8gbm8tb3AgYW5kIGNvbnRyb2wgcGFzc2VzIHN0cmFpZ2h0IHRocm91Z2guIEZhaWwtb3BlbiBvbiBhbnkgc3RvcmUgZXJyb3IuXG4gICAgLy8gQW4gaW1wZXJzb25hdGlvbiBzZXNzaW9uIGlzIGNoZWNrZWQgZXZlbiB3aGVuIE5PIHN0b3JlIGlzIHJlZ2lzdGVyZWQ6IHRoZVxuICAgIC8vIHRva2VuVmVyc2lvbiBjaGVjayBiZWxvdyBpcyBhIG5vLW9wIHdpdGhvdXQgYSBzdG9yZSwgYnV0IGZvciBhIHNlc3Npb25cbiAgICAvLyB0aGF0IHdvdWxkIHNpbGVudGx5IG1lYW4gXCJuZXZlciByZXZva2VkXCIuIEhlcmUgbm8gc3RvcmUg4oeSIHVuYXZhaWxhYmxlIOKHklxuICAgIC8vIHJlamVjdGVkLiBTZWUgYFRva2VuUmV2b2NhdGlvblN0b3JlLmdldFNlc3Npb25SZXZvY2F0aW9uYC5cbiAgICBjb25zdCBpbXBlcnNvbmF0aW9uID0gaXNJbXBlcnNvbmF0aW9uU2Vzc2lvbihkZWNvZGVkKTtcbiAgICBpZiAoaW1wZXJzb25hdGlvbiB8fCAodG9rZW5SZXZvY2F0aW9uU3RvcmUgJiYgZGVjb2RlZC5zdWIgJiYgdHlwZW9mIGRlY29kZWQudG9rZW5WZXJzaW9uID09PSAnbnVtYmVyJykpIHtcbiAgICAgIC8vIGAuY2F0Y2gobmV4dClgIGZvcndhcmRzIGEgRE9XTlNUUkVBTSBzeW5jaHJvbm91cyB0aHJvdyBmcm9tIGBuZXh0KClgIHRvXG4gICAgICAvLyBFeHByZXNzJ3MgZXJyb3IgbWlkZGxld2FyZSDigJQgd2l0aG91dCBpdCwgdGhhdCB0aHJvdyB3b3VsZCBzdXJmYWNlIGFzIGFuXG4gICAgICAvLyB1bmhhbmRsZWQgcmVqZWN0aW9uICh0aGlzIGBuZXh0KClgIHJ1bnMgaW4gYSBtaWNyb3Rhc2ssIG91dHNpZGUgdGhlXG4gICAgICAvLyBzdXJyb3VuZGluZyB0cnkvY2F0Y2ggYW5kIEV4cHJlc3MncyBwZXItbGF5ZXIgZGlzcGF0Y2gpLiBUaGUgY2hlY2tzXG4gICAgICAvLyB0aGVtc2VsdmVzIG5ldmVyIHJlamVjdCwgc28gdGhlIGNhdGNoIG9ubHkgZXZlciBzZWVzIGEgZG93bnN0cmVhbSBlcnJvci5cbiAgICAgIChhc3luYyAoKSA9PiB7XG4gICAgICAgIGlmIChpbXBlcnNvbmF0aW9uKSB7XG4gICAgICAgICAgY29uc3Qgc3RhdGUgPSBhd2FpdCBzZXNzaW9uUmV2b2NhdGlvblN0YXRlKGRlY29kZWQuanRpIGFzIHN0cmluZyk7XG4gICAgICAgICAgaWYgKHN0YXRlICE9PSAnbGl2ZScpIHtcbiAgICAgICAgICAgIHJldHVybiBzZW5kRXJyb3IoXG4gICAgICAgICAgICAgIHJlcyxcbiAgICAgICAgICAgICAgSHR0cFN0YXR1cy5VTkFVVEhPUklaRUQsXG4gICAgICAgICAgICAgIHN0YXRlID09PSAncmV2b2tlZCdcbiAgICAgICAgICAgICAgICA/ICdUaGlzIGltcGVyc29uYXRpb24gc2Vzc2lvbiBoYXMgYmVlbiBlbmRlZCdcbiAgICAgICAgICAgICAgICA6ICdUaGlzIGltcGVyc29uYXRpb24gc2Vzc2lvbiBjb3VsZCBub3QgYmUgdmVyaWZpZWQnLFxuICAgICAgICAgICAgICBFcnJvckNvZGUuVE9LRU5fUkVWT0tFRCxcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGlmICh0b2tlblJldm9jYXRpb25TdG9yZSAmJiBkZWNvZGVkLnN1YiAmJiB0eXBlb2YgZGVjb2RlZC50b2tlblZlcnNpb24gPT09ICdudW1iZXInICYmIGF3YWl0IGlzVG9rZW5SZXZva2VkKGRlY29kZWQpKSB7XG4gICAgICAgICAgcmV0dXJuIHNlbmRFcnJvcihyZXMsIEh0dHBTdGF0dXMuVU5BVVRIT1JJWkVELCAnU2Vzc2lvbiBoYXMgYmVlbiByZXZva2VkOyBwbGVhc2Ugc2lnbiBpbiBhZ2FpbicsIEVycm9yQ29kZS5UT0tFTl9SRVZPS0VEKTtcbiAgICAgICAgfVxuICAgICAgICBuZXh0KCk7XG4gICAgICB9KSgpLmNhdGNoKG5leHQpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIG5leHQoKTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBqd3QuVG9rZW5FeHBpcmVkRXJyb3IpIHtcbiAgICAgIHJldHVybiBzZW5kRXJyb3IocmVzLCBIdHRwU3RhdHVzLlVOQVVUSE9SSVpFRCwgJ1Rva2VuIGhhcyBleHBpcmVkJywgRXJyb3JDb2RlLlRPS0VOX0VYUElSRUQpO1xuICAgIH1cblxuICAgIC8vIFRoZSBzaWduaW5nIGtleXMgY291bGRuJ3QgYmUgZmV0Y2hlZCwgc28gdGhlIHRva2VuJ3MgdmFsaWRpdHkgaXMgVU5LTk9XTi5cbiAgICAvLyBGYWlsIENMT1NFRCB3aXRoIGEgcmV0cnlhYmxlIDUwMyDigJQgbmV2ZXIgYSBwYXNzLCBhbmQgbmV2ZXIgYSA0MDEgdGhhdFxuICAgIC8vIHdvdWxkIHNlbmQgYSBsZWdpdGltYXRlIGNsaWVudCBvZmYgdG8gcmUtYXV0aGVudGljYXRlIG92ZXIgb3VyIG91dGFnZS5cbiAgICAvLyBTYW1lIHJlYXNvbmluZyBmb3IgdGhlIFNFUlZJQ0UgY2hhaW46IG5vIHJlYWRhYmxlIGtleSBidW5kbGUgbWVhbnMgbm8gd2F5XG4gICAgLy8gdG8gdGVsbCBhIHBlZXIncyB0b2tlbiBmcm9tIGEgZm9yZ2VyeSwgc28gdGhlIHJlcXVlc3QgaXMgcmVmdXNlZCB3aXRoIGFcbiAgICAvLyByZXRyeWFibGUgNTAzIHJhdGhlciB0aGFuIGFkbWl0dGVkIG9yIGJvdW5jZWQgdG8gcmUtYXV0aGVudGljYXRlLlxuICAgIGlmIChlcnJvciBpbnN0YW5jZW9mIEp3a3NVbmF2YWlsYWJsZUVycm9yIHx8IGVycm9yIGluc3RhbmNlb2YgU2VydmljZUtleUVycm9yKSB7XG4gICAgICBsb2dnZXIud2FybignUmVqZWN0aW5nIHJlcXVlc3Q6IHRva2VuIHNpZ25pbmcga2V5cyB1bmF2YWlsYWJsZScsIHsgZXJyb3I6IGVycm9yLm1lc3NhZ2UgfSk7XG4gICAgICByZXR1cm4gc2VuZEVycm9yKFxuICAgICAgICByZXMsIEh0dHBTdGF0dXMuU0VSVklDRV9VTkFWQUlMQUJMRSxcbiAgICAgICAgJ1Rva2VuIHZlcmlmaWNhdGlvbiBpcyB0ZW1wb3JhcmlseSB1bmF2YWlsYWJsZTsgcGxlYXNlIHJldHJ5JyxcbiAgICAgICAgRXJyb3JDb2RlLlNFUlZJQ0VfVU5BVkFJTEFCTEUsXG4gICAgICApO1xuICAgIH1cblxuICAgIGlmIChlcnJvciBpbnN0YW5jZW9mIFVua25vd25LaWRFcnJvciB8fCBlcnJvciBpbnN0YW5jZW9mIGp3dC5Kc29uV2ViVG9rZW5FcnJvcikge1xuICAgICAgcmV0dXJuIHNlbmRFcnJvcihyZXMsIEh0dHBTdGF0dXMuVU5BVVRIT1JJWkVELCAnSW52YWxpZCB0b2tlbicsIEVycm9yQ29kZS5UT0tFTl9JTlZBTElEKTtcbiAgICB9XG5cbiAgICByZXR1cm4gc2VuZEVycm9yKHJlcywgSHR0cFN0YXR1cy5VTkFVVEhPUklaRUQsICdBdXRoZW50aWNhdGlvbiBmYWlsZWQnLCBFcnJvckNvZGUuVU5BVVRIT1JJWkVEKTtcbiAgfVxufVxuXG4vKipcbiAqIFdoZXRoZXIgYSBzZXQgb2YgdmVyaWZpZWQgY2xhaW1zIHNwZWFrcyBmb3IgYSBQRVJTT04ncyBvd24gc2Vzc2lvbiDigJQgdGhlIG9ubHlcbiAqIGtpbmQgb2YgY3JlZGVudGlhbCBhbiBhc3N1cmFuY2UgbGV2ZWwgY2FuIGJlIGFzc2VydGVkIGFib3V0LlxuICpcbiAqIEV4Y2x1ZGVzIGFsbCB0aHJlZSBtYWNoaW5lIHNoYXBlczogYW4gaW50ZXJuYWwgc2VydmljZSBwcmluY2lwYWwsIGFuIG9yZ1xuICogc2VydmljZSBhY2NvdW50LCBhbmQgYW55IGV4Y2hhbmdlZCBhY2Nlc3Mga2V5IChgdG9rZW5fdXNlOiAnYXBpX2tleSdgLCBpLmUuIGFcbiAqIFBBVCBvciBhIHNlcnZpY2UtYWNjb3VudCBrZXkpLCBlYWNoIG9mIHdoaWNoIGF1dGhlbnRpY2F0ZXMgYSBwcm9ncmFtIGhvbGRpbmcgYVxuICogc2VjcmV0IHJhdGhlciB0aGFuIGEgcGVyc29uIHByZXNlbnRpbmcgZmFjdG9ycy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzSHVtYW5QcmluY2lwYWwoY2xhaW1zOiBQaWNrPEp3dFBheWxvYWQsICdwcmluY2lwYWxUeXBlJyB8ICd0b2tlbl91c2UnPiB8IHVuZGVmaW5lZCk6IGJvb2xlYW4ge1xuICByZXR1cm4gY2xhaW1zPy5wcmluY2lwYWxUeXBlID09PSAndXNlcicgJiYgY2xhaW1zLnRva2VuX3VzZSA9PT0gJ2FjY2Vzcyc7XG59XG5cbi8qKiBXaGF0IGFuIGFzc3VyYW5jZSBnYXRlIGRlbWFuZHMuICovXG5leHBvcnQgaW50ZXJmYWNlIEFzc3VyYW5jZU9wdGlvbnMge1xuICBtaW5Bc3N1cmFuY2U6IEFzc3VyYW5jZUxldmVsO1xuICBtYXhBZ2U/OiBudW1iZXI7XG59XG5cbi8qKlxuICogU3RhbmRhbG9uZSBhc3N1cmFuY2UgZ2F0ZSwgZm9yIGEgc2VydmljZSB3aG9zZSBvd24gYHJlcXVpcmVBdXRoYCBpcyBub3RcbiAqIGFwaS1jb3JlJ3MgKHBsYXRmb3JtJ3MgaXMgaXRzIG93biwgYmVjYXVzZSBpdCByZWFkcyBNb25nbykuIENvbXBvc2UgaXQgQUZURVJcbiAqIGF1dGhlbnRpY2F0aW9uOiBgcm91dGVyLmdldCgnL3gnLCByZXF1aXJlQXV0aCwgcmVxdWlyZUFzc3VyYW5jZSh7IG1pbkFzc3VyYW5jZTogMiB9KSwgaClgLlxuICpcbiAqIElkZW50aWNhbCBydWxlcyBhbmQgaWRlbnRpY2FsIHJlZnVzYWxzIHRvIGByZXF1aXJlQXV0aCh7IG1pbkFzc3VyYW5jZSB9KWAg4oCUXG4gKiB0aGF0IG9wdGlvbiBzaW1wbHkgY2FsbHMgdGhlIHNhbWUgY2hlY2sgaW5saW5lLCBzbyB0aGVyZSBpcyBvbmUgaW1wbGVtZW50YXRpb25cbiAqIG9mIFwiaXMgdGhpcyBzZXNzaW9uIE1GQS1ncmFkZVwiIGluIHRoZSBjb2RlYmFzZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlcXVpcmVBc3N1cmFuY2Uob3B0aW9uczogQXNzdXJhbmNlT3B0aW9ucykge1xuICByZXR1cm4gdGFnUm91dGVHYXRlKChyZXE6IFJlcXVlc3QsIHJlczogUmVzcG9uc2UsIG5leHQ6IE5leHRGdW5jdGlvbik6IHZvaWQgPT4ge1xuICAgIGlmICghcmVxLnVzZXIpIHtcbiAgICAgIHJldHVybiBzZW5kRXJyb3IocmVzLCBIdHRwU3RhdHVzLlVOQVVUSE9SSVpFRCwgJ0F1dGhlbnRpY2F0aW9uIHJlcXVpcmVkJywgRXJyb3JDb2RlLlVOQVVUSE9SSVpFRCk7XG4gICAgfVxuICAgIGlmIChyZWZ1c2VGb3JBc3N1cmFuY2Uob3B0aW9ucywgcmVxLnVzZXIgYXMgSnd0UGF5bG9hZCwgcmVxLCByZXMpKSByZXR1cm47XG4gICAgbmV4dCgpO1xuICB9LCB7IGtpbmQ6ICdhc3N1cmFuY2UnLCBtaW5Bc3N1cmFuY2U6IG9wdGlvbnMubWluQXNzdXJhbmNlLCAuLi4ob3B0aW9ucy5tYXhBZ2UgIT09IHVuZGVmaW5lZCA/IHsgbWF4QWdlOiBvcHRpb25zLm1heEFnZSB9IDoge30pIH0pO1xufVxuXG4vKipcbiAqIEVuZm9yY2UgYG1pbkFzc3VyYW5jZWAgLyBgbWF4QWdlYCBvbiBhIHZlcmlmaWVkIHRva2VuLiBSZXR1cm5zIHRydWUgd2hlbiB0aGVcbiAqIHJlcXVlc3Qgd2FzIFJFRlVTRUQgKGEgcmVzcG9uc2UgaGFzIGJlZW4gc2VudCkuXG4gKlxuICogVGhyZWUgZGlzdGluY3QgcmVmdXNhbHMsIGJlY2F1c2UgdGhlIGNsaWVudCdzIG5leHQgbW92ZSBkaWZmZXJzIGZvciBlYWNoOlxuICogYSBtYWNoaW5lIG11c3Qgc3RvcCAoNDAzKSwgYSB3ZWFrIHNlc3Npb24gbXVzdCBnYWluIGEgZmFjdG9yICg0MDFcbiAqIGBNRkFfUkVRVUlSRURgIOKGkiBlbnJvbG1lbnQsIG5ldmVyIGEgc2lnbi1vdXQpLCBhbmQgYSBzdGFsZSBvbmUgbXVzdCBzaW1wbHlcbiAqIGF1dGhlbnRpY2F0ZSBhZ2FpbiAoNDAxIGBSRUFVVEhfUkVRVUlSRURgKS5cbiAqL1xuZnVuY3Rpb24gcmVmdXNlRm9yQXNzdXJhbmNlKFxuICBvcHRpb25zOiBBc3N1cmFuY2VPcHRpb25zLFxuICBkZWNvZGVkOiBKd3RQYXlsb2FkLFxuICByZXE6IFJlcXVlc3QsXG4gIHJlczogUmVzcG9uc2UsXG4pOiBib29sZWFuIHtcbiAgY29uc3QgbWluQXNzdXJhbmNlID0gb3B0aW9ucy5taW5Bc3N1cmFuY2U7XG4gIGNvbnN0IHJlZnVzZSA9IChyZWFzb246IHN0cmluZywgc3RhdHVzOiBudW1iZXIsIG1lc3NhZ2U6IHN0cmluZywgY29kZTogRXJyb3JDb2RlKTogdHJ1ZSA9PiB7XG4gICAgZW1pdENvdW50ZXIoJ21mYV9lbmZvcmNlbWVudF9yZWZ1c2VkX3RvdGFsJywgeyBzZXJ2aWNlOiBzZXJ2aWNlSWRlbnRpdHkoKSwgcmVhc29uIH0pO1xuICAgIHJlY29yZEF1dGh6RGVuaWFsKHJlcSwgYGFzc3VyYW5jZToke21pbkFzc3VyYW5jZX1gKTtcbiAgICBzZW5kRXJyb3IocmVzLCBzdGF0dXMsIG1lc3NhZ2UsIGNvZGUpO1xuICAgIHJldHVybiB0cnVlO1xuICB9O1xuXG4gIGlmICghaXNIdW1hblByaW5jaXBhbChkZWNvZGVkKSkge1xuICAgIHJldHVybiByZWZ1c2UoXG4gICAgICAnbWFjaGluZV9wcmluY2lwYWwnLCBIdHRwU3RhdHVzLkZPUkJJRERFTixcbiAgICAgICdUaGlzIGFjdGlvbiByZXF1aXJlcyBhIHBlcnNvbiBzaWduZWQgaW4gd2l0aCB0d28tZmFjdG9yIGF1dGhlbnRpY2F0aW9uIOKAlCBBUEkga2V5cyBhbmQgc2VydmljZSBhY2NvdW50cyBjYW5ub3QgcGVyZm9ybSBpdCcsXG4gICAgICBFcnJvckNvZGUuSFVNQU5fU0VTU0lPTl9SRVFVSVJFRCxcbiAgICApO1xuICB9XG4gIGlmICgoZGVjb2RlZC5hYWwgPz8gMSkgPCBtaW5Bc3N1cmFuY2UpIHtcbiAgICByZXR1cm4gcmVmdXNlKFxuICAgICAgJ3dlYWtfc2Vzc2lvbicsIEh0dHBTdGF0dXMuVU5BVVRIT1JJWkVELFxuICAgICAgJ1RoaXMgYWN0aW9uIHJlcXVpcmVzIHR3by1mYWN0b3IgYXV0aGVudGljYXRpb24g4oCUIHNpZ24gaW4gYWdhaW4gd2l0aCBhIHBhc3NrZXkgb3IgYW4gYXV0aGVudGljYXRvciBjb2RlJyxcbiAgICAgIEVycm9yQ29kZS5NRkFfUkVRVUlSRUQsXG4gICAgKTtcbiAgfVxuICBpZiAob3B0aW9ucy5tYXhBZ2UgIT09IHVuZGVmaW5lZCkge1xuICAgIGNvbnN0IGF1dGhUaW1lID0gZGVjb2RlZC5hdXRoX3RpbWU7XG4gICAgLy8gTm8gYGF1dGhfdGltZWAgaXMgbm90IFwicmVjZW50IGVub3VnaCBieSBkZWZhdWx0XCIg4oCUIGBoYXNWYWxpZElkZW50aXR5Q2xhaW1zYFxuICAgIC8vIGFscmVhZHkgcmVxdWlyZXMgaXQgb24gYSB1c2VyIHRva2VuLCBzbyBhbiBhYnNlbnQgb25lIG1lYW5zIGEgdG9rZW4gdGhpc1xuICAgIC8vIGdhdGUgY2Fubm90IHJlYXNvbiBhYm91dC4gRmFpbCBjbG9zZWQuXG4gICAgaWYgKHR5cGVvZiBhdXRoVGltZSAhPT0gJ251bWJlcicgfHwgTWF0aC5mbG9vcihEYXRlLm5vdygpIC8gMTAwMCkgLSBhdXRoVGltZSA+IG9wdGlvbnMubWF4QWdlKSB7XG4gICAgICByZXR1cm4gcmVmdXNlKFxuICAgICAgICAnc3RhbGVfc2Vzc2lvbicsIEh0dHBTdGF0dXMuVU5BVVRIT1JJWkVELFxuICAgICAgICAnVGhpcyBhY3Rpb24gcmVxdWlyZXMgYSByZWNlbnQgc2lnbi1pbiDigJQgcGxlYXNlIGF1dGhlbnRpY2F0ZSBhZ2FpbicsXG4gICAgICAgIEVycm9yQ29kZS5SRUFVVEhfUkVRVUlSRUQsXG4gICAgICApO1xuICAgIH1cbiAgfVxuICByZXR1cm4gZmFsc2U7XG59XG5cbi8qKlxuICogV2hldGhlciBhIHZlcmlmaWVkIHRva2VuIGNhcnJpZXMgYSB3ZWxsLWZvcm1lZCBpZGVudGl0eTogYSBrbm93blxuICogYHByaW5jaXBhbFR5cGVgIGFuZCBgdG9rZW5fdXNlYCwgYW5kIHRoZSBjbGFpbXMgdGhhdCBraW5kIG9mIHByaW5jaXBhbCBtdXN0XG4gKiBoYXZlLiBGYWlscyBjbG9zZWQg4oCUIGEgdG9rZW4gbWludGVkIGJlZm9yZSB0aGVzZSBjbGFpbXMgZXhpc3RlZCwgb3Igb25lIHdpdGggYVxuICogY29udHJhZGljdG9yeSBjb21iaW5hdGlvbiwgaXMgbm90IGFuIGlkZW50aXR5IGFueSBnYXRlIHNob3VsZCByZWFzb24gYWJvdXQuXG4gKlxuICogLSBgc2VydmljZWA6IGB0b2tlbl91c2U6ICdhY2Nlc3MnYCBhbmQgYSBgc2VydmljZTo8bmFtZT5gIHN1YmplY3QgKHRoZSBuYW1lXG4gKiAgIGZlZWRzIHRoZSBkZW55bGlzdCBhbmQgYXVkaXQgYXR0cmlidXRpb24pLlxuICogLSBgdXNlcmAgLyBgc2VydmljZV9hY2NvdW50YDogYGFtcmAgKGtub3duIG1ldGhvZHMpLCBgYWFsYCBhbmQgYGF1dGhfdGltZWAuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBoYXNWYWxpZElkZW50aXR5Q2xhaW1zKGRlY29kZWQ6IFBhcnRpYWw8Snd0UGF5bG9hZD4pOiBib29sZWFuIHtcbiAgaWYgKCFkZWNvZGVkLnByaW5jaXBhbFR5cGUgfHwgIVBSSU5DSVBBTF9UWVBFUy5pbmNsdWRlcyhkZWNvZGVkLnByaW5jaXBhbFR5cGUpKSByZXR1cm4gZmFsc2U7XG4gIGlmICghZGVjb2RlZC50b2tlbl91c2UgfHwgIVRPS0VOX1VTRVMuaW5jbHVkZXMoZGVjb2RlZC50b2tlbl91c2UpKSByZXR1cm4gZmFsc2U7XG4gIGlmIChkZWNvZGVkLnByaW5jaXBhbFR5cGUgPT09ICdzZXJ2aWNlJykge1xuICAgIHJldHVybiBkZWNvZGVkLnRva2VuX3VzZSA9PT0gJ2FjY2VzcydcbiAgICAgICYmIHR5cGVvZiBkZWNvZGVkLnN1YiA9PT0gJ3N0cmluZydcbiAgICAgICYmIGRlY29kZWQuc3ViLnN0YXJ0c1dpdGgoU0VSVklDRV9TVUJKRUNUX1BSRUZJWClcbiAgICAgICYmIGRlY29kZWQuc3ViLmxlbmd0aCA+IFNFUlZJQ0VfU1VCSkVDVF9QUkVGSVgubGVuZ3RoO1xuICB9XG4gIHJldHVybiBBcnJheS5pc0FycmF5KGRlY29kZWQuYW1yKVxuICAgICYmIGRlY29kZWQuYW1yLmV2ZXJ5KChtKSA9PiBBVVRIX01FVEhPRFMuaW5jbHVkZXMobSkpXG4gICAgJiYgKGRlY29kZWQuYWFsID09PSAxIHx8IGRlY29kZWQuYWFsID09PSAyKVxuICAgICYmIHR5cGVvZiBkZWNvZGVkLmF1dGhfdGltZSA9PT0gJ251bWJlcic7XG59XG5cbi8qKlxuICogV2hldGhlciB0aGUgcmVxdWVzdCdzIHVzZXIgaG9sZHMgYHBlcm1pc3Npb25gLiBTdXBlcmFkbWlucyBpbXBsaWNpdGx5IGhvbGRcbiAqIGV2ZXJ5IHBlcm1pc3Npb24uIFJlYWRzIHRoZSByZXNvbHZlZCBgcGVybWlzc2lvbnNgIGNsYWltIChzZXQgYXQgdG9rZW4gaXNzdWUsXG4gKiBvciByZS1kZXJpdmVkIHBlciByZXF1ZXN0IGJ5IHRoZSBwbGF0Zm9ybSkuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB1c2VySGFzUGVybWlzc2lvbihyZXE6IFJlcXVlc3QsIHBlcm1pc3Npb246IFBlcm1pc3Npb24pOiBib29sZWFuIHtcbiAgcmV0dXJuIGhhc1Blcm1pc3Npb24ocmVxLnVzZXI/LnBlcm1pc3Npb25zLCBwZXJtaXNzaW9uLCByZXEudXNlcj8uaXNTdXBlckFkbWluKTtcbn1cblxuLyoqXG4gKiBDb250ZXh0IHBhc3NlZCB0byBhIHJlZ2lzdGVyZWQgYXV0aG9yaXphdGlvbi1kZW5pYWwgYXVkaXRvciB3aGVuIGFcbiAqIHN0YXRlLWNoYW5naW5nIHJlcXVlc3QgaXMgcmVqZWN0ZWQgYnkgYHJlcXVpcmVQZXJtaXNzaW9uYCAvXG4gKiBgcmVxdWlyZVN5c3RlbUFkbWluYC5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBBdXRoekRlbmlhbEluZm8ge1xuICAvKiogVGhlIGRlbmllZCB1c2VyJ3MgaWQgKGBzdWJgKSwgaWYgYXV0aGVudGljYXRlZC4gKi9cbiAgYWN0b3JJZD86IHN0cmluZztcbiAgYWN0b3JFbWFpbD86IHN0cmluZztcbiAgLyoqIFRoZSB1c2VyJ3MgYWN0aXZlIG9yZyBhdCBkZW5pYWwgdGltZS4gKi9cbiAgb3JnSWQ/OiBzdHJpbmc7XG4gIC8qKiBIVFRQIG1ldGhvZCArIHBhdGggb2YgdGhlIHJlamVjdGVkIHJlcXVlc3QuICovXG4gIG1ldGhvZDogc3RyaW5nO1xuICBwYXRoOiBzdHJpbmc7XG4gIC8qKiBXaGF0IHdhcyByZXF1aXJlZDogdGhlIG1pc3NpbmcgcGVybWlzc2lvbihzKSwgb3IgJ3N5c3RlbS1hZG1pbicuICovXG4gIHJlcXVpcmVkOiBzdHJpbmc7XG59XG5cbi8qKlxuICogT3B0aW9uYWwgc2luayBmb3IgZGVuaWVkLWF1dGhvcml6YXRpb24gZXZlbnRzLiBMZWZ0IHVuc2V0IGJ5IGRlZmF1bHQgc29cbiAqIGFwaS1jb3JlIHN0YXlzIGRlY291cGxlZCBmcm9tIGFueSBhdWRpdCB0cmFuc3BvcnQg4oCUIGEgc2VydmljZSByZWdpc3RlcnMgb25lXG4gKiBhdCBib290ICh0eXBpY2FsbHkgZm9yd2FyZGluZyB0byBpdHMgYFJlbW90ZUF1ZGl0Q2xpZW50YCBhcyBhblxuICogYGF1dGh6LmRlbmllZGAgZXZlbnQsIG9yLCBvbiBwbGF0Zm9ybSwgdG8gdGhlIGxvY2FsIGBhdWRpdCgpYCBoZWxwZXIpLlxuICogTVVTVCBiZSBiZXN0LWVmZm9ydDogaXQgaXMgaW52b2tlZCBpbnNpZGUgdGhlIHJlcXVlc3QgcGF0aCwgc28gaXQgbXVzdCBuZXZlclxuICogdGhyb3cgb3IgYmxvY2sgKHRoZSBnYXRlIHdyYXBzIHRoZSBjYWxsIGluIHRyeS9jYXRjaCByZWdhcmRsZXNzKS5cbiAqL1xubGV0IGF1dGh6RGVuaWFsQXVkaXRvcjogKChpbmZvOiBBdXRoekRlbmlhbEluZm8pID0+IHZvaWQpIHwgdW5kZWZpbmVkO1xuXG4vKipcbiAqIFJlZ2lzdGVyIChvciBjbGVhciwgd2l0aCBgdW5kZWZpbmVkYCkgdGhlIHByb2Nlc3Mtd2lkZSBhdXRob3JpemF0aW9uLWRlbmlhbFxuICogYXVkaXRvci4gSWRlbXBvdGVudDsgdGhlIGxhc3QgcmVnaXN0cmF0aW9uIHdpbnMuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzZXRBdXRoekRlbmlhbEF1ZGl0b3IoZm46ICgoaW5mbzogQXV0aHpEZW5pYWxJbmZvKSA9PiB2b2lkKSB8IHVuZGVmaW5lZCk6IHZvaWQge1xuICBhdXRoekRlbmlhbEF1ZGl0b3IgPSBmbjtcbn1cblxuLyoqXG4gKiBFbWl0IGEgZGVuaWFsIGV2ZW50LCBiZXN0LWVmZm9ydC4gT25seSBmaXJlcyBmb3Igc3RhdGUtY2hhbmdpbmcgKG5vbi1HRVQsXG4gKiBub24tSEVBRC9PUFRJT05TKSByZXF1ZXN0cyDigJQgYSByZWplY3RlZCBHRVQgaXMgbG93LXNpZ25hbCBwcm9iaW5nIG5vaXNlIGFuZFxuICogd291bGQgYW1wbGlmeSBhdWRpdCB2b2x1bWUgdW5kZXIgYSBzY2FuLiBOZXZlciB0aHJvd3MuXG4gKlxuICogVGhlIHBlcm1pc3Npb24gZ2F0ZXMgaGVyZSBjYWxsIGl0IHRoZW1zZWx2ZXMuIEV4cG9ydCBpdCBmb3IgZGF0YS1kcml2ZW4gY2hlY2tzXG4gKiBhIHJvdXRlIG1ha2VzIGlubGluZSAoY3Jvc3Mtb3JnIGFjY2Vzcywgc2VydmljZS1vbmx5IGVuZHBvaW50cyksIHNvIHRob3NlIDQwM3NcbiAqIHJlYWNoIHRoZSBzYW1lIGBhdXRoei5kZW5pZWRgIHRyYWlsLiBgcmVxdWlyZWRgIG5hbWVzIHdoYXQgd2FzIG1pc3NpbmcuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZWNvcmRBdXRoekRlbmlhbChyZXE6IFJlcXVlc3QsIHJlcXVpcmVkOiBzdHJpbmcpOiB2b2lkIHtcbiAgY29uc3QgYXVkaXRvciA9IGF1dGh6RGVuaWFsQXVkaXRvcjtcbiAgaWYgKCFhdWRpdG9yKSByZXR1cm47XG4gIGNvbnN0IG1ldGhvZCA9IHJlcS5tZXRob2QudG9VcHBlckNhc2UoKTtcbiAgaWYgKG1ldGhvZCA9PT0gJ0dFVCcgfHwgbWV0aG9kID09PSAnSEVBRCcgfHwgbWV0aG9kID09PSAnT1BUSU9OUycpIHJldHVybjtcbiAgdHJ5IHtcbiAgICBhdWRpdG9yKHtcbiAgICAgIGFjdG9ySWQ6IHJlcS51c2VyPy5zdWIsXG4gICAgICBhY3RvckVtYWlsOiByZXEudXNlcj8uZW1haWwsXG4gICAgICBvcmdJZDogcmVxLnVzZXI/Lm9yZ2FuaXphdGlvbklkLFxuICAgICAgbWV0aG9kLFxuICAgICAgLy8gU3RyaXAgdGhlIHF1ZXJ5IHN0cmluZyDigJQgYSBkZW5pZWQgcmVxdWVzdCBtYXkgY2FycnkgYSB0b2tlbi9zZWNyZXQgYXMgYVxuICAgICAgLy8gcXVlcnkgcGFyYW0sIGFuZCB0aGlzIHBhdGggaXMgcGVyc2lzdGVkIHZlcmJhdGltIGludG8gdGhlIGF1ZGl0IGxvZy5cbiAgICAgIHBhdGg6IChyZXEub3JpZ2luYWxVcmwgfHwgcmVxLnVybCkuc3BsaXQoJz8nKVswXSxcbiAgICAgIHJlcXVpcmVkLFxuICAgIH0pO1xuICB9IGNhdGNoIHtcbiAgICAvLyBCZXN0LWVmZm9ydCDigJQgYSBicm9rZW4gYXVkaXRvciBtdXN0IG5ldmVyIGJyZWFrIHRoZSBhdXRoIGdhdGUuXG4gIH1cbn1cblxuLyoqXG4gKiBSZXF1aXJlcyB0aGF0IHRoZSB1c2VyIGhvbGQgQVQgTEVBU1QgT05FIG9mIHRoZSBnaXZlbiBwZXJtaXNzaW9ucyAob3IgYmUgYVxuICogc3VwZXJhZG1pbikuIFVzZSBhZnRlciByZXF1aXJlQXV0aC4gTWlycm9ycyBgcmVxdWlyZVJvbGVgJ3MgYW55LW9mIHNlbWFudGljcztcbiAqIHBhc3MgYSBzaW5nbGUgcGVybWlzc2lvbiBmb3IgYSBzcGVjaWZpYyBhY3Rpb24sIG9yIHNldmVyYWwgd2hlbiBhbnkgb25lIG9mXG4gKiB0aGVtIHNob3VsZCBncmFudCBhY2Nlc3MuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXF1aXJlUGVybWlzc2lvbiguLi5wZXJtaXNzaW9uczogUGVybWlzc2lvbltdKSB7XG4gIHJldHVybiB0YWdSb3V0ZUdhdGUoKHJlcTogUmVxdWVzdCwgcmVzOiBSZXNwb25zZSwgbmV4dDogTmV4dEZ1bmN0aW9uKTogdm9pZCA9PiB7XG4gICAgaWYgKCFyZXEudXNlcikge1xuICAgICAgcmV0dXJuIHNlbmRFcnJvcihyZXMsIEh0dHBTdGF0dXMuVU5BVVRIT1JJWkVELCAnQXV0aGVudGljYXRpb24gcmVxdWlyZWQnLCBFcnJvckNvZGUuVU5BVVRIT1JJWkVEKTtcbiAgICB9XG4gICAgLy8gdXNlckhhc1Blcm1pc3Npb24g4oaSIGhhc1Blcm1pc3Npb24gYWxyZWFkeSBncmFudHMgc3VwZXJhZG1pbnMgZXZlcnlcbiAgICAvLyBwZXJtaXNzaW9uLCBzbyB0aGlzIHNpbmdsZSBjaGVjayBjb3ZlcnMgYm90aCB0aGUgc3VwZXJhZG1pbiBieXBhc3MgYW5kXG4gICAgLy8gdGhlIGFueS1vZiBtZW1iZXJzaGlwIHRlc3Qgd2l0aG91dCByZS1pbmxpbmluZyBlaXRoZXIuXG4gICAgaWYgKHBlcm1pc3Npb25zLnNvbWUoKHApID0+IHVzZXJIYXNQZXJtaXNzaW9uKHJlcSwgcCkpKSByZXR1cm4gbmV4dCgpO1xuICAgIHJlY29yZEF1dGh6RGVuaWFsKHJlcSwgcGVybWlzc2lvbnMuam9pbignIG9yICcpKTtcbiAgICByZXR1cm4gc2VuZEVycm9yKFxuICAgICAgcmVzLCBIdHRwU3RhdHVzLkZPUkJJRERFTixcbiAgICAgIGBNaXNzaW5nIHJlcXVpcmVkIHBlcm1pc3Npb246ICR7cGVybWlzc2lvbnMuam9pbignIG9yICcpfWAsXG4gICAgICBFcnJvckNvZGUuSU5TVUZGSUNJRU5UX1BFUk1JU1NJT05TLFxuICAgICk7XG4gIH0sIHsga2luZDogJ3Blcm1pc3Npb24nLCBtb2RlOiAnYW55JywgcGVybWlzc2lvbnMgfSk7XG59XG5cbi8qKlxuICogUmVxdWlyZXMgdGhhdCB0aGUgdXNlciBob2xkIEVWRVJZIG9uZSBvZiB0aGUgZ2l2ZW4gcGVybWlzc2lvbnMgKG9yIGJlIGFcbiAqIHN1cGVyYWRtaW4pIOKAlCB0aGUgQU5EIGNvdW50ZXJwYXJ0IHRvIGByZXF1aXJlUGVybWlzc2lvbmAncyBhbnktb2YuIFVzZSBmb3IgYVxuICogc2Vuc2l0aXZlIGFjdGlvbiB0aGF0IGxlZ2l0aW1hdGVseSBkZW1hbmRzIHR3byBkaXN0aW5jdCBjYXBhYmlsaXRpZXMgYXQgb25jZVxuICogKGUuZy4gYSBjcm9zcy1zdXJmYWNlIG9wZXJhdGlvbiksIHNvIHRoZSBndWFyYW50ZWUgaXMgZXhwbGljaXQgcmF0aGVyIHRoYW5cbiAqIGFwcHJveGltYXRlZCBieSBjaGFpbmluZyB0d28gYHJlcXVpcmVQZXJtaXNzaW9uYCBnYXRlcy4gU3VwZXJhZG1pbnMgYnlwYXNzXG4gKiAodGhleSBpbXBsaWNpdGx5IGhvbGQgZXZlcnkgcGVybWlzc2lvbikuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXF1aXJlQWxsUGVybWlzc2lvbnMoLi4ucGVybWlzc2lvbnM6IFBlcm1pc3Npb25bXSkge1xuICByZXR1cm4gdGFnUm91dGVHYXRlKChyZXE6IFJlcXVlc3QsIHJlczogUmVzcG9uc2UsIG5leHQ6IE5leHRGdW5jdGlvbik6IHZvaWQgPT4ge1xuICAgIGlmICghcmVxLnVzZXIpIHtcbiAgICAgIHJldHVybiBzZW5kRXJyb3IocmVzLCBIdHRwU3RhdHVzLlVOQVVUSE9SSVpFRCwgJ0F1dGhlbnRpY2F0aW9uIHJlcXVpcmVkJywgRXJyb3JDb2RlLlVOQVVUSE9SSVpFRCk7XG4gICAgfVxuICAgIGNvbnN0IG1pc3NpbmcgPSBwZXJtaXNzaW9ucy5maWx0ZXIoKHApID0+ICF1c2VySGFzUGVybWlzc2lvbihyZXEsIHApKTtcbiAgICBpZiAobWlzc2luZy5sZW5ndGggPT09IDApIHJldHVybiBuZXh0KCk7XG4gICAgcmVjb3JkQXV0aHpEZW5pYWwocmVxLCBwZXJtaXNzaW9ucy5qb2luKCcgYW5kICcpKTtcbiAgICByZXR1cm4gc2VuZEVycm9yKFxuICAgICAgcmVzLCBIdHRwU3RhdHVzLkZPUkJJRERFTixcbiAgICAgIGBNaXNzaW5nIHJlcXVpcmVkIHBlcm1pc3Npb246ICR7bWlzc2luZy5qb2luKCcgYW5kICcpfWAsXG4gICAgICBFcnJvckNvZGUuSU5TVUZGSUNJRU5UX1BFUk1JU1NJT05TLFxuICAgICk7XG4gIH0sIHsga2luZDogJ3Blcm1pc3Npb24nLCBtb2RlOiAnYWxsJywgcGVybWlzc2lvbnMgfSk7XG59XG5cbi8qKlxuICogTGlrZSB7QGxpbmsgcmVxdWlyZVBlcm1pc3Npb259IChhbnktb2YpIGJ1dCBBTFNPIGFkbWl0cyBhbiBpbnRlcm5hbCBzZXJ2aWNlXG4gKiBwcmluY2lwYWwgKGBwcmluY2lwYWxUeXBlOiAnc2VydmljZSdgKS4gRm9yIFJFQUQgZW5kcG9pbnRzIHRoYXQgQk9USFxuICogaW50ZXJhY3RpdmUgdXNlcnMg4oCUIHdobyBtdXN0IGhvbGQgb25lIG9mIHRoZSBgOnJlYWRgIGNhcGFiaWxpdGllcyDigJQgQU5EXG4gKiBzZXJ2aWNlLXRvLXNlcnZpY2UgY2FsbGVycyBsZWdpdGltYXRlbHkgaGl0OyBzZXJ2aWNlIHRva2VucyBjYXJyeSBub1xuICogcGVybWlzc2lvbiBjbGFpbXMgKHRoZXkncmUgbGVhc3QtcHJpdmlsZWdlIGByb2xlOm1lbWJlcmApLCBzbyBhIHBsYWluXG4gKiBgcmVxdWlyZVBlcm1pc3Npb25gIHdvdWxkIHdyb25nbHkgNDAzIHRoZW0uIFN1cGVyYWRtaW5zIHBhc3MgdmlhXG4gKiBgdXNlckhhc1Blcm1pc3Npb25gJ3MgaW1wbGljaXQtYWxsLiBVc2Ugb25seSB3aGVyZSBhIHNlcnZpY2UgY2FsbGVyIGlzIGEga25vd24sXG4gKiBpbnRlbmRlZCBjb25zdW1lciBvZiB0aGUgcm91dGUgKHZlcmlmeSB0aGUgY2FsbGVycyk7IHByZWZlciBwbGFpblxuICogYHJlcXVpcmVQZXJtaXNzaW9uYCBmb3IgcHVyZWx5IHVzZXItZmFjaW5nIHJlYWRzLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVxdWlyZVBlcm1pc3Npb25PclNlcnZpY2UoLi4ucGVybWlzc2lvbnM6IFBlcm1pc3Npb25bXSkge1xuICByZXR1cm4gdGFnUm91dGVHYXRlKChyZXE6IFJlcXVlc3QsIHJlczogUmVzcG9uc2UsIG5leHQ6IE5leHRGdW5jdGlvbik6IHZvaWQgPT4ge1xuICAgIGlmICghcmVxLnVzZXIpIHtcbiAgICAgIHJldHVybiBzZW5kRXJyb3IocmVzLCBIdHRwU3RhdHVzLlVOQVVUSE9SSVpFRCwgJ0F1dGhlbnRpY2F0aW9uIHJlcXVpcmVkJywgRXJyb3JDb2RlLlVOQVVUSE9SSVpFRCk7XG4gICAgfVxuICAgIGlmIChpc1NlcnZpY2VQcmluY2lwYWwocmVxKSB8fCBwZXJtaXNzaW9ucy5zb21lKChwKSA9PiB1c2VySGFzUGVybWlzc2lvbihyZXEsIHApKSkgcmV0dXJuIG5leHQoKTtcbiAgICByZWNvcmRBdXRoekRlbmlhbChyZXEsIHBlcm1pc3Npb25zLmpvaW4oJyBvciAnKSk7XG4gICAgcmV0dXJuIHNlbmRFcnJvcihcbiAgICAgIHJlcywgSHR0cFN0YXR1cy5GT1JCSURERU4sXG4gICAgICBgTWlzc2luZyByZXF1aXJlZCBwZXJtaXNzaW9uOiAke3Blcm1pc3Npb25zLmpvaW4oJyBvciAnKX1gLFxuICAgICAgRXJyb3JDb2RlLklOU1VGRklDSUVOVF9QRVJNSVNTSU9OUyxcbiAgICApO1xuICB9LCB7IGtpbmQ6ICdwZXJtaXNzaW9uJywgbW9kZTogJ2FueScsIHBlcm1pc3Npb25zLCBhbGxvd1NlcnZpY2U6IHRydWUgfSk7XG59XG5cbi8qKlxuICogR2F0ZSBhbiBlbmRwb2ludCB0byBpbnRlcm5hbCBzZXJ2aWNlLXRvLXNlcnZpY2UgY2FsbGVycyBvbmx5IChhXG4gKiBgcHJpbmNpcGFsVHlwZTogJ3NlcnZpY2UnYCBwcmluY2lwYWwgbWludGVkIHZpYSB7QGxpbmsgc2lnblNlcnZpY2VUb2tlbn0gLyBgZ2V0U2VydmljZUF1dGhIZWFkZXJgKS5cbiAqIFJlamVjdHMgYW55IHVzZXIgdG9rZW4uIEZvciBOT04tdXNlci1mYWNpbmcgZW5kcG9pbnRzIOKAlCBlbnRpdHktZXZlbnQgaW5nZXN0LFxuICogYXV0by1zdWJzY3JpYmUsIGFuZCBzaW1pbGFyIHBlZXItc2VydmljZSBob29rcyDigJQgdGhhdCBhIGJyb3dzZXIgbXVzdCBuZXZlclxuICogcmVhY2guIENvbXBvc2UgYWZ0ZXIgYHJlcXVpcmVBdXRoYCBzbyBgcmVxLnVzZXJgIGlzIHBvcHVsYXRlZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlcXVpcmVTZXJ2aWNlUHJpbmNpcGFsKHJlcTogUmVxdWVzdCwgcmVzOiBSZXNwb25zZSwgbmV4dDogTmV4dEZ1bmN0aW9uKTogdm9pZCB7XG4gIGlmICghaXNTZXJ2aWNlUHJpbmNpcGFsKHJlcSkpIHtcbiAgICAvLyA0MDMgKG5vdCA0MDApIOKAlCB0aGlzIGlzIGFuIGF1dGhvcml6YXRpb24gcmVmdXNhbDsgc3RhdHVzIG11c3QgbWF0Y2ggdGhlXG4gICAgLy8gSU5TVUZGSUNJRU5UX1BFUk1JU1NJT05TIGNvZGUgYW5kIHRoZSBzaWJsaW5nIGdhdGVzIChyZXF1aXJlUGVybWlzc2lvbiwgZXRjLikuXG4gICAgcmV0dXJuIHNlbmRFcnJvcihyZXMsIEh0dHBTdGF0dXMuRk9SQklEREVOLCAnSW50ZXJuYWwgc2VydmljZSBjYWxscyBvbmx5JywgRXJyb3JDb2RlLklOU1VGRklDSUVOVF9QRVJNSVNTSU9OUyk7XG4gIH1cbiAgbmV4dCgpO1xufVxudGFnUm91dGVHYXRlKHJlcXVpcmVTZXJ2aWNlUHJpbmNpcGFsLCB7IGtpbmQ6ICdzZXJ2aWNlUHJpbmNpcGFsJyB9KTtcblxuLyoqXG4gKiBUSEUgZ2F0ZSBmb3IgYW4gSU5URVJOQUwgcm91dGUgKCMxNCkg4oCUIHRoZSBvbmUgZXZlcnkgYC9pbnRlcm5hbC8qYCBwYXRoLCB0aGVcbiAqIHF1b3RhIHVzYWdlIGNvdW50ZXJzLCB0aGUgZW50aXR5LWV2ZW50IGluZ2VzdCBhbmQgdGhlIGF1ZGl0IGluZ2VzdCBnbyB0aHJvdWdoLlxuICpcbiAqIFR3byBydWxlcywgYm90aCBmYWlsLWNsb3NlZDpcbiAqXG4gKiAgMS4gKipObyB1c2VyIHRva2VuLCBldmVyLioqIE5vdCBhIG1lbWJlcidzLCBub3QgYSBzdXBlcmFkbWluJ3MsIG5vdCBhXG4gKiAgICAgc2VydmljZS1hY2NvdW50IGtleSdzLiBBbiBpbnRlcm5hbCByb3V0ZSBpcyBhIHBlZXItc2VydmljZSBBUEkgc3VyZmFjZSwgc29cbiAqICAgICBcImEgc3VmZmljaWVudGx5IHByaXZpbGVnZWQgaHVtYW5cIiBpcyBub3QgYW4gYWNjZXB0YWJsZSBjYWxsZXIg4oCUIHRoYXRcbiAqICAgICBlcXVpdmFsZW5jZSBpcyBleGFjdGx5IGhvdyBhIGJyb3dzZXItcmVhY2hhYmxlIHBhdGggYmVjb21lcyBhIHRlbmFudFxuICogICAgIGJvdW5kYXJ5IGJ1Zy4gYHJlcXVpcmVTZXJ2aWNlUHJpbmNpcGFsYCBhbHJlYWR5IHJlZnVzZWQgdXNlcnM7IHRoaXMgYWxzb1xuICogICAgIGNsb3NlcyB0aGUgYHx8IGlzU3lzdGVtQWRtaW4ocmVxKWAgZXNjYXBlIGhhdGNoZXMgdGhhdCBoYWQgZ3Jvd24gYXJvdW5kXG4gKiAgICAgdGhlIGluZGl2aWR1YWwgaW50ZXJuYWwgcm91dGVzLlxuICogIDIuICoqT25seSB0aGUgTkFNRUQgY2FsbGVycy4qKiBgY2FsbGVyc2AgbGlzdHMgdGhlIHNlcnZpY2VzIHRoYXQgbGVnaXRpbWF0ZWx5XG4gKiAgICAgY2FsbCB0aGlzIHJvdXRlLCBhbmQgdGhlIG5hbWUgaXMgY3J5cHRvZ3JhcGhpY2FsbHkgYm91bmQgdG8gdGhlIHNpZ25pbmdcbiAqICAgICBrZXkgKGBzZXJ2aWNlcy9zZXJ2aWNlLWtleXMudHNgKSwgc28gdGhpcyBpcyBhbiBpZGVudGl0eSBjaGVjayByYXRoZXIgdGhhblxuICogICAgIGEgY2xhaW0gY2hlY2suIEl0IGlzIHRoZSBzYW1lIGFsbG93LWxpc3QgdGhlIG1lc2ggcG9saWN5IG5hbWVzLCBhdCB0aGVcbiAqICAgICBsYXllciB0aGF0IGFsc28gaG9sZHMgaW4gZG9ja2VyIGNvbXBvc2UsIHdoZXJlIHRoZXJlIGlzIG5vIG1lc2ggYXQgYWxsIOKAlFxuICogICAgIHRoZSBJc3RpbyBgQXV0aG9yaXphdGlvblBvbGljeWAgaXMgZGVmZW5jZSBpbiBkZXB0aCBvbiB0b3AsIG5ldmVyIHRoZVxuICogICAgIGVuZm9yY2VtZW50LlxuICpcbiAqIENvbXBvc2UgYWZ0ZXIgYHJlcXVpcmVBdXRoYCBzbyBgcmVxLnVzZXJgIGlzIHBvcHVsYXRlZC4gUmVmdXNhbHMgYXJlIGNvdW50ZWRcbiAqIChgaW50ZXJuYWxfcm91dGVfcmVmdXNlZF90b3RhbGApIGFuZCBhdWRpdGVkIHRocm91Z2ggdGhlIHNoYXJlZCBgYXV0aHouZGVuaWVkYFxuICogc2luay5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlcXVpcmVJbnRlcm5hbFNlcnZpY2Uob3B0aW9uczogeyBjYWxsZXJzOiByZWFkb25seSBzdHJpbmdbXSB9KSB7XG4gIGNvbnN0IGFsbG93ZWQgPSBuZXcgU2V0KG9wdGlvbnMuY2FsbGVycyk7XG4gIHJldHVybiB0YWdSb3V0ZUdhdGUoKHJlcTogUmVxdWVzdCwgcmVzOiBSZXNwb25zZSwgbmV4dDogTmV4dEZ1bmN0aW9uKTogdm9pZCA9PiB7XG4gICAgY29uc3QgcmVmdXNlID0gKHJlYXNvbjogJ3VuYXV0aGVudGljYXRlZCcgfCAndXNlcl90b2tlbicgfCAnd3JvbmdfY2FsbGVyJyk6IHZvaWQgPT4ge1xuICAgICAgZW1pdENvdW50ZXIoJ2ludGVybmFsX3JvdXRlX3JlZnVzZWRfdG90YWwnLCB7XG4gICAgICAgIHNlcnZpY2U6IHNlcnZpY2VJZGVudGl0eSgpLFxuICAgICAgICByb3V0ZTogcmVxLnJvdXRlPy5wYXRoID8gYCR7cmVxLm1ldGhvZH0gJHtyZXEuYmFzZVVybH0ke3JlcS5yb3V0ZS5wYXRofWAgOiBgJHtyZXEubWV0aG9kfSAkeyhyZXEub3JpZ2luYWxVcmwgfHwgcmVxLnVybCkuc3BsaXQoJz8nKVswXX1gLFxuICAgICAgICByZWFzb24sXG4gICAgICAgIGNhbGxlcjogc2VydmljZU5hbWVPZihyZXEudXNlcikgPz8gJ25vbmUnLFxuICAgICAgfSk7XG4gICAgICByZWNvcmRBdXRoekRlbmlhbChyZXEsIGBpbnRlcm5hbC1zZXJ2aWNlICgke29wdGlvbnMuY2FsbGVycy5qb2luKCcsICcpfSlgKTtcbiAgICAgIGlmIChyZWFzb24gPT09ICd1bmF1dGhlbnRpY2F0ZWQnKSB7XG4gICAgICAgIHJldHVybiBzZW5kRXJyb3IocmVzLCBIdHRwU3RhdHVzLlVOQVVUSE9SSVpFRCwgJ0F1dGhlbnRpY2F0aW9uIHJlcXVpcmVkJywgRXJyb3JDb2RlLlVOQVVUSE9SSVpFRCk7XG4gICAgICB9XG4gICAgICBsb2dnZXIud2FybignUmVmdXNlZCBhbiBpbnRlcm5hbCByb3V0ZScsIHsgcmVhc29uLCBwYXRoOiAocmVxLm9yaWdpbmFsVXJsIHx8IHJlcS51cmwpLnNwbGl0KCc/JylbMF0sIGNhbGxlcjogc2VydmljZU5hbWVPZihyZXEudXNlcikgfSk7XG4gICAgICByZXR1cm4gc2VuZEVycm9yKHJlcywgSHR0cFN0YXR1cy5GT1JCSURERU4sICdJbnRlcm5hbCBzZXJ2aWNlIGNhbGxzIG9ubHknLCBFcnJvckNvZGUuSU5TVUZGSUNJRU5UX1BFUk1JU1NJT05TKTtcbiAgICB9O1xuXG4gICAgaWYgKCFyZXEudXNlcikgcmV0dXJuIHJlZnVzZSgndW5hdXRoZW50aWNhdGVkJyk7XG4gICAgaWYgKCFpc1NlcnZpY2VQcmluY2lwYWwocmVxKSkgcmV0dXJuIHJlZnVzZSgndXNlcl90b2tlbicpO1xuICAgIGNvbnN0IGNhbGxlciA9IHNlcnZpY2VOYW1lT2YocmVxLnVzZXIpO1xuICAgIGlmICghY2FsbGVyIHx8ICFhbGxvd2VkLmhhcyhjYWxsZXIpKSByZXR1cm4gcmVmdXNlKCd3cm9uZ19jYWxsZXInKTtcbiAgICBuZXh0KCk7XG4gIH0sIHsga2luZDogJ3NlcnZpY2VQcmluY2lwYWwnIH0sIHsga2luZDogJ2ludGVybmFsU2VydmljZScsIGNhbGxlcnM6IFsuLi5vcHRpb25zLmNhbGxlcnNdIH0pO1xufVxuXG4vKipcbiAqIFRoZSBzeXN0ZW0gdGVuYW50J3MgY2Fub25pY2FsIG9yZyAqKmlkKiog4oCUIGEgZml4ZWQsIHdlbGwta25vd24gT2JqZWN0SWQgKE5PVFxuICogdGhlIHN0cmluZyAnc3lzdGVtJykuIFRoaXMgaXMgdGhlIHNpbmdsZSBrbm9iIGV2ZXJ5IHNlcnZpY2UgcmVzb2x2ZXMgdGhlXG4gKiBzeXN0ZW0gdGVuYW50IHRocm91Z2g7IG92ZXJyaWRlIHZpYSB0aGUgYFNZU1RFTV9PUkdfSURgIGVudiBmb3IgYWx0ZXJuYXRlXG4gKiBpbnN0YWxscy4gVGhlIHN5c3RlbSBvcmcncyBodW1hbiBpZGVudGlmaWVyIHN0YXlzIHRoZSBzbHVnL25hbWUgJ3N5c3RlbSdcbiAqIChzZWUge0BsaW5rIFNZU1RFTV9PUkdfU0xVR30pOyBvbmx5IGl0cyBgX2lkYCBpcyB0aGlzIE9iamVjdElkLlxuICovXG5leHBvcnQgY29uc3QgU1lTVEVNX09SR19JRCA9IChwcm9jZXNzLmVudi5TWVNURU1fT1JHX0lEIHx8ICcwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDEnKS50b0xvd2VyQ2FzZSgpO1xuXG4vKiogVGhlIHN5c3RlbSBvcmcncyB3ZWxsLWtub3duIHNsdWcvbmFtZSAodGhlIGh1bWFuIGlkZW50aWZpZXI7IGl0cyBgX2lkYCBpcyB7QGxpbmsgU1lTVEVNX09SR19JRH0pLiAqL1xuZXhwb3J0IGNvbnN0IFNZU1RFTV9PUkdfU0xVRyA9ICdzeXN0ZW0nO1xuXG4vKipcbiAqIENoZWNrIGlmIGFuIG9yZ0lkIG9yIG9yZ05hbWUvc2x1ZyBtYXRjaGVzIHRoZSBzeXN0ZW0gb3JnLiBVc2UgdGhpcyBpbnN0ZWFkIG9mXG4gKiBjb21wYXJpbmcgZGlyZWN0bHk6IHRoZSBpZCBpcyBub3cgYW4gT2JqZWN0SWQgKHtAbGluayBTWVNURU1fT1JHX0lEfSkgd2hpbGUgdGhlXG4gKiBuYW1lL3NsdWcgaXMgJ3N5c3RlbScgKHtAbGluayBTWVNURU1fT1JHX1NMVUd9KSwgc28gdGhlIHR3byBhcmUgY29tcGFyZWQgYWdhaW5zdFxuICogdGhlaXIgcmVzcGVjdGl2ZSBjYW5vbmljYWwgdmFsdWVzLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNTeXN0ZW1PcmdJZChvcmdJZD86IHN0cmluZywgb3JnTmFtZT86IHN0cmluZyk6IGJvb2xlYW4ge1xuICByZXR1cm4gb3JnSWQ/LnRvTG93ZXJDYXNlKCkgPT09IFNZU1RFTV9PUkdfSUQgfHwgb3JnTmFtZT8udG9Mb3dlckNhc2UoKSA9PT0gU1lTVEVNX09SR19TTFVHO1xufVxuXG4vKipcbiAqIENoZWNrIGlmIHRoZSByZXF1ZXN0IGlzIGZyb20gYSBzeXN0ZW0gYWRtaW4uXG4gKlxuICogQXV0aG9yaXR5IGlzIGdyYW50ZWQgc29sZWx5IGJ5IHRoZSB1c2VyLWxldmVsIGBpc1N1cGVyQWRtaW5gIGZsYWcgY2FycmllZFxuICogaW4gdGhlIEpXVC4gVGhlIFwibWVtYmVyc2hpcCBpbiB0aGUgd2VsbC1rbm93biAnc3lzdGVtJyBvcmcgd2l0aCByb2xlXG4gKiBhZG1pbi9vd25lclwiIHBhdGggd2FzIHJlbW92ZWQg4oCUIGl0IGNvbmZsYXRlZCBhIFBpcGVsaW5lIEJ1aWxkZXIgb3BlcmF0b3JcbiAqIHdpdGggYSByZWFsIGN1c3RvbWVyIHRlbmFudCBpbiB0aGUgZGF0YSBtb2RlbCwgYW5kIG1lYW50IGFueSB1bmludGVuZGVkXG4gKiB3cml0ZSB0aGF0IGNyZWF0ZWQgYSAnc3lzdGVtJy1uYW1lZCBvcmcgY291bGQgcXVpZXRseSBncmFudCBjcm9zcy1vcmdcbiAqIGF1dGhvcml0eS4gVGhlIGBzeXN0ZW1gIG9yZyBzdGlsbCBleGlzdHMgYXMgYSAqY29udGVudCBob2xkZXIqIGZvciBzaGFyZWRcbiAqIHNhbXBsZSBkYXRhOyBpdCBqdXN0IG5vIGxvbmdlciBjb25mZXJzIHByaXZpbGVnZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzU3lzdGVtQWRtaW4ocmVxOiBSZXF1ZXN0KTogYm9vbGVhbiB7XG4gIHJldHVybiByZXEudXNlcj8uaXNTdXBlckFkbWluID09PSB0cnVlO1xufVxuXG4vKipcbiAqIFdoZXRoZXIgdGhlIHJlcXVlc3QncyB0b2tlbiBjYXJyaWVzIGEgc3BlY2lmaWMgY2FwYWJpbGl0eSBgc2NvcGVgIChlLmcuXG4gKiBgJ3JlcG9ydGluZzppbmdlc3QnYCkuIFVzZWQgdG8gZ2F0ZSBlbmRwb2ludHMgdGhhdCBhY2NlcHQgYSBuYXJyb3cgbWFjaGluZVxuICogaWRlbnRpdHkg4oCUIGEgbm9ybWFsIGludGVyYWN0aXZlIHVzZXIgdG9rZW4gaGFzIG5vIGBzY29wZWAgYW5kIHJldHVybnMgZmFsc2UuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBoYXNTY29wZShyZXE6IFJlcXVlc3QsIHNjb3BlOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgcmV0dXJuIHJlcS51c2VyPy5zY29wZSA9PT0gc2NvcGU7XG59XG5cbi8qKiBSZXF1aXJlcyBhIHN5c3RlbSBhZG1pbiDigJQgZ3JhbnRlZCBzb2xlbHkgYnkgdGhlIGBpc1N1cGVyQWRtaW5gIHRva2VuIGNsYWltXG4gKiAgKHRoZSBvcmctbWVtYmVyc2hpcCBwYXRoIHdhcyByZW1vdmVkKS4gVXNlIGFmdGVyIHJlcXVpcmVBdXRoLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlcXVpcmVTeXN0ZW1BZG1pbihcbiAgcmVxOiBSZXF1ZXN0LFxuICByZXM6IFJlc3BvbnNlLFxuICBuZXh0OiBOZXh0RnVuY3Rpb24sXG4pOiB2b2lkIHtcbiAgaWYgKCFpc1N5c3RlbUFkbWluKHJlcSkpIHtcbiAgICByZWNvcmRBdXRoekRlbmlhbChyZXEsICdzeXN0ZW0tYWRtaW4nKTtcbiAgICByZXR1cm4gc2VuZEVycm9yKFxuICAgICAgcmVzLCBIdHRwU3RhdHVzLkZPUkJJRERFTixcbiAgICAgICdBY2Nlc3MgZGVuaWVkLiBPbmx5IHN5c3RlbSBhZG1pbmlzdHJhdG9ycyBjYW4gcGVyZm9ybSB0aGlzIGFjdGlvbi4nLFxuICAgICAgRXJyb3JDb2RlLklOU1VGRklDSUVOVF9QRVJNSVNTSU9OUyxcbiAgICApO1xuICB9XG4gIG5leHQoKTtcbn1cbnRhZ1JvdXRlR2F0ZShyZXF1aXJlU3lzdGVtQWRtaW4sIHsga2luZDogJ3N5c3RlbUFkbWluJyB9KTtcblxuLyoqXG4gKiBSZXF1aXJlIGEgc3BlY2lmaWMgZmVhdHVyZSBmbGFnLiBVc2UgYWZ0ZXIgcmVxdWlyZUF1dGguXG4gKiBDaGVja3MgdGhlIGBmZWF0dXJlc2AgYXJyYXkgaW4gdGhlIEpXVCBwYXlsb2FkIChzZXQgYXQgdG9rZW4gaXNzdWFuY2UpLlxuICogU3lzYWRtaW5zIChpc1N1cGVyQWRtaW4pIGJ5cGFzcyDigJQgdGhleSBhbHdheXMgaGF2ZSBldmVyeSBmZWF0dXJlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVxdWlyZUZlYXR1cmUoZmVhdHVyZTogc3RyaW5nKSB7XG4gIHJldHVybiB0YWdSb3V0ZUdhdGUoKHJlcTogUmVxdWVzdCwgcmVzOiBSZXNwb25zZSwgbmV4dDogTmV4dEZ1bmN0aW9uKTogdm9pZCA9PiB7XG4gICAgaWYgKCFyZXEudXNlcikge1xuICAgICAgcmV0dXJuIHNlbmRFcnJvcihyZXMsIEh0dHBTdGF0dXMuVU5BVVRIT1JJWkVELCAnQXV0aGVudGljYXRpb24gcmVxdWlyZWQnLCBFcnJvckNvZGUuVU5BVVRIT1JJWkVEKTtcbiAgICB9XG5cbiAgICAvLyBTeXNhZG1pbnMgZ2V0IGFsbCBmZWF0dXJlczsgdGhlIGBmZWF0dXJlc2AgYXJyYXkgb24gdGhlaXIgdG9rZW4gaXNcbiAgICAvLyBwb3B1bGF0ZWQgd2l0aCBldmVyeSBmbGFnIGF0IGlzc3VhbmNlIHRpbWUgYnV0IHRoZSBieXBhc3MgaGVyZSBrZWVwc1xuICAgIC8vIHRoZSBydWxlIGV4cGxpY2l0IGFuZCBzdXJ2aXZlcyBhIHRva2VuIGlzc3VlZCBiZWZvcmUgYSBuZXcgZmVhdHVyZVxuICAgIC8vIGZsYWcgd2FzIGFkZGVkLlxuICAgIGlmIChyZXEudXNlci5pc1N1cGVyQWRtaW4gPT09IHRydWUpIHJldHVybiBuZXh0KCk7XG5cbiAgICBpZiAoIXJlcS51c2VyLmZlYXR1cmVzPy5pbmNsdWRlcyhmZWF0dXJlKSkge1xuICAgICAgLy8gUm91dGUgZmVhdHVyZS1nYXRlIGRlbmlhbHMgdGhyb3VnaCB0aGUgc2FtZSBhdWRpdCBzaW5rIGFzXG4gICAgICAvLyByZXF1aXJlUGVybWlzc2lvbiAvIHJlcXVpcmVTeXN0ZW1BZG1pbiBzbyBhIHByb2JlIGZvciBhblxuICAgICAgLy8gdW5lbnRpdGxlZCBjYXBhYmlsaXR5IGxlYXZlcyBhIHRyYWlsIChzdGF0ZS1jaGFuZ2luZyBtZXRob2RzIG9ubHkpLlxuICAgICAgcmVjb3JkQXV0aHpEZW5pYWwocmVxLCBgZmVhdHVyZToke2ZlYXR1cmV9YCk7XG4gICAgICByZXR1cm4gc2VuZEVycm9yKFxuICAgICAgICByZXMsIEh0dHBTdGF0dXMuRk9SQklEREVOLFxuICAgICAgICBgVGhpcyBmZWF0dXJlIHJlcXVpcmVzIGEgaGlnaGVyIHBsYW4gKCR7ZmVhdHVyZX0pYCxcbiAgICAgICAgRXJyb3JDb2RlLklOU1VGRklDSUVOVF9QRVJNSVNTSU9OUyxcbiAgICAgICk7XG4gICAgfVxuXG4gICAgbmV4dCgpO1xuICB9LCB7IGtpbmQ6ICdmZWF0dXJlJywgZmVhdHVyZSB9KTtcbn1cblxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4vLyBTZXJ2aWNlLXRvLXNlcnZpY2UgdG9rZW5zXG4vL1xuLy8gSW50ZXItc2VydmljZSBIVFRQIGNhbGxzIChiaWxsaW5nIOKGkiBtZXNzYWdlLCBwbGF0Zm9ybSDihpIgY29tcGxpYW5jZSwgZXRjLilcbi8vIG5lZWQgdG8gc2F0aXNmeSB0aGUgc2FtZSBgcmVxdWlyZUF1dGhgIG1pZGRsZXdhcmUgYXMgdXNlciByZXF1ZXN0cy5cbi8vIGBzaWduU2VydmljZVRva2VuYCBtaW50cyBhIHNob3J0LWxpdmVkIEVTMjU2IEpXVCBzaWduZWQgd2l0aCBUSElTIHNlcnZpY2Unc1xuLy8gT1dOIGtleSAoc2VlIGBzZXJ2aWNlcy9zZXJ2aWNlLWtleXMudHNgKSwgY2FycnlpbmcgYHByaW5jaXBhbFR5cGU6ICdzZXJ2aWNlJ2Bcbi8vIGFuZCBuYW1pbmcgdGhlIGNhbGxpbmcgc2VydmljZSB2aWEgYHN1YjogJ3NlcnZpY2U6PG5hbWU+J2AuIEdhdGVzIGJyYW5jaCBvblxuLy8gdGhlIGNsYWltOyB0aGUgc3ViamVjdCBuYW1lcyDigJQgYW5kIHNpbmNlICMxNCB0aGUgbmFtZSBpcyBjcnlwdG9ncmFwaGljYWxseVxuLy8gYm91bmQgdG8gdGhlIHNpZ25pbmcga2V5LCBzbyBpdCBjYW4gYWxzbyBiZSB0cnVzdGVkLlxuLy8gYHJlcXVpcmVBdXRoYCBhY2NlcHRzIHRoZXNlIHRva2VucyB0cmFuc3BhcmVudGx5IOKAlCB0aGV5IHBhc3MgYGRlY29kZWQuc3ViYFxuLy8gYW5kIGBkZWNvZGVkLnJvbGVgIGNoZWNrcywgYW5kIGRvd25zdHJlYW0gYHJlcXVpcmVPcmdhbml6YXRpb25gIC9cbi8vIGByZXF1aXJlU3lzdGVtQWRtaW5gIHJlbHkgb24gdGhlIG9yZy9yb2xlIGVtYmVkZGVkIGluIHRoZSB0b2tlbi5cbi8vXG4vLyBUb2tlbnMgZGVmYXVsdCB0byA1LW1pbnV0ZSBUVEwg4oCUIGxvbmcgZW5vdWdoIHRvIHN1cnZpdmUgYSBiYWNrZW5kIGhvcCxcbi8vIHNob3J0IGVub3VnaCB0aGF0IGEgbGVha2VkIHRva2VuIGlzIGxvdy12YWx1ZS5cbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5jb25zdCBERUZBVUxUX1NFUlZJQ0VfVE9LRU5fVFRMX1NFQ09ORFMgPSAzMDA7XG5cbi8qKlxuICogRGVueWxpc3Qgb2Ygc2VydmljZSBOQU1FUyAodGhlIGA8bmFtZT5gIGluIGBzdWI6IHNlcnZpY2U6PG5hbWU+YCkgd2hvc2UgdG9rZW5zXG4gKiBgcmVxdWlyZUF1dGhgIG11c3QgcmVqZWN0LiBSZWFkIGZyb20gYFNFUlZJQ0VfVE9LRU5fREVOWUxJU1RgIChjb21tYS1zZXBhcmF0ZWQpXG4gKiBhdCBwcm9jZXNzIHN0YXJ0LCBzbyBhcm1pbmcgaXQgaXMgYSBjb25maWcgY2hhbmdlICsgcm9sbG91dCDigJQgaXQgY3V0cyBvZmYgYVxuICogY29tcHJvbWlzZWQgc2VydmljZSBXSVRIT1VUIHJvdGF0aW5nIGFueSBrZXksIGFuZCAodW5saWtlIHRoZSBwcmUtIzE0IHNoYXJlZFxuICogc2VjcmV0KSB3aXRob3V0IGludmFsaWRhdGluZyBldmVyeSBvdGhlciBzZXJ2aWNlJ3MgdG9rZW5zIGFzIGNvbGxhdGVyYWwuXG4gKi9cbmNvbnN0IHNlcnZpY2VUb2tlbkRlbnlsaXN0ID0gbmV3IFNldChcbiAgKHByb2Nlc3MuZW52LlNFUlZJQ0VfVE9LRU5fREVOWUxJU1QgfHwgJycpXG4gICAgLnNwbGl0KCcsJylcbiAgICAubWFwKChzKSA9PiBzLnRyaW0oKSlcbiAgICAuZmlsdGVyKEJvb2xlYW4pLFxuKTtcblxuLyoqXG4gKiBUaGUgY2FsbGluZyBzZXJ2aWNlJ3MgbmFtZSBmb3IgYSBTRVJWSUNFIHByaW5jaXBhbCAoYHByaW5jaXBhbFR5cGU6ICdzZXJ2aWNlJ2ApLFxuICogZWxzZSBgdW5kZWZpbmVkYC4gQSB1c2VyIHRva2VuIG5ldmVyIHlpZWxkcyBhIG5hbWUsIHdoYXRldmVyIGl0cyBgc3ViYCBzYXlzLlxuICovXG5leHBvcnQgZnVuY3Rpb24gc2VydmljZU5hbWVPZihjbGFpbXM6IHsgcHJpbmNpcGFsVHlwZT86IHN0cmluZzsgc3ViPzogc3RyaW5nIH0gfCB1bmRlZmluZWQpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICBpZiAoY2xhaW1zPy5wcmluY2lwYWxUeXBlICE9PSAnc2VydmljZScgfHwgdHlwZW9mIGNsYWltcy5zdWIgIT09ICdzdHJpbmcnKSByZXR1cm4gdW5kZWZpbmVkO1xuICBpZiAoIWNsYWltcy5zdWIuc3RhcnRzV2l0aChTRVJWSUNFX1NVQkpFQ1RfUFJFRklYKSkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgcmV0dXJuIGNsYWltcy5zdWIuc2xpY2UoU0VSVklDRV9TVUJKRUNUX1BSRUZJWC5sZW5ndGgpIHx8IHVuZGVmaW5lZDtcbn1cblxuLyoqIFRydWUgd2hlbiB0aGUgY2xhaW1zIGFyZSBhIHNlcnZpY2UgcHJpbmNpcGFsIHdob3NlIHNlcnZpY2UgaXMgb24gdGhlIGRlbnlsaXN0LiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzU2VydmljZVRva2VuRGVuaWVkKGNsYWltczogeyBwcmluY2lwYWxUeXBlPzogc3RyaW5nOyBzdWI/OiBzdHJpbmcgfSk6IGJvb2xlYW4ge1xuICBpZiAoc2VydmljZVRva2VuRGVueWxpc3Quc2l6ZSA9PT0gMCkgcmV0dXJuIGZhbHNlO1xuICBjb25zdCBuYW1lID0gc2VydmljZU5hbWVPZihjbGFpbXMpO1xuICByZXR1cm4gbmFtZSAhPT0gdW5kZWZpbmVkICYmIHNlcnZpY2VUb2tlbkRlbnlsaXN0LmhhcyhuYW1lKTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBTZXJ2aWNlVG9rZW5PcHRpb25zIHtcbiAgLyoqIENhbGxpbmcgc2VydmljZSBpZGVudGlmaWVyIChlLmcuICdiaWxsaW5nJywgJ3BsYXRmb3JtJykuIEVtYmVkZGVkIGFzIGBzdWI6IHNlcnZpY2U6PG5hbWU+YC4gKi9cbiAgc2VydmljZU5hbWU6IHN0cmluZztcbiAgLyoqIEFjdGl2ZSBvcmcgY29udGV4dCBmb3IgdGhlIGNhbGwuIFVzZSB0aGUgdGFyZ2V0IHRlbmFudCdzIG9yZyBpZCwgb3IgdGhlXG4gICAqICB3ZWxsLWtub3duIGBTWVNURU1fT1JHX0lEYCAoYW4gT2JqZWN0SWQpIGZvciBzeXN0ZW0td2lkZSBvcHMg4oCUIE5PVCB0aGUgc3RyaW5nXG4gICAqICAnc3lzdGVtJywgd2hpY2ggaWQtYmFzZWQgc3lzdGVtLW9yZyBjaGVja3Mgd29uJ3QgcmVjb2duaXplLiAqL1xuICBvcmdJZD86IHN0cmluZztcbiAgLyoqIEFjdGl2ZSBvcmcgbmFtZS4gRGVmYXVsdHMgdG8gb3JnSWQuICovXG4gIG9yZ05hbWU/OiBzdHJpbmc7XG4gIC8qKiBUVEwgaW4gc2Vjb25kcyAoZGVmYXVsdCAzMDApLiAqL1xuICB0dGxTZWNvbmRzPzogbnVtYmVyO1xuICAvKipcbiAgICogUm9sZSB0aGUgdG9rZW4gY2FycmllcyAocmVxdWlyZWQg4oCUIG5vIGltcGxpY2l0IGRlZmF1bHQpLiAqKlBhc3MgdGhlIExPV0VTVFxuICAgKiByb2xlIHRoZSBjYWxsIGFjdHVhbGx5IG5lZWRzKiogKGAnbWVtYmVyJ2AgZm9yIHJlYWQgLyBkYXRhLXBsYW5lIGNhbGxzKSBzbyBhXG4gICAqIGxlYWtlZCBzZXJ2aWNlIHRva2VuIGNhbid0IHBlcmZvcm0gYWRtaW4gYWN0aW9ucyBpbiB0aGUgdGFyZ2V0IG9yZy5cbiAgICogYGlzQWRtaW5gIGlzIGRlcml2ZWQgZnJvbSB0aGlzIChhZG1pbnxvd25lciDihpIgdHJ1ZSkuXG4gICAqL1xuICByb2xlOiAnb3duZXInIHwgJ2FkbWluJyB8ICdtZW1iZXInO1xuICAvKipcbiAgICogT3B0aW9uYWwgZmluZS1ncmFpbmVkIHBlcm1pc3Npb24gY2xhaW0uIFByZWZlciB0aGlzICsgYHJvbGU6ICdtZW1iZXInYCBvdmVyIGFcbiAgICogaGlnaCByb2xlIHdoZW4gYSBjYWxsIG5lZWRzIE9ORSBzcGVjaWZpYyBjYXBhYmlsaXR5IChlLmcuIGBbJ3BsdWdpbnM6d3JpdGUnXWBcbiAgICogdG8gcHVzaCBhIHBsdWdpbiBpbWFnZSkg4oCUIHRoZSB0b2tlbiB0aGVuIHNhdGlzZmllcyB0aGF0IHBlcm1pc3Npb24gZ2F0ZVxuICAgKiBXSVRIT1VUIGNhcnJ5aW5nIGBpc0FkbWluYCwgc28gYSBsZWFrZWQgdG9rZW4gY2FuJ3QgcGVyZm9ybSBhZG1pbiBhY3Rpb25zLlxuICAgKi9cbiAgcGVybWlzc2lvbnM/OiBQZXJtaXNzaW9uW107XG59XG5cbi8qKlxuICogTWludCBhIEpXVCBpZGVudGlmeWluZyB0aGUgY2FsbGluZyBzZXJ2aWNlLiBVc2VkIGZvciBpbnRlci1zZXJ2aWNlIEhUVFAgY2FsbHMuXG4gKiBUaGUgdG9rZW4gc2F0aXNmaWVzIGByZXF1aXJlQXV0aGAgYW5kICh3aGVuIG9yZ0lkIGlzIHByZXNlbnQpIGByZXF1aXJlT3JnYW5pemF0aW9uYC5cbiAqIFNjb3BlIGl0IHdpdGggYG9wdHMucm9sZWAg4oCUIGxlYXN0IHByaXZpbGVnZSBrZWVwcyBhIGxlYWtlZCB0b2tlbiBsb3ctdmFsdWUuXG4gKlxuICogYG9wdHMuc2VydmljZU5hbWVgIG11c3QgYmUgVEhJUyBwcm9jZXNzJ3Mgb3duIGlkZW50aXR5IChgU0VSVklDRV9OQU1FYCk6IGFcbiAqIHNlcnZpY2UgaG9sZHMgb25seSBpdHMgb3duIHNpZ25pbmcga2V5LCBzbyBtaW50aW5nIGEgdG9rZW4gdGhhdCBuYW1lcyBhbm90aGVyXG4gKiBzZXJ2aWNlIHRocm93cyByYXRoZXIgdGhhbiBwcm9kdWNpbmcgb25lIGV2ZXJ5IHBlZXIgd291bGQgcmVqZWN0LiBUaGF0IGlzIHRoZVxuICogb25lIGJlaGF2aW91ciBjaGFuZ2UgIzE0IGZvcmNlcyBvbiBjYWxsZXJzIOKAlCBzZWUgYHNlcnZpY2VzL3NlcnZpY2Uta2V5cy50c2AuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzaWduU2VydmljZVRva2VuKG9wdHM6IFNlcnZpY2VUb2tlbk9wdGlvbnMpOiBzdHJpbmcge1xuICBjb25zdCByb2xlID0gb3B0cy5yb2xlO1xuICBjb25zdCBwYXlsb2FkOiBPbWl0PEp3dFBheWxvYWQsICdzdWInPiA9IHtcbiAgICB1c2VybmFtZTogYCR7b3B0cy5zZXJ2aWNlTmFtZX0tc2VydmljZWAsXG4gICAgZW1haWw6IGAke29wdHMuc2VydmljZU5hbWV9QGludGVybmFsYCxcbiAgICBwcmluY2lwYWxUeXBlOiAnc2VydmljZScsXG4gICAgdG9rZW5fdXNlOiAnYWNjZXNzJyxcbiAgICByb2xlLFxuICAgIGlzQWRtaW46IHJvbGUgPT09ICdvd25lcicgfHwgcm9sZSA9PT0gJ2FkbWluJyxcbiAgICB0eXBlOiAnYWNjZXNzJyxcbiAgICBvcmdhbml6YXRpb25JZDogb3B0cy5vcmdJZCxcbiAgICBvcmdhbml6YXRpb25OYW1lOiBvcHRzLm9yZ05hbWUgPz8gb3B0cy5vcmdJZCxcbiAgICAvLyBVbmlxdWUgdG9rZW4gaWQgb24gZXZlcnkgbWludC4gQ29tYmluZWQgd2l0aCB0aGUgc2hvcnQgKDMwMHMgZGVmYXVsdCkgVFRMXG4gICAgLy8gdGhpcyBnaXZlcyBlYWNoIHNlcnZpY2UgdG9rZW4gYSBkaXN0aW5jdCBpZGVudGl0eSDigJQgdGhlIGNvcnJlbGF0aW9uIGhhbmRsZVxuICAgIC8vIGZvciB0cmFjaW5nIHdoaWNoIG1pbnQgcGVyZm9ybWVkIGEgY3Jvc3Mtc2VydmljZSBhY3Rpb24sIGFuZCB0aGUgYnVpbGRpbmdcbiAgICAvLyBibG9jayBmb3IgcmVwbGF5IGRldGVjdGlvbiAoYSB2ZXJpZmllciBjYW4gdHJhY2sgc2VlbiBqdGlzKS4gSXQgZG9lcyBOT1RcbiAgICAvLyBieSBpdHNlbGYgcHJldmVudCByZXBsYXkgd2l0aGluIHRoZSBUVEwgd2luZG93LlxuICAgIGp0aTogcmFuZG9tVVVJRCgpLFxuICAgIC8vIExlYXN0LXByaXZpbGVnZSBjYXBhYmlsaXR5IGNsYWltIChvcHRpb25hbCkg4oCUIGxldHMgYSBtZW1iZXItcm9sZSB0b2tlblxuICAgIC8vIHNhdGlzZnkgYSBzcGVjaWZpYyBwZXJtaXNzaW9uIGdhdGUgd2l0aG91dCBjYXJyeWluZyBpc0FkbWluLlxuICAgIC4uLihvcHRzLnBlcm1pc3Npb25zICYmIG9wdHMucGVybWlzc2lvbnMubGVuZ3RoID4gMCA/IHsgcGVybWlzc2lvbnM6IG9wdHMucGVybWlzc2lvbnMgfSA6IHt9KSxcbiAgfTtcbiAgLy8gYHN1YmAsIGBpYXRgL2BleHBgIGFuZCB0aGUgb3B0aW9uYWwgaXNzdWVyL2F1ZGllbmNlIHRoYXQgcmVxdWlyZUF1dGhcbiAgLy8gdmVyaWZpZXMgYXJlIHN0YW1wZWQgYnkgdGhlIHNpZ25lciwgc28gdGhlcmUgaXMgZXhhY3RseSBvbmUgcGxhY2UgdGhhdFxuICAvLyBkZWNpZGVzIHdoYXQgYSBzZXJ2aWNlIHRva2VuIHNheXMuXG4gIHJldHVybiBzaWduU2VydmljZUp3dChwYXlsb2FkIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+LCB7XG4gICAgc2VydmljZU5hbWU6IG9wdHMuc2VydmljZU5hbWUsXG4gICAgZXhwaXJlc0luU2Vjb25kczogb3B0cy50dGxTZWNvbmRzID8/IERFRkFVTFRfU0VSVklDRV9UT0tFTl9UVExfU0VDT05EUyxcbiAgICAuLi5pc3N1ZXJBdWRpZW5jZU9wdGlvbnMoKSxcbiAgfSk7XG59XG5cbi8qKiBDb252ZW5pZW5jZTogcmV0dXJucyBhIGBCZWFyZXIgPHRva2VuPmAgaGVhZGVyIHZhbHVlIGZvciBmZXRjaC9heGlvcyBjYWxscy4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRTZXJ2aWNlQXV0aEhlYWRlcihvcHRzOiBTZXJ2aWNlVG9rZW5PcHRpb25zKTogc3RyaW5nIHtcbiAgcmV0dXJuIGBCZWFyZXIgJHtzaWduU2VydmljZVRva2VuKG9wdHMpfWA7XG59XG5cbi8qKiBUcnVlIHdoZW4gYHJlcS51c2VyYCBpcyBhIHNlcnZpY2UgcHJpbmNpcGFsIChgcHJpbmNpcGFsVHlwZTogJ3NlcnZpY2UnYCwgbWludGVkIGJ5IGBzaWduU2VydmljZVRva2VuYCkuICovXG5leHBvcnQgZnVuY3Rpb24gaXNTZXJ2aWNlUHJpbmNpcGFsKHJlcTogUmVxdWVzdCk6IGJvb2xlYW4ge1xuICByZXR1cm4gcmVxLnVzZXI/LnByaW5jaXBhbFR5cGUgPT09ICdzZXJ2aWNlJztcbn1cblxuLyoqXG4gKiBUcnVlIHdoZW4gYHJlcS51c2VyYCBpcyBhbiBPUkcgU0VSVklDRSBBQ0NPVU5UIChgcHJpbmNpcGFsVHlwZTpcbiAqICdzZXJ2aWNlX2FjY291bnQnYCkg4oCUIGEgbm9uLWh1bWFuIHByaW5jaXBhbCBvd25lZCBieSBvbmUgb3JnLCBhdXRoZW50aWNhdGluZ1xuICogd2l0aCBhIGBwYl9zYV/igKZgIGtleSBleGNoYW5nZWQgYXQgcGxhdGZvcm0uXG4gKlxuICogQSBzZXJ2aWNlIGFjY291bnQgaXMgTk9UIGFuIGludGVybmFsIHNlcnZpY2UgcHJpbmNpcGFsOiBpdCBob2xkcyBvcmcgUm9sZXMgYW5kXG4gKiBpcyBzdWJqZWN0IHRvIGV2ZXJ5IHBlcm1pc3Npb24gZ2F0ZSBhIG1lbWJlciBpcy4gV2hhdCBpdCBjYW4gbmV2ZXIgZG8gaXNcbiAqIHNhdGlzZnkgYSBIVU1BTi1wcmVzZW5jZSByZXF1aXJlbWVudCDigJQgc3RlcC11cCAoYW5kIGFueSBsYXRlciBhc3N1cmFuY2UgZ2F0ZSlcbiAqIHJlZnVzZXMgaXQgb3V0cmlnaHQsIGJlY2F1c2UgdGhlcmUgaXMgbm8gcGVyc29uIGJlaGluZCBpdCB0byByZS12ZXJpZnkuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc1NlcnZpY2VBY2NvdW50UHJpbmNpcGFsKHJlcTogUmVxdWVzdCk6IGJvb2xlYW4ge1xuICByZXR1cm4gcmVxLnVzZXI/LnByaW5jaXBhbFR5cGUgPT09ICdzZXJ2aWNlX2FjY291bnQnO1xufVxuXG4vKiogVHJ1ZSB3aGVuIGByZXEudXNlcmAgaXMgdGhlIG5hbWVkIGludGVybmFsIHNlcnZpY2UgKGUuZy4gYCdiaWxsaW5nJ2ApLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzU2VydmljZVByaW5jaXBhbE5hbWVkKHJlcTogUmVxdWVzdCwgc2VydmljZU5hbWU6IHN0cmluZyk6IGJvb2xlYW4ge1xuICByZXR1cm4gc2VydmljZU5hbWVPZihyZXEudXNlcikgPT09IHNlcnZpY2VOYW1lO1xufVxuXG4vKipcbiAqIFBSRS1hdXRoIGNoZWNrOiBjcnlwdG9ncmFwaGljYWxseSB2ZXJpZnkgdGhlIHJlcXVlc3QgY2FycmllcyBhIHZhbGlkLCBzaWduZWRcbiAqIFNFUlZJQ0UgdG9rZW4gKGBwcmluY2lwYWxUeXBlOiAnc2VydmljZSdgKS4gVW5saWtlIHtAbGluayBpc1NlcnZpY2VQcmluY2lwYWx9XG4gKiAod2hpY2ggcmVhZHMgdGhlIGFscmVhZHktcG9wdWxhdGVkIGByZXEudXNlcmApLCB0aGlzIHZlcmlmaWVzIHRoZSBiZWFyZXIgdG9rZW5cbiAqIGl0c2VsZiwgc28gaXQgaXMgc2FmZSB0byBjYWxsIEJFRk9SRSBgcmVxdWlyZUF1dGhgIHJ1bnMg4oCUIGUuZy4gdGhlIGdsb2JhbCByYXRlXG4gKiBsaW1pdGVyJ3MgYHNraXBgLCB3aGljaCBtdXN0IG5vdCB0cnVzdCB0aGUgc3Bvb2ZhYmxlIGB4LWludGVybmFsLXNlcnZpY2VgXG4gKiBoZWFkZXIuIE1pcnJvcnMgYHJlcXVpcmVBdXRoYCdzIFNFUlZJQ0UgY2hhaW4gZXhhY3RseSAodGhlIHNpZ25lcidzIG93biBrZXksXG4gKiByZXNvbHZlZCBieSBga2lkYCwgd2l0aCB0aGUgYHN1YmAvc2lnbmVyIGFncmVlbWVudCBjaGVjayBhbmQgdGhlIG9wdGlvbmFsXG4gKiBpc3N1ZXIvYXVkaWVuY2UpIGFuZCByZXR1cm5zIGBmYWxzZWAgb24gYW55IG1pc3NpbmcvaW52YWxpZC9ub24tc2VydmljZSB0b2tlblxuICog4oCUIGluY2x1ZGluZyBhbnkgcGxhdGZvcm0tc2lnbmVkIFVTRVIgdG9rZW4sIHdob3NlIGBraWRgIGlzIG5vdCBpbiB0aGUgc2VydmljZVxuICogYnVuZGxlIGF0IGFsbC4gU3RheXMgU1lOQ0hST05PVVMsIHdoaWNoIGlzIHdoeSB0aGUgcGVyLXNlcnZpY2UgcHVibGljIGtleXMgYXJlXG4gKiBkaXN0cmlidXRlZCBhcyBhIG1vdW50ZWQgYnVuZGxlIHJhdGhlciB0aGFuIGZldGNoZWQgb3ZlciBIVFRQLlxuICovXG5leHBvcnQgZnVuY3Rpb24gdmVyaWZ5U2VydmljZVByaW5jaXBhbChyZXE6IFJlcXVlc3QpOiBib29sZWFuIHtcbiAgY29uc3QgcGFydHMgPSByZXEuaGVhZGVycy5hdXRob3JpemF0aW9uPy5zcGxpdCgnICcpO1xuICBpZiAoIXBhcnRzIHx8IHBhcnRzLmxlbmd0aCAhPT0gMiB8fCBwYXJ0c1swXSAhPT0gJ0JlYXJlcicpIHJldHVybiBmYWxzZTtcbiAgdHJ5IHtcbiAgICBjb25zdCBoZWFkZXIgPSBkZWNvZGVKd3RIZWFkZXIocGFydHNbMV0pO1xuICAgIGlmICghaGVhZGVyPy5raWQgfHwgIWlzU2VydmljZUtpZChoZWFkZXIua2lkKSkgcmV0dXJuIGZhbHNlO1xuICAgIGNvbnN0IGRlY29kZWQgPSB2ZXJpZnlTZXJ2aWNlSnd0PEp3dFBheWxvYWQ+KHBhcnRzWzFdLCB7IGtpZDogaGVhZGVyLmtpZCwgLi4uaXNzdWVyQXVkaWVuY2VPcHRpb25zKCkgfSk7XG4gICAgaWYgKGRlY29kZWQudHlwZSAhPT0gJ2FjY2VzcycgfHwgZGVjb2RlZC5wcmluY2lwYWxUeXBlICE9PSAnc2VydmljZScgfHwgIWhhc1ZhbGlkSWRlbnRpdHlDbGFpbXMoZGVjb2RlZCkpIHJldHVybiBmYWxzZTtcbiAgICAvLyBBIGRlbnlsaXN0ZWQgKGtpbGxlZCkgc2VydmljZSBtdXN0IE5PVCBiZSB0cmVhdGVkIGFzIGEgdHJ1c3RlZCBwcmluY2lwYWwg4oCUXG4gICAgLy8gb3RoZXJ3aXNlIGl0IGtlZXBzIHRoZSByYXRlLWxpbWl0ZXIgZXhlbXB0aW9uIGV2ZW4gdGhvdWdoIHJlcXVpcmVBdXRoIHJlamVjdHNcbiAgICAvLyBpdCBvbiByZWFsIHJvdXRlcy4gRm9sZCB0aGUga2lsbC1zd2l0Y2ggaW50byB0aGUgcHJlLWF1dGggY2hlY2sgdG9vLlxuICAgIHJldHVybiAhaXNTZXJ2aWNlVG9rZW5EZW5pZWQoZGVjb2RlZCk7XG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxufVxuIl19