@pipeline-builder/api-core 4.1.13 → 4.1.15
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.
- package/README.md +3 -2
- package/lib/constants/index.d.ts +0 -1
- package/lib/constants/index.js +1 -2
- package/lib/errors/app-errors.d.ts +8 -3
- package/lib/errors/app-errors.js +10 -5
- package/lib/helpers/access-helpers.d.ts +4 -6
- package/lib/helpers/access-helpers.js +6 -8
- package/lib/helpers/index.d.ts +3 -3
- package/lib/helpers/index.js +4 -4
- package/lib/helpers/org-hierarchy-http.d.ts +11 -10
- package/lib/helpers/org-hierarchy-http.js +24 -35
- package/lib/helpers/org-hierarchy.d.ts +37 -3
- package/lib/helpers/org-hierarchy.js +45 -4
- package/lib/helpers/restore-helpers.d.ts +44 -24
- package/lib/helpers/restore-helpers.js +41 -52
- package/lib/helpers/sse-helpers.d.ts +29 -7
- package/lib/helpers/sse-helpers.js +36 -9
- package/lib/index.d.ts +16 -14
- package/lib/index.js +17 -15
- package/lib/middleware/assurance.d.ts +116 -0
- package/lib/middleware/assurance.js +176 -0
- package/lib/middleware/auth.d.ts +5 -427
- package/lib/middleware/auth.js +36 -789
- package/lib/middleware/ecosystem-guard.d.ts +47 -0
- package/lib/middleware/ecosystem-guard.js +60 -0
- package/lib/middleware/index.d.ts +11 -4
- package/lib/middleware/index.js +12 -5
- package/lib/middleware/jwt-verify.d.ts +52 -0
- package/lib/middleware/jwt-verify.js +105 -0
- package/lib/middleware/permission-gates.d.ts +133 -0
- package/lib/middleware/permission-gates.js +260 -0
- package/lib/middleware/revocation.d.ts +96 -0
- package/lib/middleware/revocation.js +162 -0
- package/lib/middleware/route-table.d.ts +11 -0
- package/lib/middleware/route-table.js +4 -1
- package/lib/middleware/service-tokens.d.ts +83 -0
- package/lib/middleware/service-tokens.js +158 -0
- package/lib/middleware/step-up.d.ts +2 -2
- package/lib/middleware/step-up.js +8 -7
- package/lib/middleware/system-org.d.ts +20 -0
- package/lib/middleware/system-org.js +25 -0
- package/lib/openapi/routes/plugin-routes.js +133 -10
- package/lib/openapi/schema-registry.js +2 -5
- package/lib/routes/index.d.ts +1 -1
- package/lib/routes/index.js +2 -2
- package/lib/services/api-key-exchange.js +7 -5
- package/lib/services/audit-spool.d.ts +34 -10
- package/lib/services/audit-spool.js +75 -34
- package/lib/services/cache-service.d.ts +7 -0
- package/lib/services/cache-service.js +1 -1
- package/lib/services/circuit-breaker.d.ts +14 -1
- package/lib/services/circuit-breaker.js +36 -10
- package/lib/services/compliance-client.d.ts +10 -2
- package/lib/services/compliance-client.js +17 -10
- package/lib/services/compliance-event-subscriber.js +6 -6
- package/lib/services/durable-event-bus.js +8 -11
- package/lib/services/ecosystem-notify-client.d.ts +32 -0
- package/lib/services/ecosystem-notify-client.js +71 -0
- package/lib/services/env-redis.d.ts +4 -1
- package/lib/services/env-redis.js +32 -3
- package/lib/services/http-client.d.ts +19 -0
- package/lib/services/http-client.js +98 -19
- package/lib/services/index.d.ts +25 -24
- package/lib/services/index.js +25 -22
- package/lib/services/jwks-cache.js +5 -4
- package/lib/services/leader-lock.d.ts +22 -5
- package/lib/services/leader-lock.js +61 -6
- package/lib/services/quota.d.ts +9 -4
- package/lib/services/quota.js +34 -40
- package/lib/services/remote-audit-client.d.ts +28 -32
- package/lib/services/remote-audit-client.js +166 -49
- package/lib/services/retry-forever.js +5 -11
- package/lib/services/retry-strategy.d.ts +1 -1
- package/lib/services/retry-strategy.js +5 -4
- package/lib/services/scheduler.d.ts +8 -3
- package/lib/services/scheduler.js +17 -5
- package/lib/services/service-boot.d.ts +14 -13
- package/lib/services/service-boot.js +18 -15
- package/lib/services/service-keys.d.ts +1 -1
- package/lib/services/service-keys.js +12 -18
- package/lib/services/sse-ticket-store.d.ts +9 -1
- package/lib/services/sse-ticket-store.js +24 -9
- package/lib/services/system-notification.d.ts +27 -0
- package/lib/services/system-notification.js +50 -0
- package/lib/services/token-revocation.d.ts +50 -1
- package/lib/services/token-revocation.js +103 -3
- package/lib/types/audit-events.d.ts +6 -6
- package/lib/types/audit-events.js +1 -1
- package/lib/types/common.d.ts +32 -13
- package/lib/types/common.js +2 -1
- package/lib/types/ecosystem-notifications.d.ts +142 -0
- package/lib/types/ecosystem-notifications.js +210 -0
- package/lib/types/ecosystem.d.ts +77 -0
- package/lib/types/ecosystem.js +119 -0
- package/lib/types/error-codes.d.ts +81 -0
- package/lib/types/error-codes.js +108 -1
- package/lib/types/feature-flags.d.ts +21 -1
- package/lib/types/feature-flags.js +36 -2
- package/lib/types/index.d.ts +14 -9
- package/lib/types/index.js +15 -10
- package/lib/types/permissions.d.ts +46 -8
- package/lib/types/permissions.js +75 -12
- package/lib/types/plugin-catalog.d.ts +35 -0
- package/lib/types/plugin-catalog.js +39 -0
- package/lib/types/plugin-health.d.ts +102 -0
- package/lib/types/plugin-health.js +184 -0
- package/lib/types/quota-tiers.d.ts +15 -0
- package/lib/types/quota-tiers.js +23 -3
- package/lib/types/wire-vocabulary.d.ts +102 -0
- package/lib/types/wire-vocabulary.js +94 -0
- package/lib/utils/alias-resolver.js +2 -2
- package/lib/utils/audit.d.ts +5 -2
- package/lib/utils/audit.js +6 -3
- package/lib/utils/compliance-attributes.js +3 -4
- package/lib/utils/concurrency.d.ts +7 -0
- package/lib/utils/concurrency.js +13 -1
- package/lib/utils/env.d.ts +3 -4
- package/lib/utils/env.js +4 -5
- package/lib/utils/identity.d.ts +13 -4
- package/lib/utils/identity.js +18 -10
- package/lib/utils/index.d.ts +13 -10
- package/lib/utils/index.js +13 -10
- package/lib/utils/jwk.d.ts +4 -0
- package/lib/utils/jwk.js +13 -1
- package/lib/utils/logger.d.ts +1 -1
- package/lib/utils/logger.js +1 -1
- package/lib/utils/object.d.ts +11 -0
- package/lib/utils/object.js +24 -1
- package/lib/utils/params.d.ts +8 -22
- package/lib/utils/params.js +15 -43
- package/lib/utils/plugin-compliance.d.ts +98 -0
- package/lib/utils/plugin-compliance.js +78 -0
- package/lib/utils/proof-of-work.d.ts +69 -0
- package/lib/utils/proof-of-work.js +139 -0
- package/lib/utils/response.d.ts +16 -6
- package/lib/utils/response.js +18 -15
- package/lib/utils/retention.d.ts +17 -0
- package/lib/utils/retention.js +30 -0
- package/lib/utils/secret-encryption.d.ts +7 -7
- package/lib/utils/secret-encryption.js +9 -10
- package/lib/utils/secret-rotation.js +2 -2
- package/lib/utils/sensitive-patterns.js +4 -5
- package/lib/utils/service-registry.d.ts +15 -0
- package/lib/utils/service-registry.js +24 -0
- package/lib/utils/ssrf.d.ts +11 -2
- package/lib/utils/ssrf.js +112 -33
- package/lib/validation/ai-schemas.js +3 -2
- package/lib/validation/common-schemas.d.ts +0 -9
- package/lib/validation/common-schemas.js +1 -7
- package/lib/validation/dockerfile-static.d.ts +26 -0
- package/lib/validation/dockerfile-static.js +210 -0
- package/lib/validation/index.d.ts +13 -4
- package/lib/validation/index.js +14 -5
- package/lib/validation/message-schemas.js +6 -4
- package/lib/validation/pipeline-schemas.d.ts +8 -2
- package/lib/validation/pipeline-schemas.js +30 -4
- package/lib/validation/plugin-base-images.d.ts +20 -0
- package/lib/validation/plugin-base-images.js +17 -0
- package/lib/validation/plugin-catalog-detect.d.ts +86 -0
- package/lib/validation/plugin-catalog-detect.js +237 -0
- package/lib/validation/plugin-catalog-metadata.d.ts +141 -0
- package/lib/validation/plugin-catalog-metadata.js +162 -0
- package/lib/validation/plugin-heuristics.d.ts +41 -0
- package/lib/validation/plugin-heuristics.js +211 -0
- package/lib/validation/plugin-lint.d.ts +18 -0
- package/lib/validation/plugin-lint.js +136 -0
- package/lib/validation/plugin-name-confusable.d.ts +15 -0
- package/lib/validation/plugin-name-confusable.js +81 -0
- package/lib/validation/plugin-schemas.d.ts +40 -26
- package/lib/validation/plugin-schemas.js +26 -23
- package/lib/validation/plugin-spec-schema.d.ts +112 -0
- package/lib/validation/plugin-spec-schema.js +163 -0
- package/lib/validation/plugin-template-contract.d.ts +64 -0
- package/lib/validation/plugin-template-contract.js +113 -0
- package/package.json +69 -4
- package/lib/testing/mock-api-core.d.ts +0 -150
- package/lib/testing/mock-api-core.js +0 -246
- package/lib/testing/mock-drizzle.d.ts +0 -6
- package/lib/testing/mock-drizzle.js +0 -57
- package/lib/testing/route-coverage.d.ts +0 -64
- package/lib/testing/route-coverage.js +0 -183
- package/lib/testing/service-tokens.d.ts +0 -66
- package/lib/testing/service-tokens.js +0 -137
- package/lib/testing/tier-mock.d.ts +0 -44
- package/lib/testing/tier-mock.js +0 -65
- package/lib/testing/user-tokens.d.ts +0 -75
- package/lib/testing/user-tokens.js +0 -115
package/lib/middleware/auth.js
CHANGED
|
@@ -1,88 +1,24 @@
|
|
|
1
1
|
// Copyright 2026 Pipeline Builder Contributors
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
-
import { randomUUID } from 'crypto';
|
|
4
3
|
import jwt from 'jsonwebtoken';
|
|
5
4
|
import { tagRouteGate } from './route-table.js';
|
|
6
5
|
import { HttpStatus } from '../constants/http-status.js';
|
|
7
|
-
import { JwksUnavailableError, UnknownKidError
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
6
|
+
import { JwksUnavailableError, UnknownKidError } from '../services/jwks-cache.js';
|
|
7
|
+
import { ServiceKeyError, serviceIdentity } from '../services/service-keys.js';
|
|
8
|
+
import {} from '../types/common.js';
|
|
10
9
|
import { ErrorCode } from '../types/error-codes.js';
|
|
11
|
-
import { hasPermission } from '../types/permissions.js';
|
|
12
10
|
import { isOpaqueApiKey } from '../utils/api-key.js';
|
|
13
11
|
import { getHeaderString } from '../utils/headers.js';
|
|
14
12
|
import { getIdentity } from '../utils/identity.js';
|
|
15
|
-
import { USER_TOKEN_ALGORITHM, decodeJwtHeader } from '../utils/jwk.js';
|
|
16
|
-
import { createLogger } from '../utils/logger.js';
|
|
17
13
|
import { emitCounter } from '../utils/metric-emitter.js';
|
|
18
14
|
import { sendError } from '../utils/response.js';
|
|
15
|
+
import { checkRevocation, isImpersonationWriteBlocked, needsRevocationCheck } from './revocation.js';
|
|
16
|
+
import { hasValidIdentityClaims, verifyBearerToken } from './jwt-verify.js';
|
|
17
|
+
import { isServiceTokenDenied, serviceNameOf } from './service-tokens.js';
|
|
18
|
+
import { recordAuthzDenial } from './permission-gates.js';
|
|
19
|
+
import { refuseForAssurance } from './assurance.js';
|
|
20
|
+
import { createLogger } from '../utils/logger.js';
|
|
19
21
|
const logger = createLogger('auth-middleware');
|
|
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
|
-
};
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
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.
|
|
41
|
-
*/
|
|
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`);
|
|
46
|
-
}
|
|
47
|
-
const key = await platformJwksCache().getKey(header.kid);
|
|
48
|
-
return jwt.verify(token, key, { algorithms: [USER_TOKEN_ALGORITHM], ...issuerAudienceOptions() });
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* Verify ANY bearer token and return its claims.
|
|
52
|
-
*
|
|
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:
|
|
57
|
-
*
|
|
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.
|
|
64
|
-
*
|
|
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.
|
|
67
|
-
*/
|
|
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');
|
|
77
|
-
}
|
|
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');
|
|
83
|
-
}
|
|
84
|
-
return claims;
|
|
85
|
-
}
|
|
86
22
|
export function requireAuth(reqOrOptions, res, next) {
|
|
87
23
|
if (reqOrOptions && res && next && 'headers' in reqOrOptions) {
|
|
88
24
|
return _requireAuth({}, reqOrOptions, res, next);
|
|
@@ -97,86 +33,6 @@ export function requireAuth(reqOrOptions, res, next) {
|
|
|
97
33
|
return gate;
|
|
98
34
|
}
|
|
99
35
|
tagRouteGate(requireAuth, { kind: 'auth' });
|
|
100
|
-
let tokenRevocationStore;
|
|
101
|
-
/**
|
|
102
|
-
* Register (or clear, with `undefined`) the process-wide token-revocation store.
|
|
103
|
-
* When unset (the default), `requireAuth` performs NO revocation check (it relies
|
|
104
|
-
* on the short access-token TTL); services opt in at boot by wiring their Redis
|
|
105
|
-
* client. Platform keeps its own Mongo-backed check and need not register one.
|
|
106
|
-
*/
|
|
107
|
-
export function setTokenRevocationStore(store) {
|
|
108
|
-
tokenRevocationStore = store;
|
|
109
|
-
if (store)
|
|
110
|
-
revocationStoreMissingWarned = false; // re-arm if a store is (re)registered
|
|
111
|
-
}
|
|
112
|
-
/** One-shot guard so the "revocation inactive" warning doesn't flood the logs. */
|
|
113
|
-
let revocationStoreMissingWarned = false;
|
|
114
|
-
/**
|
|
115
|
-
* Returns true when `decoded` has been revoked per the registered store: its
|
|
116
|
-
* embedded `tokenVersion` is strictly behind the store's current version.
|
|
117
|
-
* Fail-open — any store error, a missing entry, or a token/store without a
|
|
118
|
-
* usable version yields `false` (allow). Never throws.
|
|
119
|
-
*/
|
|
120
|
-
async function isTokenRevoked(decoded) {
|
|
121
|
-
const store = tokenRevocationStore;
|
|
122
|
-
if (!store) {
|
|
123
|
-
// Make the "revocation is OFF" state OBSERVABLE: a service that verifies user
|
|
124
|
-
// tokens but forgot `setTokenRevocationStore()` silently disables the session
|
|
125
|
-
// kill-switch. Warn ONCE (only for a revocable user token) so a misconfigured
|
|
126
|
-
// boot surfaces in the logs instead of failing open invisibly.
|
|
127
|
-
if (!revocationStoreMissingWarned && decoded.sub && typeof decoded.tokenVersion === 'number') {
|
|
128
|
-
revocationStoreMissingWarned = true;
|
|
129
|
-
logger.warn('Token revocation store NOT registered — revocation checks are INACTIVE (setTokenRevocationStore was never called); revoked/compromised sessions stay valid until natural TTL');
|
|
130
|
-
}
|
|
131
|
-
return false;
|
|
132
|
-
}
|
|
133
|
-
if (!decoded.sub || typeof decoded.tokenVersion !== 'number')
|
|
134
|
-
return false;
|
|
135
|
-
try {
|
|
136
|
-
const current = await store.getCurrentVersion(decoded.sub);
|
|
137
|
-
return current !== null && decoded.tokenVersion < current;
|
|
138
|
-
}
|
|
139
|
-
catch {
|
|
140
|
-
// Fail-open: a revocation-store outage must not lock every user out.
|
|
141
|
-
return false;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
/**
|
|
145
|
-
* Resolve an impersonation session's revocation state. Never throws: any failure
|
|
146
|
-
* — no store, a store that can't answer, a read error — is `unavailable`, which
|
|
147
|
-
* callers treat as revoked.
|
|
148
|
-
*/
|
|
149
|
-
async function sessionRevocationState(jti) {
|
|
150
|
-
const store = tokenRevocationStore;
|
|
151
|
-
if (!store?.getSessionRevocation)
|
|
152
|
-
return 'unavailable';
|
|
153
|
-
try {
|
|
154
|
-
return await store.getSessionRevocation(jti);
|
|
155
|
-
}
|
|
156
|
-
catch {
|
|
157
|
-
return 'unavailable';
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
/** An impersonation session token: it names the operator AND carries its own session id. */
|
|
161
|
-
function isImpersonationSession(decoded) {
|
|
162
|
-
return typeof decoded.impersonatorId === 'string' && typeof decoded.jti === 'string' && decoded.jti.length > 0;
|
|
163
|
-
}
|
|
164
|
-
/**
|
|
165
|
-
* Public revocation check for routes that verify a platform JWT OUTSIDE
|
|
166
|
-
* `requireAuth` (e.g. the image-registry `/token` mint path, which resolves
|
|
167
|
-
* identity itself). Returns true when the token's `tokenVersion` is strictly
|
|
168
|
-
* behind the store's current version. Fail-open (never throws) — a store outage
|
|
169
|
-
* or a token/store without a usable version yields false (allow), matching
|
|
170
|
-
* `requireAuth`. Pass the verified JWT claims (`sub`, `tokenVersion`).
|
|
171
|
-
*/
|
|
172
|
-
export async function isAccessTokenRevoked(claims) {
|
|
173
|
-
// An impersonation session is revoked unless the store positively says live —
|
|
174
|
-
// including on this out-of-band path, or a revoked session could still mint
|
|
175
|
-
// registry tokens.
|
|
176
|
-
if (isImpersonationSession(claims) && await sessionRevocationState(claims.jti) !== 'live')
|
|
177
|
-
return true;
|
|
178
|
-
return isTokenRevoked(claims);
|
|
179
|
-
}
|
|
180
36
|
function _requireAuth(options, req, res, next) {
|
|
181
37
|
const authHeader = req.headers.authorization;
|
|
182
38
|
if (!authHeader) {
|
|
@@ -227,9 +83,10 @@ async function verifyAndAttach(options, rawToken, req, res, next) {
|
|
|
227
83
|
try {
|
|
228
84
|
// Two chains, one entry point (see `verifyBearerToken`): a user token must
|
|
229
85
|
// be ES256 signed by platform and verified against its published JWKS; an
|
|
230
|
-
// internal service token
|
|
231
|
-
// a service principal. Both pin the algorithm (no
|
|
232
|
-
// `alg:none`) and both apply the optional issuer/audience
|
|
86
|
+
// internal service token must be ES256 signed by that service's OWN key and
|
|
87
|
+
// declare itself a service principal. Both pin the algorithm (no
|
|
88
|
+
// alg-confusion, no `alg:none`) and both apply the optional issuer/audience
|
|
89
|
+
// binding.
|
|
233
90
|
const decoded = await verifyBearerToken(rawToken);
|
|
234
91
|
if (decoded.type !== 'access') {
|
|
235
92
|
return sendError(res, HttpStatus.UNAUTHORIZED, 'Only access tokens can be used for API requests', ErrorCode.TOKEN_INVALID);
|
|
@@ -238,10 +95,9 @@ async function verifyAndAttach(options, rawToken, req, res, next) {
|
|
|
238
95
|
return sendError(res, HttpStatus.UNAUTHORIZED, 'Token missing required fields', ErrorCode.TOKEN_INVALID);
|
|
239
96
|
}
|
|
240
97
|
// Service-token kill-switch: reject a service principal whose service has
|
|
241
|
-
// been added to the denylist.
|
|
242
|
-
//
|
|
243
|
-
//
|
|
244
|
-
// service be cut off surgically. O(1) Set lookup, zero cost when the denylist
|
|
98
|
+
// been added to the denylist. Otherwise the only way to invalidate a
|
|
99
|
+
// service's tokens before their (short) TTL is rotating that service's
|
|
100
|
+
// signing key; this cuts one compromised/rogue service off immediately. O(1) Set lookup, zero cost when the denylist
|
|
245
101
|
// is empty (the default), so it never taxes the S2S hot path unless armed.
|
|
246
102
|
if (isServiceTokenDenied(decoded)) {
|
|
247
103
|
emitCounter('service_token_denied_total', { service: serviceNameOf(decoded) ?? 'unknown' });
|
|
@@ -249,7 +105,16 @@ async function verifyAndAttach(options, rawToken, req, res, next) {
|
|
|
249
105
|
return sendError(res, HttpStatus.UNAUTHORIZED, 'Service token revoked', ErrorCode.TOKEN_REVOKED);
|
|
250
106
|
}
|
|
251
107
|
req.user = { ...decoded };
|
|
252
|
-
//
|
|
108
|
+
// READ-ONLY IMPERSONATION. The token names the operator AND says it may only
|
|
109
|
+
// look: every service refuses a state change under it, not only platform —
|
|
110
|
+
// a support session that could write to plugin/compliance/billing is not
|
|
111
|
+
// read-only. Checked before any other gate so no route can forget it.
|
|
112
|
+
if (isImpersonationWriteBlocked(req.method, decoded)) {
|
|
113
|
+
if (req.method)
|
|
114
|
+
recordAuthzDenial(req, 'impersonation-read-only');
|
|
115
|
+
return sendError(res, HttpStatus.FORBIDDEN, 'Write requests are disabled during read-only impersonation. Stop impersonating to make changes.', ErrorCode.IMPERSONATION_READ_ONLY);
|
|
116
|
+
}
|
|
117
|
+
// BOOTSTRAP-ADMIN ENROLMENT SESSION. Such a token exists so
|
|
253
118
|
// the install's only admin can enrol a factor; it is `aal: 1` and must not
|
|
254
119
|
// reach anything else. Platform — which owns the exception and knows which
|
|
255
120
|
// of its own routes `init-platform.sh` calls — allows an explicit few before
|
|
@@ -296,35 +161,17 @@ async function verifyAndAttach(options, rawToken, req, res, next) {
|
|
|
296
161
|
if (reqCtx) {
|
|
297
162
|
reqCtx.identity = getIdentity(req);
|
|
298
163
|
}
|
|
299
|
-
// Session
|
|
300
|
-
//
|
|
301
|
-
|
|
302
|
-
// no-op and control passes straight through. Fail-open on any store error.
|
|
303
|
-
// An impersonation session is checked even when NO store is registered: the
|
|
304
|
-
// tokenVersion check below is a no-op without a store, but for a session
|
|
305
|
-
// that would silently mean "never revoked". Here no store ⇒ unavailable ⇒
|
|
306
|
-
// rejected. See `TokenRevocationStore.getSessionRevocation`.
|
|
307
|
-
const impersonation = isImpersonationSession(decoded);
|
|
308
|
-
if (impersonation || (tokenRevocationStore && decoded.sub && typeof decoded.tokenVersion === 'number')) {
|
|
164
|
+
// Session invalidation (token-version store + impersonation-session
|
|
165
|
+
// liveness). No store registered ⇒ only impersonation sessions are checked.
|
|
166
|
+
if (needsRevocationCheck(decoded)) {
|
|
309
167
|
// `.catch(next)` forwards a DOWNSTREAM synchronous throw from `next()` to
|
|
310
|
-
// Express's error middleware —
|
|
311
|
-
//
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
if (impersonation) {
|
|
316
|
-
const state = await sessionRevocationState(decoded.jti);
|
|
317
|
-
if (state !== 'live') {
|
|
318
|
-
return sendError(res, HttpStatus.UNAUTHORIZED, state === 'revoked'
|
|
319
|
-
? 'This impersonation session has been ended'
|
|
320
|
-
: 'This impersonation session could not be verified', ErrorCode.TOKEN_REVOKED);
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
if (tokenRevocationStore && decoded.sub && typeof decoded.tokenVersion === 'number' && await isTokenRevoked(decoded)) {
|
|
324
|
-
return sendError(res, HttpStatus.UNAUTHORIZED, 'Session has been revoked; please sign in again', ErrorCode.TOKEN_REVOKED);
|
|
325
|
-
}
|
|
168
|
+
// Express's error middleware — this `next()` runs in a microtask, outside
|
|
169
|
+
// the surrounding try/catch. The check itself never rejects.
|
|
170
|
+
checkRevocation(decoded).then((refusal) => {
|
|
171
|
+
if (refusal)
|
|
172
|
+
return sendError(res, HttpStatus.UNAUTHORIZED, refusal, ErrorCode.TOKEN_REVOKED);
|
|
326
173
|
next();
|
|
327
|
-
})
|
|
174
|
+
}).catch(next);
|
|
328
175
|
return;
|
|
329
176
|
}
|
|
330
177
|
next();
|
|
@@ -349,604 +196,4 @@ async function verifyAndAttach(options, rawToken, req, res, next) {
|
|
|
349
196
|
return sendError(res, HttpStatus.UNAUTHORIZED, 'Authentication failed', ErrorCode.UNAUTHORIZED);
|
|
350
197
|
}
|
|
351
198
|
}
|
|
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
|
-
// A named exemption is checked AFTER authentication and before the level, so
|
|
379
|
-
// it can never admit an unauthenticated caller, and it is counted every time
|
|
380
|
-
// it fires — an exemption nobody can see is how a gate quietly stops being one.
|
|
381
|
-
if (options.exempt?.when(req) === true) {
|
|
382
|
-
emitCounter('assurance_exempted_total', { service: serviceIdentity(), reason: options.exempt.reason });
|
|
383
|
-
return next();
|
|
384
|
-
}
|
|
385
|
-
if (refuseForAssurance(options, req.user, req, res))
|
|
386
|
-
return;
|
|
387
|
-
next();
|
|
388
|
-
}, {
|
|
389
|
-
kind: 'assurance',
|
|
390
|
-
minAssurance: options.minAssurance,
|
|
391
|
-
...(options.maxAge !== undefined ? { maxAge: options.maxAge } : {}),
|
|
392
|
-
...(options.exempt ? { exempt: options.exempt.reason } : {}),
|
|
393
|
-
});
|
|
394
|
-
}
|
|
395
|
-
/**
|
|
396
|
-
* Handler-level twin of {@link requireAssurance}, for a route where only SOME
|
|
397
|
-
* requests must be MFA-grade — e.g. a policy route on which TIGHTENING a setting
|
|
398
|
-
* stays open to a single-factor session (so an admin without MFA can adopt it)
|
|
399
|
-
* but LOOSENING it does not. Same rules and the same three refusals. Returns
|
|
400
|
-
* true when the request was REFUSED (a response has been sent).
|
|
401
|
-
*/
|
|
402
|
-
export function refuseWeakSession(req, res, options) {
|
|
403
|
-
if (!req.user) {
|
|
404
|
-
sendError(res, HttpStatus.UNAUTHORIZED, 'Authentication required', ErrorCode.UNAUTHORIZED);
|
|
405
|
-
return true;
|
|
406
|
-
}
|
|
407
|
-
return refuseForAssurance(options, req.user, req, res);
|
|
408
|
-
}
|
|
409
|
-
/** `details.reason` on a refusal by {@link requireOrgAdminAssurance}, so the UI
|
|
410
|
-
* can say it is the ORG's policy asking, not the route's own requirement. */
|
|
411
|
-
export const ORG_ADMIN_MFA_REASON = 'org_admin_policy';
|
|
412
|
-
/**
|
|
413
|
-
* The refusal {@link requireOrgAdminAssurance} would send for these claims, or
|
|
414
|
-
* `undefined` when the request may proceed. Exported so a handler whose policy
|
|
415
|
-
* applies to only PART of a route (e.g. `generate-token`, where opening a new
|
|
416
|
-
* machine credential is gated but renewing an existing one is not) applies the
|
|
417
|
-
* exact same rule rather than a copy of it.
|
|
418
|
-
*/
|
|
419
|
-
export function orgAdminAssuranceRefusal(claims, options) {
|
|
420
|
-
// The claim is only ever `2`, and only when the policy is on (see JwtPayload).
|
|
421
|
-
if (!claims || claims.org_admin_aal !== 2)
|
|
422
|
-
return undefined;
|
|
423
|
-
if (!isHumanPrincipal(claims)) {
|
|
424
|
-
if (options.machines === 'allow')
|
|
425
|
-
return undefined;
|
|
426
|
-
return {
|
|
427
|
-
status: HttpStatus.FORBIDDEN,
|
|
428
|
-
code: ErrorCode.HUMAN_SESSION_REQUIRED,
|
|
429
|
-
reason: 'machine_principal',
|
|
430
|
-
message: 'Your organization requires two-factor authentication for this action — API keys and service accounts cannot perform it',
|
|
431
|
-
};
|
|
432
|
-
}
|
|
433
|
-
if ((claims.aal ?? 1) >= 2)
|
|
434
|
-
return undefined;
|
|
435
|
-
return {
|
|
436
|
-
status: HttpStatus.UNAUTHORIZED,
|
|
437
|
-
code: ErrorCode.MFA_REQUIRED,
|
|
438
|
-
reason: 'weak_session',
|
|
439
|
-
message: 'Your organization requires two-factor authentication for administrative actions — sign in again with a passkey or an authenticator code',
|
|
440
|
-
};
|
|
441
|
-
}
|
|
442
|
-
/**
|
|
443
|
-
* Apply {@link orgAdminAssuranceRefusal} and send its refusal. Returns true when
|
|
444
|
-
* the request was REFUSED (a response has been sent). For handler-level use;
|
|
445
|
-
* routes use {@link requireOrgAdminAssurance}.
|
|
446
|
-
*/
|
|
447
|
-
export function refuseForOrgAdminAssurance(req, res, options) {
|
|
448
|
-
const refusal = orgAdminAssuranceRefusal(req.user, options);
|
|
449
|
-
if (!refusal)
|
|
450
|
-
return false;
|
|
451
|
-
emitCounter('mfa_enforcement_refused_total', { service: serviceIdentity(), reason: `org_admin_${refusal.reason}` });
|
|
452
|
-
recordAuthzDenial(req, 'assurance:org-admin');
|
|
453
|
-
sendError(res, refusal.status, refusal.message, refusal.code, { reason: ORG_ADMIN_MFA_REASON });
|
|
454
|
-
return true;
|
|
455
|
-
}
|
|
456
|
-
/**
|
|
457
|
-
* The org policy "administrative actions require MFA" (`adminActionsRequireMfa`).
|
|
458
|
-
*
|
|
459
|
-
* Unlike {@link requireAssurance}, the requirement is the ORG's choice, not the
|
|
460
|
-
* route's: the gate reads the `org_admin_aal` claim, set at token issue from the
|
|
461
|
-
* active org's policy (strictest across its ancestors), so a service that cannot
|
|
462
|
-
* read the org document still enforces it. With the policy off the gate is a
|
|
463
|
-
* no-op; with it on, a single-factor session is refused 401 `MFA_REQUIRED`
|
|
464
|
-
* (with `details.reason: 'org_admin_policy'`) — the same code the client already
|
|
465
|
-
* turns into "enrol a factor / sign in with it", never a sign-out.
|
|
466
|
-
*
|
|
467
|
-
* `machines` is decided per route (see {@link OrgAdminAssuranceMachines}): the
|
|
468
|
-
* policy is about how strongly a PERSON's session was opened, so automation that
|
|
469
|
-
* legitimately drives a route keeps working (`allow`), while a route that mints
|
|
470
|
-
* a further credential refuses machines outright (`refuse`, 403
|
|
471
|
-
* `HUMAN_SESSION_REQUIRED` — the same refusal `requireAssurance` gives them).
|
|
472
|
-
*/
|
|
473
|
-
export function requireOrgAdminAssurance(options) {
|
|
474
|
-
return tagRouteGate((req, res, next) => {
|
|
475
|
-
if (!req.user) {
|
|
476
|
-
return sendError(res, HttpStatus.UNAUTHORIZED, 'Authentication required', ErrorCode.UNAUTHORIZED);
|
|
477
|
-
}
|
|
478
|
-
if (refuseForOrgAdminAssurance(req, res, options))
|
|
479
|
-
return;
|
|
480
|
-
next();
|
|
481
|
-
}, { kind: 'orgAdminAssurance', machines: options.machines });
|
|
482
|
-
}
|
|
483
|
-
/**
|
|
484
|
-
* Enforce `minAssurance` / `maxAge` on a verified token. Returns true when the
|
|
485
|
-
* request was REFUSED (a response has been sent).
|
|
486
|
-
*
|
|
487
|
-
* Three distinct refusals, because the client's next move differs for each:
|
|
488
|
-
* a machine must stop (403), a weak session must gain a factor (401
|
|
489
|
-
* `MFA_REQUIRED` → enrolment, never a sign-out), and a stale one must simply
|
|
490
|
-
* authenticate again (401 `REAUTH_REQUIRED`).
|
|
491
|
-
*/
|
|
492
|
-
function refuseForAssurance(options, decoded, req, res) {
|
|
493
|
-
const minAssurance = options.minAssurance;
|
|
494
|
-
const refuse = (reason, status, message, code) => {
|
|
495
|
-
emitCounter('mfa_enforcement_refused_total', { service: serviceIdentity(), reason });
|
|
496
|
-
recordAuthzDenial(req, `assurance:${minAssurance}`);
|
|
497
|
-
sendError(res, status, message, code);
|
|
498
|
-
return true;
|
|
499
|
-
};
|
|
500
|
-
if (!isHumanPrincipal(decoded)) {
|
|
501
|
-
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);
|
|
502
|
-
}
|
|
503
|
-
if ((decoded.aal ?? 1) < minAssurance) {
|
|
504
|
-
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);
|
|
505
|
-
}
|
|
506
|
-
if (options.maxAge !== undefined) {
|
|
507
|
-
const authTime = decoded.auth_time;
|
|
508
|
-
// No `auth_time` is not "recent enough by default" — `hasValidIdentityClaims`
|
|
509
|
-
// already requires it on a user token, so an absent one means a token this
|
|
510
|
-
// gate cannot reason about. Fail closed.
|
|
511
|
-
if (typeof authTime !== 'number' || Math.floor(Date.now() / 1000) - authTime > options.maxAge) {
|
|
512
|
-
return refuse('stale_session', HttpStatus.UNAUTHORIZED, 'This action requires a recent sign-in — please authenticate again', ErrorCode.REAUTH_REQUIRED);
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
return false;
|
|
516
|
-
}
|
|
517
|
-
/**
|
|
518
|
-
* Whether a verified token carries a well-formed identity: a known
|
|
519
|
-
* `principalType` and `token_use`, and the claims that kind of principal must
|
|
520
|
-
* have. Fails closed — a token minted before these claims existed, or one with a
|
|
521
|
-
* contradictory combination, is not an identity any gate should reason about.
|
|
522
|
-
*
|
|
523
|
-
* - `service`: `token_use: 'access'` and a `service:<name>` subject (the name
|
|
524
|
-
* feeds the denylist and audit attribution).
|
|
525
|
-
* - `user` / `service_account`: `amr` (known methods), `aal` and `auth_time`.
|
|
526
|
-
*/
|
|
527
|
-
export function hasValidIdentityClaims(decoded) {
|
|
528
|
-
if (!decoded.principalType || !PRINCIPAL_TYPES.includes(decoded.principalType))
|
|
529
|
-
return false;
|
|
530
|
-
if (!decoded.token_use || !TOKEN_USES.includes(decoded.token_use))
|
|
531
|
-
return false;
|
|
532
|
-
if (decoded.principalType === 'service') {
|
|
533
|
-
return decoded.token_use === 'access'
|
|
534
|
-
&& typeof decoded.sub === 'string'
|
|
535
|
-
&& decoded.sub.startsWith(SERVICE_SUBJECT_PREFIX)
|
|
536
|
-
&& decoded.sub.length > SERVICE_SUBJECT_PREFIX.length;
|
|
537
|
-
}
|
|
538
|
-
return Array.isArray(decoded.amr)
|
|
539
|
-
&& decoded.amr.every((m) => AUTH_METHODS.includes(m))
|
|
540
|
-
&& (decoded.aal === 1 || decoded.aal === 2)
|
|
541
|
-
&& typeof decoded.auth_time === 'number';
|
|
542
|
-
}
|
|
543
|
-
/**
|
|
544
|
-
* Whether the request's user holds `permission`. Superadmins implicitly hold
|
|
545
|
-
* every permission. Reads the resolved `permissions` claim (set at token issue,
|
|
546
|
-
* or re-derived per request by the platform).
|
|
547
|
-
*/
|
|
548
|
-
export function userHasPermission(req, permission) {
|
|
549
|
-
return hasPermission(req.user?.permissions, permission, req.user?.isSuperAdmin);
|
|
550
|
-
}
|
|
551
|
-
/**
|
|
552
|
-
* Optional sink for denied-authorization events. Left unset by default so
|
|
553
|
-
* api-core stays decoupled from any audit transport — a service registers one
|
|
554
|
-
* at boot (typically forwarding to its `RemoteAuditClient` as an
|
|
555
|
-
* `authz.denied` event, or, on platform, to the local `audit()` helper).
|
|
556
|
-
* MUST be best-effort: it is invoked inside the request path, so it must never
|
|
557
|
-
* throw or block (the gate wraps the call in try/catch regardless).
|
|
558
|
-
*/
|
|
559
|
-
let authzDenialAuditor;
|
|
560
|
-
/**
|
|
561
|
-
* Register (or clear, with `undefined`) the process-wide authorization-denial
|
|
562
|
-
* auditor. Idempotent; the last registration wins.
|
|
563
|
-
*/
|
|
564
|
-
export function setAuthzDenialAuditor(fn) {
|
|
565
|
-
authzDenialAuditor = fn;
|
|
566
|
-
}
|
|
567
|
-
/**
|
|
568
|
-
* Emit a denial event, best-effort. Only fires for state-changing (non-GET,
|
|
569
|
-
* non-HEAD/OPTIONS) requests — a rejected GET is low-signal probing noise and
|
|
570
|
-
* would amplify audit volume under a scan. Never throws.
|
|
571
|
-
*
|
|
572
|
-
* The permission gates here call it themselves. Export it for data-driven checks
|
|
573
|
-
* a route makes inline (cross-org access, service-only endpoints), so those 403s
|
|
574
|
-
* reach the same `authz.denied` trail. `required` names what was missing.
|
|
575
|
-
*/
|
|
576
|
-
export function recordAuthzDenial(req, required) {
|
|
577
|
-
const auditor = authzDenialAuditor;
|
|
578
|
-
if (!auditor)
|
|
579
|
-
return;
|
|
580
|
-
const method = req.method.toUpperCase();
|
|
581
|
-
if (method === 'GET' || method === 'HEAD' || method === 'OPTIONS')
|
|
582
|
-
return;
|
|
583
|
-
try {
|
|
584
|
-
auditor({
|
|
585
|
-
actorId: req.user?.sub,
|
|
586
|
-
actorEmail: req.user?.email,
|
|
587
|
-
orgId: req.user?.organizationId,
|
|
588
|
-
method,
|
|
589
|
-
// Strip the query string — a denied request may carry a token/secret as a
|
|
590
|
-
// query param, and this path is persisted verbatim into the audit log.
|
|
591
|
-
path: (req.originalUrl || req.url).split('?')[0],
|
|
592
|
-
required,
|
|
593
|
-
});
|
|
594
|
-
}
|
|
595
|
-
catch {
|
|
596
|
-
// Best-effort — a broken auditor must never break the auth gate.
|
|
597
|
-
}
|
|
598
|
-
}
|
|
599
|
-
/**
|
|
600
|
-
* Requires that the user hold AT LEAST ONE of the given permissions (or be a
|
|
601
|
-
* superadmin). Use after requireAuth. Mirrors `requireRole`'s any-of semantics;
|
|
602
|
-
* pass a single permission for a specific action, or several when any one of
|
|
603
|
-
* them should grant access.
|
|
604
|
-
*/
|
|
605
|
-
export function requirePermission(...permissions) {
|
|
606
|
-
return tagRouteGate((req, res, next) => {
|
|
607
|
-
if (!req.user) {
|
|
608
|
-
return sendError(res, HttpStatus.UNAUTHORIZED, 'Authentication required', ErrorCode.UNAUTHORIZED);
|
|
609
|
-
}
|
|
610
|
-
// userHasPermission → hasPermission already grants superadmins every
|
|
611
|
-
// permission, so this single check covers both the superadmin bypass and
|
|
612
|
-
// the any-of membership test without re-inlining either.
|
|
613
|
-
if (permissions.some((p) => userHasPermission(req, p)))
|
|
614
|
-
return next();
|
|
615
|
-
recordAuthzDenial(req, permissions.join(' or '));
|
|
616
|
-
return sendError(res, HttpStatus.FORBIDDEN, `Missing required permission: ${permissions.join(' or ')}`, ErrorCode.INSUFFICIENT_PERMISSIONS);
|
|
617
|
-
}, { kind: 'permission', mode: 'any', permissions });
|
|
618
|
-
}
|
|
619
|
-
/**
|
|
620
|
-
* Requires that the user hold EVERY one of the given permissions (or be a
|
|
621
|
-
* superadmin) — the AND counterpart to `requirePermission`'s any-of. Use for a
|
|
622
|
-
* sensitive action that legitimately demands two distinct capabilities at once
|
|
623
|
-
* (e.g. a cross-surface operation), so the guarantee is explicit rather than
|
|
624
|
-
* approximated by chaining two `requirePermission` gates. Superadmins bypass
|
|
625
|
-
* (they implicitly hold every permission).
|
|
626
|
-
*/
|
|
627
|
-
export function requireAllPermissions(...permissions) {
|
|
628
|
-
return tagRouteGate((req, res, next) => {
|
|
629
|
-
if (!req.user) {
|
|
630
|
-
return sendError(res, HttpStatus.UNAUTHORIZED, 'Authentication required', ErrorCode.UNAUTHORIZED);
|
|
631
|
-
}
|
|
632
|
-
const missing = permissions.filter((p) => !userHasPermission(req, p));
|
|
633
|
-
if (missing.length === 0)
|
|
634
|
-
return next();
|
|
635
|
-
recordAuthzDenial(req, permissions.join(' and '));
|
|
636
|
-
return sendError(res, HttpStatus.FORBIDDEN, `Missing required permission: ${missing.join(' and ')}`, ErrorCode.INSUFFICIENT_PERMISSIONS);
|
|
637
|
-
}, { kind: 'permission', mode: 'all', permissions });
|
|
638
|
-
}
|
|
639
|
-
/**
|
|
640
|
-
* Like {@link requirePermission} (any-of) but ALSO admits an internal service
|
|
641
|
-
* principal (`principalType: 'service'`). For READ endpoints that BOTH
|
|
642
|
-
* interactive users — who must hold one of the `:read` capabilities — AND
|
|
643
|
-
* service-to-service callers legitimately hit; service tokens carry no
|
|
644
|
-
* permission claims (they're least-privilege `role:member`), so a plain
|
|
645
|
-
* `requirePermission` would wrongly 403 them. Superadmins pass via
|
|
646
|
-
* `userHasPermission`'s implicit-all. Use only where a service caller is a known,
|
|
647
|
-
* intended consumer of the route (verify the callers); prefer plain
|
|
648
|
-
* `requirePermission` for purely user-facing reads.
|
|
649
|
-
*/
|
|
650
|
-
export function requirePermissionOrService(...permissions) {
|
|
651
|
-
return tagRouteGate((req, res, next) => {
|
|
652
|
-
if (!req.user) {
|
|
653
|
-
return sendError(res, HttpStatus.UNAUTHORIZED, 'Authentication required', ErrorCode.UNAUTHORIZED);
|
|
654
|
-
}
|
|
655
|
-
if (isServicePrincipal(req) || permissions.some((p) => userHasPermission(req, p)))
|
|
656
|
-
return next();
|
|
657
|
-
recordAuthzDenial(req, permissions.join(' or '));
|
|
658
|
-
return sendError(res, HttpStatus.FORBIDDEN, `Missing required permission: ${permissions.join(' or ')}`, ErrorCode.INSUFFICIENT_PERMISSIONS);
|
|
659
|
-
}, { kind: 'permission', mode: 'any', permissions, allowService: true });
|
|
660
|
-
}
|
|
661
|
-
/**
|
|
662
|
-
* Gate an endpoint to internal service-to-service callers only (a
|
|
663
|
-
* `principalType: 'service'` principal minted via {@link signServiceToken} / `getServiceAuthHeader`).
|
|
664
|
-
* Rejects any user token. For NON-user-facing endpoints — entity-event ingest,
|
|
665
|
-
* auto-subscribe, and similar peer-service hooks — that a browser must never
|
|
666
|
-
* reach. Compose after `requireAuth` so `req.user` is populated.
|
|
667
|
-
*/
|
|
668
|
-
export function requireServicePrincipal(req, res, next) {
|
|
669
|
-
if (!isServicePrincipal(req)) {
|
|
670
|
-
// 403 (not 400) — this is an authorization refusal; status must match the
|
|
671
|
-
// INSUFFICIENT_PERMISSIONS code and the sibling gates (requirePermission, etc.).
|
|
672
|
-
return sendError(res, HttpStatus.FORBIDDEN, 'Internal service calls only', ErrorCode.INSUFFICIENT_PERMISSIONS);
|
|
673
|
-
}
|
|
674
|
-
next();
|
|
675
|
-
}
|
|
676
|
-
tagRouteGate(requireServicePrincipal, { kind: 'servicePrincipal' });
|
|
677
|
-
/**
|
|
678
|
-
* THE gate for an INTERNAL route (#14) — the one every `/internal/*` path, the
|
|
679
|
-
* quota usage counters, the entity-event ingest and the audit ingest go through.
|
|
680
|
-
*
|
|
681
|
-
* Two rules, both fail-closed:
|
|
682
|
-
*
|
|
683
|
-
* 1. **No user token, ever.** Not a member's, not a superadmin's, not a
|
|
684
|
-
* service-account key's. An internal route is a peer-service API surface, so
|
|
685
|
-
* "a sufficiently privileged human" is not an acceptable caller — that
|
|
686
|
-
* equivalence is exactly how a browser-reachable path becomes a tenant
|
|
687
|
-
* boundary bug. `requireServicePrincipal` already refused users; this also
|
|
688
|
-
* closes the `|| isSystemAdmin(req)` escape hatches that had grown around
|
|
689
|
-
* the individual internal routes.
|
|
690
|
-
* 2. **Only the NAMED callers.** `callers` lists the services that legitimately
|
|
691
|
-
* call this route, and the name is cryptographically bound to the signing
|
|
692
|
-
* key (`services/service-keys.ts`), so this is an identity check rather than
|
|
693
|
-
* a claim check. It is the same allow-list the mesh policy names, at the
|
|
694
|
-
* layer that also holds in docker compose, where there is no mesh at all —
|
|
695
|
-
* the Istio `AuthorizationPolicy` is defence in depth on top, never the
|
|
696
|
-
* enforcement.
|
|
697
|
-
*
|
|
698
|
-
* Compose after `requireAuth` so `req.user` is populated. Refusals are counted
|
|
699
|
-
* (`internal_route_refused_total`) and audited through the shared `authz.denied`
|
|
700
|
-
* sink.
|
|
701
|
-
*/
|
|
702
|
-
export function requireInternalService(options) {
|
|
703
|
-
const allowed = new Set(options.callers);
|
|
704
|
-
return tagRouteGate((req, res, next) => {
|
|
705
|
-
const refuse = (reason) => {
|
|
706
|
-
emitCounter('internal_route_refused_total', {
|
|
707
|
-
service: serviceIdentity(),
|
|
708
|
-
route: req.route?.path ? `${req.method} ${req.baseUrl}${req.route.path}` : `${req.method} ${(req.originalUrl || req.url).split('?')[0]}`,
|
|
709
|
-
reason,
|
|
710
|
-
caller: serviceNameOf(req.user) ?? 'none',
|
|
711
|
-
});
|
|
712
|
-
recordAuthzDenial(req, `internal-service (${options.callers.join(', ')})`);
|
|
713
|
-
if (reason === 'unauthenticated') {
|
|
714
|
-
return sendError(res, HttpStatus.UNAUTHORIZED, 'Authentication required', ErrorCode.UNAUTHORIZED);
|
|
715
|
-
}
|
|
716
|
-
logger.warn('Refused an internal route', { reason, path: (req.originalUrl || req.url).split('?')[0], caller: serviceNameOf(req.user) });
|
|
717
|
-
return sendError(res, HttpStatus.FORBIDDEN, 'Internal service calls only', ErrorCode.INSUFFICIENT_PERMISSIONS);
|
|
718
|
-
};
|
|
719
|
-
if (!req.user)
|
|
720
|
-
return refuse('unauthenticated');
|
|
721
|
-
if (!isServicePrincipal(req))
|
|
722
|
-
return refuse('user_token');
|
|
723
|
-
const caller = serviceNameOf(req.user);
|
|
724
|
-
if (!caller || !allowed.has(caller))
|
|
725
|
-
return refuse('wrong_caller');
|
|
726
|
-
next();
|
|
727
|
-
}, { kind: 'servicePrincipal' }, { kind: 'internalService', callers: [...options.callers] });
|
|
728
|
-
}
|
|
729
|
-
/**
|
|
730
|
-
* The system tenant's canonical org **id** — a fixed, well-known ObjectId (NOT
|
|
731
|
-
* the string 'system'). This is the single knob every service resolves the
|
|
732
|
-
* system tenant through; override via the `SYSTEM_ORG_ID` env for alternate
|
|
733
|
-
* installs. The system org's human identifier stays the slug/name 'system'
|
|
734
|
-
* (see {@link SYSTEM_ORG_SLUG}); only its `_id` is this ObjectId.
|
|
735
|
-
*/
|
|
736
|
-
export const SYSTEM_ORG_ID = (process.env.SYSTEM_ORG_ID || '000000000000000000000001').toLowerCase();
|
|
737
|
-
/** The system org's well-known slug/name (the human identifier; its `_id` is {@link SYSTEM_ORG_ID}). */
|
|
738
|
-
export const SYSTEM_ORG_SLUG = 'system';
|
|
739
|
-
/**
|
|
740
|
-
* Check if an orgId or orgName/slug matches the system org. Use this instead of
|
|
741
|
-
* comparing directly: the id is now an ObjectId ({@link SYSTEM_ORG_ID}) while the
|
|
742
|
-
* name/slug is 'system' ({@link SYSTEM_ORG_SLUG}), so the two are compared against
|
|
743
|
-
* their respective canonical values.
|
|
744
|
-
*/
|
|
745
|
-
export function isSystemOrgId(orgId, orgName) {
|
|
746
|
-
return orgId?.toLowerCase() === SYSTEM_ORG_ID || orgName?.toLowerCase() === SYSTEM_ORG_SLUG;
|
|
747
|
-
}
|
|
748
|
-
/**
|
|
749
|
-
* Check if the request is from a system admin.
|
|
750
|
-
*
|
|
751
|
-
* Authority is granted solely by the user-level `isSuperAdmin` flag carried
|
|
752
|
-
* in the JWT. The "membership in the well-known 'system' org with role
|
|
753
|
-
* admin/owner" path was removed — it conflated a Pipeline Builder operator
|
|
754
|
-
* with a real customer tenant in the data model, and meant any unintended
|
|
755
|
-
* write that created a 'system'-named org could quietly grant cross-org
|
|
756
|
-
* authority. The `system` org still exists as a *content holder* for shared
|
|
757
|
-
* sample data; it just no longer confers privilege.
|
|
758
|
-
*/
|
|
759
|
-
export function isSystemAdmin(req) {
|
|
760
|
-
return req.user?.isSuperAdmin === true;
|
|
761
|
-
}
|
|
762
|
-
/**
|
|
763
|
-
* Whether the request's token carries a specific capability `scope` (e.g.
|
|
764
|
-
* `'reporting:ingest'`). Used to gate endpoints that accept a narrow machine
|
|
765
|
-
* identity — a normal interactive user token has no `scope` and returns false.
|
|
766
|
-
*/
|
|
767
|
-
export function hasScope(req, scope) {
|
|
768
|
-
return req.user?.scope === scope;
|
|
769
|
-
}
|
|
770
|
-
/** Requires a system admin — granted solely by the `isSuperAdmin` token claim
|
|
771
|
-
* (the org-membership path was removed). Use after requireAuth. */
|
|
772
|
-
export function requireSystemAdmin(req, res, next) {
|
|
773
|
-
if (!isSystemAdmin(req)) {
|
|
774
|
-
recordAuthzDenial(req, 'system-admin');
|
|
775
|
-
return sendError(res, HttpStatus.FORBIDDEN, 'Access denied. Only system administrators can perform this action.', ErrorCode.INSUFFICIENT_PERMISSIONS);
|
|
776
|
-
}
|
|
777
|
-
next();
|
|
778
|
-
}
|
|
779
|
-
tagRouteGate(requireSystemAdmin, { kind: 'systemAdmin' });
|
|
780
|
-
/**
|
|
781
|
-
* Require a specific feature flag. Use after requireAuth.
|
|
782
|
-
* Checks the `features` array in the JWT payload (set at token issuance).
|
|
783
|
-
* Sysadmins (isSuperAdmin) bypass — they always have every feature.
|
|
784
|
-
*/
|
|
785
|
-
export function requireFeature(feature) {
|
|
786
|
-
return tagRouteGate((req, res, next) => {
|
|
787
|
-
if (!req.user) {
|
|
788
|
-
return sendError(res, HttpStatus.UNAUTHORIZED, 'Authentication required', ErrorCode.UNAUTHORIZED);
|
|
789
|
-
}
|
|
790
|
-
// Sysadmins get all features; the `features` array on their token is
|
|
791
|
-
// populated with every flag at issuance time but the bypass here keeps
|
|
792
|
-
// the rule explicit and survives a token issued before a new feature
|
|
793
|
-
// flag was added.
|
|
794
|
-
if (req.user.isSuperAdmin === true)
|
|
795
|
-
return next();
|
|
796
|
-
if (!req.user.features?.includes(feature)) {
|
|
797
|
-
// Route feature-gate denials through the same audit sink as
|
|
798
|
-
// requirePermission / requireSystemAdmin so a probe for an
|
|
799
|
-
// unentitled capability leaves a trail (state-changing methods only).
|
|
800
|
-
recordAuthzDenial(req, `feature:${feature}`);
|
|
801
|
-
return sendError(res, HttpStatus.FORBIDDEN, `This feature requires a higher plan (${feature})`, ErrorCode.INSUFFICIENT_PERMISSIONS);
|
|
802
|
-
}
|
|
803
|
-
next();
|
|
804
|
-
}, { kind: 'feature', feature });
|
|
805
|
-
}
|
|
806
|
-
// ---------------------------------------------------------------------------
|
|
807
|
-
// Service-to-service tokens
|
|
808
|
-
//
|
|
809
|
-
// Inter-service HTTP calls (billing → message, platform → compliance, etc.)
|
|
810
|
-
// need to satisfy the same `requireAuth` middleware as user requests.
|
|
811
|
-
// `signServiceToken` mints a short-lived ES256 JWT signed with THIS service's
|
|
812
|
-
// OWN key (see `services/service-keys.ts`), carrying `principalType: 'service'`
|
|
813
|
-
// and naming the calling service via `sub: 'service:<name>'`. Gates branch on
|
|
814
|
-
// the claim; the subject names — and since #14 the name is cryptographically
|
|
815
|
-
// bound to the signing key, so it can also be trusted.
|
|
816
|
-
// `requireAuth` accepts these tokens transparently — they pass `decoded.sub`
|
|
817
|
-
// and `decoded.role` checks, and downstream `requireOrganization` /
|
|
818
|
-
// `requireSystemAdmin` rely on the org/role embedded in the token.
|
|
819
|
-
//
|
|
820
|
-
// Tokens default to 5-minute TTL — long enough to survive a backend hop,
|
|
821
|
-
// short enough that a leaked token is low-value.
|
|
822
|
-
// ---------------------------------------------------------------------------
|
|
823
|
-
const DEFAULT_SERVICE_TOKEN_TTL_SECONDS = 300;
|
|
824
|
-
/**
|
|
825
|
-
* Denylist of service NAMES (the `<name>` in `sub: service:<name>`) whose tokens
|
|
826
|
-
* `requireAuth` must reject. Read from `SERVICE_TOKEN_DENYLIST` (comma-separated)
|
|
827
|
-
* at process start, so arming it is a config change + rollout — it cuts off a
|
|
828
|
-
* compromised service WITHOUT rotating any key, and (unlike the pre-#14 shared
|
|
829
|
-
* secret) without invalidating every other service's tokens as collateral.
|
|
830
|
-
*/
|
|
831
|
-
const serviceTokenDenylist = new Set((process.env.SERVICE_TOKEN_DENYLIST || '')
|
|
832
|
-
.split(',')
|
|
833
|
-
.map((s) => s.trim())
|
|
834
|
-
.filter(Boolean));
|
|
835
|
-
/**
|
|
836
|
-
* The calling service's name for a SERVICE principal (`principalType: 'service'`),
|
|
837
|
-
* else `undefined`. A user token never yields a name, whatever its `sub` says.
|
|
838
|
-
*/
|
|
839
|
-
export function serviceNameOf(claims) {
|
|
840
|
-
if (claims?.principalType !== 'service' || typeof claims.sub !== 'string')
|
|
841
|
-
return undefined;
|
|
842
|
-
if (!claims.sub.startsWith(SERVICE_SUBJECT_PREFIX))
|
|
843
|
-
return undefined;
|
|
844
|
-
return claims.sub.slice(SERVICE_SUBJECT_PREFIX.length) || undefined;
|
|
845
|
-
}
|
|
846
|
-
/** True when the claims are a service principal whose service is on the denylist. */
|
|
847
|
-
export function isServiceTokenDenied(claims) {
|
|
848
|
-
if (serviceTokenDenylist.size === 0)
|
|
849
|
-
return false;
|
|
850
|
-
const name = serviceNameOf(claims);
|
|
851
|
-
return name !== undefined && serviceTokenDenylist.has(name);
|
|
852
|
-
}
|
|
853
|
-
/**
|
|
854
|
-
* Mint a JWT identifying the calling service. Used for inter-service HTTP calls.
|
|
855
|
-
* The token satisfies `requireAuth` and (when orgId is present) `requireOrganization`.
|
|
856
|
-
* Scope it with `opts.role` — least privilege keeps a leaked token low-value.
|
|
857
|
-
*
|
|
858
|
-
* `opts.serviceName` must be THIS process's own identity (`SERVICE_NAME`): a
|
|
859
|
-
* service holds only its own signing key, so minting a token that names another
|
|
860
|
-
* service throws rather than producing one every peer would reject. That is the
|
|
861
|
-
* one behaviour change #14 forces on callers — see `services/service-keys.ts`.
|
|
862
|
-
*/
|
|
863
|
-
export function signServiceToken(opts) {
|
|
864
|
-
const role = opts.role;
|
|
865
|
-
const payload = {
|
|
866
|
-
username: `${opts.serviceName}-service`,
|
|
867
|
-
email: `${opts.serviceName}@internal`,
|
|
868
|
-
principalType: 'service',
|
|
869
|
-
token_use: 'access',
|
|
870
|
-
role,
|
|
871
|
-
isAdmin: role === 'owner' || role === 'admin',
|
|
872
|
-
type: 'access',
|
|
873
|
-
organizationId: opts.orgId,
|
|
874
|
-
organizationName: opts.orgName ?? opts.orgId,
|
|
875
|
-
// Unique token id on every mint. Combined with the short (300s default) TTL
|
|
876
|
-
// this gives each service token a distinct identity — the correlation handle
|
|
877
|
-
// for tracing which mint performed a cross-service action, and the building
|
|
878
|
-
// block for replay detection (a verifier can track seen jtis). It does NOT
|
|
879
|
-
// by itself prevent replay within the TTL window.
|
|
880
|
-
jti: randomUUID(),
|
|
881
|
-
// Least-privilege capability claim (optional) — lets a member-role token
|
|
882
|
-
// satisfy a specific permission gate without carrying isAdmin.
|
|
883
|
-
...(opts.permissions && opts.permissions.length > 0 ? { permissions: opts.permissions } : {}),
|
|
884
|
-
};
|
|
885
|
-
// `sub`, `iat`/`exp` and the optional issuer/audience that requireAuth
|
|
886
|
-
// verifies are stamped by the signer, so there is exactly one place that
|
|
887
|
-
// decides what a service token says.
|
|
888
|
-
return signServiceJwt(payload, {
|
|
889
|
-
serviceName: opts.serviceName,
|
|
890
|
-
expiresInSeconds: opts.ttlSeconds ?? DEFAULT_SERVICE_TOKEN_TTL_SECONDS,
|
|
891
|
-
...issuerAudienceOptions(),
|
|
892
|
-
});
|
|
893
|
-
}
|
|
894
|
-
/** Convenience: returns a `Bearer <token>` header value for fetch/axios calls. */
|
|
895
|
-
export function getServiceAuthHeader(opts) {
|
|
896
|
-
return `Bearer ${signServiceToken(opts)}`;
|
|
897
|
-
}
|
|
898
|
-
/** True when `req.user` is a service principal (`principalType: 'service'`, minted by `signServiceToken`). */
|
|
899
|
-
export function isServicePrincipal(req) {
|
|
900
|
-
return req.user?.principalType === 'service';
|
|
901
|
-
}
|
|
902
|
-
/**
|
|
903
|
-
* True when `req.user` is an ORG SERVICE ACCOUNT (`principalType:
|
|
904
|
-
* 'service_account'`) — a non-human principal owned by one org, authenticating
|
|
905
|
-
* with a `pb_sa_…` key exchanged at platform.
|
|
906
|
-
*
|
|
907
|
-
* A service account is NOT an internal service principal: it holds org Roles and
|
|
908
|
-
* is subject to every permission gate a member is. What it can never do is
|
|
909
|
-
* satisfy a HUMAN-presence requirement — step-up (and any later assurance gate)
|
|
910
|
-
* refuses it outright, because there is no person behind it to re-verify.
|
|
911
|
-
*/
|
|
912
|
-
export function isServiceAccountPrincipal(req) {
|
|
913
|
-
return req.user?.principalType === 'service_account';
|
|
914
|
-
}
|
|
915
|
-
/** True when `req.user` is the named internal service (e.g. `'billing'`). */
|
|
916
|
-
export function isServicePrincipalNamed(req, serviceName) {
|
|
917
|
-
return serviceNameOf(req.user) === serviceName;
|
|
918
|
-
}
|
|
919
|
-
/**
|
|
920
|
-
* PRE-auth check: cryptographically verify the request carries a valid, signed
|
|
921
|
-
* SERVICE token (`principalType: 'service'`). Unlike {@link isServicePrincipal}
|
|
922
|
-
* (which reads the already-populated `req.user`), this verifies the bearer token
|
|
923
|
-
* itself, so it is safe to call BEFORE `requireAuth` runs — e.g. the global rate
|
|
924
|
-
* limiter's `skip`, which must not trust the spoofable `x-internal-service`
|
|
925
|
-
* header. Mirrors `requireAuth`'s SERVICE chain exactly (the signer's own key,
|
|
926
|
-
* resolved by `kid`, with the `sub`/signer agreement check and the optional
|
|
927
|
-
* issuer/audience) and returns `false` on any missing/invalid/non-service token
|
|
928
|
-
* — including any platform-signed USER token, whose `kid` is not in the service
|
|
929
|
-
* bundle at all. Stays SYNCHRONOUS, which is why the per-service public keys are
|
|
930
|
-
* distributed as a mounted bundle rather than fetched over HTTP.
|
|
931
|
-
*/
|
|
932
|
-
export function verifyServicePrincipal(req) {
|
|
933
|
-
const parts = req.headers.authorization?.split(' ');
|
|
934
|
-
if (!parts || parts.length !== 2 || parts[0] !== 'Bearer')
|
|
935
|
-
return false;
|
|
936
|
-
try {
|
|
937
|
-
const header = decodeJwtHeader(parts[1]);
|
|
938
|
-
if (!header?.kid || !isServiceKid(header.kid))
|
|
939
|
-
return false;
|
|
940
|
-
const decoded = verifyServiceJwt(parts[1], { kid: header.kid, ...issuerAudienceOptions() });
|
|
941
|
-
if (decoded.type !== 'access' || decoded.principalType !== 'service' || !hasValidIdentityClaims(decoded))
|
|
942
|
-
return false;
|
|
943
|
-
// A denylisted (killed) service must NOT be treated as a trusted principal —
|
|
944
|
-
// otherwise it keeps the rate-limiter exemption even though requireAuth rejects
|
|
945
|
-
// it on real routes. Fold the kill-switch into the pre-auth check too.
|
|
946
|
-
return !isServiceTokenDenied(decoded);
|
|
947
|
-
}
|
|
948
|
-
catch {
|
|
949
|
-
return false;
|
|
950
|
-
}
|
|
951
|
-
}
|
|
952
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0aC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9taWRkbGV3YXJlL2F1dGgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQUV0QyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sUUFBUSxDQUFDO0FBRXBDLE9BQU8sR0FBRyxNQUFNLGNBQWMsQ0FBQztBQUMvQixPQUFPLEVBQUUsWUFBWSxFQUFrQyxNQUFNLGtCQUFrQixDQUFDO0FBQ2hGLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUN6RCxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsZUFBZSxFQUFFLGlCQUFpQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDckcsT0FBTyxFQUNMLHNCQUFzQixFQUN0QixlQUFlLEVBQ2YsWUFBWSxFQUNaLGVBQWUsRUFDZixjQUFjLEVBQ2QsZ0JBQWdCLEdBQ2pCLE1BQU0sNkJBQTZCLENBQUM7QUFDckMsT0FBTyxFQUFFLFlBQVksRUFBRSxlQUFlLEVBQUUsVUFBVSxFQUF3QyxNQUFNLG9CQUFvQixDQUFDO0FBQ3JILE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUVwRCxPQUFPLEVBQW1CLGFBQWEsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ3pFLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUNyRCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDdEQsT0FBTyxFQUFFLFdBQVcsRUFBd0IsTUFBTSxzQkFBc0IsQ0FBQztBQUN6RSxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsZUFBZSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDeEUsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ2xELE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUN6RCxPQUFPLEVBQUUs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Q2pELENBQUM7QUFFRDs7Ozs7Ozs7Ozs7O0dBWUc7QUFDSCxNQUFNLFVBQVUsc0JBQXNCLENBQUMsR0FBWTtJQUNqRCxNQUFNLEtBQUssR0FBRyxHQUFHLENBQUMsT0FBTyxDQUFDLGFBQWEsRUFBRSxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDcEQsSUFBSSxDQUFDLEtBQUssSUFBSSxLQUFLLENBQUMsTUFBTSxLQUFLLENBQUMsSUFBSSxLQUFLLENBQUMsQ0FBQyxDQUFDLEtBQUssUUFBUTtRQUFFLE9BQU8sS0FBSyxDQUFDO0lBQ3hFLElBQUksQ0FBQztRQUNILE1BQU0sTUFBTSxHQUFHLGVBQWUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUN6QyxJQUFJLENBQUMsTUFBTSxFQUFFLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDO1lBQUUsT0FBTyxLQUFLLENBQUM7UUFDNUQsTUFBTSxPQUFPLEdBQUcsZ0JBQWdCLENBQWEsS0FBSyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsR0FBRyxFQUFFLE1BQU0sQ0FBQyxHQUFHLEVBQUUsR0FBRyxxQkFBcUIsRUFBRSxFQUFFLENBQUMsQ0FBQztRQUN4RyxJQUFJLE9BQU8sQ0FBQyxJQUFJLEtBQUssUUFBUSxJQUFJLE9BQU8sQ0FBQyxhQUFhLEtBQUssU0FBUyxJQUFJLENBQUMsc0JBQXNCLENBQUMsT0FBTyxDQUFDO1lBQUUsT0FBTyxLQUFLLENBQUM7UUFDdkgsNkVBQTZFO1FBQzdFLGdGQUFnRjtRQUNoRix1RUFBdUU7UUFDdkUsT0FBTyxDQUFDLG9CQUFvQixDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ3hDLENBQUM7SUFBQyxNQUFNLENBQUM7UUFDUCxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7QUFDSCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbmltcG9ydCB7IHJhbmRvbVVVSUQgfSBmcm9tICdjcnlwdG8nO1xuaW1wb3J0IHR5cGUgeyBSZXF1ZXN0LCBSZXNwb25zZSwgTmV4dEZ1bmN0aW9uIH0gZnJvbSAnZXhwcmVzcyc7XG5pbXBvcnQgand0IGZyb20gJ2pzb253ZWJ0b2tlbic7XG5pbXBvcnQgeyB0YWdSb3V0ZUdhdGUsIHR5cGUgT3JnQWRtaW5Bc3N1cmFuY2VNYWNoaW5lcyB9IGZyb20gJy4vcm91dGUtdGFibGUuanMnO1xuaW1wb3J0IHsgSHR0cFN0YXR1cyB9IGZyb20gJy4uL2NvbnN0YW50cy9odHRwLXN0YXR1cy5qcyc7XG5pbXBvcnQgeyBKd2tzVW5hdmFpbGFibGVFcnJvciwgVW5rbm93bktpZEVycm9yLCBwbGF0Zm9ybUp3a3NDYWNoZSB9IGZyb20gJy4uL3NlcnZpY2VzL2p3a3MtY2FjaGUuanMnO1xuaW1wb3J0IHtcbiAgU0VSVklDRV9TVUJKRUNUX1BSRUZJWCxcbiAgU2VydmljZUtleUVycm9yLFxuICBpc1NlcnZpY2VLaWQsXG4gIHNlcnZpY2VJZGVudGl0eSxcbiAgc2lnblNlcnZpY2VKd3QsXG4gIHZlcmlmeVNlcnZpY2VKd3QsXG59IGZyb20gJy4uL3NlcnZpY2VzL3NlcnZpY2Uta2V5cy5qcyc7XG5pbXBvcnQgeyBBVVRIX01FVEhPRFMsIFBSSU5DSVBBTF9UWVBFUywgVE9LRU5fVVNFUywgdHlwZSBBc3N1cmFuY2VMZXZlbCwgdHlwZSBKd3RQYXlsb2FkIH0gZnJvbSAnLi4vdHlwZXMvY29tbW9uLmpzJztcbmltcG9ydCB7IEVycm9yQ29kZSB9IGZyb20gJy4uL3R5cGVzL2Vycm9yLWNvZGVzLmpzJztcbmltcG9ydCB0eXBlIHsgSHR0cFJlcXVlc3QgfSBmcm9tICcuLi90eXBlcy9odHRwLmpzJztcbmltcG9ydCB7IHR5cGUgUGVybWlzc2lvbiwgaGFzUGVybWlzc2lvbiB9IGZyb20gJy4uL3R5cGVzL3Blcm1pc3Npb25zLmpzJztcbmltcG9ydCB7IGlzT3BhcXVlQXBpS2V5IH0gZnJvbSAnLi4vdXRpbHMvYXBpLWtleS5qcyc7XG5pbXBvcnQgeyBnZXRIZWFkZXJTdHJpbmcgfSBmcm9tICcuLi91dGlscy9oZWFkZXJzLmpzJztcbmltcG9ydCB7IGdldElkZW50aXR5LCB0eXBlIFJlcXVlc3RJZGVudGl0eSB9IGZyb20gJy4uL3V0aWxzL2lkZW50aXR5LmpzJztcbmltcG9ydCB7IFVTRVJfVE9LRU5fQUxHT1JJVEhNLCBkZWNvZGVKd3RIZWFkZXIgfSBmcm9tICcuLi91dGlscy9qd2suanMnO1xuaW1wb3J0IHsgY3JlYXRlTG9nZ2VyIH0gZnJvbSAnLi4vdXRpbHMvbG9nZ2VyLmpzJztcbmltcG9ydCB7IGVtaXRDb3VudGVyIH0gZnJvbSAnLi4vdXRpbHMvbWV0cmljLWVtaXR0ZXIuanMnO1xuaW1wb3J0IHsgc2VuZEVycm9yIH0gZnJvbSAnLi4vdXRpbHMvcmVzcG9uc2UuanMnO1xuXG5jb25zdCBsb2dnZXIgPSBjcmVhdGVMb2dnZXIoJ2F1dGgtbWlkZGxld2FyZScpO1xuXG4vKiogSXNzdWVyL2F1ZGllbmNlIHBpbm5pbmcsIHdoZW4gdGhlIGRlcGxveW1lbnQgY29uZmlndXJlcyB0aGVtLiBTaGFyZWQgYnkgYm90aCBjaGFpbnMuICovXG5mdW5jdGlvbiBpc3N1ZXJBdWRpZW5jZU9wdGlvbnMoKTogeyBpc3N1ZXI/OiBzdHJpbmc7IGF1ZGllbmNlPzogc3RyaW5nIH0ge1xuICByZXR1cm4ge1xuICAgIC4uLihwcm9jZXNzLmVudi5KV1RfSVNTVUVSID8geyBpc3N1ZXI6IHByb2Nlc3MuZW52LkpXVF9JU1NVRVIgfSA6IHt9KSxcbiAgICAuLi4ocHJvY2Vzcy5lbnYuSldUX0FVRElFTkNFID8geyBhdWRpZW5jZTogcHJvY2Vzcy5lbnYuSldUX0FVRElFTkNFIH0gOiB7fSksXG4gIH07XG59XG5cbi8qKlxuICogVmVyaWZ5IGEgdG9rZW4gdGhhdCBzcGVha3MgZm9yIGEgUEVSU09OIOKAlCBhY2Nlc3MsIHN0ZXAtdXAsIGFuZCB0aGUgdG9rZW4gYW5cbiAqIG9wYXF1ZSBhY2Nlc3Mga2V5IGlzIGV4Y2hhbmdlZCBmb3Ig4oCUIGFnYWluc3QgcGxhdGZvcm0ncyBwdWJsaXNoZWQgc2lnbmluZ1xuICoga2V5cy5cbiAqXG4gKiBFUzI1NiBhbmQgYSBga2lkYCBhcmUgYm90aCBtYW5kYXRvcnk6IG5vIGBraWRgIG1lYW5zIG5vIHdheSB0byBwaWNrIHRoZSByaWdodFxuICoga2V5IGFjcm9zcyBhIHJvdGF0aW9uLCBhbmQgYW55IG90aGVyIGFsZ29yaXRobSBpcyByZWZ1c2VkIG91dHJpZ2h0LCB3aGljaCBpc1xuICogd2hhdCBtYWtlcyBcIm5vIHNlcnZpY2UgYWNjZXB0cyBhbiBIUzI1NiB1c2VyIHRva2VuXCIgYSBwcm9wZXJ0eSBvZiB0aGUgY29kZVxuICogcmF0aGVyIHRoYW4gYSBjb252ZW50aW9uLiBLZXkgbG9va3VwIGdvZXMgdGhyb3VnaCB0aGUgc2hhcmVkIEpXS1MgY2FjaGVcbiAqICgxMC1taW51dGUgcmVmcmVzaCwgb25lIHJlZmV0Y2ggb24gYW4gdW5rbm93biBga2lkYCwgYnJpZWYgbmVnYXRpdmUgY2FjaGUpLlxuICpcbiAqIEB0aHJvd3Mge1Vua25vd25LaWRFcnJvcn0gdGhlIGtleSBzZXQgaXMgY3VycmVudCBhbmQgaGFzIG5vIHN1Y2gga2V5IOKGkiA0MDEuXG4gKiBAdGhyb3dzIHtKd2tzVW5hdmFpbGFibGVFcnJvcn0gdGhlIGtleSBzZXQgY291bGQgbm90IGJlIG9idGFpbmVkIOKGkiA1MDM7IGFuXG4gKiAgICAgICAgIHVudmVyaWZpYWJsZSB0b2tlbiBpcyBuZXZlciB0cmVhdGVkIGFzIHZhbGlkLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gdmVyaWZ5VXNlckp3dDxUID0gSnd0UGF5bG9hZD4odG9rZW46IHN0cmluZyk6IFByb21pc2U8VD4ge1xuICBjb25zdCBoZWFkZXIgPSBkZWNvZGVKd3RIZWFkZXIodG9rZW4pO1xuICBpZiAoaGVhZGVyPy5hbGcgIT09IFVTRVJfVE9LRU5fQUxHT1JJVEhNIHx8ICFoZWFkZXIua2lkKSB7XG4gICAgdGhyb3cgbmV3IGp3dC5Kc29uV2ViVG9rZW5FcnJvcihgVXNlciB0b2tlbnMgbXVzdCBiZSBzaWduZWQgd2l0aCAke1VTRVJfVE9LRU5fQUxHT1JJVEhNfSBhbmQgY2FycnkgYSBraWRgKTtcbiAgfVxuICBjb25zdCBrZXkgPSBhd2FpdCBwbGF0Zm9ybUp3a3NDYWNoZSgpLmdldEtleShoZWFkZXIua2lkKTtcbiAgcmV0dXJuIGp3dC52ZXJpZnkodG9rZW4sIGtleSwgeyBhbGdvcml0aG1zOiBbVVNFUl9UT0tFTl9BTEdPUklUSE1dLCAuLi5pc3N1ZXJBdWRpZW5jZU9wdGlvbnMoKSB9KSBhcyBUO1xufVxuXG4vKipcbiAqIFZlcmlmeSBBTlkgYmVhcmVyIHRva2VuIGFuZCByZXR1cm4gaXRzIGNsYWltcy5cbiAqXG4gKiBTaW5jZSAjMTQgdGhlcmUgaXMgbm8gc2hhcmVkIHNlY3JldCBsZWZ0OiBCT1RIIGNoYWlucyBhcmUgRVMyNTYgd2l0aCBhIGBraWRgLFxuICogc28gdGhlIGRpc3BhdGNoIGlzIGJ5ICoqd2hvIG93bnMgdGhlIGBraWRgKiogcmF0aGVyIHRoYW4gYnkgYWxnb3JpdGhtIOKAlCBhbmRcbiAqIGJlY2F1c2UgYSBga2lkYCBpcyBhbiBSRkMgNzYzOCB0aHVtYnByaW50LCBvd25lcnNoaXAgaXMgYSBmYWN0IGFib3V0IHRoZSBrZXksXG4gKiBub3QgYSBjbGFpbSB0aGUgdG9rZW4gbWFrZXMgYWJvdXQgaXRzZWxmOlxuICpcbiAqIC0gYSBga2lkYCBwdWJsaXNoZWQgaW4gdGhlIHBlci1zZXJ2aWNlIGtleSBidW5kbGUg4oaSIGFuIElOVEVSTkFMIFNFUlZJQ0UgdG9rZW5cbiAqICAgKHtAbGluayBzaWduU2VydmljZVRva2VufSksIHZlcmlmaWVkIHdpdGggdGhhdCBzZXJ2aWNlJ3Mga2V5OyBpdHMgYHN1YmAgbXVzdFxuICogICBuYW1lIHRoZSBzYW1lIHNlcnZpY2UsIHNvIG9uZSBzZXJ2aWNlIGNhbiBuZXZlciBzcGVhayBmb3IgYW5vdGhlci5cbiAqIC0gYW55dGhpbmcgZWxzZSDihpIgYSBwbGF0Zm9ybS1zaWduZWQgVVNFUiB0b2tlbiwgdmVyaWZpZWQgYWdhaW5zdCBwbGF0Zm9ybSdzXG4gKiAgIHB1Ymxpc2hlZCBKV0tTLiBBIHRva2VuIGNsYWltaW5nIGBwcmluY2lwYWxUeXBlOiAnc2VydmljZSdgIGlzIHJlZnVzZWRcbiAqICAgaGVyZTogYW4gaW50ZXJuYWwgaWRlbnRpdHkgbWF5IG5vdCByaWRlIHRoZSB1c2VyIHNpZ25pbmcga2V5LlxuICpcbiAqIEFueXRoaW5nIHRoYXQgaXMgbm90IEVTMjU2IHdpdGggYSBga2lkYCBmYWlscyBpbiBib3RoIGNoYWlucywgd2hpY2ggaXMgd2hhdFxuICogbWFrZXMgXCJubyBIUzI1NiB0b2tlbiBpcyBhY2NlcHRlZCBhbnl3aGVyZVwiIGEgcHJvcGVydHkgb2YgdGhlIGNvZGUuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiB2ZXJpZnlCZWFyZXJUb2tlbih0b2tlbjogc3RyaW5nKTogUHJvbWlzZTxKd3RQYXlsb2FkPiB7XG4gIGNvbnN0IGhlYWRlciA9IGRlY29kZUp3dEhlYWRlcih0b2tlbik7XG4gIGlmICghaGVhZGVyPy5hbGcpIHRocm93IG5ldyBqd3QuSnNvbldlYlRva2VuRXJyb3IoJ01hbGZvcm1lZCB0b2tlbiBoZWFkZXInKTtcblxuICBpZiAoaGVhZGVyLmtpZCAmJiBpc1NlcnZpY2VLaWQoaGVhZGVyLmtpZCkpIHtcbiAgICBjb25zdCBjbGFpbXMgPSB2ZXJpZnlTZXJ2aWNlSnd0PEp3dFBheWxvYWQ+KHRva2VuLCB7IGtpZDogaGVhZGVyLmtpZCwgLi4uaXNzdWVyQXVkaWVuY2VPcHRpb25zKCkgfSk7XG4gICAgaWYgKGNsYWltcy5wcmluY2lwYWxUeXBlICE9PSAnc2VydmljZScpIHtcbiAgICAgIGVtaXRDb3VudGVyKCdzZXJ2aWNlX2tleV9ub25fc2VydmljZV90b2tlbl9yZWplY3RlZF90b3RhbCcsIHsgYWxnOiBoZWFkZXIuYWxnIH0pO1xuICAgICAgdGhyb3cgbmV3IGp3dC5Kc29uV2ViVG9rZW5FcnJvcignQSBzZXJ2aWNlIHNpZ25pbmcga2V5IG1heSBvbmx5IG1pbnQgYSBzZXJ2aWNlIHByaW5jaXBhbCcpO1xuICAgIH1cbiAgICByZXR1cm4gY2xhaW1zO1xuICB9XG5cbiAgY29uc3QgY2xhaW1zID0gYXdhaXQgdmVyaWZ5VXNlckp3dCh0b2tlbik7XG4gIGlmIChjbGFpbXMucHJpbmNpcGFsVHlwZSA9PT0gJ3NlcnZpY2UnKSB7XG4gICAgdGhyb3cgbmV3IGp3dC5Kc29uV2ViVG9rZW5FcnJvcignU2VydmljZSBwcmluY2lwYWxzIG1heSBub3QgYmUgc2lnbmVkIHdpdGggdGhlIHVzZXIgc2lnbmluZyBrZXknKTtcbiAgfVxuICByZXR1cm4gY2xhaW1zO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFJlcXVpcmVBdXRoT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBBbGxvdyB4LW9yZy1pZC94LW9yZy1uYW1lIGhlYWRlcnMgdG8gb3ZlcnJpZGUgdGhlIEpXVCdzIG9yZ2FuaXphdGlvbiBmaWVsZHMuXG4gICAqXG4gICAqIFdoZW4gZW5hYmxlZCwgdGhlIGB4LW9yZy1pZGAvYHgtb3JnLW5hbWVgIGhlYWRlcnMgb3ZlcnJpZGUgdGhlIGNhbGxlcidzIG9yZ1xuICAgKiDigJQgYnV0IE9OTFkgZm9yIGEgdmVyaWZpZWQgU1lTLUFETUlOIChgaXNTdXBlckFkbWluYCBjbGFpbSkuIEZvciBhbnkgb3JkaW5hcnlcbiAgICogYXV0aGVudGljYXRlZCB1c2VyIHRoZSBoZWFkZXJzIGFyZSBpZ25vcmVkLCBzbyBlbmFibGluZyB0aGlzIGNhbiBuZXZlciBsZXQgYVxuICAgKiBub3JtYWwgdXNlciBpbXBlcnNvbmF0ZSBhbm90aGVyIHRlbmFudCdzIG9yZy4gVXNlIGZvciBjcm9zcy1vcmcgYWRtaW4gdG9vbGluZ1xuICAgKiAoZS5nLiBhIHN5c2FkbWluIG1hbmFnaW5nIGEgZ2l2ZW4gb3JnJ3MgYmlsbGluZykuIElmIHVuc3VyZSwgbGVhdmUgaXQgZGlzYWJsZWQuXG4gICAqL1xuICBhbGxvd09yZ0hlYWRlck92ZXJyaWRlPzogYm9vbGVhbjtcbiAgLyoqXG4gICAqIERlbWFuZCB0aGF0IHRoZSB3aG9sZSBTRVNTSU9OIGJlIGF0IGxlYXN0IHRoaXMgYXNzdXJhbmNlIGxldmVsICgjOCkuXG4gICAqXG4gICAqIGBtaW5Bc3N1cmFuY2U6IDJgIG1lYW5zIHRoZSBwZXJzb24gYXV0aGVudGljYXRlZCB3aXRoIGEgc2Vjb25kIGZhY3RvciDigJQgYVxuICAgKiBwYXNza2V5IHdpdGggdXNlciB2ZXJpZmljYXRpb24sIGEgcGFzc3dvcmQgcGx1cyBhbiBhdXRoZW50aWNhdG9yIGNvZGUsIG9yXG4gICAqIFNTTyB0aHJvdWdoIGFuIElkUCB0aGUgb3JnIG1hcmtlZCBhcyBlbmZvcmNpbmcgTUZBLiBBIHdlYWtlciB0b2tlbiBnZXRzXG4gICAqICoqNDAxIGBNRkFfUkVRVUlSRURgKiosIHdoaWNoIHRoZSBjbGllbnQgYW5zd2VycyBieSBzZW5kaW5nIHRoZSBwZXJzb24gdG9cbiAgICogZW5yb2xtZW50IG9yIHRvIGEgc3Ryb25nZXIgc2lnbi1pbjsgcmVmcmVzaGluZyBjYW5ub3QgaGVscCwgYmVjYXVzZSBgYWFsYFxuICAgKiBsaXZlcyBvbiB0aGUgc2Vzc2lvbiBzbG90IGFuZCBhIHJlZnJlc2ggbmV2ZXIgcmFpc2VzIGl0LlxuICAgKlxuICAgKiBUaGlzIGlzIHRoZSBTRVNTSU9OLWxldmVsIGNvdW50ZXJwYXJ0IHRvIHtAbGluayByZXF1aXJlU3RlcFVwfSwgd2hpY2ggc3RheXNcbiAgICogYSBmcmVzaCwgcGVyLWFjdGlvbiBjb25maXJtYXRpb24uIFVzZSBib3RoIG9uIHRoZSBtb3N0IGRhbmdlcm91cyByb3V0ZXMuXG4gICAqXG4gICAqIE1BQ0hJTkVTIE5FVkVSIFNBVElTRlkgSVQuIEEgc2VydmljZSBwcmluY2lwYWwsIGFuIG9yZyBzZXJ2aWNlIGFjY291bnQgYW5kXG4gICAqIGFuIGV4Y2hhbmdlZCBhY2Nlc3Mga2V5IGFsbCBnZXQgKio0MDMgYEhVTUFOX1NFU1NJT05fUkVRVUlSRURgKiog4oCUIHRoZXJlIGlzXG4gICAqIG5vIHBlcnNvbiBiZWhpbmQgdGhlbSB0byBoYXZlIHByZXNlbnRlZCBhIGZhY3Rvciwgc28gXCJhc3N1cmFuY2VcIiBpcyBub3QgYVxuICAgKiBxdWVzdGlvbiB0aGVpciBjcmVkZW50aWFsIGNhbiBhbnN3ZXIuIFRoYXQgaXMgZGVsaWJlcmF0ZWx5IG5vdCBhIHNpbGVudFxuICAgKiBwYXNzLXRocm91Z2ggZm9yIGludGVybmFsIHNlcnZpY2VzOiBhIHJvdXRlIHRoYXQgZGVtYW5kcyBNRkEgaXMgYSByb3V0ZSBhXG4gICAqIGh1bWFuIGlzIGRvaW5nIHNvbWV0aGluZyBkYW5nZXJvdXMgb24uXG4gICAqL1xuICBtaW5Bc3N1cmFuY2U/OiBBc3N1cmFuY2VMZXZlbDtcbiAgLyoqXG4gICAqIFdpdGgge0BsaW5rIG1pbkFzc3VyYW5jZX0sIGFkZGl0aW9uYWxseSBib3VuZCBob3cgbG9uZyBhZ28gdGhhdCBzaWduLWluXG4gICAqIGhhcHBlbmVkIChzZWNvbmRzLCBjb21wYXJlZCBhZ2FpbnN0IHRoZSB0b2tlbidzIGBhdXRoX3RpbWVgKS4gQSBzZXNzaW9uIHRoYXRcbiAgICogaXMgTUZBLWdyYWRlIGJ1dCBvbGRlciB0aGFuIHRoaXMgZ2V0cyAqKjQwMSBgUkVBVVRIX1JFUVVJUkVEYCoqLiBJZ25vcmVkXG4gICAqIHdpdGhvdXQgYG1pbkFzc3VyYW5jZWAg4oCUIFwiaG93IHJlY2VudFwiIGlzIG9ubHkgbWVhbmluZ2Z1bCBvbmNlIFwiaG93IHN0cm9uZ1wiXG4gICAqIGlzIGJlaW5nIGFza2VkLlxuICAgKi9cbiAgbWF4QWdlPzogbnVtYmVyO1xufVxuXG4vKiogSldUIGF1dGggbWlkZGxld2FyZS4gVXNlIGRpcmVjdGx5IG9yIGNhbGwgd2l0aCBvcHRpb25zLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlcXVpcmVBdXRoKFxuICByZXE6IFJlcXVlc3QsXG4gIHJlczogUmVzcG9uc2UsXG4gIG5leHQ6IE5leHRGdW5jdGlvbixcbik6IHZvaWQ7XG5leHBvcnQgZnVuY3Rpb24gcmVxdWlyZUF1dGgoXG4gIG9wdGlvbnM/OiBSZXF1aXJlQXV0aE9wdGlvbnMsXG4pOiAocmVxOiBSZXF1ZXN0LCByZXM6IFJlc3BvbnNlLCBuZXh0OiBOZXh0RnVuY3Rpb24pID0+IHZvaWQ7XG5leHBvcnQgZnVuY3Rpb24gcmVxdWlyZUF1dGgoXG4gIHJlcU9yT3B0aW9ucz86IFJlcXVlc3QgfCBSZXF1aXJlQXV0aE9wdGlvbnMsXG4gIHJlcz86IFJlc3BvbnNlLFxuICBuZXh0PzogTmV4dEZ1bmN0aW9uLFxuKTogdm9pZCB8ICgocmVxOiBSZXF1ZXN0LCByZXM6IFJlc3BvbnNlLCBuZXh0OiBOZXh0RnVuY3Rpb24pID0+IHZvaWQpIHtcbiAgaWYgKHJlcU9yT3B0aW9ucyAmJiByZXMgJiYgbmV4dCAmJiAnaGVhZGVycycgaW4gcmVxT3JPcHRpb25zKSB7XG4gICAgcmV0dXJuIF9yZXF1aXJlQXV0aCh7fSwgcmVxT3JPcHRpb25zIGFzIFJlcXVlc3QsIHJlcywgbmV4dCk7XG4gIH1cblxuICBjb25zdCBvcHRpb25zID0gKHJlcU9yT3B0aW9ucyBhcyBSZXF1aXJlQXV0aE9wdGlvbnMpIHx8IHt9O1xuICBjb25zdCBnYXRlID0gdGFnUm91dGVHYXRlKChyZXE6IFJlcXVlc3QsIHJlc0lubmVyOiBSZXNwb25zZSwgbmV4dElubmVyOiBOZXh0RnVuY3Rpb24pID0+IHtcbiAgICBfcmVxdWlyZUF1dGgob3B0aW9ucywgcmVxLCByZXNJbm5lciwgbmV4dElubmVyKTtcbiAgfSwgeyBraW5kOiAnYXV0aCcgfSk7XG4gIGlmIChvcHRpb25zLm1pbkFzc3VyYW5jZSkge1xuICAgIHRhZ1JvdXRlR2F0ZShnYXRlLCB7IGtpbmQ6ICdhc3N1cmFuY2UnLCBtaW5Bc3N1cmFuY2U6IG9wdGlvbnMubWluQXNzdXJhbmNlLCAuLi4ob3B0aW9ucy5tYXhBZ2UgIT09IHVuZGVmaW5lZCA/IHsgbWF4QWdlOiBvcHRpb25zLm1heEFnZSB9IDoge30pIH0pO1xuICB9XG4gIHJldHVybiBnYXRlO1xufVxudGFnUm91dGVHYXRlKHJlcXVpcmVBdXRoLCB7IGtpbmQ6ICdhdXRoJyB9KTtcblxuLyoqXG4gKiBBIHNvdXJjZSBvZiB0aGUgQ1VSUkVOVCBgdG9rZW5WZXJzaW9uYCBmb3IgYSB1c2VyLCBiYWNrZWQgYnkgYSBzdG9yZSB0aGVcbiAqIHN0YXRlbGVzcyBzZXJ2aWNlcyBjYW4gcmVhZCAoaW4gcHJhY3RpY2UgYSBSZWRpcyBrZXkgdGhlIHBsYXRmb3JtIHB1Ymxpc2hlc1xuICogdG8gb24gZXZlcnkgcHJpdmlsZWdlIGNoYW5nZSkuIFJlZ2lzdGVyZWQgdmlhIHtAbGluayBzZXRUb2tlblJldm9jYXRpb25TdG9yZX0uXG4gKlxuICogYGdldEN1cnJlbnRWZXJzaW9uYCByZXR1cm5zIHRoZSB1c2VyJ3MgY3VycmVudCB2ZXJzaW9uLCBvciBgbnVsbGAgd2hlbiB0aGVcbiAqIHN0b3JlIGhhcyBubyBlbnRyeSDigJQgYSBtaXNzIGlzIHRyZWF0ZWQgYXMgXCJubyBrbm93biByZXZvY2F0aW9uXCIgKGZhaWwtb3Blbik6XG4gKiByZXZvY2F0aW9uIGVudHJpZXMgYXJlIHB1Ymxpc2hlZCB3aXRoIGEgVFRMIG1hdGNoaW5nIHRoZSBhY2Nlc3MtdG9rZW5cbiAqIGxpZmV0aW1lLCBzbyBhIG1pc3NpbmcgZW50cnkgbWVhbnMgYW55IHRva2VuIG9sZCBlbm91Z2ggdG8gcHJlZGF0ZSBpdCBoYXNcbiAqIGFscmVhZHkgZXhwaXJlZCBvbiBpdHMgb3duLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFRva2VuUmV2b2NhdGlvblN0b3JlIHtcbiAgZ2V0Q3VycmVudFZlcnNpb24odXNlcklkOiBzdHJpbmcpOiBQcm9taXNlPG51bWJlciB8IG51bGw+O1xuICAvKipcbiAgICogV2hldGhlciBvbmUgSU1QRVJTT05BVElPTiBzZXNzaW9uIChieSB0b2tlbiBganRpYCkgaGFzIGJlZW4gZW5kZWQgZWFybHkuXG4gICAqXG4gICAqIE9wdGlvbmFsIHNvIGEgc3RvcmUgdGhhdCBwcmVkYXRlcyBpdCBzdGlsbCBsaW5rcyDigJQgYnV0IGEgc3RvcmUgV0lUSE9VVCBpdFxuICAgKiBjYW5ub3QgYW5zd2VyLCBhbmQgYW4gaW1wZXJzb25hdGlvbiB0b2tlbiBpcyB0aGVuIFJFSkVDVEVELiBVbmxpa2VcbiAgICogYGdldEN1cnJlbnRWZXJzaW9uYCwgdGhpcyBpcyBkZWxpYmVyYXRlbHkgbm90IGZhaWwtb3BlbjogdGhlIHBsYXRmb3JtIGVuZHMgYVxuICAgKiBzZXNzaW9uIHdoZW4gc29tZW9uZSB3aXRoZHJhd3MgY29uc2VudCwgYW5kIGEgd2l0aGRyYXduIGNvbnNlbnQgdGhhdCBrZWVwc1xuICAgKiB3b3JraW5nIGluIGV2ZXJ5IG90aGVyIHNlcnZpY2UgaXMgbm90IHdpdGhkcmF3bi5cbiAgICovXG4gIGdldFNlc3Npb25SZXZvY2F0aW9uPyhqdGk6IHN0cmluZyk6IFByb21pc2U8U2Vzc2lvblJldm9jYXRpb25TdGF0ZT47XG59XG5cbi8qKlxuICogYHJldm9rZWRgICAgICDigJQgdGhlIHNlc3Npb24gd2FzIGVuZGVkOyByZWplY3QuXG4gKiBgbGl2ZWAgICAgICAgIOKAlCBubyByZXZvY2F0aW9uIHJlY29yZGVkOyBhbGxvdy5cbiAqIGB1bmF2YWlsYWJsZWAg4oCUIHRoZSBzdG9yZSBjb3VsZG4ndCBiZSByZWFkIG9yIGNhbid0IGFuc3dlcjsgUkVKRUNULiBEaXN0aW5jdFxuICogICAgICAgICAgICAgICAgIGZyb20gYGxpdmVgIHByZWNpc2VseSBzbyBhbiBvdXRhZ2UgY2FuJ3QgcmVhZCBhcyBcIm5vdCByZXZva2VkXCIuXG4gKi9cbmV4cG9ydCB0eXBlIFNlc3Npb25SZXZvY2F0aW9uU3RhdGUgPSAncmV2b2tlZCcgfCAnbGl2ZScgfCAndW5hdmFpbGFibGUnO1xuXG5sZXQgdG9rZW5SZXZvY2F0aW9uU3RvcmU6IFRva2VuUmV2b2NhdGlvblN0b3JlIHwgdW5kZWZpbmVkO1xuXG4vKipcbiAqIFJlZ2lzdGVyIChvciBjbGVhciwgd2l0aCBgdW5kZWZpbmVkYCkgdGhlIHByb2Nlc3Mtd2lkZSB0b2tlbi1yZXZvY2F0aW9uIHN0b3JlLlxuICogV2hlbiB1bnNldCAodGhlIGRlZmF1bHQpLCBgcmVxdWlyZUF1dGhgIHBlcmZvcm1zIE5PIHJldm9jYXRpb24gY2hlY2sgKGl0IHJlbGllc1xuICogb24gdGhlIHNob3J0IGFjY2Vzcy10b2tlbiBUVEwpOyBzZXJ2aWNlcyBvcHQgaW4gYXQgYm9vdCBieSB3aXJpbmcgdGhlaXIgUmVkaXNcbiAqIGNsaWVudC4gUGxhdGZvcm0ga2VlcHMgaXRzIG93biBNb25nby1iYWNrZWQgY2hlY2sgYW5kIG5lZWQgbm90IHJlZ2lzdGVyIG9uZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNldFRva2VuUmV2b2NhdGlvblN0b3JlKHN0b3JlOiBUb2tlblJldm9jYXRpb25TdG9yZSB8IHVuZGVmaW5lZCk6IHZvaWQge1xuICB0b2tlblJldm9jYXRpb25TdG9yZSA9IHN0b3JlO1xuICBpZiAoc3RvcmUpIHJldm9jYXRpb25TdG9yZU1pc3NpbmdXYXJuZWQgPSBmYWxzZTsgLy8gcmUtYXJtIGlmIGEgc3RvcmUgaXMgKHJlKXJlZ2lzdGVyZWRcbn1cblxuLyoqIE9uZS1zaG90IGd1YXJkIHNvIHRoZSBcInJldm9jYXRpb24gaW5hY3RpdmVcIiB3YXJuaW5nIGRvZXNuJ3QgZmxvb2QgdGhlIGxvZ3MuICovXG5sZXQgcmV2b2NhdGlvblN0b3JlTWlzc2luZ1dhcm5lZCA9IGZhbHNlO1xuXG4vKipcbiAqIFJldHVybnMgdHJ1ZSB3aGVuIGBkZWNvZGVkYCBoYXMgYmVlbiByZXZva2VkIHBlciB0aGUgcmVnaXN0ZXJlZCBzdG9yZTogaXRzXG4gKiBlbWJlZGRlZCBgdG9rZW5WZXJzaW9uYCBpcyBzdHJpY3RseSBiZWhpbmQgdGhlIHN0b3JlJ3MgY3VycmVudCB2ZXJzaW9uLlxuICogRmFpbC1vcGVuIOKAlCBhbnkgc3RvcmUgZXJyb3IsIGEgbWlzc2luZyBlbnRyeSwgb3IgYSB0b2tlbi9zdG9yZSB3aXRob3V0IGFcbiAqIHVzYWJsZSB2ZXJzaW9uIHlpZWxkcyBgZmFsc2VgIChhbGxvdykuIE5ldmVyIHRocm93cy5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gaXNUb2tlblJldm9rZWQoZGVjb2RlZDogSnd0UGF5bG9hZCk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICBjb25zdCBzdG9yZSA9IHRva2VuUmV2b2NhdGlvblN0b3JlO1xuICBpZiAoIXN0b3JlKSB7XG4gICAgLy8gTWFrZSB0aGUgXCJyZXZvY2F0aW9uIGlzIE9GRlwiIHN0YXRlIE9CU0VSVkFCTEU6IGEgc2VydmljZSB0aGF0IHZlcmlmaWVzIHVzZXJcbiAgICAvLyB0b2tlbnMgYnV0IGZvcmdvdCBgc2V0VG9rZW5SZXZvY2F0aW9uU3RvcmUoKWAgc2lsZW50bHkgZGlzYWJsZXMgdGhlIHNlc3Npb25cbiAgICAvLyBraWxsLXN3aXRjaC4gV2FybiBPTkNFIChvbmx5IGZvciBhIHJldm9jYWJsZSB1c2VyIHRva2VuKSBzbyBhIG1pc2NvbmZpZ3VyZWRcbiAgICAvLyBib290IHN1cmZhY2VzIGluIHRoZSBsb2dzIGluc3RlYWQgb2YgZmFpbGluZyBvcGVuIGludmlzaWJseS5cbiAgICBpZiAoIXJldm9jYXRpb25TdG9yZU1pc3NpbmdXYXJuZWQgJiYgZGVjb2RlZC5zdWIgJiYgdHlwZW9mIGRlY29kZWQudG9rZW5WZXJzaW9uID09PSAnbnVtYmVyJykge1xuICAgICAgcmV2b2NhdGlvblN0b3JlTWlzc2luZ1dhcm5lZCA9IHRydWU7XG4gICAgICBsb2dnZXIud2FybignVG9rZW4gcmV2b2NhdGlvbiBzdG9yZSBOT1QgcmVnaXN0ZXJlZCDigJQgcmV2b2NhdGlvbiBjaGVja3MgYXJlIElOQUNUSVZFIChzZXRUb2tlblJldm9jYXRpb25TdG9yZSB3YXMgbmV2ZXIgY2FsbGVkKTsgcmV2b2tlZC9jb21wcm9taXNlZCBzZXNzaW9ucyBzdGF5IHZhbGlkIHVudGlsIG5hdHVyYWwgVFRMJyk7XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuICBpZiAoIWRlY29kZWQuc3ViIHx8IHR5cGVvZiBkZWNvZGVkLnRva2VuVmVyc2lvbiAhPT0gJ251bWJlcicpIHJldHVybiBmYWxzZTtcbiAgdHJ5IHtcbiAgICBjb25zdCBjdXJyZW50ID0gYXdhaXQgc3RvcmUuZ2V0Q3VycmVudFZlcnNpb24oZGVjb2RlZC5zdWIpO1xuICAgIHJldHVybiBjdXJyZW50ICE9PSBudWxsICYmIGRlY29kZWQudG9rZW5WZXJzaW9uIDwgY3VycmVudDtcbiAgfSBjYXRjaCB7XG4gICAgLy8gRmFpbC1vcGVuOiBhIHJldm9jYXRpb24tc3RvcmUgb3V0YWdlIG11c3Qgbm90IGxvY2sgZXZlcnkgdXNlciBvdXQuXG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG59XG5cbi8qKlxuICogUmVzb2x2ZSBhbiBpbXBlcnNvbmF0aW9uIHNlc3Npb24ncyByZXZvY2F0aW9uIHN0YXRlLiBOZXZlciB0aHJvd3M6IGFueSBmYWlsdXJlXG4gKiDigJQgbm8gc3RvcmUsIGEgc3RvcmUgdGhhdCBjYW4ndCBhbnN3ZXIsIGEgcmVhZCBlcnJvciDigJQgaXMgYHVuYXZhaWxhYmxlYCwgd2hpY2hcbiAqIGNhbGxlcnMgdHJlYXQgYXMgcmV2b2tlZC5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gc2Vzc2lvblJldm9jYXRpb25TdGF0ZShqdGk6IHN0cmluZyk6IFByb21pc2U8U2Vzc2lvblJldm9jYXRpb25TdGF0ZT4ge1xuICBjb25zdCBzdG9yZSA9IHRva2VuUmV2b2NhdGlvblN0b3JlO1xuICBpZiAoIXN0b3JlPy5nZXRTZXNzaW9uUmV2b2NhdGlvbikgcmV0dXJuICd1bmF2YWlsYWJsZSc7XG4gIHRyeSB7XG4gICAgcmV0dXJuIGF3YWl0IHN0b3JlLmdldFNlc3Npb25SZXZvY2F0aW9uKGp0aSk7XG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiAndW5hdmFpbGFibGUnO1xuICB9XG59XG5cbi8qKiBBbiBpbXBlcnNvbmF0aW9uIHNlc3Npb24gdG9rZW46IGl0IG5hbWVzIHRoZSBvcGVyYXRvciBBTkQgY2FycmllcyBpdHMgb3duIHNlc3Npb24gaWQuICovXG5mdW5jdGlvbiBpc0ltcGVyc29uYXRpb25TZXNzaW9uKGRlY29kZWQ6IHsgaW1wZXJzb25hdG9ySWQ/OiB1bmtub3duOyBqdGk/OiB1bmtub3duIH0pOiBkZWNvZGVkIGlzIHsgaW1wZXJzb25hdG9ySWQ6IHN0cmluZzsganRpOiBzdHJpbmcgfSB7XG4gIHJldHVybiB0eXBlb2YgZGVjb2RlZC5pbXBlcnNvbmF0b3JJZCA9PT0gJ3N0cmluZycgJiYgdHlwZW9mIGRlY29kZWQuanRpID09PSAnc3RyaW5nJyAmJiBkZWNvZGVkLmp0aS5sZW5ndGggPiAwO1xufVxuXG4vKipcbiAqIFB1YmxpYyByZXZvY2F0aW9uIGNoZWNrIGZvciByb3V0ZXMgdGhhdCB2ZXJpZnkgYSBwbGF0Zm9ybSBKV1QgT1VUU0lERVxuICogYHJlcXVpcmVBdXRoYCAoZS5nLiB0aGUgaW1hZ2UtcmVnaXN0cnkgYC90b2tlbmAgbWludCBwYXRoLCB3aGljaCByZXNvbHZlc1xuICogaWRlbnRpdHkgaXRzZWxmKS4gUmV0dXJucyB0cnVlIHdoZW4gdGhlIHRva2VuJ3MgYHRva2VuVmVyc2lvbmAgaXMgc3RyaWN0bHlcbiAqIGJlaGluZCB0aGUgc3RvcmUncyBjdXJyZW50IHZlcnNpb24uIEZhaWwtb3BlbiAobmV2ZXIgdGhyb3dzKSDigJQgYSBzdG9yZSBvdXRhZ2VcbiAqIG9yIGEgdG9rZW4vc3RvcmUgd2l0aG91dCBhIHVzYWJsZSB2ZXJzaW9uIHlpZWxkcyBmYWxzZSAoYWxsb3cpLCBtYXRjaGluZ1xuICogYHJlcXVpcmVBdXRoYC4gUGFzcyB0aGUgdmVyaWZpZWQgSldUIGNsYWltcyAoYHN1YmAsIGB0b2tlblZlcnNpb25gKS5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGlzQWNjZXNzVG9rZW5SZXZva2VkKFxuICBjbGFpbXM6IHsgc3ViPzogc3RyaW5nOyB0b2tlblZlcnNpb24/OiBudW1iZXI7IGp0aT86IHN0cmluZzsgaW1wZXJzb25hdG9ySWQ/OiBzdHJpbmcgfSxcbik6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAvLyBBbiBpbXBlcnNvbmF0aW9uIHNlc3Npb24gaXMgcmV2b2tlZCB1bmxlc3MgdGhlIHN0b3JlIHBvc2l0aXZlbHkgc2F5cyBsaXZlIOKAlFxuICAvLyBpbmNsdWRpbmcgb24gdGhpcyBvdXQtb2YtYmFuZCBwYXRoLCBvciBhIHJldm9rZWQgc2Vzc2lvbiBjb3VsZCBzdGlsbCBtaW50XG4gIC8vIHJlZ2lzdHJ5IHRva2Vucy5cbiAgaWYgKGlzSW1wZXJzb25hdGlvblNlc3Npb24oY2xhaW1zKSAmJiBhd2FpdCBzZXNzaW9uUmV2b2NhdGlvblN0YXRlKGNsYWltcy5qdGkpICE9PSAnbGl2ZScpIHJldHVybiB0cnVlO1xuICByZXR1cm4gaXNUb2tlblJldm9rZWQoY2xhaW1zIGFzIEp3dFBheWxvYWQpO1xufVxuXG5mdW5jdGlvbiBfcmVxdWlyZUF1dGgoXG4gIG9wdGlvbnM6IFJlcXVpcmVBdXRoT3B0aW9ucyxcbiAgcmVxOiBSZXF1ZXN0LFxuICByZXM6IFJlc3BvbnNlLFxuICBuZXh0OiBOZXh0RnVuY3Rpb24sXG4pOiB2b2lkIHtcbiAgY29uc3QgYXV0aEhlYWRlciA9IHJlcS5oZWFkZXJzLmF1dGhvcml6YXRpb247XG5cbiAgaWYgKCFhdXRoSGVhZGVyKSB7XG4gICAgcmV0dXJuIHNlbmRFcnJvcihyZXMsIEh0dHBTdGF0dXMuVU5BVVRIT1JJWkVELCAnQXV0aG9yaXphdGlvbiBoZWFkZXIgcmVxdWlyZWQnLCBFcnJvckNvZGUuVE9LRU5fTUlTU0lORyk7XG4gIH1cblxuICBjb25zdCBwYXJ0cyA9IGF1dGhIZWFkZXIuc3BsaXQoJyAnKTtcbiAgaWYgKHBhcnRzLmxlbmd0aCAhPT0gMiB8fCBwYXJ0c1swXSAhPT0gJ0JlYXJlcicpIHtcbiAgICByZXR1cm4gc2VuZEVycm9yKHJlcywgSHR0cFN0YXR1cy5VTkFVVEhPUklaRUQsICdJbnZhbGlkIGF1dGhvcml6YXRpb24gZm9ybWF0LiBVc2U6IEJlYXJlciA8dG9rZW4+JywgRXJyb3JDb2RlLlRPS0VOX0lOVkFMSUQpO1xuICB9XG5cbiAgLy8gQW4gT1BBUVVFIEFDQ0VTUyBLRVkgKGBwYl9wYXRf4oCmYCAvIGBwYl9zYV/igKZgKSBjYXJyaWVzIG5vIGNsYWltcyBhbmQgbm9cbiAgLy8gc2lnbmF0dXJlLCBzbyBpdCBjYW5ub3QgYmUgdmVyaWZpZWQgaGVyZS4gVHJhZGUgaXQgYXQgcGxhdGZvcm0gZm9yIGFcbiAgLy8gc2hvcnQtbGl2ZWQgSldUIChjYWNoZWQgaW4tcHJvY2VzcyB1bnRpbCBpdCBleHBpcmVzKSBhbmQgdGhlbiB2ZXJpZnkgdGhhdFxuICAvLyBKV1Qgb24gdGhlIG5vcm1hbCBwYXRoIOKAlCBzZXJ2aWNlcyBuZXZlciByZWFkIGEga2V5IGhhc2guIFNlZVxuICAvLyBgc2VydmljZXMvYXBpLWtleS1leGNoYW5nZS50c2AuXG4gIGlmIChpc09wYXF1ZUFwaUtleShwYXJ0c1sxXSkpIHtcbiAgICB2b2lkIHJlc29sdmVBcGlLZXkob3B0aW9ucywgcGFydHNbMV0sIHJlcSwgcmVzLCBuZXh0KTtcbiAgICByZXR1cm47XG4gIH1cblxuICAvLyBgLmNhdGNoKG5leHQpYCBmb3J3YXJkcyBhIERPV05TVFJFQU0gc3luY2hyb25vdXMgdGhyb3cgZnJvbSBgbmV4dCgpYCB0b1xuICAvLyBFeHByZXNzJ3MgZXJyb3IgbWlkZGxld2FyZSDigJQgdmVyaWZpY2F0aW9uIGl0c2VsZiBuZXZlciByZWplY3RzIChpdCBtYXBzXG4gIC8vIGV2ZXJ5IGZhaWx1cmUgdG8gYSByZXNwb25zZSkuXG4gIHZvaWQgdmVyaWZ5QW5kQXR0YWNoKG9wdGlvbnMsIHBhcnRzWzFdLCByZXEsIHJlcywgbmV4dCkuY2F0Y2gobmV4dCk7XG59XG5cbi8qKlxuICogRXhjaGFuZ2UgYW4gb3BhcXVlIGtleSBmb3IgYSBKV1QsIHRoZW4gY29udGludWUgb24gdGhlIG5vcm1hbCB2ZXJpZmljYXRpb25cbiAqIHBhdGguIEEgcmVmdXNlZCBrZXkgaXMgYSA0MDE7IGFuIHVucmVhY2hhYmxlIHBsYXRmb3JtIGlzIGEgNTAzIChuZXZlciBhIHBhc3Mg4oCUXG4gKiBhbiB1bnZlcmlmaWFibGUgY3JlZGVudGlhbCBpcyBub3QgYW4gaWRlbnRpdHkpLlxuICovXG5hc3luYyBmdW5jdGlvbiByZXNvbHZlQXBpS2V5KFxuICBvcHRpb25zOiBSZXF1aXJlQXV0aE9wdGlvbnMsXG4gIGtleTogc3RyaW5nLFxuICByZXE6IFJlcXVlc3QsXG4gIHJlczogUmVzcG9uc2UsXG4gIG5leHQ6IE5leHRGdW5jdGlvbixcbik6IFByb21pc2U8dm9pZD4ge1xuICAvLyBMb2FkZWQgTEFaSUxZLCBvbiB0aGUgZmlyc3Qga2V5IGV2ZXIgcHJlc2VudGVkLiBBIHN0YXRpYyBpbXBvcnQgd291bGQgcHV0XG4gIC8vIHRoZSBIVFRQIGNsaWVudCAoYW5kIHBsYXRmb3JtJ3MgYWRkcmVzcykgaW50byB0aGUgaW1wb3J0IGdyYXBoIG9mIGV2ZXJ5XG4gIC8vIG1vZHVsZSB0aGF0IG1lcmVseSB1c2VzIGByZXF1aXJlQXV0aGAsIHdoaWNoIGJvdGggd2lkZW5zIHRoZSBib290IGdyYXBoIGFuZFxuICAvLyBicmVha3MgYW55IHRlc3QgdGhhdCBtb2NrcyBgaHR0cC1jbGllbnQuanNgIHdpdGggYSBwYXJ0aWFsIG1vZHVsZS5cbiAgY29uc3QgeyBleGNoYW5nZUFwaUtleSwgQXBpS2V5RXhjaGFuZ2VVbmF2YWlsYWJsZUVycm9yIH0gPSBhd2FpdCBpbXBvcnQoJy4uL3NlcnZpY2VzL2FwaS1rZXktZXhjaGFuZ2UuanMnKTtcbiAgbGV0IHRva2VuOiBzdHJpbmc7XG4gIHRyeSB7XG4gICAgdG9rZW4gPSBhd2FpdCBleGNoYW5nZUFwaUtleShrZXkpO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIGlmIChlcnJvciBpbnN0YW5jZW9mIEFwaUtleUV4Y2hhbmdlVW5hdmFpbGFibGVFcnJvcikge1xuICAgICAgcmV0dXJuIHNlbmRFcnJvcihcbiAgICAgICAgcmVzLCBIdHRwU3RhdHVzLlNFUlZJQ0VfVU5BVkFJTEFCTEUsXG4gICAgICAgICdBY2Nlc3Mta2V5IHZlcmlmaWNhdGlvbiBpcyB0ZW1wb3JhcmlseSB1bmF2YWlsYWJsZTsgcGxlYXNlIHJldHJ5JyxcbiAgICAgICAgRXJyb3JDb2RlLlNFUlZJQ0VfVU5BVkFJTEFCTEUsXG4gICAgICApO1xuICAgIH1cbiAgICByZXR1cm4gc2VuZEVycm9yKHJlcywgSHR0cFN0YXR1cy5VTkFVVEhPUklaRUQsICdJbnZhbGlkIG9yIHJldm9rZWQgYWNjZXNzIGtleScsIEVycm9yQ29kZS5UT0tFTl9JTlZBTElEKTtcbiAgfVxuICBhd2FpdCB2ZXJpZnlBbmRBdHRhY2gob3B0aW9ucywgdG9rZW4sIHJlcSwgcmVzLCBuZXh0KTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gdmVyaWZ5QW5kQXR0YWNoKFxuICBvcHRpb25zOiBSZXF1aXJlQXV0aE9wdGlvbnMsXG4gIHJhd1Rva2VuOiBzdHJpbmcsXG4gIHJlcTogUmVxdWVzdCxcbiAgcmVzOiBSZXNwb25zZSxcbiAgbmV4dDogTmV4dEZ1bmN0aW9uLFxuKTogUHJvbWlzZTx2b2lkPiB7XG4gIHRyeSB7XG4gICAgLy8gVHdvIGNoYWlucywgb25lIGVudHJ5IHBvaW50IChzZWUgYHZlcmlmeUJlYXJlclRva2VuYCk6IGEgdXNlciB0b2tlbiBtdXN0XG4gICAgLy8gYmUgRVMyNTYgc2lnbmVkIGJ5IHBsYXRmb3JtIGFuZCB2ZXJpZmllZCBhZ2FpbnN0IGl0cyBwdWJsaXNoZWQgSldLUzsgYW5cbiAgICAvLyBpbnRlcm5hbCBzZXJ2aWNlIHRva2VuIHN0YXlzIG9uIHRoZSBzaGFyZWQgc2VjcmV0IGFuZCBtdXN0IGRlY2xhcmUgaXRzZWxmXG4gICAgLy8gYSBzZXJ2aWNlIHByaW5jaXBhbC4gQm90aCBwaW4gdGhlIGFsZ29yaXRobSAobm8gYWxnLWNvbmZ1c2lvbiwgbm9cbiAgICAvLyBgYWxnOm5vbmVgKSBhbmQgYm90aCBhcHBseSB0aGUgb3B0aW9uYWwgaXNzdWVyL2F1ZGllbmNlIGJpbmRpbmcuXG4gICAgY29uc3QgZGVjb2RlZCA9IGF3YWl0IHZlcmlmeUJlYXJlclRva2VuKHJhd1Rva2VuKTtcblxuICAgIGlmIChkZWNvZGVkLnR5cGUgIT09ICdhY2Nlc3MnKSB7XG4gICAgICByZXR1cm4gc2VuZEVycm9yKHJlcywgSHR0cFN0YXR1cy5VTkFVVEhPUklaRUQsICdPbmx5IGFjY2VzcyB0b2tlbnMgY2FuIGJlIHVzZWQgZm9yIEFQSSByZXF1ZXN0cycsIEVycm9yQ29kZS5UT0tFTl9JTlZBTElEKTtcbiAgICB9XG5cbiAgICBpZiAoIWRlY29kZWQuc3ViIHx8ICFkZWNvZGVkLnJvbGUgfHwgIWhhc1ZhbGlkSWRlbnRpdHlDbGFpbXMoZGVjb2RlZCkpIHtcbiAgICAgIHJldHVybiBzZW5kRXJyb3IocmVzLCBIdHRwU3RhdHVzLlVOQVVUSE9SSVpFRCwgJ1Rva2VuIG1pc3NpbmcgcmVxdWlyZWQgZmllbGRzJywgRXJyb3JDb2RlLlRPS0VOX0lOVkFMSUQpO1xuICAgIH1cblxuICAgIC8vIFNlcnZpY2UtdG9rZW4ga2lsbC1zd2l0Y2g6IHJlamVjdCBhIHNlcnZpY2UgcHJpbmNpcGFsIHdob3NlIHNlcnZpY2UgaGFzXG4gICAgLy8gYmVlbiBhZGRlZCB0byB0aGUgZGVueWxpc3QuIFJvdGF0aW5nIHRoZSBzaGFyZWQgSldUIHNlY3JldCBpcyB0aGUgb25seVxuICAgIC8vIG90aGVyIHdheSB0byBpbnZhbGlkYXRlIGEgc2VydmljZSB0b2tlbiBiZWZvcmUgaXRzIChzaG9ydCkgVFRMIOKAlCBidXQgdGhhdFxuICAgIC8vIG51a2VzIEVWRVJZIHNlcnZpY2UgdG9rZW4gZmxlZXQtd2lkZS4gVGhpcyBsZXRzIG9uZSBjb21wcm9taXNlZC9yb2d1ZVxuICAgIC8vIHNlcnZpY2UgYmUgY3V0IG9mZiBzdXJnaWNhbGx5LiBPKDEpIFNldCBsb29rdXAsIHplcm8gY29zdCB3aGVuIHRoZSBkZW55bGlzdFxuICAgIC8vIGlzIGVtcHR5ICh0aGUgZGVmYXVsdCksIHNvIGl0IG5ldmVyIHRheGVzIHRoZSBTMlMgaG90IHBhdGggdW5sZXNzIGFybWVkLlxuICAgIGlmIChpc1NlcnZpY2VUb2tlbkRlbmllZChkZWNvZGVkKSkge1xuICAgICAgZW1pdENvdW50ZXIoJ3NlcnZpY2VfdG9rZW5fZGVuaWVkX3RvdGFsJywgeyBzZXJ2aWNlOiBzZXJ2aWNlTmFtZU9mKGRlY29kZWQpID8/ICd1bmtub3duJyB9KTtcbiAgICAgIGxvZ2dlci53YXJuKCdSZWplY3RlZCBkZW55bGlzdGVkIHNlcnZpY2UgdG9rZW4nLCB7IHN1YjogZGVjb2RlZC5zdWIgfSk7XG4gICAgICByZXR1cm4gc2VuZEVycm9yKHJlcywgSHR0cFN0YXR1cy5VTkFVVEhPUklaRUQsICdTZXJ2aWNlIHRva2VuIHJldm9rZWQnLCBFcnJvckNvZGUuVE9LRU5fUkVWT0tFRCk7XG4gICAgfVxuXG4gICAgcmVxLnVzZXIgPSB7IC4uLmRlY29kZWQgfTtcblxuICAgIC8vIEJPT1RTVFJBUC1BRE1JTiBFTlJPTE1FTlQgU0VTU0lPTiAoIzgsIHJldmlzaW9uIDQpLiBTdWNoIGEgdG9rZW4gZXhpc3RzIHNvXG4gICAgLy8gdGhlIGluc3RhbGwncyBvbmx5IGFkbWluIGNhbiBlbnJvbCBhIGZhY3RvcjsgaXQgaXMgYGFhbDogMWAgYW5kIG11c3Qgbm90XG4gICAgLy8gcmVhY2ggYW55dGhpbmcgZWxzZS4gUGxhdGZvcm0g4oCUIHdoaWNoIG93bnMgdGhlIGV4Y2VwdGlvbiBhbmQga25vd3Mgd2hpY2hcbiAgICAvLyBvZiBpdHMgb3duIHJvdXRlcyBgaW5pdC1wbGF0Zm9ybS5zaGAgY2FsbHMg4oCUIGFsbG93cyBhbiBleHBsaWNpdCBmZXcgYmVmb3JlXG4gICAgLy8gdGhpcyBwb2ludCAoc2VlIGl0cyBvd24gYHJlcXVpcmVBdXRoYCk7IGluIEVWRVJZIG90aGVyIHNlcnZpY2UgdGhlIGFuc3dlclxuICAgIC8vIGlzIHNpbXBseSBubywgc28gdGhlIHJlYWNoIHJlc3RyaWN0aW9uIGhvbGRzIHdpdGhvdXQgYSBwZXItc2VydmljZVxuICAgIC8vIGFsbG93bGlzdCB0byBrZWVwIGluIHN5bmMuXG4gICAgaWYgKGRlY29kZWQubWZhRW5yb2xsbWVudFBlbmRpbmcgPT09IHRydWUpIHtcbiAgICAgIGVtaXRDb3VudGVyKCdtZmFfZW5mb3JjZW1lbnRfcmVmdXNlZF90b3RhbCcsIHsgc2VydmljZTogc2VydmljZUlkZW50aXR5KCksIHJlYXNvbjogJ2Jvb3RzdHJhcF9zZXNzaW9uJyB9KTtcbiAgICAgIHJlY29yZEF1dGh6RGVuaWFsKHJlcSwgJ21mYS1lbnJvbG1lbnQnKTtcbiAgICAgIHJldHVybiBzZW5kRXJyb3IoXG4gICAgICAgIHJlcywgSHR0cFN0YXR1cy5GT1JCSURERU4sXG4gICAgICAgICdGaW5pc2ggc2V0dGluZyB1cCB0d28tZmFjdG9yIGF1dGhlbnRpY2F0aW9uIGJlZm9yZSB1c2luZyB0aGUgcmVzdCBvZiBQaXBlbGluZSBCdWlsZGVyJyxcbiAgICAgICAgRXJyb3JDb2RlLk1GQV9FTlJPTExNRU5UX1JFUVVJUkVELFxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyBTZXNzaW9uLWxldmVsIGFzc3VyYW5jZSAoYHJlcXVpcmVBdXRoKHsgbWluQXNzdXJhbmNlLCBtYXhBZ2UgfSlgKS5cbiAgICBpZiAob3B0aW9ucy5taW5Bc3N1cmFuY2VcbiAgICAgICYmIHJlZnVzZUZvckFzc3VyYW5jZSh7IG1pbkFzc3VyYW5jZTogb3B0aW9ucy5taW5Bc3N1cmFuY2UsIC4uLihvcHRpb25zLm1heEFnZSAhPT0gdW5kZWZpbmVkID8geyBtYXhBZ2U6IG9wdGlvbnMubWF4QWdlIH0gOiB7fSkgfSwgZGVjb2RlZCwgcmVxLCByZXMpKSByZXR1cm47XG5cbiAgICAvLyBUaGUgeC1vcmctaWQveC1vcmctbmFtZSBvdmVycmlkZSBsZXRzIGEgU1lTLUFETUlOIGFjdCBvbiBhIGNob3NlbiBvcmdcbiAgICAvLyAoY3Jvc3Mtb3JnIGFkbWluIHRvb2xpbmcpLiBJdCBpcyBnYXRlZCBvbiB0aGUgdmVyaWZpZWQgYGlzU3VwZXJBZG1pbmAgY2xhaW1cbiAgICAvLyBoZXJlIHNvIHRoYXQgZXZlbiBhIHJvdXRlIHdoaWNoIG1pc3Rha2VubHkgZW5hYmxlcyBgYWxsb3dPcmdIZWFkZXJPdmVycmlkZWBcbiAgICAvLyBjYW4gTkVWRVIgbGV0IGFuIG9yZGluYXJ5IGF1dGhlbnRpY2F0ZWQgdXNlciBzcG9vZiBhbm90aGVyIHRlbmFudCdzIG9yZyB2aWFcbiAgICAvLyB0aGUgaGVhZGVyIOKAlCBkZWZlbmNlLWluLWRlcHRoIGFnYWluc3QgdGhlIGNyb3NzLXRlbmFudCBicmVhayB0aGlzIGNhdXNlZC5cbiAgICBpZiAob3B0aW9ucy5hbGxvd09yZ0hlYWRlck92ZXJyaWRlICYmIGRlY29kZWQuaXNTdXBlckFkbWluID09PSB0cnVlKSB7XG4gICAgICBjb25zdCBoZWFkZXJPcmdJZCA9IGdldEhlYWRlclN0cmluZyhyZXEuaGVhZGVyc1sneC1vcmctaWQnXSk7XG4gICAgICBjb25zdCBoZWFkZXJPcmdOYW1lID0gZ2V0SGVhZGVyU3RyaW5nKHJlcS5oZWFkZXJzWyd4LW9yZy1uYW1lJ10pO1xuICAgICAgaWYgKGhlYWRlck9yZ0lkKSByZXEudXNlci5vcmdhbml6YXRpb25JZCA9IGhlYWRlck9yZ0lkO1xuICAgICAgaWYgKGhlYWRlck9yZ05hbWUpIHJlcS51c2VyLm9yZ2FuaXphdGlvbk5hbWUgPSBoZWFkZXJPcmdOYW1lO1xuICAgIH1cblxuICAgIC8vIFJlLWRlcml2ZSB0aGUgcmVxdWVzdCdzIHRlbmFudCBpZGVudGl0eSBmcm9tIHRoZSBOT1ctdmVyaWZpZWQgSldULlxuICAgIC8vXG4gICAgLy8gYGF0dGFjaFJlcXVlc3RDb250ZXh0YCBydW5zIGFzIGEgZ2xvYmFsIG1pZGRsZXdhcmUgQkVGT1JFIHRoaXMgcGVyLXJvdXRlXG4gICAgLy8gYHJlcXVpcmVBdXRoYCwgc28gaXQgY2FwdHVyZWQgYHJlcS5jb250ZXh0LmlkZW50aXR5YCB3aGlsZSBgcmVxLnVzZXJgIHdhc1xuICAgIC8vIHN0aWxsIHVuZGVmaW5lZCDigJQgYXQgd2hpY2ggcG9pbnQgYGdldElkZW50aXR5YCBmYWxscyBiYWNrIHRvIHRoZSByYXcsXG4gICAgLy8gY2xpZW50LXNldHRhYmxlIGB4LW9yZy1pZGAvYHgtdXNlci1pZGAgaGVhZGVycy4gRXZlcnkgZG93bnN0cmVhbSB0ZW5hbnQtXG4gICAgLy8gYXV0aG9yaXR5IGNvbnN1bWVyIChyZXF1aXJlT3JnSWQsIHdpdGhUZW5hbnRDb250ZXh0J3MgUkxTIHNjb3BlLCBjaGVja1F1b3RhLFxuICAgIC8vIHdpdGhSb3V0ZSwgYW5kIHRoZSBpZGVtcG90ZW5jeSBuYW1lc3BhY2UpIHJlYWRzIGByZXEuY29udGV4dC5pZGVudGl0eWAsIHNvXG4gICAgLy8gdGhhdCBmcm96ZW4gaGVhZGVyLWRlcml2ZWQgdmFsdWUg4oCUIG5vdCB0aGUgSldUIOKAlCB3YXMgZ292ZXJuaW5nIHRlbmFuY3kgb25cbiAgICAvLyBhbnkgbm9uLW5naW54IHBhdGguIFJlY29tcHV0aW5nIGhlcmUsIGF0IHRoZSBzaW5nbGUgcG9zdC12ZXJpZmljYXRpb24gY2hva2VcbiAgICAvLyBwb2ludCwgbWFrZXMgYGdldElkZW50aXR5YCBwcmVmZXIgdGhlIHZlcmlmaWVkIGByZXEudXNlcmAgKHNlZSBpZGVudGl0eS50cylcbiAgICAvLyBzbyB0ZW5hbmN5IGlzIEpXVC1hdXRob3JpdGF0aXZlLiBUaGUgbmdpbnggYHgtb3JnLWlkYCBvdmVyd3JpdGUgc3RheXMgYXNcbiAgICAvLyBkZWZlbmNlLWluLWRlcHRoLiBHdWFyZGVkIG9uIGByZXEuY29udGV4dGAgc28gc2VydmljZXMvcGF0aHMgdGhhdCBuZXZlclxuICAgIC8vIGF0dGFjaCBhIGNvbnRleHQgKG9yIHJ1biByZXF1aXJlQXV0aCBwcmUtY29udGV4dCkgYXJlIHVuYWZmZWN0ZWQuXG4gICAgY29uc3QgcmVxQ3R4ID0gKHJlcSBhcyBSZXF1ZXN0ICYgeyBjb250ZXh0PzogeyBpZGVudGl0eTogUmVxdWVzdElkZW50aXR5IH0gfSkuY29udGV4dDtcbiAgICBpZiAocmVxQ3R4KSB7XG4gICAgICByZXFDdHguaWRlbnRpdHkgPSBnZXRJZGVudGl0eShyZXEgYXMgdW5rbm93biBhcyBIdHRwUmVxdWVzdCk7XG4gICAgfVxuXG4gICAgLy8gU2Vzc2lvbi1pbnZhbGlkYXRpb24gY2hlY2sgZm9yIHRoZSBzdGF0ZWxlc3Mgc2VydmljZXM6IHJlamVjdCBhIHRva2VuXG4gICAgLy8gd2hvc2UgYHRva2VuVmVyc2lvbmAgaXMgYmVoaW5kIHRoZSByZXZvY2F0aW9uIHN0b3JlJ3MgY3VycmVudCB2YWx1ZSAoYVxuICAgIC8vIHByaXZpbGVnZSBjaGFuZ2UgdGhlIHBsYXRmb3JtIHB1Ymxpc2hlZCkuIE5vIHN0b3JlIHJlZ2lzdGVyZWQg4oeSIHRoaXMgaXMgYVxuICAgIC8vIG5vLW9wIGFuZCBjb250cm9sIHBhc3NlcyBzdHJhaWdodCB0aHJvdWdoLiBGYWlsLW9wZW4gb24gYW55IHN0b3JlIGVycm9yLlxuICAgIC8vIEFuIGltcGVyc29uYXRpb24gc2Vzc2lvbiBpcyBjaGVja2VkIGV2ZW4gd2hlbiBOTyBzdG9yZSBpcyByZWdpc3RlcmVkOiB0aGVcbiAgICAvLyB0b2tlblZlcnNpb24gY2hlY2sgYmVsb3cgaXMgYSBuby1vcCB3aXRob3V0IGEgc3RvcmUsIGJ1dCBmb3IgYSBzZXNzaW9uXG4gICAgLy8gdGhhdCB3b3VsZCBzaWxlbnRseSBtZWFuIFwibmV2ZXIgcmV2b2tlZFwiLiBIZXJlIG5vIHN0b3JlIOKHkiB1bmF2YWlsYWJsZSDih5JcbiAgICAvLyByZWplY3RlZC4gU2VlIGBUb2tlblJldm9jYXRpb25TdG9yZS5nZXRTZXNzaW9uUmV2b2NhdGlvbmAuXG4gICAgY29uc3QgaW1wZXJzb25hdGlvbiA9IGlzSW1wZXJzb25hdGlvblNlc3Npb24oZGVjb2RlZCk7XG4gICAgaWYgKGltcGVyc29uYXRpb24gfHwgKHRva2VuUmV2b2NhdGlvblN0b3JlICYmIGRlY29kZWQuc3ViICYmIHR5cGVvZiBkZWNvZGVkLnRva2VuVmVyc2lvbiA9PT0gJ251bWJlcicpKSB7XG4gICAgICAvLyBgLmNhdGNoKG5leHQpYCBmb3J3YXJkcyBhIERPV05TVFJFQU0gc3luY2hyb25vdXMgdGhyb3cgZnJvbSBgbmV4dCgpYCB0b1xuICAgICAgLy8gRXhwcmVzcydzIGVycm9yIG1pZGRsZXdhcmUg4oCUIHdpdGhvdXQgaXQsIHRoYXQgdGhyb3cgd291bGQgc3VyZmFjZSBhcyBhblxuICAgICAgLy8gdW5oYW5kbGVkIHJlamVjdGlvbiAodGhpcyBgbmV4dCgpYCBydW5zIGluIGEgbWljcm90YXNrLCBvdXRzaWRlIHRoZVxuICAgICAgLy8gc3Vycm91bmRpbmcgdHJ5L2NhdGNoIGFuZCBFeHByZXNzJ3MgcGVyLWxheWVyIGRpc3BhdGNoKS4gVGhlIGNoZWNrc1xuICAgICAgLy8gdGhlbXNlbHZlcyBuZXZlciByZWplY3QsIHNvIHRoZSBjYXRjaCBvbmx5IGV2ZXIgc2VlcyBhIGRvd25zdHJlYW0gZXJyb3IuXG4gICAgICAoYXN5bmMgKCkgPT4ge1xuICAgICAgICBpZiAoaW1wZXJzb25hdGlvbikge1xuICAgICAgICAgIGNvbnN0IHN0YXRlID0gYXdhaXQgc2Vzc2lvblJldm9jYXRpb25TdGF0ZShkZWNvZGVkLmp0aSBhcyBzdHJpbmcpO1xuICAgICAgICAgIGlmIChzdGF0ZSAhPT0gJ2xpdmUnKSB7XG4gICAgICAgICAgICByZXR1cm4gc2VuZEVycm9yKFxuICAgICAgICAgICAgICByZXMsXG4gICAgICAgICAgICAgIEh0dHBTdGF0dXMuVU5BVVRIT1JJWkVELFxuICAgICAgICAgICAgICBzdGF0ZSA9PT0gJ3Jldm9rZWQnXG4gICAgICAgICAgICAgICAgPyAnVGhpcyBpbXBlcnNvbmF0aW9uIHNlc3Npb24gaGFzIGJlZW4gZW5kZWQnXG4gICAgICAgICAgICAgICAgOiAnVGhpcyBpbXBlcnNvbmF0aW9uIHNlc3Npb24gY291bGQgbm90IGJlIHZlcmlmaWVkJyxcbiAgICAgICAgICAgICAgRXJyb3JDb2RlLlRPS0VOX1JFVk9LRUQsXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAodG9rZW5SZXZvY2F0aW9uU3RvcmUgJiYgZGVjb2RlZC5zdWIgJiYgdHlwZW9mIGRlY29kZWQudG9rZW5WZXJzaW9uID09PSAnbnVtYmVyJyAmJiBhd2FpdCBpc1Rva2VuUmV2b2tlZChkZWNvZGVkKSkge1xuICAgICAgICAgIHJldHVybiBzZW5kRXJyb3IocmVzLCBIdHRwU3RhdHVzLlVOQVVUSE9SSVpFRCwgJ1Nlc3Npb24gaGFzIGJlZW4gcmV2b2tlZDsgcGxlYXNlIHNpZ24gaW4gYWdhaW4nLCBFcnJvckNvZGUuVE9LRU5fUkVWT0tFRCk7XG4gICAgICAgIH1cbiAgICAgICAgbmV4dCgpO1xuICAgICAgfSkoKS5jYXRjaChuZXh0KTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBuZXh0KCk7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgaWYgKGVycm9yIGluc3RhbmNlb2Ygand0LlRva2VuRXhwaXJlZEVycm9yKSB7XG4gICAgICByZXR1cm4gc2VuZEVycm9yKHJlcywgSHR0cFN0YXR1cy5VTkFVVEhPUklaRUQsICdUb2tlbiBoYXMgZXhwaXJlZCcsIEVycm9yQ29kZS5UT0tFTl9FWFBJUkVEKTtcbiAgICB9XG5cbiAgICAvLyBUaGUgc2lnbmluZyBrZXlzIGNvdWxkbid0IGJlIGZldGNoZWQsIHNvIHRoZSB0b2tlbidzIHZhbGlkaXR5IGlzIFVOS05PV04uXG4gICAgLy8gRmFpbCBDTE9TRUQgd2l0aCBhIHJldHJ5YWJsZSA1MDMg4oCUIG5ldmVyIGEgcGFzcywgYW5kIG5ldmVyIGEgNDAxIHRoYXRcbiAgICAvLyB3b3VsZCBzZW5kIGEgbGVnaXRpbWF0ZSBjbGllbnQgb2ZmIHRvIHJlLWF1dGhlbnRpY2F0ZSBvdmVyIG91ciBvdXRhZ2UuXG4gICAgLy8gU2FtZSByZWFzb25pbmcgZm9yIHRoZSBTRVJWSUNFIGNoYWluOiBubyByZWFkYWJsZSBrZXkgYnVuZGxlIG1lYW5zIG5vIHdheVxuICAgIC8vIHRvIHRlbGwgYSBwZWVyJ3MgdG9rZW4gZnJvbSBhIGZvcmdlcnksIHNvIHRoZSByZXF1ZXN0IGlzIHJlZnVzZWQgd2l0aCBhXG4gICAgLy8gcmV0cnlhYmxlIDUwMyByYXRoZXIgdGhhbiBhZG1pdHRlZCBvciBib3VuY2VkIHRvIHJlLWF1dGhlbnRpY2F0ZS5cbiAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBKd2tzVW5hdmFpbGFibGVFcnJvciB8fCBlcnJvciBpbnN0YW5jZW9mIFNlcnZpY2VLZXlFcnJvcikge1xuICAgICAgbG9nZ2VyLndhcm4oJ1JlamVjdGluZyByZXF1ZXN0OiB0b2tlbiBzaWduaW5nIGtleXMgdW5hdmFpbGFibGUnLCB7IGVycm9yOiBlcnJvci5tZXNzYWdlIH0pO1xuICAgICAgcmV0dXJuIHNlbmRFcnJvcihcbiAgICAgICAgcmVzLCBIdHRwU3RhdHVzLlNFUlZJQ0VfVU5BVkFJTEFCTEUsXG4gICAgICAgICdUb2tlbiB2ZXJpZmljYXRpb24gaXMgdGVtcG9yYXJpbHkgdW5hdmFpbGFibGU7IHBsZWFzZSByZXRyeScsXG4gICAgICAgIEVycm9yQ29kZS5TRVJWSUNFX1VOQVZBSUxBQkxFLFxuICAgICAgKTtcbiAgICB9XG5cbiAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBVbmtub3duS2lkRXJyb3IgfHwgZXJyb3IgaW5zdGFuY2VvZiBqd3QuSnNvbldlYlRva2VuRXJyb3IpIHtcbiAgICAgIHJldHVybiBzZW5kRXJyb3IocmVzLCBIdHRwU3RhdHVzLlVOQVVUSE9SSVpFRCwgJ0ludmFsaWQgdG9rZW4nLCBFcnJvckNvZGUuVE9LRU5fSU5WQUxJRCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHNlbmRFcnJvcihyZXMsIEh0dHBTdGF0dXMuVU5BVVRIT1JJWkVELCAnQXV0aGVudGljYXRpb24gZmFpbGVkJywgRXJyb3JDb2RlLlVOQVVUSE9SSVpFRCk7XG4gIH1cbn1cblxuLyoqXG4gKiBXaGV0aGVyIGEgc2V0IG9mIHZlcmlmaWVkIGNsYWltcyBzcGVha3MgZm9yIGEgUEVSU09OJ3Mgb3duIHNlc3Npb24g4oCUIHRoZSBvbmx5XG4gKiBraW5kIG9mIGNyZWRlbnRpYWwgYW4gYXNzdXJhbmNlIGxldmVsIGNhbiBiZSBhc3NlcnRlZCBhYm91dC5cbiAqXG4gKiBFeGNsdWRlcyBhbGwgdGhyZWUgbWFjaGluZSBzaGFwZXM6IGFuIGludGVybmFsIHNlcnZpY2UgcHJpbmNpcGFsLCBhbiBvcmdcbiAqIHNlcnZpY2UgYWNjb3VudCwgYW5kIGFueSBleGNoYW5nZWQgYWNjZXNzIGtleSAoYHRva2VuX3VzZTogJ2FwaV9rZXknYCwgaS5lLiBhXG4gKiBQQVQgb3IgYSBzZXJ2aWNlLWFjY291bnQga2V5KSwgZWFjaCBvZiB3aGljaCBhdXRoZW50aWNhdGVzIGEgcHJvZ3JhbSBob2xkaW5nIGFcbiAqIHNlY3JldCByYXRoZXIgdGhhbiBhIHBlcnNvbiBwcmVzZW50aW5nIGZhY3RvcnMuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc0h1bWFuUHJpbmNpcGFsKGNsYWltczogUGljazxKd3RQYXlsb2FkLCAncHJpbmNpcGFsVHlwZScgfCAndG9rZW5fdXNlJz4gfCB1bmRlZmluZWQpOiBib29sZWFuIHtcbiAgcmV0dXJuIGNsYWltcz8ucHJpbmNpcGFsVHlwZSA9PT0gJ3VzZXInICYmIGNsYWltcy50b2tlbl91c2UgPT09ICdhY2Nlc3MnO1xufVxuXG4vKiogV2hhdCBhbiBhc3N1cmFuY2UgZ2F0ZSBkZW1hbmRzLiAqL1xuZXhwb3J0IGludGVyZmFjZSBBc3N1cmFuY2VPcHRpb25zIHtcbiAgbWluQXNzdXJhbmNlOiBBc3N1cmFuY2VMZXZlbDtcbiAgbWF4QWdlPzogbnVtYmVyO1xuICAvKipcbiAgICogQSBOQU1FRCBjYXJ2ZS1vdXQgZm9yIHJlcXVlc3RzIHRoYXQgY2Fubm90IHBvc3NpYmx5IHNhdGlzZnkgdGhlIGxldmVsIGFuZFxuICAgKiBtdXN0IHN0aWxsIGJlIHNlcnZlZCDigJQgdG9kYXkgb25seSBvbmUgZXhpc3RzOiB0aGUgYm9vdHN0cmFwLWFkbWluaXN0cmF0b3JcbiAgICogd2luZG93LCB3aGVyZSBhIGZyZXNoIGluc3RhbGwncyBzaW5nbGUgYWRtaW4gaGFzIG5vIGZhY3RvciB5ZXQgYW5kIHRoZSBzZXR1cFxuICAgKiBjYWxscyB0aGF0IGNyZWF0ZSB0aGUgaW5zdGFsbCdzIGF1dG9tYXRpb24gY3JlZGVudGlhbCB3b3VsZCBvdGhlcndpc2UgYmVcbiAgICogdW5yZWFjaGFibGUgKHNlZSBwbGF0Zm9ybSdzIGBpc0Jvb3RzdHJhcFNldHVwUmVxdWVzdGApLlxuICAgKlxuICAgKiBJdCBpcyBkZWxpYmVyYXRlbHkgc2hhcGVkIGFzIGB7IHJlYXNvbiwgd2hlbiB9YCByYXRoZXIgdGhhbiBhIGJhcmUgcHJlZGljYXRlOlxuICAgKiB0aGUgcmVhc29uIGlzIGNvdW50ZWQgKGBhc3N1cmFuY2VfZXhlbXB0ZWRfdG90YWx7cmVhc29ufWApIGFuZCBwdWJsaXNoZWQgb25cbiAgICogdGhlIHJvdXRlIHRhYmxlIGFzIGBhc3N1cmFuY2VFeGVtcHRgLCBzbyBhbiBleGVtcHRpb24gY2Fubm90IGJlIGFkZGVkIHdpdGhvdXRcbiAgICogc2hvd2luZyB1cCBpbiB0aGUgZ2VuZXJhdGVkIHRhYmxlIGEgcmV2aWV3ZXIgcmVhZHMuIFRoZSBnYXRlIGtlZXBzIGl0c1xuICAgKiBgbWluQXNzdXJhbmNlYCB0YWcgZWl0aGVyIHdheSDigJQgdGhlIHJvdXRlIHN0aWxsIHJlcXVpcmVzIE1GQS1ncmFkZSBmb3JcbiAgICogZXZlcnlvbmUgdGhlIGNhcnZlLW91dCBkb2VzIG5vdCBuYW1lLlxuICAgKi9cbiAgZXhlbXB0PzogeyByZWFzb246IHN0cmluZzsgd2hlbjogKHJlcTogUmVxdWVzdCkgPT4gYm9vbGVhbiB9O1xufVxuXG4vKipcbiAqIFN0YW5kYWxvbmUgYXNzdXJhbmNlIGdhdGUsIGZvciBhIHNlcnZpY2Ugd2hvc2Ugb3duIGByZXF1aXJlQXV0aGAgaXMgbm90XG4gKiBhcGktY29yZSdzIChwbGF0Zm9ybSdzIGlzIGl0cyBvd24sIGJlY2F1c2UgaXQgcmVhZHMgTW9uZ28pLiBDb21wb3NlIGl0IEFGVEVSXG4gKiBhdXRoZW50aWNhdGlvbjogYHJvdXRlci5nZXQoJy94JywgcmVxdWlyZUF1dGgsIHJlcXVpcmVBc3N1cmFuY2UoeyBtaW5Bc3N1cmFuY2U6IDIgfSksIGgpYC5cbiAqXG4gKiBJZGVudGljYWwgcnVsZXMgYW5kIGlkZW50aWNhbCByZWZ1c2FscyB0byBgcmVxdWlyZUF1dGgoeyBtaW5Bc3N1cmFuY2UgfSlgIOKAlFxuICogdGhhdCBvcHRpb24gc2ltcGx5IGNhbGxzIHRoZSBzYW1lIGNoZWNrIGlubGluZSwgc28gdGhlcmUgaXMgb25lIGltcGxlbWVudGF0aW9uXG4gKiBvZiBcImlzIHRoaXMgc2Vzc2lvbiBNRkEtZ3JhZGVcIiBpbiB0aGUgY29kZWJhc2UuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXF1aXJlQXNzdXJhbmNlKG9wdGlvbnM6IEFzc3VyYW5jZU9wdGlvbnMpIHtcbiAgcmV0dXJuIHRhZ1JvdXRlR2F0ZSgocmVxOiBSZXF1ZXN0LCByZXM6IFJlc3BvbnNlLCBuZXh0OiBOZXh0RnVuY3Rpb24pOiB2b2lkID0+IHtcbiAgICBpZiAoIXJlcS51c2VyKSB7XG4gICAgICByZXR1cm4gc2VuZEVycm9yKHJlcywgSHR0cFN0YXR1cy5VTkFVVEhPUklaRUQsICdBdXRoZW50aWNhdGlvbiByZXF1aXJlZCcsIEVycm9yQ29kZS5VTkFVVEhPUklaRUQpO1xuICAgIH1cbiAgICAvLyBBIG5hbWVkIGV4ZW1wdGlvbiBpcyBjaGVja2VkIEFGVEVSIGF1dGhlbnRpY2F0aW9uIGFuZCBiZWZvcmUgdGhlIGxldmVsLCBzb1xuICAgIC8vIGl0IGNhbiBuZXZlciBhZG1pdCBhbiB1bmF1dGhlbnRpY2F0ZWQgY2FsbGVyLCBhbmQgaXQgaXMgY291bnRlZCBldmVyeSB0aW1lXG4gICAgLy8gaXQgZmlyZXMg4oCUIGFuIGV4ZW1wdGlvbiBub2JvZHkgY2FuIHNlZSBpcyBob3cgYSBnYXRlIHF1aWV0bHkgc3RvcHMgYmVpbmcgb25lLlxuICAgIGlmIChvcHRpb25zLmV4ZW1wdD8ud2hlbihyZXEpID09PSB0cnVlKSB7XG4gICAgICBlbWl0Q291bnRlcignYXNzdXJhbmNlX2V4ZW1wdGVkX3RvdGFsJywgeyBzZXJ2aWNlOiBzZXJ2aWNlSWRlbnRpdHkoKSwgcmVhc29uOiBvcHRpb25zLmV4ZW1wdC5yZWFzb24gfSk7XG4gICAgICByZXR1cm4gbmV4dCgpO1xuICAgIH1cbiAgICBpZiAocmVmdXNlRm9yQXNzdXJhbmNlKG9wdGlvbnMsIHJlcS51c2VyIGFzIEp3dFBheWxvYWQsIHJlcSwgcmVzKSkgcmV0dXJuO1xuICAgIG5leHQoKTtcbiAgfSwge1xuICAgIGtpbmQ6ICdhc3N1cmFuY2UnLFxuICAgIG1pbkFzc3VyYW5jZTogb3B0aW9ucy5taW5Bc3N1cmFuY2UsXG4gICAgLi4uKG9wdGlvbnMubWF4QWdlICE9PSB1bmRlZmluZWQgPyB7IG1heEFnZTogb3B0aW9ucy5tYXhBZ2UgfSA6IHt9KSxcbiAgICAuLi4ob3B0aW9ucy5leGVtcHQgPyB7IGV4ZW1wdDogb3B0aW9ucy5leGVtcHQucmVhc29uIH0gOiB7fSksXG4gIH0pO1xufVxuXG4vKipcbiAqIEhhbmRsZXItbGV2ZWwgdHdpbiBvZiB7QGxpbmsgcmVxdWlyZUFzc3VyYW5jZX0sIGZvciBhIHJvdXRlIHdoZXJlIG9ubHkgU09NRVxuICogcmVxdWVzdHMgbXVzdCBiZSBNRkEtZ3JhZGUg4oCUIGUuZy4gYSBwb2xpY3kgcm91dGUgb24gd2hpY2ggVElHSFRFTklORyBhIHNldHRpbmdcbiAqIHN0YXlzIG9wZW4gdG8gYSBzaW5nbGUtZmFjdG9yIHNlc3Npb24gKHNvIGFuIGFkbWluIHdpdGhvdXQgTUZBIGNhbiBhZG9wdCBpdClcbiAqIGJ1dCBMT09TRU5JTkcgaXQgZG9lcyBub3QuIFNhbWUgcnVsZXMgYW5kIHRoZSBzYW1lIHRocmVlIHJlZnVzYWxzLiBSZXR1cm5zXG4gKiB0cnVlIHdoZW4gdGhlIHJlcXVlc3Qgd2FzIFJFRlVTRUQgKGEgcmVzcG9uc2UgaGFzIGJlZW4gc2VudCkuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZWZ1c2VXZWFrU2Vzc2lvbihyZXE6IFJlcXVlc3QsIHJlczogUmVzcG9uc2UsIG9wdGlvbnM6IEFzc3VyYW5jZU9wdGlvbnMpOiBib29sZWFuIHtcbiAgaWYgKCFyZXEudXNlcikge1xuICAgIHNlbmRFcnJvcihyZXMsIEh0dHBTdGF0dXMuVU5BVVRIT1JJWkVELCAnQXV0aGVudGljYXRpb24gcmVxdWlyZWQnLCBFcnJvckNvZGUuVU5BVVRIT1JJWkVEKTtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuICByZXR1cm4gcmVmdXNlRm9yQXNzdXJhbmNlKG9wdGlvbnMsIHJlcS51c2VyIGFzIEp3dFBheWxvYWQsIHJlcSwgcmVzKTtcbn1cblxuLyoqIFdoYXQge0BsaW5rIHJlcXVpcmVPcmdBZG1pbkFzc3VyYW5jZX0gZGVtYW5kcyBvZiBhIHJvdXRlLiAqL1xuZXhwb3J0IGludGVyZmFjZSBPcmdBZG1pbkFzc3VyYW5jZU9wdGlvbnMge1xuICAvKiogV2hhdCBhIG1hY2hpbmUgY3JlZGVudGlhbCAoUEFULCBzZXJ2aWNlIGFjY291bnQsIG1hY2hpbmUgc2Vzc2lvbikgbWVldHMgb25cbiAgICogIHRoaXMgcm91dGUgd2hpbGUgdGhlIHBvbGljeSBpcyBvbiDigJQgc2VlIHtAbGluayBPcmdBZG1pbkFzc3VyYW5jZU1hY2hpbmVzfS5cbiAgICogIFJlcXVpcmVkLCBzbyBldmVyeSByb3V0ZSBzdGF0ZXMgaXRzIGRlY2lzaW9uIHJhdGhlciB0aGFuIGluaGVyaXRpbmcgb25lLiAqL1xuICBtYWNoaW5lczogT3JnQWRtaW5Bc3N1cmFuY2VNYWNoaW5lcztcbn1cblxuLyoqIGBkZXRhaWxzLnJlYXNvbmAgb24gYSByZWZ1c2FsIGJ5IHtAbGluayByZXF1aXJlT3JnQWRtaW5Bc3N1cmFuY2V9LCBzbyB0aGUgVUlcbiAqICBjYW4gc2F5IGl0IGlzIHRoZSBPUkcncyBwb2xpY3kgYXNraW5nLCBub3QgdGhlIHJvdXRlJ3Mgb3duIHJlcXVpcmVtZW50LiAqL1xuZXhwb3J0IGNvbnN0IE9SR19BRE1JTl9NRkFfUkVBU09OID0gJ29yZ19hZG1pbl9wb2xpY3knO1xuXG4vKipcbiAqIFRoZSByZWZ1c2FsIHtAbGluayByZXF1aXJlT3JnQWRtaW5Bc3N1cmFuY2V9IHdvdWxkIHNlbmQgZm9yIHRoZXNlIGNsYWltcywgb3JcbiAqIGB1bmRlZmluZWRgIHdoZW4gdGhlIHJlcXVlc3QgbWF5IHByb2NlZWQuIEV4cG9ydGVkIHNvIGEgaGFuZGxlciB3aG9zZSBwb2xpY3lcbiAqIGFwcGxpZXMgdG8gb25seSBQQVJUIG9mIGEgcm91dGUgKGUuZy4gYGdlbmVyYXRlLXRva2VuYCwgd2hlcmUgb3BlbmluZyBhIG5ld1xuICogbWFjaGluZSBjcmVkZW50aWFsIGlzIGdhdGVkIGJ1dCByZW5ld2luZyBhbiBleGlzdGluZyBvbmUgaXMgbm90KSBhcHBsaWVzIHRoZVxuICogZXhhY3Qgc2FtZSBydWxlIHJhdGhlciB0aGFuIGEgY29weSBvZiBpdC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG9yZ0FkbWluQXNzdXJhbmNlUmVmdXNhbChcbiAgY2xhaW1zOiBKd3RQYXlsb2FkIHwgdW5kZWZpbmVkLFxuICBvcHRpb25zOiBPcmdBZG1pbkFzc3VyYW5jZU9wdGlvbnMsXG4pOiB7IHN0YXR1czogbnVtYmVyOyBjb2RlOiBFcnJvckNvZGU7IG1lc3NhZ2U6IHN0cmluZzsgcmVhc29uOiAnbWFjaGluZV9wcmluY2lwYWwnIHwgJ3dlYWtfc2Vzc2lvbicgfSB8IHVuZGVmaW5lZCB7XG4gIC8vIFRoZSBjbGFpbSBpcyBvbmx5IGV2ZXIgYDJgLCBhbmQgb25seSB3aGVuIHRoZSBwb2xpY3kgaXMgb24gKHNlZSBKd3RQYXlsb2FkKS5cbiAgaWYgKCFjbGFpbXMgfHwgY2xhaW1zLm9yZ19hZG1pbl9hYWwgIT09IDIpIHJldHVybiB1bmRlZmluZWQ7XG4gIGlmICghaXNIdW1hblByaW5jaXBhbChjbGFpbXMpKSB7XG4gICAgaWYgKG9wdGlvbnMubWFjaGluZXMgPT09ICdhbGxvdycpIHJldHVybiB1bmRlZmluZWQ7XG4gICAgcmV0dXJuIHtcbiAgICAgIHN0YXR1czogSHR0cFN0YXR1cy5GT1JCSURERU4sXG4gICAgICBjb2RlOiBFcnJvckNvZGUuSFVNQU5fU0VTU0lPTl9SRVFVSVJFRCxcbiAgICAgIHJlYXNvbjogJ21hY2hpbmVfcHJpbmNpcGFsJyxcbiAgICAgIG1lc3NhZ2U6ICdZb3VyIG9yZ2FuaXphdGlvbiByZXF1aXJlcyB0d28tZmFjdG9yIGF1dGhlbnRpY2F0aW9uIGZvciB0aGlzIGFjdGlvbiDigJQgQVBJIGtleXMgYW5kIHNlcnZpY2UgYWNjb3VudHMgY2Fubm90IHBlcmZvcm0gaXQnLFxuICAgIH07XG4gIH1cbiAgaWYgKChjbGFpbXMuYWFsID8/IDEpID49IDIpIHJldHVybiB1bmRlZmluZWQ7XG4gIHJldHVybiB7XG4gICAgc3RhdHVzOiBIdHRwU3RhdHVzLlVOQVVUSE9SSVpFRCxcbiAgICBjb2RlOiBFcnJvckNvZGUuTUZBX1JFUVVJUkVELFxuICAgIHJlYXNvbjogJ3dlYWtfc2Vzc2lvbicsXG4gICAgbWVzc2FnZTogJ1lvdXIgb3JnYW5pemF0aW9uIHJlcXVpcmVzIHR3by1mYWN0b3IgYXV0aGVudGljYXRpb24gZm9yIGFkbWluaXN0cmF0aXZlIGFjdGlvbnMg4oCUIHNpZ24gaW4gYWdhaW4gd2l0aCBhIHBhc3NrZXkgb3IgYW4gYXV0aGVudGljYXRvciBjb2RlJyxcbiAgfTtcbn1cblxuLyoqXG4gKiBBcHBseSB7QGxpbmsgb3JnQWRtaW5Bc3N1cmFuY2VSZWZ1c2FsfSBhbmQgc2VuZCBpdHMgcmVmdXNhbC4gUmV0dXJucyB0cnVlIHdoZW5cbiAqIHRoZSByZXF1ZXN0IHdhcyBSRUZVU0VEIChhIHJlc3BvbnNlIGhhcyBiZWVuIHNlbnQpLiBGb3IgaGFuZGxlci1sZXZlbCB1c2U7XG4gKiByb3V0ZXMgdXNlIHtAbGluayByZXF1aXJlT3JnQWRtaW5Bc3N1cmFuY2V9LlxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVmdXNlRm9yT3JnQWRtaW5Bc3N1cmFuY2UocmVxOiBSZXF1ZXN0LCByZXM6IFJlc3BvbnNlLCBvcHRpb25zOiBPcmdBZG1pbkFzc3VyYW5jZU9wdGlvbnMpOiBib29sZWFuIHtcbiAgY29uc3QgcmVmdXNhbCA9IG9yZ0FkbWluQXNzdXJhbmNlUmVmdXNhbChyZXEudXNlciBhcyBKd3RQYXlsb2FkIHwgdW5kZWZpbmVkLCBvcHRpb25zKTtcbiAgaWYgKCFyZWZ1c2FsKSByZXR1cm4gZmFsc2U7XG4gIGVtaXRDb3VudGVyKCdtZmFfZW5mb3JjZW1lbnRfcmVmdXNlZF90b3RhbCcsIHsgc2VydmljZTogc2VydmljZUlkZW50aXR5KCksIHJlYXNvbjogYG9yZ19hZG1pbl8ke3JlZnVzYWwucmVhc29ufWAgfSk7XG4gIHJlY29yZEF1dGh6RGVuaWFsKHJlcSwgJ2Fzc3VyYW5jZTpvcmctYWRtaW4nKTtcbiAgc2VuZEVycm9yKHJlcywgcmVmdXNhbC5zdGF0dXMsIHJlZnVzYWwubWVzc2FnZSwgcmVmdXNhbC5jb2RlLCB7IHJlYXNvbjogT1JHX0FETUlOX01GQV9SRUFTT04gfSk7XG4gIHJldHVybiB0cnVlO1xufVxuXG4vKipcbiAqIFRoZSBvcmcgcG9saWN5IFwiYWRtaW5pc3RyYXRpdmUgYWN0aW9ucyByZXF1aXJlIE1GQVwiIChgYWRtaW5BY3Rpb25zUmVxdWlyZU1mYWApLlxuICpcbiAqIFVubGlrZSB7QGxpbmsgcmVxdWlyZUFzc3VyYW5jZX0sIHRoZSByZXF1aXJlbWVudCBpcyB0aGUgT1JHJ3MgY2hvaWNlLCBub3QgdGhlXG4gKiByb3V0ZSdzOiB0aGUgZ2F0ZSByZWFkcyB0aGUgYG9yZ19hZG1pbl9hYWxgIGNsYWltLCBzZXQgYXQgdG9rZW4gaXNzdWUgZnJvbSB0aGVcbiAqIGFjdGl2ZSBvcmcncyBwb2xpY3kgKHN0cmljdGVzdCBhY3Jvc3MgaXRzIGFuY2VzdG9ycyksIHNvIGEgc2VydmljZSB0aGF0IGNhbm5vdFxuICogcmVhZCB0aGUgb3JnIGRvY3VtZW50IHN0aWxsIGVuZm9yY2VzIGl0LiBXaXRoIHRoZSBwb2xpY3kgb2ZmIHRoZSBnYXRlIGlzIGFcbiAqIG5vLW9wOyB3aXRoIGl0IG9uLCBhIHNpbmdsZS1mYWN0b3Igc2Vzc2lvbiBpcyByZWZ1c2VkIDQwMSBgTUZBX1JFUVVJUkVEYFxuICogKHdpdGggYGRldGFpbHMucmVhc29uOiAnb3JnX2FkbWluX3BvbGljeSdgKSDigJQgdGhlIHNhbWUgY29kZSB0aGUgY2xpZW50IGFscmVhZHlcbiAqIHR1cm5zIGludG8gXCJlbnJvbCBhIGZhY3RvciAvIHNpZ24gaW4gd2l0aCBpdFwiLCBuZXZlciBhIHNpZ24tb3V0LlxuICpcbiAqIGBtYWNoaW5lc2AgaXMgZGVjaWRlZCBwZXIgcm91dGUgKHNlZSB7QGxpbmsgT3JnQWRtaW5Bc3N1cmFuY2VNYWNoaW5lc30pOiB0aGVcbiAqIHBvbGljeSBpcyBhYm91dCBob3cgc3Ryb25nbHkgYSBQRVJTT04ncyBzZXNzaW9uIHdhcyBvcGVuZWQsIHNvIGF1dG9tYXRpb24gdGhhdFxuICogbGVnaXRpbWF0ZWx5IGRyaXZlcyBhIHJvdXRlIGtlZXBzIHdvcmtpbmcgKGBhbGxvd2ApLCB3aGlsZSBhIHJvdXRlIHRoYXQgbWludHNcbiAqIGEgZnVydGhlciBjcmVkZW50aWFsIHJlZnVzZXMgbWFjaGluZXMgb3V0cmlnaHQgKGByZWZ1c2VgLCA0MDNcbiAqIGBIVU1BTl9TRVNTSU9OX1JFUVVJUkVEYCDigJQgdGhlIHNhbWUgcmVmdXNhbCBgcmVxdWlyZUFzc3VyYW5jZWAgZ2l2ZXMgdGhlbSkuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXF1aXJlT3JnQWRtaW5Bc3N1cmFuY2Uob3B0aW9uczogT3JnQWRtaW5Bc3N1cmFuY2VPcHRpb25zKSB7XG4gIHJldHVybiB0YWdSb3V0ZUdhdGUoKHJlcTogUmVxdWVzdCwgcmVzOiBSZXNwb25zZSwgbmV4dDogTmV4dEZ1bmN0aW9uKTogdm9pZCA9PiB7XG4gICAgaWYgKCFyZXEudXNlcikge1xuICAgICAgcmV0dXJuIHNlbmRFcnJvcihyZXMsIEh0dHBTdGF0dXMuVU5BVVRIT1JJWkVELCAnQXV0aGVudGljYXRpb24gcmVxdWlyZWQnLCBFcnJvckNvZGUuVU5BVVRIT1JJWkVEKTtcbiAgICB9XG4gICAgaWYgKHJlZnVzZUZvck9yZ0FkbWluQXNzdXJhbmNlKHJlcSwgcmVzLCBvcHRpb25zKSkgcmV0dXJuO1xuICAgIG5leHQoKTtcbiAgfSwgeyBraW5kOiAnb3JnQWRtaW5Bc3N1cmFuY2UnLCBtYWNoaW5lczogb3B0aW9ucy5tYWNoaW5lcyB9KTtcbn1cblxuLyoqXG4gKiBFbmZvcmNlIGBtaW5Bc3N1cmFuY2VgIC8gYG1heEFnZWAgb24gYSB2ZXJpZmllZCB0b2tlbi4gUmV0dXJucyB0cnVlIHdoZW4gdGhlXG4gKiByZXF1ZXN0IHdhcyBSRUZVU0VEIChhIHJlc3BvbnNlIGhhcyBiZWVuIHNlbnQpLlxuICpcbiAqIFRocmVlIGRpc3RpbmN0IHJlZnVzYWxzLCBiZWNhdXNlIHRoZSBjbGllbnQncyBuZXh0IG1vdmUgZGlmZmVycyBmb3IgZWFjaDpcbiAqIGEgbWFjaGluZSBtdXN0IHN0b3AgKDQwMyksIGEgd2VhayBzZXNzaW9uIG11c3QgZ2FpbiBhIGZhY3RvciAoNDAxXG4gKiBgTUZBX1JFUVVJUkVEYCDihpIgZW5yb2xtZW50LCBuZXZlciBhIHNpZ24tb3V0KSwgYW5kIGEgc3RhbGUgb25lIG11c3Qgc2ltcGx5XG4gKiBhdXRoZW50aWNhdGUgYWdhaW4gKDQwMSBgUkVBVVRIX1JFUVVJUkVEYCkuXG4gKi9cbmZ1bmN0aW9uIHJlZnVzZUZvckFzc3VyYW5jZShcbiAgb3B0aW9uczogQXNzdXJhbmNlT3B0aW9ucyxcbiAgZGVjb2RlZDogSnd0UGF5bG9hZCxcbiAgcmVxOiBSZXF1ZXN0LFxuICByZXM6IFJlc3BvbnNlLFxuKTogYm9vbGVhbiB7XG4gIGNvbnN0IG1pbkFzc3VyYW5jZSA9IG9wdGlvbnMubWluQXNzdXJhbmNlO1xuICBjb25zdCByZWZ1c2UgPSAocmVhc29uOiBzdHJpbmcsIHN0YXR1czogbnVtYmVyLCBtZXNzYWdlOiBzdHJpbmcsIGNvZGU6IEVycm9yQ29kZSk6IHRydWUgPT4ge1xuICAgIGVtaXRDb3VudGVyKCdtZmFfZW5mb3JjZW1lbnRfcmVmdXNlZF90b3RhbCcsIHsgc2VydmljZTogc2VydmljZUlkZW50aXR5KCksIHJlYXNvbiB9KTtcbiAgICByZWNvcmRBdXRoekRlbmlhbChyZXEsIGBhc3N1cmFuY2U6JHttaW5Bc3N1cmFuY2V9YCk7XG4gICAgc2VuZEVycm9yKHJlcywgc3RhdHVzLCBtZXNzYWdlLCBjb2RlKTtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfTtcblxuICBpZiAoIWlzSHVtYW5QcmluY2lwYWwoZGVjb2RlZCkpIHtcbiAgICByZXR1cm4gcmVmdXNlKFxuICAgICAgJ21hY2hpbmVfcHJpbmNpcGFsJywgSHR0cFN0YXR1cy5GT1JCSURERU4sXG4gICAgICAnVGhpcyBhY3Rpb24gcmVxdWlyZXMgYSBwZXJzb24gc2lnbmVkIGluIHdpdGggdHdvLWZhY3RvciBhdXRoZW50aWNhdGlvbiDigJQgQVBJIGtleXMgYW5kIHNlcnZpY2UgYWNjb3VudHMgY2Fubm90IHBlcmZvcm0gaXQnLFxuICAgICAgRXJyb3JDb2RlLkhVTUFOX1NFU1NJT05fUkVRVUlSRUQsXG4gICAgKTtcbiAgfVxuICBpZiAoKGRlY29kZWQuYWFsID8/IDEpIDwgbWluQXNzdXJhbmNlKSB7XG4gICAgcmV0dXJuIHJlZnVzZShcbiAgICAgICd3ZWFrX3Nlc3Npb24nLCBIdHRwU3RhdHVzLlVOQVVUSE9SSVpFRCxcbiAgICAgICdUaGlzIGFjdGlvbiByZXF1aXJlcyB0d28tZmFjdG9yIGF1dGhlbnRpY2F0aW9uIOKAlCBzaWduIGluIGFnYWluIHdpdGggYSBwYXNza2V5IG9yIGFuIGF1dGhlbnRpY2F0b3IgY29kZScsXG4gICAgICBFcnJvckNvZGUuTUZBX1JFUVVJUkVELFxuICAgICk7XG4gIH1cbiAgaWYgKG9wdGlvbnMubWF4QWdlICE9PSB1bmRlZmluZWQpIHtcbiAgICBjb25zdCBhdXRoVGltZSA9IGRlY29kZWQuYXV0aF90aW1lO1xuICAgIC8vIE5vIGBhdXRoX3RpbWVgIGlzIG5vdCBcInJlY2VudCBlbm91Z2ggYnkgZGVmYXVsdFwiIOKAlCBgaGFzVmFsaWRJZGVudGl0eUNsYWltc2BcbiAgICAvLyBhbHJlYWR5IHJlcXVpcmVzIGl0IG9uIGEgdXNlciB0b2tlbiwgc28gYW4gYWJzZW50IG9uZSBtZWFucyBhIHRva2VuIHRoaXNcbiAgICAvLyBnYXRlIGNhbm5vdCByZWFzb24gYWJvdXQuIEZhaWwgY2xvc2VkLlxuICAgIGlmICh0eXBlb2YgYXV0aFRpbWUgIT09ICdudW1iZXInIHx8IE1hdGguZmxvb3IoRGF0ZS5ub3coKSAvIDEwMDApIC0gYXV0aFRpbWUgPiBvcHRpb25zLm1heEFnZSkge1xuICAgICAgcmV0dXJuIHJlZnVzZShcbiAgICAgICAgJ3N0YWxlX3Nlc3Npb24nLCBIdHRwU3RhdHVzLlVOQVVUSE9SSVpFRCxcbiAgICAgICAgJ1RoaXMgYWN0aW9uIHJlcXVpcmVzIGEgcmVjZW50IHNpZ24taW4g4oCUIHBsZWFzZSBhdXRoZW50aWNhdGUgYWdhaW4nLFxuICAgICAgICBFcnJvckNvZGUuUkVBVVRIX1JFUVVJUkVELFxuICAgICAgKTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIGZhbHNlO1xufVxuXG4vKipcbiAqIFdoZXRoZXIgYSB2ZXJpZmllZCB0b2tlbiBjYXJyaWVzIGEgd2VsbC1mb3JtZWQgaWRlbnRpdHk6IGEga25vd25cbiAqIGBwcmluY2lwYWxUeXBlYCBhbmQgYHRva2VuX3VzZWAsIGFuZCB0aGUgY2xhaW1zIHRoYXQga2luZCBvZiBwcmluY2lwYWwgbXVzdFxuICogaGF2ZS4gRmFpbHMgY2xvc2VkIOKAlCBhIHRva2VuIG1pbnRlZCBiZWZvcmUgdGhlc2UgY2xhaW1zIGV4aXN0ZWQsIG9yIG9uZSB3aXRoIGFcbiAqIGNvbnRyYWRpY3RvcnkgY29tYmluYXRpb24sIGlzIG5vdCBhbiBpZGVudGl0eSBhbnkgZ2F0ZSBzaG91bGQgcmVhc29uIGFib3V0LlxuICpcbiAqIC0gYHNlcnZpY2VgOiBgdG9rZW5fdXNlOiAnYWNjZXNzJ2AgYW5kIGEgYHNlcnZpY2U6PG5hbWU+YCBzdWJqZWN0ICh0aGUgbmFtZVxuICogICBmZWVkcyB0aGUgZGVueWxpc3QgYW5kIGF1ZGl0IGF0dHJpYnV0aW9uKS5cbiAqIC0gYHVzZXJgIC8gYHNlcnZpY2VfYWNjb3VudGA6IGBhbXJgIChrbm93biBtZXRob2RzKSwgYGFhbGAgYW5kIGBhdXRoX3RpbWVgLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaGFzVmFsaWRJZGVudGl0eUNsYWltcyhkZWNvZGVkOiBQYXJ0aWFsPEp3dFBheWxvYWQ+KTogYm9vbGVhbiB7XG4gIGlmICghZGVjb2RlZC5wcmluY2lwYWxUeXBlIHx8ICFQUklOQ0lQQUxfVFlQRVMuaW5jbHVkZXMoZGVjb2RlZC5wcmluY2lwYWxUeXBlKSkgcmV0dXJuIGZhbHNlO1xuICBpZiAoIWRlY29kZWQudG9rZW5fdXNlIHx8ICFUT0tFTl9VU0VTLmluY2x1ZGVzKGRlY29kZWQudG9rZW5fdXNlKSkgcmV0dXJuIGZhbHNlO1xuICBpZiAoZGVjb2RlZC5wcmluY2lwYWxUeXBlID09PSAnc2VydmljZScpIHtcbiAgICByZXR1cm4gZGVjb2RlZC50b2tlbl91c2UgPT09ICdhY2Nlc3MnXG4gICAgICAmJiB0eXBlb2YgZGVjb2RlZC5zdWIgPT09ICdzdHJpbmcnXG4gICAgICAmJiBkZWNvZGVkLnN1Yi5zdGFydHNXaXRoKFNFUlZJQ0VfU1VCSkVDVF9QUkVGSVgpXG4gICAgICAmJiBkZWNvZGVkLnN1Yi5sZW5ndGggPiBTRVJWSUNFX1NVQkpFQ1RfUFJFRklYLmxlbmd0aDtcbiAgfVxuICByZXR1cm4gQXJyYXkuaXNBcnJheShkZWNvZGVkLmFtcilcbiAgICAmJiBkZWNvZGVkLmFtci5ldmVyeSgobSkgPT4gQVVUSF9NRVRIT0RTLmluY2x1ZGVzKG0pKVxuICAgICYmIChkZWNvZGVkLmFhbCA9PT0gMSB8fCBkZWNvZGVkLmFhbCA9PT0gMilcbiAgICAmJiB0eXBlb2YgZGVjb2RlZC5hdXRoX3RpbWUgPT09ICdudW1iZXInO1xufVxuXG4vKipcbiAqIFdoZXRoZXIgdGhlIHJlcXVlc3QncyB1c2VyIGhvbGRzIGBwZXJtaXNzaW9uYC4gU3VwZXJhZG1pbnMgaW1wbGljaXRseSBob2xkXG4gKiBldmVyeSBwZXJtaXNzaW9uLiBSZWFkcyB0aGUgcmVzb2x2ZWQgYHBlcm1pc3Npb25zYCBjbGFpbSAoc2V0IGF0IHRva2VuIGlzc3VlLFxuICogb3IgcmUtZGVyaXZlZCBwZXIgcmVxdWVzdCBieSB0aGUgcGxhdGZvcm0pLlxuICovXG5leHBvcnQgZnVuY3Rpb24gdXNlckhhc1Blcm1pc3Npb24ocmVxOiBSZXF1ZXN0LCBwZXJtaXNzaW9uOiBQZXJtaXNzaW9uKTogYm9vbGVhbiB7XG4gIHJldHVybiBoYXNQZXJtaXNzaW9uKHJlcS51c2VyPy5wZXJtaXNzaW9ucywgcGVybWlzc2lvbiwgcmVxLnVzZXI/LmlzU3VwZXJBZG1pbik7XG59XG5cbi8qKlxuICogQ29udGV4dCBwYXNzZWQgdG8gYSByZWdpc3RlcmVkIGF1dGhvcml6YXRpb24tZGVuaWFsIGF1ZGl0b3Igd2hlbiBhXG4gKiBzdGF0ZS1jaGFuZ2luZyByZXF1ZXN0IGlzIHJlamVjdGVkIGJ5IGByZXF1aXJlUGVybWlzc2lvbmAgL1xuICogYHJlcXVpcmVTeXN0ZW1BZG1pbmAuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQXV0aHpEZW5pYWxJbmZvIHtcbiAgLyoqIFRoZSBkZW5pZWQgdXNlcidzIGlkIChgc3ViYCksIGlmIGF1dGhlbnRpY2F0ZWQuICovXG4gIGFjdG9ySWQ/OiBzdHJpbmc7XG4gIGFjdG9yRW1haWw/OiBzdHJpbmc7XG4gIC8qKiBUaGUgdXNlcidzIGFjdGl2ZSBvcmcgYXQgZGVuaWFsIHRpbWUuICovXG4gIG9yZ0lkPzogc3RyaW5nO1xuICAvKiogSFRUUCBtZXRob2QgKyBwYXRoIG9mIHRoZSByZWplY3RlZCByZXF1ZXN0LiAqL1xuICBtZXRob2Q6IHN0cmluZztcbiAgcGF0aDogc3RyaW5nO1xuICAvKiogV2hhdCB3YXMgcmVxdWlyZWQ6IHRoZSBtaXNzaW5nIHBlcm1pc3Npb24ocyksIG9yICdzeXN0ZW0tYWRtaW4nLiAqL1xuICByZXF1aXJlZDogc3RyaW5nO1xufVxuXG4vKipcbiAqIE9wdGlvbmFsIHNpbmsgZm9yIGRlbmllZC1hdXRob3JpemF0aW9uIGV2ZW50cy4gTGVmdCB1bnNldCBieSBkZWZhdWx0IHNvXG4gKiBhcGktY29yZSBzdGF5cyBkZWNvdXBsZWQgZnJvbSBhbnkgYXVkaXQgdHJhbnNwb3J0IOKAlCBhIHNlcnZpY2UgcmVnaXN0ZXJzIG9uZVxuICogYXQgYm9vdCAodHlwaWNhbGx5IGZvcndhcmRpbmcgdG8gaXRzIGBSZW1vdGVBdWRpdENsaWVudGAgYXMgYW5cbiAqIGBhdXRoei5kZW5pZWRgIGV2ZW50LCBvciwgb24gcGxhdGZvcm0sIHRvIHRoZSBsb2NhbCBgYXVkaXQoKWAgaGVscGVyKS5cbiAqIE1VU1QgYmUgYmVzdC1lZmZvcnQ6IGl0IGlzIGludm9rZWQgaW5zaWRlIHRoZSByZXF1ZXN0IHBhdGgsIHNvIGl0IG11c3QgbmV2ZXJcbiAqIHRocm93IG9yIGJsb2NrICh0aGUgZ2F0ZSB3cmFwcyB0aGUgY2FsbCBpbiB0cnkvY2F0Y2ggcmVnYXJkbGVzcykuXG4gKi9cbmxldCBhdXRoekRlbmlhbEF1ZGl0b3I6ICgoaW5mbzogQXV0aHpEZW5pYWxJbmZvKSA9PiB2b2lkKSB8IHVuZGVmaW5lZDtcblxuLyoqXG4gKiBSZWdpc3RlciAob3IgY2xlYXIsIHdpdGggYHVuZGVmaW5lZGApIHRoZSBwcm9jZXNzLXdpZGUgYXV0aG9yaXphdGlvbi1kZW5pYWxcbiAqIGF1ZGl0b3IuIElkZW1wb3RlbnQ7IHRoZSBsYXN0IHJlZ2lzdHJhdGlvbiB3aW5zLlxuICovXG5leHBvcnQgZnVuY3Rpb24gc2V0QXV0aHpEZW5pYWxBdWRpdG9yKGZuOiAoKGluZm86IEF1dGh6RGVuaWFsSW5mbykgPT4gdm9pZCkgfCB1bmRlZmluZWQpOiB2b2lkIHtcbiAgYXV0aHpEZW5pYWxBdWRpdG9yID0gZm47XG59XG5cbi8qKlxuICogRW1pdCBhIGRlbmlhbCBldmVudCwgYmVzdC1lZmZvcnQuIE9ubHkgZmlyZXMgZm9yIHN0YXRlLWNoYW5naW5nIChub24tR0VULFxuICogbm9uLUhFQUQvT1BUSU9OUykgcmVxdWVzdHMg4oCUIGEgcmVqZWN0ZWQgR0VUIGlzIGxvdy1zaWduYWwgcHJvYmluZyBub2lzZSBhbmRcbiAqIHdvdWxkIGFtcGxpZnkgYXVkaXQgdm9sdW1lIHVuZGVyIGEgc2Nhbi4gTmV2ZXIgdGhyb3dzLlxuICpcbiAqIFRoZSBwZXJtaXNzaW9uIGdhdGVzIGhlcmUgY2FsbCBpdCB0aGVtc2VsdmVzLiBFeHBvcnQgaXQgZm9yIGRhdGEtZHJpdmVuIGNoZWNrc1xuICogYSByb3V0ZSBtYWtlcyBpbmxpbmUgKGNyb3NzLW9yZyBhY2Nlc3MsIHNlcnZpY2Utb25seSBlbmRwb2ludHMpLCBzbyB0aG9zZSA0MDNzXG4gKiByZWFjaCB0aGUgc2FtZSBgYXV0aHouZGVuaWVkYCB0cmFpbC4gYHJlcXVpcmVkYCBuYW1lcyB3aGF0IHdhcyBtaXNzaW5nLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVjb3JkQXV0aHpEZW5pYWwocmVxOiBSZXF1ZXN0LCByZXF1aXJlZDogc3RyaW5nKTogdm9pZCB7XG4gIGNvbnN0IGF1ZGl0b3IgPSBhdXRoekRlbmlhbEF1ZGl0b3I7XG4gIGlmICghYXVkaXRvcikgcmV0dXJuO1xuICBjb25zdCBtZXRob2QgPSByZXEubWV0aG9kLnRvVXBwZXJDYXNlKCk7XG4gIGlmIChtZXRob2QgPT09ICdHRVQnIHx8IG1ldGhvZCA9PT0gJ0hFQUQnIHx8IG1ldGhvZCA9PT0gJ09QVElPTlMnKSByZXR1cm47XG4gIHRyeSB7XG4gICAgYXVkaXRvcih7XG4gICAgICBhY3RvcklkOiByZXEudXNlcj8uc3ViLFxuICAgICAgYWN0b3JFbWFpbDogcmVxLnVzZXI/LmVtYWlsLFxuICAgICAgb3JnSWQ6IHJlcS51c2VyPy5vcmdhbml6YXRpb25JZCxcbiAgICAgIG1ldGhvZCxcbiAgICAgIC8vIFN0cmlwIHRoZSBxdWVyeSBzdHJpbmcg4oCUIGEgZGVuaWVkIHJlcXVlc3QgbWF5IGNhcnJ5IGEgdG9rZW4vc2VjcmV0IGFzIGFcbiAgICAgIC8vIHF1ZXJ5IHBhcmFtLCBhbmQgdGhpcyBwYXRoIGlzIHBlcnNpc3RlZCB2ZXJiYXRpbSBpbnRvIHRoZSBhdWRpdCBsb2cuXG4gICAgICBwYXRoOiAocmVxLm9yaWdpbmFsVXJsIHx8IHJlcS51cmwpLnNwbGl0KCc/JylbMF0sXG4gICAgICByZXF1aXJlZCxcbiAgICB9KTtcbiAgfSBjYXRjaCB7XG4gICAgLy8gQmVzdC1lZmZvcnQg4oCUIGEgYnJva2VuIGF1ZGl0b3IgbXVzdCBuZXZlciBicmVhayB0aGUgYXV0aCBnYXRlLlxuICB9XG59XG5cbi8qKlxuICogUmVxdWlyZXMgdGhhdCB0aGUgdXNlciBob2xkIEFUIExFQVNUIE9ORSBvZiB0aGUgZ2l2ZW4gcGVybWlzc2lvbnMgKG9yIGJlIGFcbiAqIHN1cGVyYWRtaW4pLiBVc2UgYWZ0ZXIgcmVxdWlyZUF1dGguIE1pcnJvcnMgYHJlcXVpcmVSb2xlYCdzIGFueS1vZiBzZW1hbnRpY3M7XG4gKiBwYXNzIGEgc2luZ2xlIHBlcm1pc3Npb24gZm9yIGEgc3BlY2lmaWMgYWN0aW9uLCBvciBzZXZlcmFsIHdoZW4gYW55IG9uZSBvZlxuICogdGhlbSBzaG91bGQgZ3JhbnQgYWNjZXNzLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVxdWlyZVBlcm1pc3Npb24oLi4ucGVybWlzc2lvbnM6IFBlcm1pc3Npb25bXSkge1xuICByZXR1cm4gdGFnUm91dGVHYXRlKChyZXE6IFJlcXVlc3QsIHJlczogUmVzcG9uc2UsIG5leHQ6IE5leHRGdW5jdGlvbik6IHZvaWQgPT4ge1xuICAgIGlmICghcmVxLnVzZXIpIHtcbiAgICAgIHJldHVybiBzZW5kRXJyb3IocmVzLCBIdHRwU3RhdHVzLlVOQVVUSE9SSVpFRCwgJ0F1dGhlbnRpY2F0aW9uIHJlcXVpcmVkJywgRXJyb3JDb2RlLlVOQVVUSE9SSVpFRCk7XG4gICAgfVxuICAgIC8vIHVzZXJIYXNQZXJtaXNzaW9uIOKGkiBoYXNQZXJtaXNzaW9uIGFscmVhZHkgZ3JhbnRzIHN1cGVyYWRtaW5zIGV2ZXJ5XG4gICAgLy8gcGVybWlzc2lvbiwgc28gdGhpcyBzaW5nbGUgY2hlY2sgY292ZXJzIGJvdGggdGhlIHN1cGVyYWRtaW4gYnlwYXNzIGFuZFxuICAgIC8vIHRoZSBhbnktb2YgbWVtYmVyc2hpcCB0ZXN0IHdpdGhvdXQgcmUtaW5saW5pbmcgZWl0aGVyLlxuICAgIGlmIChwZXJtaXNzaW9ucy5zb21lKChwKSA9PiB1c2VySGFzUGVybWlzc2lvbihyZXEsIHApKSkgcmV0dXJuIG5leHQoKTtcbiAgICByZWNvcmRBdXRoekRlbmlhbChyZXEsIHBlcm1pc3Npb25zLmpvaW4oJyBvciAnKSk7XG4gICAgcmV0dXJuIHNlbmRFcnJvcihcbiAgICAgIHJlcywgSHR0cFN0YXR1cy5GT1JCSURERU4sXG4gICAgICBgTWlzc2luZyByZXF1aXJlZCBwZXJtaXNzaW9uOiAke3Blcm1pc3Npb25zLmpvaW4oJyBvciAnKX1gLFxuICAgICAgRXJyb3JDb2RlLklOU1VGRklDSUVOVF9QRVJNSVNTSU9OUyxcbiAgICApO1xuICB9LCB7IGtpbmQ6ICdwZXJtaXNzaW9uJywgbW9kZTogJ2FueScsIHBlcm1pc3Npb25zIH0pO1xufVxuXG4vKipcbiAqIFJlcXVpcmVzIHRoYXQgdGhlIHVzZXIgaG9sZCBFVkVSWSBvbmUgb2YgdGhlIGdpdmVuIHBlcm1pc3Npb25zIChvciBiZSBhXG4gKiBzdXBlcmFkbWluKSDigJQgdGhlIEFORCBjb3VudGVycGFydCB0byBgcmVxdWlyZVBlcm1pc3Npb25gJ3MgYW55LW9mLiBVc2UgZm9yIGFcbiAqIHNlbnNpdGl2ZSBhY3Rpb24gdGhhdCBsZWdpdGltYXRlbHkgZGVtYW5kcyB0d28gZGlzdGluY3QgY2FwYWJpbGl0aWVzIGF0IG9uY2VcbiAqIChlLmcuIGEgY3Jvc3Mtc3VyZmFjZSBvcGVyYXRpb24pLCBzbyB0aGUgZ3VhcmFudGVlIGlzIGV4cGxpY2l0IHJhdGhlciB0aGFuXG4gKiBhcHByb3hpbWF0ZWQgYnkgY2hhaW5pbmcgdHdvIGByZXF1aXJlUGVybWlzc2lvbmAgZ2F0ZXMuIFN1cGVyYWRtaW5zIGJ5cGFzc1xuICogKHRoZXkgaW1wbGljaXRseSBob2xkIGV2ZXJ5IHBlcm1pc3Npb24pLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVxdWlyZUFsbFBlcm1pc3Npb25zKC4uLnBlcm1pc3Npb25zOiBQZXJtaXNzaW9uW10pIHtcbiAgcmV0dXJuIHRhZ1JvdXRlR2F0ZSgocmVxOiBSZXF1ZXN0LCByZXM6IFJlc3BvbnNlLCBuZXh0OiBOZXh0RnVuY3Rpb24pOiB2b2lkID0+IHtcbiAgICBpZiAoIXJlcS51c2VyKSB7XG4gICAgICByZXR1cm4gc2VuZEVycm9yKHJlcywgSHR0cFN0YXR1cy5VTkFVVEhPUklaRUQsICdBdXRoZW50aWNhdGlvbiByZXF1aXJlZCcsIEVycm9yQ29kZS5VTkFVVEhPUklaRUQpO1xuICAgIH1cbiAgICBjb25zdCBtaXNzaW5nID0gcGVybWlzc2lvbnMuZmlsdGVyKChwKSA9PiAhdXNlckhhc1Blcm1pc3Npb24ocmVxLCBwKSk7XG4gICAgaWYgKG1pc3NpbmcubGVuZ3RoID09PSAwKSByZXR1cm4gbmV4dCgpO1xuICAgIHJlY29yZEF1dGh6RGVuaWFsKHJlcSwgcGVybWlzc2lvbnMuam9pbignIGFuZCAnKSk7XG4gICAgcmV0dXJuIHNlbmRFcnJvcihcbiAgICAgIHJlcywgSHR0cFN0YXR1cy5GT1JCSURERU4sXG4gICAgICBgTWlzc2luZyByZXF1aXJlZCBwZXJtaXNzaW9uOiAke21pc3Npbmcuam9pbignIGFuZCAnKX1gLFxuICAgICAgRXJyb3JDb2RlLklOU1VGRklDSUVOVF9QRVJNSVNTSU9OUyxcbiAgICApO1xuICB9LCB7IGtpbmQ6ICdwZXJtaXNzaW9uJywgbW9kZTogJ2FsbCcsIHBlcm1pc3Npb25zIH0pO1xufVxuXG4vKipcbiAqIExpa2Uge0BsaW5rIHJlcXVpcmVQZXJtaXNzaW9ufSAoYW55LW9mKSBidXQgQUxTTyBhZG1pdHMgYW4gaW50ZXJuYWwgc2VydmljZVxuICogcHJpbmNpcGFsIChgcHJpbmNpcGFsVHlwZTogJ3NlcnZpY2UnYCkuIEZvciBSRUFEIGVuZHBvaW50cyB0aGF0IEJPVEhcbiAqIGludGVyYWN0aXZlIHVzZXJzIOKAlCB3aG8gbXVzdCBob2xkIG9uZSBvZiB0aGUgYDpyZWFkYCBjYXBhYmlsaXRpZXMg4oCUIEFORFxuICogc2VydmljZS10by1zZXJ2aWNlIGNhbGxlcnMgbGVnaXRpbWF0ZWx5IGhpdDsgc2VydmljZSB0b2tlbnMgY2Fycnkgbm9cbiAqIHBlcm1pc3Npb24gY2xhaW1zICh0aGV5J3JlIGxlYXN0LXByaXZpbGVnZSBgcm9sZTptZW1iZXJgKSwgc28gYSBwbGFpblxuICogYHJlcXVpcmVQZXJtaXNzaW9uYCB3b3VsZCB3cm9uZ2x5IDQwMyB0aGVtLiBTdXBlcmFkbWlucyBwYXNzIHZpYVxuICogYHVzZXJIYXNQZXJtaXNzaW9uYCdzIGltcGxpY2l0LWFsbC4gVXNlIG9ubHkgd2hlcmUgYSBzZXJ2aWNlIGNhbGxlciBpcyBhIGtub3duLFxuICogaW50ZW5kZWQgY29uc3VtZXIgb2YgdGhlIHJvdXRlICh2ZXJpZnkgdGhlIGNhbGxlcnMpOyBwcmVmZXIgcGxhaW5cbiAqIGByZXF1aXJlUGVybWlzc2lvbmAgZm9yIHB1cmVseSB1c2VyLWZhY2luZyByZWFkcy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlcXVpcmVQZXJtaXNzaW9uT3JTZXJ2aWNlKC4uLnBlcm1pc3Npb25zOiBQZXJtaXNzaW9uW10pIHtcbiAgcmV0dXJuIHRhZ1JvdXRlR2F0ZSgocmVxOiBSZXF1ZXN0LCByZXM6IFJlc3BvbnNlLCBuZXh0OiBOZXh0RnVuY3Rpb24pOiB2b2lkID0+IHtcbiAgICBpZiAoIXJlcS51c2VyKSB7XG4gICAgICByZXR1cm4gc2VuZEVycm9yKHJlcywgSHR0cFN0YXR1cy5VTkFVVEhPUklaRUQsICdBdXRoZW50aWNhdGlvbiByZXF1aXJlZCcsIEVycm9yQ29kZS5VTkFVVEhPUklaRUQpO1xuICAgIH1cbiAgICBpZiAoaXNTZXJ2aWNlUHJpbmNpcGFsKHJlcSkgfHwgcGVybWlzc2lvbnMuc29tZSgocCkgPT4gdXNlckhhc1Blcm1pc3Npb24ocmVxLCBwKSkpIHJldHVybiBuZXh0KCk7XG4gICAgcmVjb3JkQXV0aHpEZW5pYWwocmVxLCBwZXJtaXNzaW9ucy5qb2luKCcgb3IgJykpO1xuICAgIHJldHVybiBzZW5kRXJyb3IoXG4gICAgICByZXMsIEh0dHBTdGF0dXMuRk9SQklEREVOLFxuICAgICAgYE1pc3NpbmcgcmVxdWlyZWQgcGVybWlzc2lvbjogJHtwZXJtaXNzaW9ucy5qb2luKCcgb3IgJyl9YCxcbiAgICAgIEVycm9yQ29kZS5JTlNVRkZJQ0lFTlRfUEVSTUlTU0lPTlMsXG4gICAgKTtcbiAgfSwgeyBraW5kOiAncGVybWlzc2lvbicsIG1vZGU6ICdhbnknLCBwZXJtaXNzaW9ucywgYWxsb3dTZXJ2aWNlOiB0cnVlIH0pO1xufVxuXG4vKipcbiAqIEdhdGUgYW4gZW5kcG9pbnQgdG8gaW50ZXJuYWwgc2VydmljZS10by1zZXJ2aWNlIGNhbGxlcnMgb25seSAoYVxuICogYHByaW5jaXBhbFR5cGU6ICdzZXJ2aWNlJ2AgcHJpbmNpcGFsIG1pbnRlZCB2aWEge0BsaW5rIHNpZ25TZXJ2aWNlVG9rZW59IC8gYGdldFNlcnZpY2VBdXRoSGVhZGVyYCkuXG4gKiBSZWplY3RzIGFueSB1c2VyIHRva2VuLiBGb3IgTk9OLXVzZXItZmFjaW5nIGVuZHBvaW50cyDigJQgZW50aXR5LWV2ZW50IGluZ2VzdCxcbiAqIGF1dG8tc3Vic2NyaWJlLCBhbmQgc2ltaWxhciBwZWVyLXNlcnZpY2UgaG9va3Mg4oCUIHRoYXQgYSBicm93c2VyIG11c3QgbmV2ZXJcbiAqIHJlYWNoLiBDb21wb3NlIGFmdGVyIGByZXF1aXJlQXV0aGAgc28gYHJlcS51c2VyYCBpcyBwb3B1bGF0ZWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXF1aXJlU2VydmljZVByaW5jaXBhbChyZXE6IFJlcXVlc3QsIHJlczogUmVzcG9uc2UsIG5leHQ6IE5leHRGdW5jdGlvbik6IHZvaWQge1xuICBpZiAoIWlzU2VydmljZVByaW5jaXBhbChyZXEpKSB7XG4gICAgLy8gNDAzIChub3QgNDAwKSDigJQgdGhpcyBpcyBhbiBhdXRob3JpemF0aW9uIHJlZnVzYWw7IHN0YXR1cyBtdXN0IG1hdGNoIHRoZVxuICAgIC8vIElOU1VGRklDSUVOVF9QRVJNSVNTSU9OUyBjb2RlIGFuZCB0aGUgc2libGluZyBnYXRlcyAocmVxdWlyZVBlcm1pc3Npb24sIGV0Yy4pLlxuICAgIHJldHVybiBzZW5kRXJyb3IocmVzLCBIdHRwU3RhdHVzLkZPUkJJRERFTiwgJ0ludGVybmFsIHNlcnZpY2UgY2FsbHMgb25seScsIEVycm9yQ29kZS5JTlNVRkZJQ0lFTlRfUEVSTUlTU0lPTlMpO1xuICB9XG4gIG5leHQoKTtcbn1cbnRhZ1JvdXRlR2F0ZShyZXF1aXJlU2VydmljZVByaW5jaXBhbCwgeyBraW5kOiAnc2VydmljZVByaW5jaXBhbCcgfSk7XG5cbi8qKlxuICogVEhFIGdhdGUgZm9yIGFuIElOVEVSTkFMIHJvdXRlICgjMTQpIOKAlCB0aGUgb25lIGV2ZXJ5IGAvaW50ZXJuYWwvKmAgcGF0aCwgdGhlXG4gKiBxdW90YSB1c2FnZSBjb3VudGVycywgdGhlIGVudGl0eS1ldmVudCBpbmdlc3QgYW5kIHRoZSBhdWRpdCBpbmdlc3QgZ28gdGhyb3VnaC5cbiAqXG4gKiBUd28gcnVsZXMsIGJvdGggZmFpbC1jbG9zZWQ6XG4gKlxuICogIDEuICoqTm8gdXNlciB0b2tlbiwgZXZlci4qKiBOb3QgYSBtZW1iZXIncywgbm90IGEgc3VwZXJhZG1pbidzLCBub3QgYVxuICogICAgIHNlcnZpY2UtYWNjb3VudCBrZXkncy4gQW4gaW50ZXJuYWwgcm91dGUgaXMgYSBwZWVyLXNlcnZpY2UgQVBJIHN1cmZhY2UsIHNvXG4gKiAgICAgXCJhIHN1ZmZpY2llbnRseSBwcml2aWxlZ2VkIGh1bWFuXCIgaXMgbm90IGFuIGFjY2VwdGFibGUgY2FsbGVyIOKAlCB0aGF0XG4gKiAgICAgZXF1aXZhbGVuY2UgaXMgZXhhY3RseSBob3cgYSBicm93c2VyLXJlYWNoYWJsZSBwYXRoIGJlY29tZXMgYSB0ZW5hbnRcbiAqICAgICBib3VuZGFyeSBidWcuIGByZXF1aXJlU2VydmljZVByaW5jaXBhbGAgYWxyZWFkeSByZWZ1c2VkIHVzZXJzOyB0aGlzIGFsc29cbiAqICAgICBjbG9zZXMgdGhlIGB8fCBpc1N5c3RlbUFkbWluKHJlcSlgIGVzY2FwZSBoYXRjaGVzIHRoYXQgaGFkIGdyb3duIGFyb3VuZFxuICogICAgIHRoZSBpbmRpdmlkdWFsIGludGVybmFsIHJvdXRlcy5cbiAqICAyLiAqKk9ubHkgdGhlIE5BTUVEIGNhbGxlcnMuKiogYGNhbGxlcnNgIGxpc3RzIHRoZSBzZXJ2aWNlcyB0aGF0IGxlZ2l0aW1hdGVseVxuICogICAgIGNhbGwgdGhpcyByb3V0ZSwgYW5kIHRoZSBuYW1lIGlzIGNyeXB0b2dyYXBoaWNhbGx5IGJvdW5kIHRvIHRoZSBzaWduaW5nXG4gKiAgICAga2V5IChgc2VydmljZXMvc2VydmljZS1rZXlzLnRzYCksIHNvIHRoaXMgaXMgYW4gaWRlbnRpdHkgY2hlY2sgcmF0aGVyIHRoYW5cbiAqICAgICBhIGNsYWltIGNoZWNrLiBJdCBpcyB0aGUgc2FtZSBhbGxvdy1saXN0IHRoZSBtZXNoIHBvbGljeSBuYW1lcywgYXQgdGhlXG4gKiAgICAgbGF5ZXIgdGhhdCBhbHNvIGhvbGRzIGluIGRvY2tlciBjb21wb3NlLCB3aGVyZSB0aGVyZSBpcyBubyBtZXNoIGF0IGFsbCDigJRcbiAqICAgICB0aGUgSXN0aW8gYEF1dGhvcml6YXRpb25Qb2xpY3lgIGlzIGRlZmVuY2UgaW4gZGVwdGggb24gdG9wLCBuZXZlciB0aGVcbiAqICAgICBlbmZvcmNlbWVudC5cbiAqXG4gKiBDb21wb3NlIGFmdGVyIGByZXF1aXJlQXV0aGAgc28gYHJlcS51c2VyYCBpcyBwb3B1bGF0ZWQuIFJlZnVzYWxzIGFyZSBjb3VudGVkXG4gKiAoYGludGVybmFsX3JvdXRlX3JlZnVzZWRfdG90YWxgKSBhbmQgYXVkaXRlZCB0aHJvdWdoIHRoZSBzaGFyZWQgYGF1dGh6LmRlbmllZGBcbiAqIHNpbmsuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXF1aXJlSW50ZXJuYWxTZXJ2aWNlKG9wdGlvbnM6IHsgY2FsbGVyczogcmVhZG9ubHkgc3RyaW5nW10gfSkge1xuICBjb25zdCBhbGxvd2VkID0gbmV3IFNldChvcHRpb25zLmNhbGxlcnMpO1xuICByZXR1cm4gdGFnUm91dGVHYXRlKChyZXE6IFJlcXVlc3QsIHJlczogUmVzcG9uc2UsIG5leHQ6IE5leHRGdW5jdGlvbik6IHZvaWQgPT4ge1xuICAgIGNvbnN0IHJlZnVzZSA9IChyZWFzb246ICd1bmF1dGhlbnRpY2F0ZWQnIHwgJ3VzZXJfdG9rZW4nIHwgJ3dyb25nX2NhbGxlcicpOiB2b2lkID0+IHtcbiAgICAgIGVtaXRDb3VudGVyKCdpbnRlcm5hbF9yb3V0ZV9yZWZ1c2VkX3RvdGFsJywge1xuICAgICAgICBzZXJ2aWNlOiBzZXJ2aWNlSWRlbnRpdHkoKSxcbiAgICAgICAgcm91dGU6IHJlcS5yb3V0ZT8ucGF0aCA/IGAke3JlcS5tZXRob2R9ICR7cmVxLmJhc2VVcmx9JHtyZXEucm91dGUucGF0aH1gIDogYCR7cmVxLm1ldGhvZH0gJHsocmVxLm9yaWdpbmFsVXJsIHx8IHJlcS51cmwpLnNwbGl0KCc/JylbMF19YCxcbiAgICAgICAgcmVhc29uLFxuICAgICAgICBjYWxsZXI6IHNlcnZpY2VOYW1lT2YocmVxLnVzZXIpID8/ICdub25lJyxcbiAgICAgIH0pO1xuICAgICAgcmVjb3JkQXV0aHpEZW5pYWwocmVxLCBgaW50ZXJuYWwtc2VydmljZSAoJHtvcHRpb25zLmNhbGxlcnMuam9pbignLCAnKX0pYCk7XG4gICAgICBpZiAocmVhc29uID09PSAndW5hdXRoZW50aWNhdGVkJykge1xuICAgICAgICByZXR1cm4gc2VuZEVycm9yKHJlcywgSHR0cFN0YXR1cy5VTkFVVEhPUklaRUQsICdBdXRoZW50aWNhdGlvbiByZXF1aXJlZCcsIEVycm9yQ29kZS5VTkFVVEhPUklaRUQpO1xuICAgICAgfVxuICAgICAgbG9nZ2VyLndhcm4oJ1JlZnVzZWQgYW4gaW50ZXJuYWwgcm91dGUnLCB7IHJlYXNvbiwgcGF0aDogKHJlcS5vcmlnaW5hbFVybCB8fCByZXEudXJsKS5zcGxpdCgnPycpWzBdLCBjYWxsZXI6IHNlcnZpY2VOYW1lT2YocmVxLnVzZXIpIH0pO1xuICAgICAgcmV0dXJuIHNlbmRFcnJvcihyZXMsIEh0dHBTdGF0dXMuRk9SQklEREVOLCAnSW50ZXJuYWwgc2VydmljZSBjYWxscyBvbmx5JywgRXJyb3JDb2RlLklOU1VGRklDSUVOVF9QRVJNSVNTSU9OUyk7XG4gICAgfTtcblxuICAgIGlmICghcmVxLnVzZXIpIHJldHVybiByZWZ1c2UoJ3VuYXV0aGVudGljYXRlZCcpO1xuICAgIGlmICghaXNTZXJ2aWNlUHJpbmNpcGFsKHJlcSkpIHJldHVybiByZWZ1c2UoJ3VzZXJfdG9rZW4nKTtcbiAgICBjb25zdCBjYWxsZXIgPSBzZXJ2aWNlTmFtZU9mKHJlcS51c2VyKTtcbiAgICBpZiAoIWNhbGxlciB8fCAhYWxsb3dlZC5oYXMoY2FsbGVyKSkgcmV0dXJuIHJlZnVzZSgnd3JvbmdfY2FsbGVyJyk7XG4gICAgbmV4dCgpO1xuICB9LCB7IGtpbmQ6ICdzZXJ2aWNlUHJpbmNpcGFsJyB9LCB7IGtpbmQ6ICdpbnRlcm5hbFNlcnZpY2UnLCBjYWxsZXJzOiBbLi4ub3B0aW9ucy5jYWxsZXJzXSB9KTtcbn1cblxuLyoqXG4gKiBUaGUgc3lzdGVtIHRlbmFudCdzIGNhbm9uaWNhbCBvcmcgKippZCoqIOKAlCBhIGZpeGVkLCB3ZWxsLWtub3duIE9iamVjdElkIChOT1RcbiAqIHRoZSBzdHJpbmcgJ3N5c3RlbScpLiBUaGlzIGlzIHRoZSBzaW5nbGUga25vYiBldmVyeSBzZXJ2aWNlIHJlc29sdmVzIHRoZVxuICogc3lzdGVtIHRlbmFudCB0aHJvdWdoOyBvdmVycmlkZSB2aWEgdGhlIGBTWVNURU1fT1JHX0lEYCBlbnYgZm9yIGFsdGVybmF0ZVxuICogaW5zdGFsbHMuIFRoZSBzeXN0ZW0gb3JnJ3MgaHVtYW4gaWRlbnRpZmllciBzdGF5cyB0aGUgc2x1Zy9uYW1lICdzeXN0ZW0nXG4gKiAoc2VlIHtAbGluayBTWVNURU1fT1JHX1NMVUd9KTsgb25seSBpdHMgYF9pZGAgaXMgdGhpcyBPYmplY3RJZC5cbiAqL1xuZXhwb3J0IGNvbnN0IFNZU1RFTV9PUkdfSUQgPSAocHJvY2Vzcy5lbnYuU1lTVEVNX09SR19JRCB8fCAnMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAxJykudG9Mb3dlckNhc2UoKTtcblxuLyoqIFRoZSBzeXN0ZW0gb3JnJ3Mgd2VsbC1rbm93biBzbHVnL25hbWUgKHRoZSBodW1hbiBpZGVudGlmaWVyOyBpdHMgYF9pZGAgaXMge0BsaW5rIFNZU1RFTV9PUkdfSUR9KS4gKi9cbmV4cG9ydCBjb25zdCBTWVNURU1fT1JHX1NMVUcgPSAnc3lzdGVtJztcblxuLyoqXG4gKiBDaGVjayBpZiBhbiBvcmdJZCBvciBvcmdOYW1lL3NsdWcgbWF0Y2hlcyB0aGUgc3lzdGVtIG9yZy4gVXNlIHRoaXMgaW5zdGVhZCBvZlxuICogY29tcGFyaW5nIGRpcmVjdGx5OiB0aGUgaWQgaXMgbm93IGFuIE9iamVjdElkICh7QGxpbmsgU1lTVEVNX09SR19JRH0pIHdoaWxlIHRoZVxuICogbmFtZS9zbHVnIGlzICdzeXN0ZW0nICh7QGxpbmsgU1lTVEVNX09SR19TTFVHfSksIHNvIHRoZSB0d28gYXJlIGNvbXBhcmVkIGFnYWluc3RcbiAqIHRoZWlyIHJlc3BlY3RpdmUgY2Fub25pY2FsIHZhbHVlcy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzU3lzdGVtT3JnSWQob3JnSWQ/OiBzdHJpbmcsIG9yZ05hbWU/OiBzdHJpbmcpOiBib29sZWFuIHtcbiAgcmV0dXJuIG9yZ0lkPy50b0xvd2VyQ2FzZSgpID09PSBTWVNURU1fT1JHX0lEIHx8IG9yZ05hbWU/LnRvTG93ZXJDYXNlKCkgPT09IFNZU1RFTV9PUkdfU0xVRztcbn1cblxuLyoqXG4gKiBDaGVjayBpZiB0aGUgcmVxdWVzdCBpcyBmcm9tIGEgc3lzdGVtIGFkbWluLlxuICpcbiAqIEF1dGhvcml0eSBpcyBncmFudGVkIHNvbGVseSBieSB0aGUgdXNlci1sZXZlbCBgaXNTdXBlckFkbWluYCBmbGFnIGNhcnJpZWRcbiAqIGluIHRoZSBKV1QuIFRoZSBcIm1lbWJlcnNoaXAgaW4gdGhlIHdlbGwta25vd24gJ3N5c3RlbScgb3JnIHdpdGggcm9sZVxuICogYWRtaW4vb3duZXJcIiBwYXRoIHdhcyByZW1vdmVkIOKAlCBpdCBjb25mbGF0ZWQgYSBQaXBlbGluZSBCdWlsZGVyIG9wZXJhdG9yXG4gKiB3aXRoIGEgcmVhbCBjdXN0b21lciB0ZW5hbnQgaW4gdGhlIGRhdGEgbW9kZWwsIGFuZCBtZWFudCBhbnkgdW5pbnRlbmRlZFxuICogd3JpdGUgdGhhdCBjcmVhdGVkIGEgJ3N5c3RlbSctbmFtZWQgb3JnIGNvdWxkIHF1aWV0bHkgZ3JhbnQgY3Jvc3Mtb3JnXG4gKiBhdXRob3JpdHkuIFRoZSBgc3lzdGVtYCBvcmcgc3RpbGwgZXhpc3RzIGFzIGEgKmNvbnRlbnQgaG9sZGVyKiBmb3Igc2hhcmVkXG4gKiBzYW1wbGUgZGF0YTsgaXQganVzdCBubyBsb25nZXIgY29uZmVycyBwcml2aWxlZ2UuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc1N5c3RlbUFkbWluKHJlcTogUmVxdWVzdCk6IGJvb2xlYW4ge1xuICByZXR1cm4gcmVxLnVzZXI/LmlzU3VwZXJBZG1pbiA9PT0gdHJ1ZTtcbn1cblxuLyoqXG4gKiBXaGV0aGVyIHRoZSByZXF1ZXN0J3MgdG9rZW4gY2FycmllcyBhIHNwZWNpZmljIGNhcGFiaWxpdHkgYHNjb3BlYCAoZS5nLlxuICogYCdyZXBvcnRpbmc6aW5nZXN0J2ApLiBVc2VkIHRvIGdhdGUgZW5kcG9pbnRzIHRoYXQgYWNjZXB0IGEgbmFycm93IG1hY2hpbmVcbiAqIGlkZW50aXR5IOKAlCBhIG5vcm1hbCBpbnRlcmFjdGl2ZSB1c2VyIHRva2VuIGhhcyBubyBgc2NvcGVgIGFuZCByZXR1cm5zIGZhbHNlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaGFzU2NvcGUocmVxOiBSZXF1ZXN0LCBzY29wZTogc3RyaW5nKTogYm9vbGVhbiB7XG4gIHJldHVybiByZXEudXNlcj8uc2NvcGUgPT09IHNjb3BlO1xufVxuXG4vKiogUmVxdWlyZXMgYSBzeXN0ZW0gYWRtaW4g4oCUIGdyYW50ZWQgc29sZWx5IGJ5IHRoZSBgaXNTdXBlckFkbWluYCB0b2tlbiBjbGFpbVxuICogICh0aGUgb3JnLW1lbWJlcnNoaXAgcGF0aCB3YXMgcmVtb3ZlZCkuIFVzZSBhZnRlciByZXF1aXJlQXV0aC4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXF1aXJlU3lzdGVtQWRtaW4oXG4gIHJlcTogUmVxdWVzdCxcbiAgcmVzOiBSZXNwb25zZSxcbiAgbmV4dDogTmV4dEZ1bmN0aW9uLFxuKTogdm9pZCB7XG4gIGlmICghaXNTeXN0ZW1BZG1pbihyZXEpKSB7XG4gICAgcmVjb3JkQXV0aHpEZW5pYWwocmVxLCAnc3lzdGVtLWFkbWluJyk7XG4gICAgcmV0dXJuIHNlbmRFcnJvcihcbiAgICAgIHJlcywgSHR0cFN0YXR1cy5GT1JCSURERU4sXG4gICAgICAnQWNjZXNzIGRlbmllZC4gT25seSBzeXN0ZW0gYWRtaW5pc3RyYXRvcnMgY2FuIHBlcmZvcm0gdGhpcyBhY3Rpb24uJyxcbiAgICAgIEVycm9yQ29kZS5JTlNVRkZJQ0lFTlRfUEVSTUlTU0lPTlMsXG4gICAgKTtcbiAgfVxuICBuZXh0KCk7XG59XG50YWdSb3V0ZUdhdGUocmVxdWlyZVN5c3RlbUFkbWluLCB7IGtpbmQ6ICdzeXN0ZW1BZG1pbicgfSk7XG5cbi8qKlxuICogUmVxdWlyZSBhIHNwZWNpZmljIGZlYXR1cmUgZmxhZy4gVXNlIGFmdGVyIHJlcXVpcmVBdXRoLlxuICogQ2hlY2tzIHRoZSBgZmVhdHVyZXNgIGFycmF5IGluIHRoZSBKV1QgcGF5bG9hZCAoc2V0IGF0IHRva2VuIGlzc3VhbmNlKS5cbiAqIFN5c2FkbWlucyAoaXNTdXBlckFkbWluKSBieXBhc3Mg4oCUIHRoZXkgYWx3YXlzIGhhdmUgZXZlcnkgZmVhdHVyZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlcXVpcmVGZWF0dXJlKGZlYXR1cmU6IHN0cmluZykge1xuICByZXR1cm4gdGFnUm91dGVHYXRlKChyZXE6IFJlcXVlc3QsIHJlczogUmVzcG9uc2UsIG5leHQ6IE5leHRGdW5jdGlvbik6IHZvaWQgPT4ge1xuICAgIGlmICghcmVxLnVzZXIpIHtcbiAgICAgIHJldHVybiBzZW5kRXJyb3IocmVzLCBIdHRwU3RhdHVzLlVOQVVUSE9SSVpFRCwgJ0F1dGhlbnRpY2F0aW9uIHJlcXVpcmVkJywgRXJyb3JDb2RlLlVOQVVUSE9SSVpFRCk7XG4gICAgfVxuXG4gICAgLy8gU3lzYWRtaW5zIGdldCBhbGwgZmVhdHVyZXM7IHRoZSBgZmVhdHVyZXNgIGFycmF5IG9uIHRoZWlyIHRva2VuIGlzXG4gICAgLy8gcG9wdWxhdGVkIHdpdGggZXZlcnkgZmxhZyBhdCBpc3N1YW5jZSB0aW1lIGJ1dCB0aGUgYnlwYXNzIGhlcmUga2VlcHNcbiAgICAvLyB0aGUgcnVsZSBleHBsaWNpdCBhbmQgc3Vydml2ZXMgYSB0b2tlbiBpc3N1ZWQgYmVmb3JlIGEgbmV3IGZlYXR1cmVcbiAgICAvLyBmbGFnIHdhcyBhZGRlZC5cbiAgICBpZiAocmVxLnVzZXIuaXNTdXBlckFkbWluID09PSB0cnVlKSByZXR1cm4gbmV4dCgpO1xuXG4gICAgaWYgKCFyZXEudXNlci5mZWF0dXJlcz8uaW5jbHVkZXMoZmVhdHVyZSkpIHtcbiAgICAgIC8vIFJvdXRlIGZlYXR1cmUtZ2F0ZSBkZW5pYWxzIHRocm91Z2ggdGhlIHNhbWUgYXVkaXQgc2luayBhc1xuICAgICAgLy8gcmVxdWlyZVBlcm1pc3Npb24gLyByZXF1aXJlU3lzdGVtQWRtaW4gc28gYSBwcm9iZSBmb3IgYW5cbiAgICAgIC8vIHVuZW50aXRsZWQgY2FwYWJpbGl0eSBsZWF2ZXMgYSB0cmFpbCAoc3RhdGUtY2hhbmdpbmcgbWV0aG9kcyBvbmx5KS5cbiAgICAgIHJlY29yZEF1dGh6RGVuaWFsKHJlcSwgYGZlYXR1cmU6JHtmZWF0dXJlfWApO1xuICAgICAgcmV0dXJuIHNlbmRFcnJvcihcbiAgICAgICAgcmVzLCBIdHRwU3RhdHVzLkZPUkJJRERFTixcbiAgICAgICAgYFRoaXMgZmVhdHVyZSByZXF1aXJlcyBhIGhpZ2hlciBwbGFuICgke2ZlYXR1cmV9KWAsXG4gICAgICAgIEVycm9yQ29kZS5JTlNVRkZJQ0lFTlRfUEVSTUlTU0lPTlMsXG4gICAgICApO1xuICAgIH1cblxuICAgIG5leHQoKTtcbiAgfSwgeyBraW5kOiAnZmVhdHVyZScsIGZlYXR1cmUgfSk7XG59XG5cbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuLy8gU2VydmljZS10by1zZXJ2aWNlIHRva2Vuc1xuLy9cbi8vIEludGVyLXNlcnZpY2UgSFRUUCBjYWxscyAoYmlsbGluZyDihpIgbWVzc2FnZSwgcGxhdGZvcm0g4oaSIGNvbXBsaWFuY2UsIGV0Yy4pXG4vLyBuZWVkIHRvIHNhdGlzZnkgdGhlIHNhbWUgYHJlcXVpcmVBdXRoYCBtaWRkbGV3YXJlIGFzIHVzZXIgcmVxdWVzdHMuXG4vLyBgc2lnblNlcnZpY2VUb2tlbmAgbWludHMgYSBzaG9ydC1saXZlZCBFUzI1NiBKV1Qgc2lnbmVkIHdpdGggVEhJUyBzZXJ2aWNlJ3Ncbi8vIE9XTiBrZXkgKHNlZSBgc2VydmljZXMvc2VydmljZS1rZXlzLnRzYCksIGNhcnJ5aW5nIGBwcmluY2lwYWxUeXBlOiAnc2VydmljZSdgXG4vLyBhbmQgbmFtaW5nIHRoZSBjYWxsaW5nIHNlcnZpY2UgdmlhIGBzdWI6ICdzZXJ2aWNlOjxuYW1lPidgLiBHYXRlcyBicmFuY2ggb25cbi8vIHRoZSBjbGFpbTsgdGhlIHN1YmplY3QgbmFtZXMg4oCUIGFuZCBzaW5jZSAjMTQgdGhlIG5hbWUgaXMgY3J5cHRvZ3JhcGhpY2FsbHlcbi8vIGJvdW5kIHRvIHRoZSBzaWduaW5nIGtleSwgc28gaXQgY2FuIGFsc28gYmUgdHJ1c3RlZC5cbi8vIGByZXF1aXJlQXV0aGAgYWNjZXB0cyB0aGVzZSB0b2tlbnMgdHJhbnNwYXJlbnRseSDigJQgdGhleSBwYXNzIGBkZWNvZGVkLnN1YmBcbi8vIGFuZCBgZGVjb2RlZC5yb2xlYCBjaGVja3MsIGFuZCBkb3duc3RyZWFtIGByZXF1aXJlT3JnYW5pemF0aW9uYCAvXG4vLyBgcmVxdWlyZVN5c3RlbUFkbWluYCByZWx5IG9uIHRoZSBvcmcvcm9sZSBlbWJlZGRlZCBpbiB0aGUgdG9rZW4uXG4vL1xuLy8gVG9rZW5zIGRlZmF1bHQgdG8gNS1taW51dGUgVFRMIOKAlCBsb25nIGVub3VnaCB0byBzdXJ2aXZlIGEgYmFja2VuZCBob3AsXG4vLyBzaG9ydCBlbm91Z2ggdGhhdCBhIGxlYWtlZCB0b2tlbiBpcyBsb3ctdmFsdWUuXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuY29uc3QgREVGQVVMVF9TRVJWSUNFX1RPS0VOX1RUTF9TRUNPTkRTID0gMzAwO1xuXG4vKipcbiAqIERlbnlsaXN0IG9mIHNlcnZpY2UgTkFNRVMgKHRoZSBgPG5hbWU+YCBpbiBgc3ViOiBzZXJ2aWNlOjxuYW1lPmApIHdob3NlIHRva2Vuc1xuICogYHJlcXVpcmVBdXRoYCBtdXN0IHJlamVjdC4gUmVhZCBmcm9tIGBTRVJWSUNFX1RPS0VOX0RFTllMSVNUYCAoY29tbWEtc2VwYXJhdGVkKVxuICogYXQgcHJvY2VzcyBzdGFydCwgc28gYXJtaW5nIGl0IGlzIGEgY29uZmlnIGNoYW5nZSArIHJvbGxvdXQg4oCUIGl0IGN1dHMgb2ZmIGFcbiAqIGNvbXByb21pc2VkIHNlcnZpY2UgV0lUSE9VVCByb3RhdGluZyBhbnkga2V5LCBhbmQgKHVubGlrZSB0aGUgcHJlLSMxNCBzaGFyZWRcbiAqIHNlY3JldCkgd2l0aG91dCBpbnZhbGlkYXRpbmcgZXZlcnkgb3RoZXIgc2VydmljZSdzIHRva2VucyBhcyBjb2xsYXRlcmFsLlxuICovXG5jb25zdCBzZXJ2aWNlVG9rZW5EZW55bGlzdCA9IG5ldyBTZXQoXG4gIChwcm9jZXNzLmVudi5TRVJWSUNFX1RPS0VOX0RFTllMSVNUIHx8ICcnKVxuICAgIC5zcGxpdCgnLCcpXG4gICAgLm1hcCgocykgPT4gcy50cmltKCkpXG4gICAgLmZpbHRlcihCb29sZWFuKSxcbik7XG5cbi8qKlxuICogVGhlIGNhbGxpbmcgc2VydmljZSdzIG5hbWUgZm9yIGEgU0VSVklDRSBwcmluY2lwYWwgKGBwcmluY2lwYWxUeXBlOiAnc2VydmljZSdgKSxcbiAqIGVsc2UgYHVuZGVmaW5lZGAuIEEgdXNlciB0b2tlbiBuZXZlciB5aWVsZHMgYSBuYW1lLCB3aGF0ZXZlciBpdHMgYHN1YmAgc2F5cy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNlcnZpY2VOYW1lT2YoY2xhaW1zOiB7IHByaW5jaXBhbFR5cGU/OiBzdHJpbmc7IHN1Yj86IHN0cmluZyB9IHwgdW5kZWZpbmVkKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgaWYgKGNsYWltcz8ucHJpbmNpcGFsVHlwZSAhPT0gJ3NlcnZpY2UnIHx8IHR5cGVvZiBjbGFpbXMuc3ViICE9PSAnc3RyaW5nJykgcmV0dXJuIHVuZGVmaW5lZDtcbiAgaWYgKCFjbGFpbXMuc3ViLnN0YXJ0c1dpdGgoU0VSVklDRV9TVUJKRUNUX1BSRUZJWCkpIHJldHVybiB1bmRlZmluZWQ7XG4gIHJldHVybiBjbGFpbXMuc3ViLnNsaWNlKFNFUlZJQ0VfU1VCSkVDVF9QUkVGSVgubGVuZ3RoKSB8fCB1bmRlZmluZWQ7XG59XG5cbi8qKiBUcnVlIHdoZW4gdGhlIGNsYWltcyBhcmUgYSBzZXJ2aWNlIHByaW5jaXBhbCB3aG9zZSBzZXJ2aWNlIGlzIG9uIHRoZSBkZW55bGlzdC4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc1NlcnZpY2VUb2tlbkRlbmllZChjbGFpbXM6IHsgcHJpbmNpcGFsVHlwZT86IHN0cmluZzsgc3ViPzogc3RyaW5nIH0pOiBib29sZWFuIHtcbiAgaWYgKHNlcnZpY2VUb2tlbkRlbnlsaXN0LnNpemUgPT09IDApIHJldHVybiBmYWxzZTtcbiAgY29uc3QgbmFtZSA9IHNlcnZpY2VOYW1lT2YoY2xhaW1zKTtcbiAgcmV0dXJuIG5hbWUgIT09IHVuZGVmaW5lZCAmJiBzZXJ2aWNlVG9rZW5EZW55bGlzdC5oYXMobmFtZSk7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgU2VydmljZVRva2VuT3B0aW9ucyB7XG4gIC8qKiBDYWxsaW5nIHNlcnZpY2UgaWRlbnRpZmllciAoZS5nLiAnYmlsbGluZycsICdwbGF0Zm9ybScpLiBFbWJlZGRlZCBhcyBgc3ViOiBzZXJ2aWNlOjxuYW1lPmAuICovXG4gIHNlcnZpY2VOYW1lOiBzdHJpbmc7XG4gIC8qKiBBY3RpdmUgb3JnIGNvbnRleHQgZm9yIHRoZSBjYWxsLiBVc2UgdGhlIHRhcmdldCB0ZW5hbnQncyBvcmcgaWQsIG9yIHRoZVxuICAgKiAgd2VsbC1rbm93biBgU1lTVEVNX09SR19JRGAgKGFuIE9iamVjdElkKSBmb3Igc3lzdGVtLXdpZGUgb3BzIOKAlCBOT1QgdGhlIHN0cmluZ1xuICAgKiAgJ3N5c3RlbScsIHdoaWNoIGlkLWJhc2VkIHN5c3RlbS1vcmcgY2hlY2tzIHdvbid0IHJlY29nbml6ZS4gKi9cbiAgb3JnSWQ/OiBzdHJpbmc7XG4gIC8qKiBBY3RpdmUgb3JnIG5hbWUuIERlZmF1bHRzIHRvIG9yZ0lkLiAqL1xuICBvcmdOYW1lPzogc3RyaW5nO1xuICAvKiogVFRMIGluIHNlY29uZHMgKGRlZmF1bHQgMzAwKS4gKi9cbiAgdHRsU2Vjb25kcz86IG51bWJlcjtcbiAgLyoqXG4gICAqIFJvbGUgdGhlIHRva2VuIGNhcnJpZXMgKHJlcXVpcmVkIOKAlCBubyBpbXBsaWNpdCBkZWZhdWx0KS4gKipQYXNzIHRoZSBMT1dFU1RcbiAgICogcm9sZSB0aGUgY2FsbCBhY3R1YWxseSBuZWVkcyoqIChgJ21lbWJlcidgIGZvciByZWFkIC8gZGF0YS1wbGFuZSBjYWxscykgc28gYVxuICAgKiBsZWFrZWQgc2VydmljZSB0b2tlbiBjYW4ndCBwZXJmb3JtIGFkbWluIGFjdGlvbnMgaW4gdGhlIHRhcmdldCBvcmcuXG4gICAqIGBpc0FkbWluYCBpcyBkZXJpdmVkIGZyb20gdGhpcyAoYWRtaW58b3duZXIg4oaSIHRydWUpLlxuICAgKi9cbiAgcm9sZTogJ293bmVyJyB8ICdhZG1pbicgfCAnbWVtYmVyJztcbiAgLyoqXG4gICAqIE9wdGlvbmFsIGZpbmUtZ3JhaW5lZCBwZXJtaXNzaW9uIGNsYWltLiBQcmVmZXIgdGhpcyArIGByb2xlOiAnbWVtYmVyJ2Agb3ZlciBhXG4gICAqIGhpZ2ggcm9sZSB3aGVuIGEgY2FsbCBuZWVkcyBPTkUgc3BlY2lmaWMgY2FwYWJpbGl0eSAoZS5nLiBgWydwbHVnaW5zOndyaXRlJ11gXG4gICAqIHRvIHB1c2ggYSBwbHVnaW4gaW1hZ2UpIOKAlCB0aGUgdG9rZW4gdGhlbiBzYXRpc2ZpZXMgdGhhdCBwZXJtaXNzaW9uIGdhdGVcbiAgICogV0lUSE9VVCBjYXJyeWluZyBgaXNBZG1pbmAsIHNvIGEgbGVha2VkIHRva2VuIGNhbid0IHBlcmZvcm0gYWRtaW4gYWN0aW9ucy5cbiAgICovXG4gIHBlcm1pc3Npb25zPzogUGVybWlzc2lvbltdO1xufVxuXG4vKipcbiAqIE1pbnQgYSBKV1QgaWRlbnRpZnlpbmcgdGhlIGNhbGxpbmcgc2VydmljZS4gVXNlZCBmb3IgaW50ZXItc2VydmljZSBIVFRQIGNhbGxzLlxuICogVGhlIHRva2VuIHNhdGlzZmllcyBgcmVxdWlyZUF1dGhgIGFuZCAod2hlbiBvcmdJZCBpcyBwcmVzZW50KSBgcmVxdWlyZU9yZ2FuaXphdGlvbmAuXG4gKiBTY29wZSBpdCB3aXRoIGBvcHRzLnJvbGVgIOKAlCBsZWFzdCBwcml2aWxlZ2Uga2VlcHMgYSBsZWFrZWQgdG9rZW4gbG93LXZhbHVlLlxuICpcbiAqIGBvcHRzLnNlcnZpY2VOYW1lYCBtdXN0IGJlIFRISVMgcHJvY2VzcydzIG93biBpZGVudGl0eSAoYFNFUlZJQ0VfTkFNRWApOiBhXG4gKiBzZXJ2aWNlIGhvbGRzIG9ubHkgaXRzIG93biBzaWduaW5nIGtleSwgc28gbWludGluZyBhIHRva2VuIHRoYXQgbmFtZXMgYW5vdGhlclxuICogc2VydmljZSB0aHJvd3MgcmF0aGVyIHRoYW4gcHJvZHVjaW5nIG9uZSBldmVyeSBwZWVyIHdvdWxkIHJlamVjdC4gVGhhdCBpcyB0aGVcbiAqIG9uZSBiZWhhdmlvdXIgY2hhbmdlICMxNCBmb3JjZXMgb24gY2FsbGVycyDigJQgc2VlIGBzZXJ2aWNlcy9zZXJ2aWNlLWtleXMudHNgLlxuICovXG5leHBvcnQgZnVuY3Rpb24gc2lnblNlcnZpY2VUb2tlbihvcHRzOiBTZXJ2aWNlVG9rZW5PcHRpb25zKTogc3RyaW5nIHtcbiAgY29uc3Qgcm9sZSA9IG9wdHMucm9sZTtcbiAgY29uc3QgcGF5bG9hZDogT21pdDxKd3RQYXlsb2FkLCAnc3ViJz4gPSB7XG4gICAgdXNlcm5hbWU6IGAke29wdHMuc2VydmljZU5hbWV9LXNlcnZpY2VgLFxuICAgIGVtYWlsOiBgJHtvcHRzLnNlcnZpY2VOYW1lfUBpbnRlcm5hbGAsXG4gICAgcHJpbmNpcGFsVHlwZTogJ3NlcnZpY2UnLFxuICAgIHRva2VuX3VzZTogJ2FjY2VzcycsXG4gICAgcm9sZSxcbiAgICBpc0FkbWluOiByb2xlID09PSAnb3duZXInIHx8IHJvbGUgPT09ICdhZG1pbicsXG4gICAgdHlwZTogJ2FjY2VzcycsXG4gICAgb3JnYW5pemF0aW9uSWQ6IG9wdHMub3JnSWQsXG4gICAgb3JnYW5pemF0aW9uTmFtZTogb3B0cy5vcmdOYW1lID8/IG9wdHMub3JnSWQsXG4gICAgLy8gVW5pcXVlIHRva2VuIGlkIG9uIGV2ZXJ5IG1pbnQuIENvbWJpbmVkIHdpdGggdGhlIHNob3J0ICgzMDBzIGRlZmF1bHQpIFRUTFxuICAgIC8vIHRoaXMgZ2l2ZXMgZWFjaCBzZXJ2aWNlIHRva2VuIGEgZGlzdGluY3QgaWRlbnRpdHkg4oCUIHRoZSBjb3JyZWxhdGlvbiBoYW5kbGVcbiAgICAvLyBmb3IgdHJhY2luZyB3aGljaCBtaW50IHBlcmZvcm1lZCBhIGNyb3NzLXNlcnZpY2UgYWN0aW9uLCBhbmQgdGhlIGJ1aWxkaW5nXG4gICAgLy8gYmxvY2sgZm9yIHJlcGxheSBkZXRlY3Rpb24gKGEgdmVyaWZpZXIgY2FuIHRyYWNrIHNlZW4ganRpcykuIEl0IGRvZXMgTk9UXG4gICAgLy8gYnkgaXRzZWxmIHByZXZlbnQgcmVwbGF5IHdpdGhpbiB0aGUgVFRMIHdpbmRvdy5cbiAgICBqdGk6IHJhbmRvbVVVSUQoKSxcbiAgICAvLyBMZWFzdC1wcml2aWxlZ2UgY2FwYWJpbGl0eSBjbGFpbSAob3B0aW9uYWwpIOKAlCBsZXRzIGEgbWVtYmVyLXJvbGUgdG9rZW5cbiAgICAvLyBzYXRpc2Z5IGEgc3BlY2lmaWMgcGVybWlzc2lvbiBnYXRlIHdpdGhvdXQgY2FycnlpbmcgaXNBZG1pbi5cbiAgICAuLi4ob3B0cy5wZXJtaXNzaW9ucyAmJiBvcHRzLnBlcm1pc3Npb25zLmxlbmd0aCA+IDAgPyB7IHBlcm1pc3Npb25zOiBvcHRzLnBlcm1pc3Npb25zIH0gOiB7fSksXG4gIH07XG4gIC8vIGBzdWJgLCBgaWF0YC9gZXhwYCBhbmQgdGhlIG9wdGlvbmFsIGlzc3Vlci9hdWRpZW5jZSB0aGF0IHJlcXVpcmVBdXRoXG4gIC8vIHZlcmlmaWVzIGFyZSBzdGFtcGVkIGJ5IHRoZSBzaWduZXIsIHNvIHRoZXJlIGlzIGV4YWN0bHkgb25lIHBsYWNlIHRoYXRcbiAgLy8gZGVjaWRlcyB3aGF0IGEgc2VydmljZSB0b2tlbiBzYXlzLlxuICByZXR1cm4gc2lnblNlcnZpY2VKd3QocGF5bG9hZCBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiwge1xuICAgIHNlcnZpY2VOYW1lOiBvcHRzLnNlcnZpY2VOYW1lLFxuICAgIGV4cGlyZXNJblNlY29uZHM6IG9wdHMudHRsU2Vjb25kcyA/PyBERUZBVUxUX1NFUlZJQ0VfVE9LRU5fVFRMX1NFQ09ORFMsXG4gICAgLi4uaXNzdWVyQXVkaWVuY2VPcHRpb25zKCksXG4gIH0pO1xufVxuXG4vKiogQ29udmVuaWVuY2U6IHJldHVybnMgYSBgQmVhcmVyIDx0b2tlbj5gIGhlYWRlciB2YWx1ZSBmb3IgZmV0Y2gvYXhpb3MgY2FsbHMuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0U2VydmljZUF1dGhIZWFkZXIob3B0czogU2VydmljZVRva2VuT3B0aW9ucyk6IHN0cmluZyB7XG4gIHJldHVybiBgQmVhcmVyICR7c2lnblNlcnZpY2VUb2tlbihvcHRzKX1gO1xufVxuXG4vKiogVHJ1ZSB3aGVuIGByZXEudXNlcmAgaXMgYSBzZXJ2aWNlIHByaW5jaXBhbCAoYHByaW5jaXBhbFR5cGU6ICdzZXJ2aWNlJ2AsIG1pbnRlZCBieSBgc2lnblNlcnZpY2VUb2tlbmApLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzU2VydmljZVByaW5jaXBhbChyZXE6IFJlcXVlc3QpOiBib29sZWFuIHtcbiAgcmV0dXJuIHJlcS51c2VyPy5wcmluY2lwYWxUeXBlID09PSAnc2VydmljZSc7XG59XG5cbi8qKlxuICogVHJ1ZSB3aGVuIGByZXEudXNlcmAgaXMgYW4gT1JHIFNFUlZJQ0UgQUNDT1VOVCAoYHByaW5jaXBhbFR5cGU6XG4gKiAnc2VydmljZV9hY2NvdW50J2ApIOKAlCBhIG5vbi1odW1hbiBwcmluY2lwYWwgb3duZWQgYnkgb25lIG9yZywgYXV0aGVudGljYXRpbmdcbiAqIHdpdGggYSBgcGJfc2Ff4oCmYCBrZXkgZXhjaGFuZ2VkIGF0IHBsYXRmb3JtLlxuICpcbiAqIEEgc2VydmljZSBhY2NvdW50IGlzIE5PVCBhbiBpbnRlcm5hbCBzZXJ2aWNlIHByaW5jaXBhbDogaXQgaG9sZHMgb3JnIFJvbGVzIGFuZFxuICogaXMgc3ViamVjdCB0byBldmVyeSBwZXJtaXNzaW9uIGdhdGUgYSBtZW1iZXIgaXMuIFdoYXQgaXQgY2FuIG5ldmVyIGRvIGlzXG4gKiBzYXRpc2Z5IGEgSFVNQU4tcHJlc2VuY2UgcmVxdWlyZW1lbnQg4oCUIHN0ZXAtdXAgKGFuZCBhbnkgbGF0ZXIgYXNzdXJhbmNlIGdhdGUpXG4gKiByZWZ1c2VzIGl0IG91dHJpZ2h0LCBiZWNhdXNlIHRoZXJlIGlzIG5vIHBlcnNvbiBiZWhpbmQgaXQgdG8gcmUtdmVyaWZ5LlxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNTZXJ2aWNlQWNjb3VudFByaW5jaXBhbChyZXE6IFJlcXVlc3QpOiBib29sZWFuIHtcbiAgcmV0dXJuIHJlcS51c2VyPy5wcmluY2lwYWxUeXBlID09PSAnc2VydmljZV9hY2NvdW50Jztcbn1cblxuLyoqIFRydWUgd2hlbiBgcmVxLnVzZXJgIGlzIHRoZSBuYW1lZCBpbnRlcm5hbCBzZXJ2aWNlIChlLmcuIGAnYmlsbGluZydgKS4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc1NlcnZpY2VQcmluY2lwYWxOYW1lZChyZXE6IFJlcXVlc3QsIHNlcnZpY2VOYW1lOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgcmV0dXJuIHNlcnZpY2VOYW1lT2YocmVxLnVzZXIpID09PSBzZXJ2aWNlTmFtZTtcbn1cblxuLyoqXG4gKiBQUkUtYXV0aCBjaGVjazogY3J5cHRvZ3JhcGhpY2FsbHkgdmVyaWZ5IHRoZSByZXF1ZXN0IGNhcnJpZXMgYSB2YWxpZCwgc2lnbmVkXG4gKiBTRVJWSUNFIHRva2VuIChgcHJpbmNpcGFsVHlwZTogJ3NlcnZpY2UnYCkuIFVubGlrZSB7QGxpbmsgaXNTZXJ2aWNlUHJpbmNpcGFsfVxuICogKHdoaWNoIHJlYWRzIHRoZSBhbHJlYWR5LXBvcHVsYXRlZCBgcmVxLnVzZXJgKSwgdGhpcyB2ZXJpZmllcyB0aGUgYmVhcmVyIHRva2VuXG4gKiBpdHNlbGYsIHNvIGl0IGlzIHNhZmUgdG8gY2FsbCBCRUZPUkUgYHJlcXVpcmVBdXRoYCBydW5zIOKAlCBlLmcuIHRoZSBnbG9iYWwgcmF0ZVxuICogbGltaXRlcidzIGBza2lwYCwgd2hpY2ggbXVzdCBub3QgdHJ1c3QgdGhlIHNwb29mYWJsZSBgeC1pbnRlcm5hbC1zZXJ2aWNlYFxuICogaGVhZGVyLiBNaXJyb3JzIGByZXF1aXJlQXV0aGAncyBTRVJWSUNFIGNoYWluIGV4YWN0bHkgKHRoZSBzaWduZXIncyBvd24ga2V5LFxuICogcmVzb2x2ZWQgYnkgYGtpZGAsIHdpdGggdGhlIGBzdWJgL3NpZ25lciBhZ3JlZW1lbnQgY2hlY2sgYW5kIHRoZSBvcHRpb25hbFxuICogaXNzdWVyL2F1ZGllbmNlKSBhbmQgcmV0dXJucyBgZmFsc2VgIG9uIGFueSBtaXNzaW5nL2ludmFsaWQvbm9uLXNlcnZpY2UgdG9rZW5cbiAqIOKAlCBpbmNsdWRpbmcgYW55IHBsYXRmb3JtLXNpZ25lZCBVU0VSIHRva2VuLCB3aG9zZSBga2lkYCBpcyBub3QgaW4gdGhlIHNlcnZpY2VcbiAqIGJ1bmRsZSBhdCBhbGwuIFN0YXlzIFNZTkNIUk9OT1VTLCB3aGljaCBpcyB3aHkgdGhlIHBlci1zZXJ2aWNlIHB1YmxpYyBrZXlzIGFyZVxuICogZGlzdHJpYnV0ZWQgYXMgYSBtb3VudGVkIGJ1bmRsZSByYXRoZXIgdGhhbiBmZXRjaGVkIG92ZXIgSFRUUC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHZlcmlmeVNlcnZpY2VQcmluY2lwYWwocmVxOiBSZXF1ZXN0KTogYm9vbGVhbiB7XG4gIGNvbnN0IHBhcnRzID0gcmVxLmhlYWRlcnMuYXV0aG9yaXphdGlvbj8uc3BsaXQoJyAnKTtcbiAgaWYgKCFwYXJ0cyB8fCBwYXJ0cy5sZW5ndGggIT09IDIgfHwgcGFydHNbMF0gIT09ICdCZWFyZXInKSByZXR1cm4gZmFsc2U7XG4gIHRyeSB7XG4gICAgY29uc3QgaGVhZGVyID0gZGVjb2RlSnd0SGVhZGVyKHBhcnRzWzFdKTtcbiAgICBpZiAoIWhlYWRlcj8ua2lkIHx8ICFpc1NlcnZpY2VLaWQoaGVhZGVyLmtpZCkpIHJldHVybiBmYWxzZTtcbiAgICBjb25zdCBkZWNvZGVkID0gdmVyaWZ5U2VydmljZUp3dDxKd3RQYXlsb2FkPihwYXJ0c1sxXSwgeyBraWQ6IGhlYWRlci5raWQsIC4uLmlzc3VlckF1ZGllbmNlT3B0aW9ucygpIH0pO1xuICAgIGlmIChkZWNvZGVkLnR5cGUgIT09ICdhY2Nlc3MnIHx8IGRlY29kZWQucHJpbmNpcGFsVHlwZSAhPT0gJ3NlcnZpY2UnIHx8ICFoYXNWYWxpZElkZW50aXR5Q2xhaW1zKGRlY29kZWQpKSByZXR1cm4gZmFsc2U7XG4gICAgLy8gQSBkZW55bGlzdGVkIChraWxsZWQpIHNlcnZpY2UgbXVzdCBOT1QgYmUgdHJlYXRlZCBhcyBhIHRydXN0ZWQgcHJpbmNpcGFsIOKAlFxuICAgIC8vIG90aGVyd2lzZSBpdCBrZWVwcyB0aGUgcmF0ZS1saW1pdGVyIGV4ZW1wdGlvbiBldmVuIHRob3VnaCByZXF1aXJlQXV0aCByZWplY3RzXG4gICAgLy8gaXQgb24gcmVhbCByb3V0ZXMuIEZvbGQgdGhlIGtpbGwtc3dpdGNoIGludG8gdGhlIHByZS1hdXRoIGNoZWNrIHRvby5cbiAgICByZXR1cm4gIWlzU2VydmljZVRva2VuRGVuaWVkKGRlY29kZWQpO1xuICB9IGNhdGNoIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbn1cbiJdfQ==
|
|
199
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0aC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9taWRkbGV3YXJlL2F1dGgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQVF0QyxPQUFPLEdBQUcsTUFBTSxjQUFjLENBQUM7QUFDL0IsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ2hELE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUN6RCxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsZUFBZSxFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDbEYsT0FBTyxFQUFFLGVBQWUsRUFBRSxlQUFlLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUMvRSxPQUFPLEVBQXVCLE1BQU0sb0JBQW9CLENBQUM7QUFDekQsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBRXBELE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUNyRCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDdEQsT0FBTyxFQUFFLFdBQVcsRUFBd0IsTUFBTSxzQkFBc0IsQ0FBQztBQUN6RSxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDekQsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ2pELE9BQU8sRUFBRSxlQUFlLEVBQUUsMkJBQTJCLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUNyRyxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUM1RSxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsYUFBYSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDMUUsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDMUQsT0FBTyxFQUFFLGtCQUFr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QUFJLEVBQUUsQ0FBQztJQUNULENBQUM7SUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1FBQ2YsSUFBSSxLQUFLLFlBQVksR0FBRyxDQUFDLGlCQUFpQixFQUFFLENBQUM7WUFDM0MsT0FBTyxTQUFTLENBQUMsR0FBRyxFQUFFLFVBQVUsQ0FBQyxZQUFZLEVBQUUsbUJBQW1CLEVBQUUsU0FBUyxDQUFDLGFBQWEsQ0FBQyxDQUFDO1FBQy9GLENBQUM7UUFFRCw0RUFBNEU7UUFDNUUsd0VBQXdFO1FBQ3hFLHlFQUF5RTtRQUN6RSw0RUFBNEU7UUFDNUUsMEVBQTBFO1FBQzFFLG9FQUFvRTtRQUNwRSxJQUFJLEtBQUssWUFBWSxvQkFBb0IsSUFBSSxLQUFLLFlBQVksZUFBZSxFQUFFLENBQUM7WUFDOUUsTUFBTSxDQUFDLElBQUksQ0FBQyxtREFBbUQsRUFBRSxFQUFFLEtBQUssRUFBRSxLQUFLLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQztZQUMzRixPQUFPLFNBQVMsQ0FDZCxHQUFHLEVBQUUsVUFBVSxDQUFDLG1CQUFtQixFQUNuQyw2REFBNkQsRUFDN0QsU0FBUyxDQUFDLG1CQUFtQixDQUM5QixDQUFDO1FBQ0osQ0FBQztRQUVELElBQUksS0FBSyxZQUFZLGVBQWUsSUFBSSxLQUFLLFlBQVksR0FBRyxDQUFDLGlCQUFpQixFQUFFLENBQUM7WUFDL0UsT0FBTyxTQUFTLENBQUMsR0FBRyxFQUFFLFVBQVUsQ0FBQyxZQUFZLEVBQUUsZUFBZSxFQUFFLFNBQVMsQ0FBQyxhQUFhLENBQUMsQ0FBQztRQUMzRixDQUFDO1FBRUQsT0FBTyxTQUFTLENBQUMsR0FBRyxFQUFFLFVBQVUsQ0FBQyxZQUFZLEVBQUUsdUJBQXVCLEVBQUUsU0FBUyxDQUFDLFlBQVksQ0FBQyxDQUFDO0lBQ2xHLENBQUM7QUFDSCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbi8qKlxuICogYHJlcXVpcmVBdXRoYDogYmVhcmVyIC8gYWNjZXNzLWtleSBhdXRoZW50aWNhdGlvbiwgdGhlIGNoZWNrcyBldmVyeVxuICogdmVyaWZpZWQgcmVxdWVzdCBwYXNzZXMsIGFuZCB0aGUgdGVuYW50IGlkZW50aXR5IGl0IGF0dGFjaGVzLlxuICovXG5cbmltcG9ydCB0eXBlIHsgUmVxdWVzdCwgUmVzcG9uc2UsIE5leHRGdW5jdGlvbiB9IGZyb20gJ2V4cHJlc3MnO1xuaW1wb3J0IGp3dCBmcm9tICdqc29ud2VidG9rZW4nO1xuaW1wb3J0IHsgdGFnUm91dGVHYXRlIH0gZnJvbSAnLi9yb3V0ZS10YWJsZS5qcyc7XG5pbXBvcnQgeyBIdHRwU3RhdHVzIH0gZnJvbSAnLi4vY29uc3RhbnRzL2h0dHAtc3RhdHVzLmpzJztcbmltcG9ydCB7IEp3a3NVbmF2YWlsYWJsZUVycm9yLCBVbmtub3duS2lkRXJyb3IgfSBmcm9tICcuLi9zZXJ2aWNlcy9qd2tzLWNhY2hlLmpzJztcbmltcG9ydCB7IFNlcnZpY2VLZXlFcnJvciwgc2VydmljZUlkZW50aXR5IH0gZnJvbSAnLi4vc2VydmljZXMvc2VydmljZS1rZXlzLmpzJztcbmltcG9ydCB7IHR5cGUgQXNzdXJhbmNlTGV2ZWwgfSBmcm9tICcuLi90eXBlcy9jb21tb24uanMnO1xuaW1wb3J0IHsgRXJyb3JDb2RlIH0gZnJvbSAnLi4vdHlwZXMvZXJyb3ItY29kZXMuanMnO1xuaW1wb3J0IHR5cGUgeyBIdHRwUmVxdWVzdCB9IGZyb20gJy4uL3R5cGVzL2h0dHAuanMnO1xuaW1wb3J0IHsgaXNPcGFxdWVBcGlLZXkgfSBmcm9tICcuLi91dGlscy9hcGkta2V5LmpzJztcbmltcG9ydCB7IGdldEhlYWRlclN0cmluZyB9IGZyb20gJy4uL3V0aWxzL2hlYWRlcnMuanMnO1xuaW1wb3J0IHsgZ2V0SWRlbnRpdHksIHR5cGUgUmVxdWVzdElkZW50aXR5IH0gZnJvbSAnLi4vdXRpbHMvaWRlbnRpdHkuanMnO1xuaW1wb3J0IHsgZW1pdENvdW50ZXIgfSBmcm9tICcuLi91dGlscy9tZXRyaWMtZW1pdHRlci5qcyc7XG5pbXBvcnQgeyBzZW5kRXJyb3IgfSBmcm9tICcuLi91dGlscy9yZXNwb25zZS5qcyc7XG5pbXBvcnQgeyBjaGVja1Jldm9jYXRpb24sIGlzSW1wZXJzb25hdGlvbldyaXRlQmxvY2tlZCwgbmVlZHNSZXZvY2F0aW9uQ2hlY2sgfSBmcm9tICcuL3Jldm9jYXRpb24uanMnO1xuaW1wb3J0IHsgaGFzVmFsaWRJZGVudGl0eUNsYWltcywgdmVyaWZ5QmVhcmVyVG9rZW4gfSBmcm9tICcuL2p3dC12ZXJpZnkuanMnO1xuaW1wb3J0IHsgaXNTZXJ2aWNlVG9rZW5EZW5pZWQsIHNlcnZpY2VOYW1lT2YgfSBmcm9tICcuL3NlcnZpY2UtdG9rZW5zLmpzJztcbmltcG9ydCB7IHJlY29yZEF1dGh6RGVuaWFsIH0gZnJvbSAnLi9wZXJtaXNzaW9uLWdhdGVzLmpzJztcbmltcG9ydCB7IHJlZnVzZUZvckFzc3VyYW5jZSB9IGZyb20gJy4vYXNzdXJhbmNlLmpzJztcbmltcG9ydCB7IGNyZWF0ZUxvZ2dlciB9IGZyb20gJy4uL3V0aWxzL2xvZ2dlci5qcyc7XG5cbmNvbnN0IGxvZ2dlciA9IGNyZWF0ZUxvZ2dlcignYXV0aC1taWRkbGV3YXJlJyk7XG5leHBvcnQgaW50ZXJmYWNlIFJlcXVpcmVBdXRoT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBBbGxvdyB4LW9yZy1pZC94LW9yZy1uYW1lIGhlYWRlcnMgdG8gb3ZlcnJpZGUgdGhlIEpXVCdzIG9yZ2FuaXphdGlvbiBmaWVsZHMuXG4gICAqXG4gICAqIFdoZW4gZW5hYmxlZCwgdGhlIGB4LW9yZy1pZGAvYHgtb3JnLW5hbWVgIGhlYWRlcnMgb3ZlcnJpZGUgdGhlIGNhbGxlcidzIG9yZ1xuICAgKiDigJQgYnV0IE9OTFkgZm9yIGEgdmVyaWZpZWQgU1lTLUFETUlOIChgaXNTdXBlckFkbWluYCBjbGFpbSkuIEZvciBhbnkgb3JkaW5hcnlcbiAgICogYXV0aGVudGljYXRlZCB1c2VyIHRoZSBoZWFkZXJzIGFyZSBpZ25vcmVkLCBzbyBlbmFibGluZyB0aGlzIGNhbiBuZXZlciBsZXQgYVxuICAgKiBub3JtYWwgdXNlciBpbXBlcnNvbmF0ZSBhbm90aGVyIHRlbmFudCdzIG9yZy4gVXNlIGZvciBjcm9zcy1vcmcgYWRtaW4gdG9vbGluZ1xuICAgKiAoZS5nLiBhIHN5c2FkbWluIG1hbmFnaW5nIGEgZ2l2ZW4gb3JnJ3MgYmlsbGluZykuIElmIHVuc3VyZSwgbGVhdmUgaXQgZGlzYWJsZWQuXG4gICAqL1xuICBhbGxvd09yZ0hlYWRlck92ZXJyaWRlPzogYm9vbGVhbjtcbiAgLyoqXG4gICAqIERlbWFuZCB0aGF0IHRoZSB3aG9sZSBTRVNTSU9OIGJlIGF0IGxlYXN0IHRoaXMgYXNzdXJhbmNlIGxldmVsLlxuICAgKlxuICAgKiBgbWluQXNzdXJhbmNlOiAyYCBtZWFucyB0aGUgcGVyc29uIGF1dGhlbnRpY2F0ZWQgd2l0aCBhIHNlY29uZCBmYWN0b3Ig4oCUIGFcbiAgICogcGFzc2tleSB3aXRoIHVzZXIgdmVyaWZpY2F0aW9uLCBhIHBhc3N3b3JkIHBsdXMgYW4gYXV0aGVudGljYXRvciBjb2RlLCBvclxuICAgKiBTU08gdGhyb3VnaCBhbiBJZFAgdGhlIG9yZyBtYXJrZWQgYXMgZW5mb3JjaW5nIE1GQS4gQSB3ZWFrZXIgdG9rZW4gZ2V0c1xuICAgKiAqKjQwMSBgTUZBX1JFUVVJUkVEYCoqLCB3aGljaCB0aGUgY2xpZW50IGFuc3dlcnMgYnkgc2VuZGluZyB0aGUgcGVyc29uIHRvXG4gICAqIGVucm9sbWVudCBvciB0byBhIHN0cm9uZ2VyIHNpZ24taW47IHJlZnJlc2hpbmcgY2Fubm90IGhlbHAsIGJlY2F1c2UgYGFhbGBcbiAgICogbGl2ZXMgb24gdGhlIHNlc3Npb24gc2xvdCBhbmQgYSByZWZyZXNoIG5ldmVyIHJhaXNlcyBpdC5cbiAgICpcbiAgICogVGhpcyBpcyB0aGUgU0VTU0lPTi1sZXZlbCBjb3VudGVycGFydCB0byB7QGxpbmsgcmVxdWlyZVN0ZXBVcH0sIHdoaWNoIHN0YXlzXG4gICAqIGEgZnJlc2gsIHBlci1hY3Rpb24gY29uZmlybWF0aW9uLiBVc2UgYm90aCBvbiB0aGUgbW9zdCBkYW5nZXJvdXMgcm91dGVzLlxuICAgKlxuICAgKiBNQUNISU5FUyBORVZFUiBTQVRJU0ZZIElULiBBIHNlcnZpY2UgcHJpbmNpcGFsLCBhbiBvcmcgc2VydmljZSBhY2NvdW50IGFuZFxuICAgKiBhbiBleGNoYW5nZWQgYWNjZXNzIGtleSBhbGwgZ2V0ICoqNDAzIGBIVU1BTl9TRVNTSU9OX1JFUVVJUkVEYCoqIOKAlCB0aGVyZSBpc1xuICAgKiBubyBwZXJzb24gYmVoaW5kIHRoZW0gdG8gaGF2ZSBwcmVzZW50ZWQgYSBmYWN0b3IsIHNvIFwiYXNzdXJhbmNlXCIgaXMgbm90IGFcbiAgICogcXVlc3Rpb24gdGhlaXIgY3JlZGVudGlhbCBjYW4gYW5zd2VyLiBUaGF0IGlzIGRlbGliZXJhdGVseSBub3QgYSBzaWxlbnRcbiAgICogcGFzcy10aHJvdWdoIGZvciBpbnRlcm5hbCBzZXJ2aWNlczogYSByb3V0ZSB0aGF0IGRlbWFuZHMgTUZBIGlzIGEgcm91dGUgYVxuICAgKiBodW1hbiBpcyBkb2luZyBzb21ldGhpbmcgZGFuZ2Vyb3VzIG9uLlxuICAgKi9cbiAgbWluQXNzdXJhbmNlPzogQXNzdXJhbmNlTGV2ZWw7XG4gIC8qKlxuICAgKiBXaXRoIHtAbGluayBtaW5Bc3N1cmFuY2V9LCBhZGRpdGlvbmFsbHkgYm91bmQgaG93IGxvbmcgYWdvIHRoYXQgc2lnbi1pblxuICAgKiBoYXBwZW5lZCAoc2Vjb25kcywgY29tcGFyZWQgYWdhaW5zdCB0aGUgdG9rZW4ncyBgYXV0aF90aW1lYCkuIEEgc2Vzc2lvbiB0aGF0XG4gICAqIGlzIE1GQS1ncmFkZSBidXQgb2xkZXIgdGhhbiB0aGlzIGdldHMgKio0MDEgYFJFQVVUSF9SRVFVSVJFRGAqKi4gSWdub3JlZFxuICAgKiB3aXRob3V0IGBtaW5Bc3N1cmFuY2VgIOKAlCBcImhvdyByZWNlbnRcIiBpcyBvbmx5IG1lYW5pbmdmdWwgb25jZSBcImhvdyBzdHJvbmdcIlxuICAgKiBpcyBiZWluZyBhc2tlZC5cbiAgICovXG4gIG1heEFnZT86IG51bWJlcjtcbn1cblxuLyoqIEpXVCBhdXRoIG1pZGRsZXdhcmUuIFVzZSBkaXJlY3RseSBvciBjYWxsIHdpdGggb3B0aW9ucy4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXF1aXJlQXV0aChcbiAgcmVxOiBSZXF1ZXN0LFxuICByZXM6IFJlc3BvbnNlLFxuICBuZXh0OiBOZXh0RnVuY3Rpb24sXG4pOiB2b2lkO1xuZXhwb3J0IGZ1bmN0aW9uIHJlcXVpcmVBdXRoKFxuICBvcHRpb25zPzogUmVxdWlyZUF1dGhPcHRpb25zLFxuKTogKHJlcTogUmVxdWVzdCwgcmVzOiBSZXNwb25zZSwgbmV4dDogTmV4dEZ1bmN0aW9uKSA9PiB2b2lkO1xuZXhwb3J0IGZ1bmN0aW9uIHJlcXVpcmVBdXRoKFxuICByZXFPck9wdGlvbnM/OiBSZXF1ZXN0IHwgUmVxdWlyZUF1dGhPcHRpb25zLFxuICByZXM/OiBSZXNwb25zZSxcbiAgbmV4dD86IE5leHRGdW5jdGlvbixcbik6IHZvaWQgfCAoKHJlcTogUmVxdWVzdCwgcmVzOiBSZXNwb25zZSwgbmV4dDogTmV4dEZ1bmN0aW9uKSA9PiB2b2lkKSB7XG4gIGlmIChyZXFPck9wdGlvbnMgJiYgcmVzICYmIG5leHQgJiYgJ2hlYWRlcnMnIGluIHJlcU9yT3B0aW9ucykge1xuICAgIHJldHVybiBfcmVxdWlyZUF1dGgoe30sIHJlcU9yT3B0aW9ucyBhcyBSZXF1ZXN0LCByZXMsIG5leHQpO1xuICB9XG5cbiAgY29uc3Qgb3B0aW9ucyA9IChyZXFPck9wdGlvbnMgYXMgUmVxdWlyZUF1dGhPcHRpb25zKSB8fCB7fTtcbiAgY29uc3QgZ2F0ZSA9IHRhZ1JvdXRlR2F0ZSgocmVxOiBSZXF1ZXN0LCByZXNJbm5lcjogUmVzcG9uc2UsIG5leHRJbm5lcjogTmV4dEZ1bmN0aW9uKSA9PiB7XG4gICAgX3JlcXVpcmVBdXRoKG9wdGlvbnMsIHJlcSwgcmVzSW5uZXIsIG5leHRJbm5lcik7XG4gIH0sIHsga2luZDogJ2F1dGgnIH0pO1xuICBpZiAob3B0aW9ucy5taW5Bc3N1cmFuY2UpIHtcbiAgICB0YWdSb3V0ZUdhdGUoZ2F0ZSwgeyBraW5kOiAnYXNzdXJhbmNlJywgbWluQXNzdXJhbmNlOiBvcHRpb25zLm1pbkFzc3VyYW5jZSwgLi4uKG9wdGlvbnMubWF4QWdlICE9PSB1bmRlZmluZWQgPyB7IG1heEFnZTogb3B0aW9ucy5tYXhBZ2UgfSA6IHt9KSB9KTtcbiAgfVxuICByZXR1cm4gZ2F0ZTtcbn1cbnRhZ1JvdXRlR2F0ZShyZXF1aXJlQXV0aCwgeyBraW5kOiAnYXV0aCcgfSk7XG5cbmZ1bmN0aW9uIF9yZXF1aXJlQXV0aChcbiAgb3B0aW9uczogUmVxdWlyZUF1dGhPcHRpb25zLFxuICByZXE6IFJlcXVlc3QsXG4gIHJlczogUmVzcG9uc2UsXG4gIG5leHQ6IE5leHRGdW5jdGlvbixcbik6IHZvaWQge1xuICBjb25zdCBhdXRoSGVhZGVyID0gcmVxLmhlYWRlcnMuYXV0aG9yaXphdGlvbjtcblxuICBpZiAoIWF1dGhIZWFkZXIpIHtcbiAgICByZXR1cm4gc2VuZEVycm9yKHJlcywgSHR0cFN0YXR1cy5VTkFVVEhPUklaRUQsICdBdXRob3JpemF0aW9uIGhlYWRlciByZXF1aXJlZCcsIEVycm9yQ29kZS5UT0tFTl9NSVNTSU5HKTtcbiAgfVxuXG4gIGNvbnN0IHBhcnRzID0gYXV0aEhlYWRlci5zcGxpdCgnICcpO1xuICBpZiAocGFydHMubGVuZ3RoICE9PSAyIHx8IHBhcnRzWzBdICE9PSAnQmVhcmVyJykge1xuICAgIHJldHVybiBzZW5kRXJyb3IocmVzLCBIdHRwU3RhdHVzLlVOQVVUSE9SSVpFRCwgJ0ludmFsaWQgYXV0aG9yaXphdGlvbiBmb3JtYXQuIFVzZTogQmVhcmVyIDx0b2tlbj4nLCBFcnJvckNvZGUuVE9LRU5fSU5WQUxJRCk7XG4gIH1cblxuICAvLyBBbiBPUEFRVUUgQUNDRVNTIEtFWSAoYHBiX3BhdF/igKZgIC8gYHBiX3NhX+KApmApIGNhcnJpZXMgbm8gY2xhaW1zIGFuZCBub1xuICAvLyBzaWduYXR1cmUsIHNvIGl0IGNhbm5vdCBiZSB2ZXJpZmllZCBoZXJlLiBUcmFkZSBpdCBhdCBwbGF0Zm9ybSBmb3IgYVxuICAvLyBzaG9ydC1saXZlZCBKV1QgKGNhY2hlZCBpbi1wcm9jZXNzIHVudGlsIGl0IGV4cGlyZXMpIGFuZCB0aGVuIHZlcmlmeSB0aGF0XG4gIC8vIEpXVCBvbiB0aGUgbm9ybWFsIHBhdGgg4oCUIHNlcnZpY2VzIG5ldmVyIHJlYWQgYSBrZXkgaGFzaC4gU2VlXG4gIC8vIGBzZXJ2aWNlcy9hcGkta2V5LWV4Y2hhbmdlLnRzYC5cbiAgaWYgKGlzT3BhcXVlQXBpS2V5KHBhcnRzWzFdKSkge1xuICAgIHZvaWQgcmVzb2x2ZUFwaUtleShvcHRpb25zLCBwYXJ0c1sxXSwgcmVxLCByZXMsIG5leHQpO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIC8vIGAuY2F0Y2gobmV4dClgIGZvcndhcmRzIGEgRE9XTlNUUkVBTSBzeW5jaHJvbm91cyB0aHJvdyBmcm9tIGBuZXh0KClgIHRvXG4gIC8vIEV4cHJlc3MncyBlcnJvciBtaWRkbGV3YXJlIOKAlCB2ZXJpZmljYXRpb24gaXRzZWxmIG5ldmVyIHJlamVjdHMgKGl0IG1hcHNcbiAgLy8gZXZlcnkgZmFpbHVyZSB0byBhIHJlc3BvbnNlKS5cbiAgdm9pZCB2ZXJpZnlBbmRBdHRhY2gob3B0aW9ucywgcGFydHNbMV0sIHJlcSwgcmVzLCBuZXh0KS5jYXRjaChuZXh0KTtcbn1cblxuLyoqXG4gKiBFeGNoYW5nZSBhbiBvcGFxdWUga2V5IGZvciBhIEpXVCwgdGhlbiBjb250aW51ZSBvbiB0aGUgbm9ybWFsIHZlcmlmaWNhdGlvblxuICogcGF0aC4gQSByZWZ1c2VkIGtleSBpcyBhIDQwMTsgYW4gdW5yZWFjaGFibGUgcGxhdGZvcm0gaXMgYSA1MDMgKG5ldmVyIGEgcGFzcyDigJRcbiAqIGFuIHVudmVyaWZpYWJsZSBjcmVkZW50aWFsIGlzIG5vdCBhbiBpZGVudGl0eSkuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHJlc29sdmVBcGlLZXkoXG4gIG9wdGlvbnM6IFJlcXVpcmVBdXRoT3B0aW9ucyxcbiAga2V5OiBzdHJpbmcsXG4gIHJlcTogUmVxdWVzdCxcbiAgcmVzOiBSZXNwb25zZSxcbiAgbmV4dDogTmV4dEZ1bmN0aW9uLFxuKTogUHJvbWlzZTx2b2lkPiB7XG4gIC8vIExvYWRlZCBMQVpJTFksIG9uIHRoZSBmaXJzdCBrZXkgZXZlciBwcmVzZW50ZWQuIEEgc3RhdGljIGltcG9ydCB3b3VsZCBwdXRcbiAgLy8gdGhlIEhUVFAgY2xpZW50IChhbmQgcGxhdGZvcm0ncyBhZGRyZXNzKSBpbnRvIHRoZSBpbXBvcnQgZ3JhcGggb2YgZXZlcnlcbiAgLy8gbW9kdWxlIHRoYXQgbWVyZWx5IHVzZXMgYHJlcXVpcmVBdXRoYCwgd2hpY2ggYm90aCB3aWRlbnMgdGhlIGJvb3QgZ3JhcGggYW5kXG4gIC8vIGJyZWFrcyBhbnkgdGVzdCB0aGF0IG1vY2tzIGBodHRwLWNsaWVudC5qc2Agd2l0aCBhIHBhcnRpYWwgbW9kdWxlLlxuICBjb25zdCB7IGV4Y2hhbmdlQXBpS2V5LCBBcGlLZXlFeGNoYW5nZVVuYXZhaWxhYmxlRXJyb3IgfSA9IGF3YWl0IGltcG9ydCgnLi4vc2VydmljZXMvYXBpLWtleS1leGNoYW5nZS5qcycpO1xuICBsZXQgdG9rZW46IHN0cmluZztcbiAgdHJ5IHtcbiAgICB0b2tlbiA9IGF3YWl0IGV4Y2hhbmdlQXBpS2V5KGtleSk7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgaWYgKGVycm9yIGluc3RhbmNlb2YgQXBpS2V5RXhjaGFuZ2VVbmF2YWlsYWJsZUVycm9yKSB7XG4gICAgICByZXR1cm4gc2VuZEVycm9yKFxuICAgICAgICByZXMsIEh0dHBTdGF0dXMuU0VSVklDRV9VTkFWQUlMQUJMRSxcbiAgICAgICAgJ0FjY2Vzcy1rZXkgdmVyaWZpY2F0aW9uIGlzIHRlbXBvcmFyaWx5IHVuYXZhaWxhYmxlOyBwbGVhc2UgcmV0cnknLFxuICAgICAgICBFcnJvckNvZGUuU0VSVklDRV9VTkFWQUlMQUJMRSxcbiAgICAgICk7XG4gICAgfVxuICAgIHJldHVybiBzZW5kRXJyb3IocmVzLCBIdHRwU3RhdHVzLlVOQVVUSE9SSVpFRCwgJ0ludmFsaWQgb3IgcmV2b2tlZCBhY2Nlc3Mga2V5JywgRXJyb3JDb2RlLlRPS0VOX0lOVkFMSUQpO1xuICB9XG4gIGF3YWl0IHZlcmlmeUFuZEF0dGFjaChvcHRpb25zLCB0b2tlbiwgcmVxLCByZXMsIG5leHQpO1xufVxuXG5hc3luYyBmdW5jdGlvbiB2ZXJpZnlBbmRBdHRhY2goXG4gIG9wdGlvbnM6IFJlcXVpcmVBdXRoT3B0aW9ucyxcbiAgcmF3VG9rZW46IHN0cmluZyxcbiAgcmVxOiBSZXF1ZXN0LFxuICByZXM6IFJlc3BvbnNlLFxuICBuZXh0OiBOZXh0RnVuY3Rpb24sXG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgdHJ5IHtcbiAgICAvLyBUd28gY2hhaW5zLCBvbmUgZW50cnkgcG9pbnQgKHNlZSBgdmVyaWZ5QmVhcmVyVG9rZW5gKTogYSB1c2VyIHRva2VuIG11c3RcbiAgICAvLyBiZSBFUzI1NiBzaWduZWQgYnkgcGxhdGZvcm0gYW5kIHZlcmlmaWVkIGFnYWluc3QgaXRzIHB1Ymxpc2hlZCBKV0tTOyBhblxuICAgIC8vIGludGVybmFsIHNlcnZpY2UgdG9rZW4gbXVzdCBiZSBFUzI1NiBzaWduZWQgYnkgdGhhdCBzZXJ2aWNlJ3MgT1dOIGtleSBhbmRcbiAgICAvLyBkZWNsYXJlIGl0c2VsZiBhIHNlcnZpY2UgcHJpbmNpcGFsLiBCb3RoIHBpbiB0aGUgYWxnb3JpdGhtIChub1xuICAgIC8vIGFsZy1jb25mdXNpb24sIG5vIGBhbGc6bm9uZWApIGFuZCBib3RoIGFwcGx5IHRoZSBvcHRpb25hbCBpc3N1ZXIvYXVkaWVuY2VcbiAgICAvLyBiaW5kaW5nLlxuICAgIGNvbnN0IGRlY29kZWQgPSBhd2FpdCB2ZXJpZnlCZWFyZXJUb2tlbihyYXdUb2tlbik7XG5cbiAgICBpZiAoZGVjb2RlZC50eXBlICE9PSAnYWNjZXNzJykge1xuICAgICAgcmV0dXJuIHNlbmRFcnJvcihyZXMsIEh0dHBTdGF0dXMuVU5BVVRIT1JJWkVELCAnT25seSBhY2Nlc3MgdG9rZW5zIGNhbiBiZSB1c2VkIGZvciBBUEkgcmVxdWVzdHMnLCBFcnJvckNvZGUuVE9LRU5fSU5WQUxJRCk7XG4gICAgfVxuXG4gICAgaWYgKCFkZWNvZGVkLnN1YiB8fCAhZGVjb2RlZC5yb2xlIHx8ICFoYXNWYWxpZElkZW50aXR5Q2xhaW1zKGRlY29kZWQpKSB7XG4gICAgICByZXR1cm4gc2VuZEVycm9yKHJlcywgSHR0cFN0YXR1cy5VTkFVVEhPUklaRUQsICdUb2tlbiBtaXNzaW5nIHJlcXVpcmVkIGZpZWxkcycsIEVycm9yQ29kZS5UT0tFTl9JTlZBTElEKTtcbiAgICB9XG5cbiAgICAvLyBTZXJ2aWNlLXRva2VuIGtpbGwtc3dpdGNoOiByZWplY3QgYSBzZXJ2aWNlIHByaW5jaXBhbCB3aG9zZSBzZXJ2aWNlIGhhc1xuICAgIC8vIGJlZW4gYWRkZWQgdG8gdGhlIGRlbnlsaXN0LiBPdGhlcndpc2UgdGhlIG9ubHkgd2F5IHRvIGludmFsaWRhdGUgYVxuICAgIC8vIHNlcnZpY2UncyB0b2tlbnMgYmVmb3JlIHRoZWlyIChzaG9ydCkgVFRMIGlzIHJvdGF0aW5nIHRoYXQgc2VydmljZSdzXG4gICAgLy8gc2lnbmluZyBrZXk7IHRoaXMgY3V0cyBvbmUgY29tcHJvbWlzZWQvcm9ndWUgc2VydmljZSBvZmYgaW1tZWRpYXRlbHkuIE8oMSkgU2V0IGxvb2t1cCwgemVybyBjb3N0IHdoZW4gdGhlIGRlbnlsaXN0XG4gICAgLy8gaXMgZW1wdHkgKHRoZSBkZWZhdWx0KSwgc28gaXQgbmV2ZXIgdGF4ZXMgdGhlIFMyUyBob3QgcGF0aCB1bmxlc3MgYXJtZWQuXG4gICAgaWYgKGlzU2VydmljZVRva2VuRGVuaWVkKGRlY29kZWQpKSB7XG4gICAgICBlbWl0Q291bnRlcignc2VydmljZV90b2tlbl9kZW5pZWRfdG90YWwnLCB7IHNlcnZpY2U6IHNlcnZpY2VOYW1lT2YoZGVjb2RlZCkgPz8gJ3Vua25vd24nIH0pO1xuICAgICAgbG9nZ2VyLndhcm4oJ1JlamVjdGVkIGRlbnlsaXN0ZWQgc2VydmljZSB0b2tlbicsIHsgc3ViOiBkZWNvZGVkLnN1YiB9KTtcbiAgICAgIHJldHVybiBzZW5kRXJyb3IocmVzLCBIdHRwU3RhdHVzLlVOQVVUSE9SSVpFRCwgJ1NlcnZpY2UgdG9rZW4gcmV2b2tlZCcsIEVycm9yQ29kZS5UT0tFTl9SRVZPS0VEKTtcbiAgICB9XG5cbiAgICByZXEudXNlciA9IHsgLi4uZGVjb2RlZCB9O1xuXG4gICAgLy8gUkVBRC1PTkxZIElNUEVSU09OQVRJT04uIFRoZSB0b2tlbiBuYW1lcyB0aGUgb3BlcmF0b3IgQU5EIHNheXMgaXQgbWF5IG9ubHlcbiAgICAvLyBsb29rOiBldmVyeSBzZXJ2aWNlIHJlZnVzZXMgYSBzdGF0ZSBjaGFuZ2UgdW5kZXIgaXQsIG5vdCBvbmx5IHBsYXRmb3JtIOKAlFxuICAgIC8vIGEgc3VwcG9ydCBzZXNzaW9uIHRoYXQgY291bGQgd3JpdGUgdG8gcGx1Z2luL2NvbXBsaWFuY2UvYmlsbGluZyBpcyBub3RcbiAgICAvLyByZWFkLW9ubHkuIENoZWNrZWQgYmVmb3JlIGFueSBvdGhlciBnYXRlIHNvIG5vIHJvdXRlIGNhbiBmb3JnZXQgaXQuXG4gICAgaWYgKGlzSW1wZXJzb25hdGlvbldyaXRlQmxvY2tlZChyZXEubWV0aG9kLCBkZWNvZGVkKSkge1xuICAgICAgaWYgKHJlcS5tZXRob2QpIHJlY29yZEF1dGh6RGVuaWFsKHJlcSwgJ2ltcGVyc29uYXRpb24tcmVhZC1vbmx5Jyk7XG4gICAgICByZXR1cm4gc2VuZEVycm9yKFxuICAgICAgICByZXMsIEh0dHBTdGF0dXMuRk9SQklEREVOLFxuICAgICAgICAnV3JpdGUgcmVxdWVzdHMgYXJlIGRpc2FibGVkIGR1cmluZyByZWFkLW9ubHkgaW1wZXJzb25hdGlvbi4gU3RvcCBpbXBlcnNvbmF0aW5nIHRvIG1ha2UgY2hhbmdlcy4nLFxuICAgICAgICBFcnJvckNvZGUuSU1QRVJTT05BVElPTl9SRUFEX09OTFksXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIEJPT1RTVFJBUC1BRE1JTiBFTlJPTE1FTlQgU0VTU0lPTi4gU3VjaCBhIHRva2VuIGV4aXN0cyBzb1xuICAgIC8vIHRoZSBpbnN0YWxsJ3Mgb25seSBhZG1pbiBjYW4gZW5yb2wgYSBmYWN0b3I7IGl0IGlzIGBhYWw6IDFgIGFuZCBtdXN0IG5vdFxuICAgIC8vIHJlYWNoIGFueXRoaW5nIGVsc2UuIFBsYXRmb3JtIOKAlCB3aGljaCBvd25zIHRoZSBleGNlcHRpb24gYW5kIGtub3dzIHdoaWNoXG4gICAgLy8gb2YgaXRzIG93biByb3V0ZXMgYGluaXQtcGxhdGZvcm0uc2hgIGNhbGxzIOKAlCBhbGxvd3MgYW4gZXhwbGljaXQgZmV3IGJlZm9yZVxuICAgIC8vIHRoaXMgcG9pbnQgKHNlZSBpdHMgb3duIGByZXF1aXJlQXV0aGApOyBpbiBFVkVSWSBvdGhlciBzZXJ2aWNlIHRoZSBhbnN3ZXJcbiAgICAvLyBpcyBzaW1wbHkgbm8sIHNvIHRoZSByZWFjaCByZXN0cmljdGlvbiBob2xkcyB3aXRob3V0IGEgcGVyLXNlcnZpY2VcbiAgICAvLyBhbGxvd2xpc3QgdG8ga2VlcCBpbiBzeW5jLlxuICAgIGlmIChkZWNvZGVkLm1mYUVucm9sbG1lbnRQZW5kaW5nID09PSB0cnVlKSB7XG4gICAgICBlbWl0Q291bnRlcignbWZhX2VuZm9yY2VtZW50X3JlZnVzZWRfdG90YWwnLCB7IHNlcnZpY2U6IHNlcnZpY2VJZGVudGl0eSgpLCByZWFzb246ICdib290c3RyYXBfc2Vzc2lvbicgfSk7XG4gICAgICByZWNvcmRBdXRoekRlbmlhbChyZXEsICdtZmEtZW5yb2xtZW50Jyk7XG4gICAgICByZXR1cm4gc2VuZEVycm9yKFxuICAgICAgICByZXMsIEh0dHBTdGF0dXMuRk9SQklEREVOLFxuICAgICAgICAnRmluaXNoIHNldHRpbmcgdXAgdHdvLWZhY3RvciBhdXRoZW50aWNhdGlvbiBiZWZvcmUgdXNpbmcgdGhlIHJlc3Qgb2YgUGlwZWxpbmUgQnVpbGRlcicsXG4gICAgICAgIEVycm9yQ29kZS5NRkFfRU5ST0xMTUVOVF9SRVFVSVJFRCxcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gU2Vzc2lvbi1sZXZlbCBhc3N1cmFuY2UgKGByZXF1aXJlQXV0aCh7IG1pbkFzc3VyYW5jZSwgbWF4QWdlIH0pYCkuXG4gICAgaWYgKG9wdGlvbnMubWluQXNzdXJhbmNlXG4gICAgICAmJiByZWZ1c2VGb3JBc3N1cmFuY2UoeyBtaW5Bc3N1cmFuY2U6IG9wdGlvbnMubWluQXNzdXJhbmNlLCAuLi4ob3B0aW9ucy5tYXhBZ2UgIT09IHVuZGVmaW5lZCA/IHsgbWF4QWdlOiBvcHRpb25zLm1heEFnZSB9IDoge30pIH0sIGRlY29kZWQsIHJlcSwgcmVzKSkgcmV0dXJuO1xuXG4gICAgLy8gVGhlIHgtb3JnLWlkL3gtb3JnLW5hbWUgb3ZlcnJpZGUgbGV0cyBhIFNZUy1BRE1JTiBhY3Qgb24gYSBjaG9zZW4gb3JnXG4gICAgLy8gKGNyb3NzLW9yZyBhZG1pbiB0b29saW5nKS4gSXQgaXMgZ2F0ZWQgb24gdGhlIHZlcmlmaWVkIGBpc1N1cGVyQWRtaW5gIGNsYWltXG4gICAgLy8gaGVyZSBzbyB0aGF0IGV2ZW4gYSByb3V0ZSB3aGljaCBtaXN0YWtlbmx5IGVuYWJsZXMgYGFsbG93T3JnSGVhZGVyT3ZlcnJpZGVgXG4gICAgLy8gY2FuIE5FVkVSIGxldCBhbiBvcmRpbmFyeSBhdXRoZW50aWNhdGVkIHVzZXIgc3Bvb2YgYW5vdGhlciB0ZW5hbnQncyBvcmcgdmlhXG4gICAgLy8gdGhlIGhlYWRlciDigJQgZGVmZW5jZS1pbi1kZXB0aCBhZ2FpbnN0IHRoZSBjcm9zcy10ZW5hbnQgYnJlYWsgdGhpcyBjYXVzZWQuXG4gICAgaWYgKG9wdGlvbnMuYWxsb3dPcmdIZWFkZXJPdmVycmlkZSAmJiBkZWNvZGVkLmlzU3VwZXJBZG1pbiA9PT0gdHJ1ZSkge1xuICAgICAgY29uc3QgaGVhZGVyT3JnSWQgPSBnZXRIZWFkZXJTdHJpbmcocmVxLmhlYWRlcnNbJ3gtb3JnLWlkJ10pO1xuICAgICAgY29uc3QgaGVhZGVyT3JnTmFtZSA9IGdldEhlYWRlclN0cmluZyhyZXEuaGVhZGVyc1sneC1vcmctbmFtZSddKTtcbiAgICAgIGlmIChoZWFkZXJPcmdJZCkgcmVxLnVzZXIub3JnYW5pemF0aW9uSWQgPSBoZWFkZXJPcmdJZDtcbiAgICAgIGlmIChoZWFkZXJPcmdOYW1lKSByZXEudXNlci5vcmdhbml6YXRpb25OYW1lID0gaGVhZGVyT3JnTmFtZTtcbiAgICB9XG5cbiAgICAvLyBSZS1kZXJpdmUgdGhlIHJlcXVlc3QncyB0ZW5hbnQgaWRlbnRpdHkgZnJvbSB0aGUgTk9XLXZlcmlmaWVkIEpXVC5cbiAgICAvL1xuICAgIC8vIGBhdHRhY2hSZXF1ZXN0Q29udGV4dGAgcnVucyBhcyBhIGdsb2JhbCBtaWRkbGV3YXJlIEJFRk9SRSB0aGlzIHBlci1yb3V0ZVxuICAgIC8vIGByZXF1aXJlQXV0aGAsIHNvIGl0IGNhcHR1cmVkIGByZXEuY29udGV4dC5pZGVudGl0eWAgd2hpbGUgYHJlcS51c2VyYCB3YXNcbiAgICAvLyBzdGlsbCB1bmRlZmluZWQg4oCUIGF0IHdoaWNoIHBvaW50IGBnZXRJZGVudGl0eWAgZmFsbHMgYmFjayB0byB0aGUgcmF3LFxuICAgIC8vIGNsaWVudC1zZXR0YWJsZSBgeC1vcmctaWRgL2B4LXVzZXItaWRgIGhlYWRlcnMuIEV2ZXJ5IGRvd25zdHJlYW0gdGVuYW50LVxuICAgIC8vIGF1dGhvcml0eSBjb25zdW1lciAocmVxdWlyZU9yZ0lkLCB3aXRoVGVuYW50Q29udGV4dCdzIFJMUyBzY29wZSwgY2hlY2tRdW90YSxcbiAgICAvLyB3aXRoUm91dGUsIGFuZCB0aGUgaWRlbXBvdGVuY3kgbmFtZXNwYWNlKSByZWFkcyBgcmVxLmNvbnRleHQuaWRlbnRpdHlgLCBzb1xuICAgIC8vIHRoYXQgZnJvemVuIGhlYWRlci1kZXJpdmVkIHZhbHVlIOKAlCBub3QgdGhlIEpXVCDigJQgd2FzIGdvdmVybmluZyB0ZW5hbmN5IG9uXG4gICAgLy8gYW55IG5vbi1uZ2lueCBwYXRoLiBSZWNvbXB1dGluZyBoZXJlLCBhdCB0aGUgc2luZ2xlIHBvc3QtdmVyaWZpY2F0aW9uIGNob2tlXG4gICAgLy8gcG9pbnQsIG1ha2VzIGBnZXRJZGVudGl0eWAgcHJlZmVyIHRoZSB2ZXJpZmllZCBgcmVxLnVzZXJgIChzZWUgaWRlbnRpdHkudHMpXG4gICAgLy8gc28gdGVuYW5jeSBpcyBKV1QtYXV0aG9yaXRhdGl2ZS4gVGhlIG5naW54IGB4LW9yZy1pZGAgb3ZlcndyaXRlIHN0YXlzIGFzXG4gICAgLy8gZGVmZW5jZS1pbi1kZXB0aC4gR3VhcmRlZCBvbiBgcmVxLmNvbnRleHRgIHNvIHNlcnZpY2VzL3BhdGhzIHRoYXQgbmV2ZXJcbiAgICAvLyBhdHRhY2ggYSBjb250ZXh0IChvciBydW4gcmVxdWlyZUF1dGggcHJlLWNvbnRleHQpIGFyZSB1bmFmZmVjdGVkLlxuICAgIGNvbnN0IHJlcUN0eCA9IChyZXEgYXMgUmVxdWVzdCAmIHsgY29udGV4dD86IHsgaWRlbnRpdHk6IFJlcXVlc3RJZGVudGl0eSB9IH0pLmNvbnRleHQ7XG4gICAgaWYgKHJlcUN0eCkge1xuICAgICAgcmVxQ3R4LmlkZW50aXR5ID0gZ2V0SWRlbnRpdHkocmVxIGFzIHVua25vd24gYXMgSHR0cFJlcXVlc3QpO1xuICAgIH1cblxuICAgIC8vIFNlc3Npb24gaW52YWxpZGF0aW9uICh0b2tlbi12ZXJzaW9uIHN0b3JlICsgaW1wZXJzb25hdGlvbi1zZXNzaW9uXG4gICAgLy8gbGl2ZW5lc3MpLiBObyBzdG9yZSByZWdpc3RlcmVkIOKHkiBvbmx5IGltcGVyc29uYXRpb24gc2Vzc2lvbnMgYXJlIGNoZWNrZWQuXG4gICAgaWYgKG5lZWRzUmV2b2NhdGlvbkNoZWNrKGRlY29kZWQpKSB7XG4gICAgICAvLyBgLmNhdGNoKG5leHQpYCBmb3J3YXJkcyBhIERPV05TVFJFQU0gc3luY2hyb25vdXMgdGhyb3cgZnJvbSBgbmV4dCgpYCB0b1xuICAgICAgLy8gRXhwcmVzcydzIGVycm9yIG1pZGRsZXdhcmUg4oCUIHRoaXMgYG5leHQoKWAgcnVucyBpbiBhIG1pY3JvdGFzaywgb3V0c2lkZVxuICAgICAgLy8gdGhlIHN1cnJvdW5kaW5nIHRyeS9jYXRjaC4gVGhlIGNoZWNrIGl0c2VsZiBuZXZlciByZWplY3RzLlxuICAgICAgY2hlY2tSZXZvY2F0aW9uKGRlY29kZWQpLnRoZW4oKHJlZnVzYWwpID0+IHtcbiAgICAgICAgaWYgKHJlZnVzYWwpIHJldHVybiBzZW5kRXJyb3IocmVzLCBIdHRwU3RhdHVzLlVOQVVUSE9SSVpFRCwgcmVmdXNhbCwgRXJyb3JDb2RlLlRPS0VOX1JFVk9LRUQpO1xuICAgICAgICBuZXh0KCk7XG4gICAgICB9KS5jYXRjaChuZXh0KTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBuZXh0KCk7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgaWYgKGVycm9yIGluc3RhbmNlb2Ygand0LlRva2VuRXhwaXJlZEVycm9yKSB7XG4gICAgICByZXR1cm4gc2VuZEVycm9yKHJlcywgSHR0cFN0YXR1cy5VTkFVVEhPUklaRUQsICdUb2tlbiBoYXMgZXhwaXJlZCcsIEVycm9yQ29kZS5UT0tFTl9FWFBJUkVEKTtcbiAgICB9XG5cbiAgICAvLyBUaGUgc2lnbmluZyBrZXlzIGNvdWxkbid0IGJlIGZldGNoZWQsIHNvIHRoZSB0b2tlbidzIHZhbGlkaXR5IGlzIFVOS05PV04uXG4gICAgLy8gRmFpbCBDTE9TRUQgd2l0aCBhIHJldHJ5YWJsZSA1MDMg4oCUIG5ldmVyIGEgcGFzcywgYW5kIG5ldmVyIGEgNDAxIHRoYXRcbiAgICAvLyB3b3VsZCBzZW5kIGEgbGVnaXRpbWF0ZSBjbGllbnQgb2ZmIHRvIHJlLWF1dGhlbnRpY2F0ZSBvdmVyIG91ciBvdXRhZ2UuXG4gICAgLy8gU2FtZSByZWFzb25pbmcgZm9yIHRoZSBTRVJWSUNFIGNoYWluOiBubyByZWFkYWJsZSBrZXkgYnVuZGxlIG1lYW5zIG5vIHdheVxuICAgIC8vIHRvIHRlbGwgYSBwZWVyJ3MgdG9rZW4gZnJvbSBhIGZvcmdlcnksIHNvIHRoZSByZXF1ZXN0IGlzIHJlZnVzZWQgd2l0aCBhXG4gICAgLy8gcmV0cnlhYmxlIDUwMyByYXRoZXIgdGhhbiBhZG1pdHRlZCBvciBib3VuY2VkIHRvIHJlLWF1dGhlbnRpY2F0ZS5cbiAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBKd2tzVW5hdmFpbGFibGVFcnJvciB8fCBlcnJvciBpbnN0YW5jZW9mIFNlcnZpY2VLZXlFcnJvcikge1xuICAgICAgbG9nZ2VyLndhcm4oJ1JlamVjdGluZyByZXF1ZXN0OiB0b2tlbiBzaWduaW5nIGtleXMgdW5hdmFpbGFibGUnLCB7IGVycm9yOiBlcnJvci5tZXNzYWdlIH0pO1xuICAgICAgcmV0dXJuIHNlbmRFcnJvcihcbiAgICAgICAgcmVzLCBIdHRwU3RhdHVzLlNFUlZJQ0VfVU5BVkFJTEFCTEUsXG4gICAgICAgICdUb2tlbiB2ZXJpZmljYXRpb24gaXMgdGVtcG9yYXJpbHkgdW5hdmFpbGFibGU7IHBsZWFzZSByZXRyeScsXG4gICAgICAgIEVycm9yQ29kZS5TRVJWSUNFX1VOQVZBSUxBQkxFLFxuICAgICAgKTtcbiAgICB9XG5cbiAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBVbmtub3duS2lkRXJyb3IgfHwgZXJyb3IgaW5zdGFuY2VvZiBqd3QuSnNvbldlYlRva2VuRXJyb3IpIHtcbiAgICAgIHJldHVybiBzZW5kRXJyb3IocmVzLCBIdHRwU3RhdHVzLlVOQVVUSE9SSVpFRCwgJ0ludmFsaWQgdG9rZW4nLCBFcnJvckNvZGUuVE9LRU5fSU5WQUxJRCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHNlbmRFcnJvcihyZXMsIEh0dHBTdGF0dXMuVU5BVVRIT1JJWkVELCAnQXV0aGVudGljYXRpb24gZmFpbGVkJywgRXJyb3JDb2RlLlVOQVVUSE9SSVpFRCk7XG4gIH1cbn1cblxuIl19
|