@dbx-tools/email 0.6.41 → 0.6.43

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.
@@ -0,0 +1,135 @@
1
+ /**
2
+ * One-time-code store + session JWT for the email-OTP gate.
3
+ *
4
+ * Two pieces:
5
+ *
6
+ * - **Code store** - a 6-digit code is generated with `crypto.randomInt` and
7
+ * kept server-side as a SHA-256 hash with an expiry and an attempt counter
8
+ * (never the plaintext, never in the JWT). `verifyCode` is constant-time on
9
+ * the hash, enforces the TTL, and burns the code after too many attempts or
10
+ * one success. In-memory `Map` keyed by lowercased email - fine for a
11
+ * single-instance app behind a tunnel.
12
+ * - **Session JWT** - on a correct code, `signSession` mints a short-lived
13
+ * HS256 JWT (via `jose`) carrying only the email; `verifySession` validates
14
+ * it. The signing key comes from `AUTH_JWT_SECRET`; when unset the gate
15
+ * FAILS OPEN with an ephemeral per-process key (sessions reset on restart)
16
+ * rather than refusing service - a Databricks App is already access-limited,
17
+ * so an unset secret degrades to "sessions don't survive restarts", not
18
+ * "nobody can log in".
19
+ *
20
+ * @module
21
+ */
22
+ import { createHash, randomBytes, randomInt, timingSafeEqual } from "node:crypto";
23
+ import { jwtVerify, SignJWT } from "jose";
24
+ import { log } from "@dbx-tools/shared-core";
25
+ const logger = log.logger("email:auth:otp");
26
+ /** JWT issuer/audience so a token minted for this gate isn't accepted elsewhere. */
27
+ const JWT_AUD = "dbx-tools-email-auth";
28
+ /** SHA-256 hex of a value (for the stored code + a stable key comparison). */
29
+ function sha256(value) {
30
+ return createHash("sha256").update(value).digest("hex");
31
+ }
32
+ /** Constant-time compare of two hex digests of equal length. */
33
+ function safeEqualHex(a, b) {
34
+ if (a.length !== b.length)
35
+ return false;
36
+ return timingSafeEqual(Buffer.from(a, "hex"), Buffer.from(b, "hex"));
37
+ }
38
+ /** In-memory store of pending one-time codes, keyed by lowercased email. */
39
+ export class CodeStore {
40
+ ttlMs;
41
+ maxAttempts;
42
+ codes = new Map();
43
+ constructor(ttlMs, maxAttempts) {
44
+ this.ttlMs = ttlMs;
45
+ this.maxAttempts = maxAttempts;
46
+ }
47
+ /**
48
+ * Generate, store (hashed), and RETURN a fresh 6-digit code for `email`. The
49
+ * caller emails the returned plaintext; only the hash is retained. Replaces
50
+ * any pending code for the address.
51
+ */
52
+ issue(email, now = Date.now()) {
53
+ const code = String(randomInt(0, 1_000_000)).padStart(6, "0");
54
+ this.codes.set(email.toLowerCase(), {
55
+ hash: sha256(code),
56
+ expiresAt: now + this.ttlMs,
57
+ attempts: 0,
58
+ });
59
+ return code;
60
+ }
61
+ /**
62
+ * Check `code` for `email`. Consumes the entry on success or when attempts are
63
+ * exhausted, so a code is single-use and can't be brute-forced past the cap.
64
+ */
65
+ verify(email, code, now = Date.now()) {
66
+ const key = email.toLowerCase();
67
+ const entry = this.codes.get(key);
68
+ if (!entry)
69
+ return "invalid";
70
+ if (now >= entry.expiresAt) {
71
+ this.codes.delete(key);
72
+ return "expired";
73
+ }
74
+ entry.attempts += 1;
75
+ if (safeEqualHex(entry.hash, sha256(code))) {
76
+ this.codes.delete(key);
77
+ return "ok";
78
+ }
79
+ if (entry.attempts >= this.maxAttempts) {
80
+ this.codes.delete(key);
81
+ return "too-many-attempts";
82
+ }
83
+ return "invalid";
84
+ }
85
+ /** Drop every pending code (tests). */
86
+ clear() {
87
+ this.codes.clear();
88
+ }
89
+ }
90
+ /**
91
+ * Resolve the HS256 signing key. Prefers `AUTH_JWT_SECRET`; when unset, mints an
92
+ * ephemeral per-process key (fail-open) and warns once. Memoized so every
93
+ * sign/verify in a process shares one key.
94
+ */
95
+ let cachedKey;
96
+ function signingKey() {
97
+ if (cachedKey)
98
+ return cachedKey;
99
+ const secret = process.env.AUTH_JWT_SECRET?.trim();
100
+ if (secret) {
101
+ cachedKey = new TextEncoder().encode(secret);
102
+ }
103
+ else {
104
+ logger.warn("AUTH_JWT_SECRET is not set - using an ephemeral per-process key; sessions will not survive a restart");
105
+ cachedKey = randomBytes(32);
106
+ }
107
+ return cachedKey;
108
+ }
109
+ /** Reset the memoized key (tests, or after changing the env in-process). */
110
+ export function resetSigningKey() {
111
+ cachedKey = undefined;
112
+ }
113
+ /** Mint a short-lived session JWT for `email`, expiring in `ttlSeconds`. */
114
+ export async function signSession(email, ttlSeconds) {
115
+ return new SignJWT({ email })
116
+ .setProtectedHeader({ alg: "HS256" })
117
+ .setSubject(email)
118
+ .setAudience(JWT_AUD)
119
+ .setIssuedAt()
120
+ .setExpirationTime(`${ttlSeconds}s`)
121
+ .sign(signingKey());
122
+ }
123
+ /** Validate a session JWT, returning the email it was minted for, or `undefined`. */
124
+ export async function verifySession(token) {
125
+ if (!token)
126
+ return undefined;
127
+ try {
128
+ const { payload } = await jwtVerify(token, signingKey(), { audience: JWT_AUD });
129
+ return typeof payload.email === "string" ? payload.email : undefined;
130
+ }
131
+ catch {
132
+ return undefined;
133
+ }
134
+ }
135
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3RwLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2F1dGgvb3RwLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQW9CRztBQUVILE9BQU8sRUFBRSxVQUFVLEVBQUUsV0FBVyxFQUFFLFNBQVMsRUFBRSxlQUFlLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDbEYsT0FBTyxFQUFFLFNBQVMsRUFBRSxPQUFPLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDMUMsT0FBTyxFQUFFLEdBQUcsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBRTdDLE1BQU0sTUFBTSxHQUFHLEdBQUcsQ0FBQyxNQUFNLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztBQUU1QyxvRkFBb0Y7QUFDcEYsTUFBTSxPQUFPLEdBQUcsc0JBQXNCLENBQUM7QUFFdkMsOEVBQThFO0FBQzlFLFNBQVMsTUFBTSxDQUFDLEtBQWE7SUFDM0IsT0FBTyxVQUFVLENBQUMsUUFBUSxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztBQUMxRCxDQUFDO0FBRUQsZ0VBQWdFO0FBQ2hFLFNBQVMsWUFBWSxDQUFDLENBQVMsRUFBRSxDQUFTO0lBQ3hDLElBQUksQ0FBQyxDQUFDLE1BQU0sS0FBSyxDQUFDLENBQUMsTUFBTTtRQUFFLE9BQU8sS0FBSyxDQUFDO0lBQ3hDLE9BQU8sZUFBZSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQyxFQUFFLEtBQUssQ0FBQyxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQyxFQUFFLEtBQUssQ0FBQyxDQUFDLENBQUM7QUFDdkUsQ0FBQztBQVdELDRFQUE0RTtBQUM1RSxNQUFNLE9BQU8sU0FBUztJQUlEO0lBQ0E7SUFKRixLQUFLLEdBQUcsSUFBSSxHQUFHLEVBQXFCLENBQUM7SUFFdEQsWUFDbUIsS0FBYSxFQUNiLFdBQW1CO1FBRG5CLFVBQUss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QUFDLEVBQUUsR0FBRyxFQUFFLE9BQU8sRUFBRSxDQUFDO1NBQ3BDLFVBQVUsQ0FBQyxLQUFLLENBQUM7U0FDakIsV0FBVyxDQUFDLE9BQU8sQ0FBQztTQUNwQixXQUFXLEVBQUU7U0FDYixpQkFBaUIsQ0FBQyxHQUFHLFVBQVUsR0FBRyxDQUFDO1NBQ25DLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDO0FBQ3hCLENBQUM7QUFFRCxxRkFBcUY7QUFDckYsTUFBTSxDQUFDLEtBQUssVUFBVSxhQUFhLENBQUMsS0FBeUI7SUFDM0QsSUFBSSxDQUFDLEtBQUs7UUFBRSxPQUFPLFNBQVMsQ0FBQztJQUM3QixJQUFJLENBQUM7UUFDSCxNQUFNLEVBQUUsT0FBTyxFQUFFLEdBQUcsTUFBTSxTQUFTLENBQUMsS0FBSyxFQUFFLFVBQVUsRUFBRSxFQUFFLEVBQUUsUUFBUSxFQUFFLE9BQU8sRUFBRSxDQUFDLENBQUM7UUFDaEYsT0FBTyxPQUFPLE9BQU8sQ0FBQyxLQUFLLEtBQUssUUFBUSxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7SUFDdkUsQ0FBQztJQUFDLE1BQU0sQ0FBQztRQUNQLE9BQU8sU0FBUyxDQUFDO0lBQ25CLENBQUM7QUFDSCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBPbmUtdGltZS1jb2RlIHN0b3JlICsgc2Vzc2lvbiBKV1QgZm9yIHRoZSBlbWFpbC1PVFAgZ2F0ZS5cbiAqXG4gKiBUd28gcGllY2VzOlxuICpcbiAqICAgLSAqKkNvZGUgc3RvcmUqKiAtIGEgNi1kaWdpdCBjb2RlIGlzIGdlbmVyYXRlZCB3aXRoIGBjcnlwdG8ucmFuZG9tSW50YCBhbmRcbiAqICAgICBrZXB0IHNlcnZlci1zaWRlIGFzIGEgU0hBLTI1NiBoYXNoIHdpdGggYW4gZXhwaXJ5IGFuZCBhbiBhdHRlbXB0IGNvdW50ZXJcbiAqICAgICAobmV2ZXIgdGhlIHBsYWludGV4dCwgbmV2ZXIgaW4gdGhlIEpXVCkuIGB2ZXJpZnlDb2RlYCBpcyBjb25zdGFudC10aW1lIG9uXG4gKiAgICAgdGhlIGhhc2gsIGVuZm9yY2VzIHRoZSBUVEwsIGFuZCBidXJucyB0aGUgY29kZSBhZnRlciB0b28gbWFueSBhdHRlbXB0cyBvclxuICogICAgIG9uZSBzdWNjZXNzLiBJbi1tZW1vcnkgYE1hcGAga2V5ZWQgYnkgbG93ZXJjYXNlZCBlbWFpbCAtIGZpbmUgZm9yIGFcbiAqICAgICBzaW5nbGUtaW5zdGFuY2UgYXBwIGJlaGluZCBhIHR1bm5lbC5cbiAqICAgLSAqKlNlc3Npb24gSldUKiogLSBvbiBhIGNvcnJlY3QgY29kZSwgYHNpZ25TZXNzaW9uYCBtaW50cyBhIHNob3J0LWxpdmVkXG4gKiAgICAgSFMyNTYgSldUICh2aWEgYGpvc2VgKSBjYXJyeWluZyBvbmx5IHRoZSBlbWFpbDsgYHZlcmlmeVNlc3Npb25gIHZhbGlkYXRlc1xuICogICAgIGl0LiBUaGUgc2lnbmluZyBrZXkgY29tZXMgZnJvbSBgQVVUSF9KV1RfU0VDUkVUYDsgd2hlbiB1bnNldCB0aGUgZ2F0ZVxuICogICAgIEZBSUxTIE9QRU4gd2l0aCBhbiBlcGhlbWVyYWwgcGVyLXByb2Nlc3Mga2V5IChzZXNzaW9ucyByZXNldCBvbiByZXN0YXJ0KVxuICogICAgIHJhdGhlciB0aGFuIHJlZnVzaW5nIHNlcnZpY2UgLSBhIERhdGFicmlja3MgQXBwIGlzIGFscmVhZHkgYWNjZXNzLWxpbWl0ZWQsXG4gKiAgICAgc28gYW4gdW5zZXQgc2VjcmV0IGRlZ3JhZGVzIHRvIFwic2Vzc2lvbnMgZG9uJ3Qgc3Vydml2ZSByZXN0YXJ0c1wiLCBub3RcbiAqICAgICBcIm5vYm9keSBjYW4gbG9nIGluXCIuXG4gKlxuICogQG1vZHVsZVxuICovXG5cbmltcG9ydCB7IGNyZWF0ZUhhc2gsIHJhbmRvbUJ5dGVzLCByYW5kb21JbnQsIHRpbWluZ1NhZmVFcXVhbCB9IGZyb20gXCJub2RlOmNyeXB0b1wiO1xuaW1wb3J0IHsgand0VmVyaWZ5LCBTaWduSldUIH0gZnJvbSBcImpvc2VcIjtcbmltcG9ydCB7IGxvZyB9IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1jb3JlXCI7XG5cbmNvbnN0IGxvZ2dlciA9IGxvZy5sb2dnZXIoXCJlbWFpbDphdXRoOm90cFwiKTtcblxuLyoqIEpXVCBpc3N1ZXIvYXVkaWVuY2Ugc28gYSB0b2tlbiBtaW50ZWQgZm9yIHRoaXMgZ2F0ZSBpc24ndCBhY2NlcHRlZCBlbHNld2hlcmUuICovXG5jb25zdCBKV1RfQVVEID0gXCJkYngtdG9vbHMtZW1haWwtYXV0aFwiO1xuXG4vKiogU0hBLTI1NiBoZXggb2YgYSB2YWx1ZSAoZm9yIHRoZSBzdG9yZWQgY29kZSArIGEgc3RhYmxlIGtleSBjb21wYXJpc29uKS4gKi9cbmZ1bmN0aW9uIHNoYTI1Nih2YWx1ZTogc3RyaW5nKTogc3RyaW5nIHtcbiAgcmV0dXJuIGNyZWF0ZUhhc2goXCJzaGEyNTZcIikudXBkYXRlKHZhbHVlKS5kaWdlc3QoXCJoZXhcIik7XG59XG5cbi8qKiBDb25zdGFudC10aW1lIGNvbXBhcmUgb2YgdHdvIGhleCBkaWdlc3RzIG9mIGVxdWFsIGxlbmd0aC4gKi9cbmZ1bmN0aW9uIHNhZmVFcXVhbEhleChhOiBzdHJpbmcsIGI6IHN0cmluZyk6IGJvb2xlYW4ge1xuICBpZiAoYS5sZW5ndGggIT09IGIubGVuZ3RoKSByZXR1cm4gZmFsc2U7XG4gIHJldHVybiB0aW1pbmdTYWZlRXF1YWwoQnVmZmVyLmZyb20oYSwgXCJoZXhcIiksIEJ1ZmZlci5mcm9tKGIsIFwiaGV4XCIpKTtcbn1cblxuaW50ZXJmYWNlIENvZGVFbnRyeSB7XG4gIGhhc2g6IHN0cmluZztcbiAgZXhwaXJlc0F0OiBudW1iZXI7XG4gIGF0dGVtcHRzOiBudW1iZXI7XG59XG5cbi8qKiBSZXN1bHQgb2Yge0BsaW5rIENvZGVTdG9yZS52ZXJpZnl9LiAqL1xuZXhwb3J0IHR5cGUgVmVyaWZ5T3V0Y29tZSA9IFwib2tcIiB8IFwiaW52YWxpZFwiIHwgXCJleHBpcmVkXCIgfCBcInRvby1tYW55LWF0dGVtcHRzXCI7XG5cbi8qKiBJbi1tZW1vcnkgc3RvcmUgb2YgcGVuZGluZyBvbmUtdGltZSBjb2Rlcywga2V5ZWQgYnkgbG93ZXJjYXNlZCBlbWFpbC4gKi9cbmV4cG9ydCBjbGFzcyBDb2RlU3RvcmUge1xuICBwcml2YXRlIHJlYWRvbmx5IGNvZGVzID0gbmV3IE1hcDxzdHJpbmcsIENvZGVFbnRyeT4oKTtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIHJlYWRvbmx5IHR0bE1zOiBudW1iZXIsXG4gICAgcHJpdmF0ZSByZWFkb25seSBtYXhBdHRlbXB0czogbnVtYmVyLFxuICApIHt9XG5cbiAgLyoqXG4gICAqIEdlbmVyYXRlLCBzdG9yZSAoaGFzaGVkKSwgYW5kIFJFVFVSTiBhIGZyZXNoIDYtZGlnaXQgY29kZSBmb3IgYGVtYWlsYC4gVGhlXG4gICAqIGNhbGxlciBlbWFpbHMgdGhlIHJldHVybmVkIHBsYWludGV4dDsgb25seSB0aGUgaGFzaCBpcyByZXRhaW5lZC4gUmVwbGFjZXNcbiAgICogYW55IHBlbmRpbmcgY29kZSBmb3IgdGhlIGFkZHJlc3MuXG4gICAqL1xuICBpc3N1ZShlbWFpbDogc3RyaW5nLCBub3c6IG51bWJlciA9IERhdGUubm93KCkpOiBzdHJpbmcge1xuICAgIGNvbnN0IGNvZGUgPSBTdHJpbmcocmFuZG9tSW50KDAsIDFfMDAwXzAwMCkpLnBhZFN0YXJ0KDYsIFwiMFwiKTtcbiAgICB0aGlzLmNvZGVzLnNldChlbWFpbC50b0xvd2VyQ2FzZSgpLCB7XG4gICAgICBoYXNoOiBzaGEyNTYoY29kZSksXG4gICAgICBleHBpcmVzQXQ6IG5vdyArIHRoaXMudHRsTXMsXG4gICAgICBhdHRlbXB0czogMCxcbiAgICB9KTtcbiAgICByZXR1cm4gY29kZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVjayBgY29kZWAgZm9yIGBlbWFpbGAuIENvbnN1bWVzIHRoZSBlbnRyeSBvbiBzdWNjZXNzIG9yIHdoZW4gYXR0ZW1wdHMgYXJlXG4gICAqIGV4aGF1c3RlZCwgc28gYSBjb2RlIGlzIHNpbmdsZS11c2UgYW5kIGNhbid0IGJlIGJydXRlLWZvcmNlZCBwYXN0IHRoZSBjYXAuXG4gICAqL1xuICB2ZXJpZnkoZW1haWw6IHN0cmluZywgY29kZTogc3RyaW5nLCBub3c6IG51bWJlciA9IERhdGUubm93KCkpOiBWZXJpZnlPdXRjb21lIHtcbiAgICBjb25zdCBrZXkgPSBlbWFpbC50b0xvd2VyQ2FzZSgpO1xuICAgIGNvbnN0IGVudHJ5ID0gdGhpcy5jb2Rlcy5nZXQoa2V5KTtcbiAgICBpZiAoIWVudHJ5KSByZXR1cm4gXCJpbnZhbGlkXCI7XG4gICAgaWYgKG5vdyA+PSBlbnRyeS5leHBpcmVzQXQpIHtcbiAgICAgIHRoaXMuY29kZXMuZGVsZXRlKGtleSk7XG4gICAgICByZXR1cm4gXCJleHBpcmVkXCI7XG4gICAgfVxuICAgIGVudHJ5LmF0dGVtcHRzICs9IDE7XG4gICAgaWYgKHNhZmVFcXVhbEhleChlbnRyeS5oYXNoLCBzaGEyNTYoY29kZSkpKSB7XG4gICAgICB0aGlzLmNvZGVzLmRlbGV0ZShrZXkpO1xuICAgICAgcmV0dXJuIFwib2tcIjtcbiAgICB9XG4gICAgaWYgKGVudHJ5LmF0dGVtcHRzID49IHRoaXMubWF4QXR0ZW1wdHMpIHtcbiAgICAgIHRoaXMuY29kZXMuZGVsZXRlKGtleSk7XG4gICAgICByZXR1cm4gXCJ0b28tbWFueS1hdHRlbXB0c1wiO1xuICAgIH1cbiAgICByZXR1cm4gXCJpbnZhbGlkXCI7XG4gIH1cblxuICAvKiogRHJvcCBldmVyeSBwZW5kaW5nIGNvZGUgKHRlc3RzKS4gKi9cbiAgY2xlYXIoKTogdm9pZCB7XG4gICAgdGhpcy5jb2Rlcy5jbGVhcigpO1xuICB9XG59XG5cbi8qKlxuICogUmVzb2x2ZSB0aGUgSFMyNTYgc2lnbmluZyBrZXkuIFByZWZlcnMgYEFVVEhfSldUX1NFQ1JFVGA7IHdoZW4gdW5zZXQsIG1pbnRzIGFuXG4gKiBlcGhlbWVyYWwgcGVyLXByb2Nlc3Mga2V5IChmYWlsLW9wZW4pIGFuZCB3YXJucyBvbmNlLiBNZW1vaXplZCBzbyBldmVyeVxuICogc2lnbi92ZXJpZnkgaW4gYSBwcm9jZXNzIHNoYXJlcyBvbmUga2V5LlxuICovXG5sZXQgY2FjaGVkS2V5OiBVaW50OEFycmF5IHwgdW5kZWZpbmVkO1xuZnVuY3Rpb24gc2lnbmluZ0tleSgpOiBVaW50OEFycmF5IHtcbiAgaWYgKGNhY2hlZEtleSkgcmV0dXJuIGNhY2hlZEtleTtcbiAgY29uc3Qgc2VjcmV0ID0gcHJvY2Vzcy5lbnYuQVVUSF9KV1RfU0VDUkVUPy50cmltKCk7XG4gIGlmIChzZWNyZXQpIHtcbiAgICBjYWNoZWRLZXkgPSBuZXcgVGV4dEVuY29kZXIoKS5lbmNvZGUoc2VjcmV0KTtcbiAgfSBlbHNlIHtcbiAgICBsb2dnZXIud2FybihcbiAgICAgIFwiQVVUSF9KV1RfU0VDUkVUIGlzIG5vdCBzZXQgLSB1c2luZyBhbiBlcGhlbWVyYWwgcGVyLXByb2Nlc3Mga2V5OyBzZXNzaW9ucyB3aWxsIG5vdCBzdXJ2aXZlIGEgcmVzdGFydFwiLFxuICAgICk7XG4gICAgY2FjaGVkS2V5ID0gcmFuZG9tQnl0ZXMoMzIpO1xuICB9XG4gIHJldHVybiBjYWNoZWRLZXk7XG59XG5cbi8qKiBSZXNldCB0aGUgbWVtb2l6ZWQga2V5ICh0ZXN0cywgb3IgYWZ0ZXIgY2hhbmdpbmcgdGhlIGVudiBpbi1wcm9jZXNzKS4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXNldFNpZ25pbmdLZXkoKTogdm9pZCB7XG4gIGNhY2hlZEtleSA9IHVuZGVmaW5lZDtcbn1cblxuLyoqIE1pbnQgYSBzaG9ydC1saXZlZCBzZXNzaW9uIEpXVCBmb3IgYGVtYWlsYCwgZXhwaXJpbmcgaW4gYHR0bFNlY29uZHNgLiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHNpZ25TZXNzaW9uKGVtYWlsOiBzdHJpbmcsIHR0bFNlY29uZHM6IG51bWJlcik6IFByb21pc2U8c3RyaW5nPiB7XG4gIHJldHVybiBuZXcgU2lnbkpXVCh7IGVtYWlsIH0pXG4gICAgLnNldFByb3RlY3RlZEhlYWRlcih7IGFsZzogXCJIUzI1NlwiIH0pXG4gICAgLnNldFN1YmplY3QoZW1haWwpXG4gICAgLnNldEF1ZGllbmNlKEpXVF9BVUQpXG4gICAgLnNldElzc3VlZEF0KClcbiAgICAuc2V0RXhwaXJhdGlvblRpbWUoYCR7dHRsU2Vjb25kc31zYClcbiAgICAuc2lnbihzaWduaW5nS2V5KCkpO1xufVxuXG4vKiogVmFsaWRhdGUgYSBzZXNzaW9uIEpXVCwgcmV0dXJuaW5nIHRoZSBlbWFpbCBpdCB3YXMgbWludGVkIGZvciwgb3IgYHVuZGVmaW5lZGAuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gdmVyaWZ5U2Vzc2lvbih0b2tlbjogc3RyaW5nIHwgdW5kZWZpbmVkKTogUHJvbWlzZTxzdHJpbmcgfCB1bmRlZmluZWQ+IHtcbiAgaWYgKCF0b2tlbikgcmV0dXJuIHVuZGVmaW5lZDtcbiAgdHJ5IHtcbiAgICBjb25zdCB7IHBheWxvYWQgfSA9IGF3YWl0IGp3dFZlcmlmeSh0b2tlbiwgc2lnbmluZ0tleSgpLCB7IGF1ZGllbmNlOiBKV1RfQVVEIH0pO1xuICAgIHJldHVybiB0eXBlb2YgcGF5bG9hZC5lbWFpbCA9PT0gXCJzdHJpbmdcIiA/IHBheWxvYWQuZW1haWwgOiB1bmRlZmluZWQ7XG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbn1cbiJdfQ==
@@ -0,0 +1,35 @@
1
+ /**
2
+ * A small in-memory fixed-window rate limiter for the email-OTP gate.
3
+ *
4
+ * Keyed by an arbitrary string (an email address or a client IP). Each key gets
5
+ * `max` hits per `windowMs`; the window resets on first use after it elapses.
6
+ * `hit()` returns whether the call is allowed and, when not, how many seconds
7
+ * until the window resets so a caller can surface a cooldown.
8
+ *
9
+ * In-memory is intentional and sufficient for a single-app-instance gate: an
10
+ * app behind a portr tunnel serves from one process. It is NOT a distributed
11
+ * limiter; a multi-replica deployment would need shared state. Entries are
12
+ * pruned lazily on access, so an idle key costs nothing after its window.
13
+ *
14
+ * @module
15
+ */
16
+ /** A fixed-window rate limiter over string keys. */
17
+ export declare class RateLimiter {
18
+ private readonly max;
19
+ private readonly windowMs;
20
+ private readonly windows;
21
+ constructor(max: number, windowMs: number);
22
+ /**
23
+ * Record a hit for `key`. Returns `{ allowed }`, plus `retryAfter` (seconds)
24
+ * when the limit is exceeded. A limit of `<= 0` disables limiting (always
25
+ * allowed), which lets a config turn it off without special-casing callers.
26
+ */
27
+ hit(key: string, now?: number): {
28
+ allowed: boolean;
29
+ retryAfter?: number;
30
+ };
31
+ /** Forget a key (e.g. clear a caller's window after a successful verify). */
32
+ reset(key: string): void;
33
+ /** Drop every window (tests). */
34
+ clear(): void;
35
+ }
@@ -0,0 +1,53 @@
1
+ /**
2
+ * A small in-memory fixed-window rate limiter for the email-OTP gate.
3
+ *
4
+ * Keyed by an arbitrary string (an email address or a client IP). Each key gets
5
+ * `max` hits per `windowMs`; the window resets on first use after it elapses.
6
+ * `hit()` returns whether the call is allowed and, when not, how many seconds
7
+ * until the window resets so a caller can surface a cooldown.
8
+ *
9
+ * In-memory is intentional and sufficient for a single-app-instance gate: an
10
+ * app behind a portr tunnel serves from one process. It is NOT a distributed
11
+ * limiter; a multi-replica deployment would need shared state. Entries are
12
+ * pruned lazily on access, so an idle key costs nothing after its window.
13
+ *
14
+ * @module
15
+ */
16
+ /** A fixed-window rate limiter over string keys. */
17
+ export class RateLimiter {
18
+ max;
19
+ windowMs;
20
+ windows = new Map();
21
+ constructor(max, windowMs) {
22
+ this.max = max;
23
+ this.windowMs = windowMs;
24
+ }
25
+ /**
26
+ * Record a hit for `key`. Returns `{ allowed }`, plus `retryAfter` (seconds)
27
+ * when the limit is exceeded. A limit of `<= 0` disables limiting (always
28
+ * allowed), which lets a config turn it off without special-casing callers.
29
+ */
30
+ hit(key, now = Date.now()) {
31
+ if (this.max <= 0)
32
+ return { allowed: true };
33
+ const existing = this.windows.get(key);
34
+ if (!existing || now >= existing.resetAt) {
35
+ this.windows.set(key, { count: 1, resetAt: now + this.windowMs });
36
+ return { allowed: true };
37
+ }
38
+ if (existing.count < this.max) {
39
+ existing.count += 1;
40
+ return { allowed: true };
41
+ }
42
+ return { allowed: false, retryAfter: Math.ceil((existing.resetAt - now) / 1000) };
43
+ }
44
+ /** Forget a key (e.g. clear a caller's window after a successful verify). */
45
+ reset(key) {
46
+ this.windows.delete(key);
47
+ }
48
+ /** Drop every window (tests). */
49
+ clear() {
50
+ this.windows.clear();
51
+ }
52
+ }
53
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmF0ZS1saW1pdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9hdXRoL3JhdGUtbGltaXQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7O0dBY0c7QUFPSCxvREFBb0Q7QUFDcEQsTUFBTSxPQUFPLFdBQVc7SUFJSDtJQUNBO0lBSkYsT0FBTyxHQUFHLElBQUksR0FBRyxFQUFrQixDQUFDO0lBRXJELFlBQ21CLEdBQVcsRUFDWCxRQUFnQjtRQURoQixRQUFHLEdBQUgsR0FBRyxDQUFRO1FBQ1gsYUFBUSxHQUFSLFFBQVEsQ0FBUTtJQUNoQyxDQUFDO0lBRUo7Ozs7T0FJRztJQUNILEdBQUcsQ0FBQyxHQUFXLEVBQUUsTUFBYyxJQUFJLENBQUMsR0FBRyxFQUFFO1FBQ3ZDLElBQUksSUFBSSxDQUFDLEdBQUcsSUFBSSxDQUFDO1lBQUUsT0FBTyxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsQ0FBQztRQUM1QyxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUN2QyxJQUFJLENBQUMsUUFBUSxJQUFJLEdBQUcsSUFBSSxRQUFRLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDekMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLEVBQUUsS0FBSyxFQUFFLENBQUMsRUFBRSxPQUFPLEVBQUUsR0FBRyxHQUFHLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDO1lBQ2xFLE9BQU8sRUFBRSxPQUFPLEVBQUUsSUFBSSxFQUFFLENBQUM7UUFDM0IsQ0FBQztRQUNELElBQUksUUFBUSxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7WUFDOUIsUUFBUSxDQUFDLEtBQUssSUFBSSxDQUFDLENBQUM7WUFDcEIsT0FBTyxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsQ0FBQztRQUMzQixDQUFDO1FBQ0QsT0FBTyxFQUFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsVUFBVSxFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxRQUFRLENBQUMsT0FBTyxHQUFHLEdBQUcsQ0FBQyxHQUFHLElBQUksQ0FBQyxFQUFFLENBQUM7SUFDcEYsQ0FBQztJQUVELDZFQUE2RTtJQUM3RSxLQUFLLENBQUMsR0FBVztRQUNmLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQzNCLENBQUM7SUFFRCxpQ0FBaUM7SUFDakMsS0FBSztRQUNILElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLENBQUM7SUFDdkIsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBBIHNtYWxsIGluLW1lbW9yeSBmaXhlZC13aW5kb3cgcmF0ZSBsaW1pdGVyIGZvciB0aGUgZW1haWwtT1RQIGdhdGUuXG4gKlxuICogS2V5ZWQgYnkgYW4gYXJiaXRyYXJ5IHN0cmluZyAoYW4gZW1haWwgYWRkcmVzcyBvciBhIGNsaWVudCBJUCkuIEVhY2gga2V5IGdldHNcbiAqIGBtYXhgIGhpdHMgcGVyIGB3aW5kb3dNc2A7IHRoZSB3aW5kb3cgcmVzZXRzIG9uIGZpcnN0IHVzZSBhZnRlciBpdCBlbGFwc2VzLlxuICogYGhpdCgpYCByZXR1cm5zIHdoZXRoZXIgdGhlIGNhbGwgaXMgYWxsb3dlZCBhbmQsIHdoZW4gbm90LCBob3cgbWFueSBzZWNvbmRzXG4gKiB1bnRpbCB0aGUgd2luZG93IHJlc2V0cyBzbyBhIGNhbGxlciBjYW4gc3VyZmFjZSBhIGNvb2xkb3duLlxuICpcbiAqIEluLW1lbW9yeSBpcyBpbnRlbnRpb25hbCBhbmQgc3VmZmljaWVudCBmb3IgYSBzaW5nbGUtYXBwLWluc3RhbmNlIGdhdGU6IGFuXG4gKiBhcHAgYmVoaW5kIGEgcG9ydHIgdHVubmVsIHNlcnZlcyBmcm9tIG9uZSBwcm9jZXNzLiBJdCBpcyBOT1QgYSBkaXN0cmlidXRlZFxuICogbGltaXRlcjsgYSBtdWx0aS1yZXBsaWNhIGRlcGxveW1lbnQgd291bGQgbmVlZCBzaGFyZWQgc3RhdGUuIEVudHJpZXMgYXJlXG4gKiBwcnVuZWQgbGF6aWx5IG9uIGFjY2Vzcywgc28gYW4gaWRsZSBrZXkgY29zdHMgbm90aGluZyBhZnRlciBpdHMgd2luZG93LlxuICpcbiAqIEBtb2R1bGVcbiAqL1xuXG5pbnRlcmZhY2UgV2luZG93IHtcbiAgY291bnQ6IG51bWJlcjtcbiAgcmVzZXRBdDogbnVtYmVyO1xufVxuXG4vKiogQSBmaXhlZC13aW5kb3cgcmF0ZSBsaW1pdGVyIG92ZXIgc3RyaW5nIGtleXMuICovXG5leHBvcnQgY2xhc3MgUmF0ZUxpbWl0ZXIge1xuICBwcml2YXRlIHJlYWRvbmx5IHdpbmRvd3MgPSBuZXcgTWFwPHN0cmluZywgV2luZG93PigpO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgcmVhZG9ubHkgbWF4OiBudW1iZXIsXG4gICAgcHJpdmF0ZSByZWFkb25seSB3aW5kb3dNczogbnVtYmVyLFxuICApIHt9XG5cbiAgLyoqXG4gICAqIFJlY29yZCBhIGhpdCBmb3IgYGtleWAuIFJldHVybnMgYHsgYWxsb3dlZCB9YCwgcGx1cyBgcmV0cnlBZnRlcmAgKHNlY29uZHMpXG4gICAqIHdoZW4gdGhlIGxpbWl0IGlzIGV4Y2VlZGVkLiBBIGxpbWl0IG9mIGA8PSAwYCBkaXNhYmxlcyBsaW1pdGluZyAoYWx3YXlzXG4gICAqIGFsbG93ZWQpLCB3aGljaCBsZXRzIGEgY29uZmlnIHR1cm4gaXQgb2ZmIHdpdGhvdXQgc3BlY2lhbC1jYXNpbmcgY2FsbGVycy5cbiAgICovXG4gIGhpdChrZXk6IHN0cmluZywgbm93OiBudW1iZXIgPSBEYXRlLm5vdygpKTogeyBhbGxvd2VkOiBib29sZWFuOyByZXRyeUFmdGVyPzogbnVtYmVyIH0ge1xuICAgIGlmICh0aGlzLm1heCA8PSAwKSByZXR1cm4geyBhbGxvd2VkOiB0cnVlIH07XG4gICAgY29uc3QgZXhpc3RpbmcgPSB0aGlzLndpbmRvd3MuZ2V0KGtleSk7XG4gICAgaWYgKCFleGlzdGluZyB8fCBub3cgPj0gZXhpc3RpbmcucmVzZXRBdCkge1xuICAgICAgdGhpcy53aW5kb3dzLnNldChrZXksIHsgY291bnQ6IDEsIHJlc2V0QXQ6IG5vdyArIHRoaXMud2luZG93TXMgfSk7XG4gICAgICByZXR1cm4geyBhbGxvd2VkOiB0cnVlIH07XG4gICAgfVxuICAgIGlmIChleGlzdGluZy5jb3VudCA8IHRoaXMubWF4KSB7XG4gICAgICBleGlzdGluZy5jb3VudCArPSAxO1xuICAgICAgcmV0dXJuIHsgYWxsb3dlZDogdHJ1ZSB9O1xuICAgIH1cbiAgICByZXR1cm4geyBhbGxvd2VkOiBmYWxzZSwgcmV0cnlBZnRlcjogTWF0aC5jZWlsKChleGlzdGluZy5yZXNldEF0IC0gbm93KSAvIDEwMDApIH07XG4gIH1cblxuICAvKiogRm9yZ2V0IGEga2V5IChlLmcuIGNsZWFyIGEgY2FsbGVyJ3Mgd2luZG93IGFmdGVyIGEgc3VjY2Vzc2Z1bCB2ZXJpZnkpLiAqL1xuICByZXNldChrZXk6IHN0cmluZyk6IHZvaWQge1xuICAgIHRoaXMud2luZG93cy5kZWxldGUoa2V5KTtcbiAgfVxuXG4gIC8qKiBEcm9wIGV2ZXJ5IHdpbmRvdyAodGVzdHMpLiAqL1xuICBjbGVhcigpOiB2b2lkIHtcbiAgICB0aGlzLndpbmRvd3MuY2xlYXIoKTtcbiAgfVxufVxuIl19
@@ -81,6 +81,32 @@ export interface EmailPluginConfig extends BasePluginConfig {
81
81
  * `BrandContext`.
82
82
  */
83
83
  brand?: EmailBrand;
84
+ /**
85
+ * Optional email-OTP ACCESS GATE. When `enabled`, the plugin mounts a login
86
+ * flow (`/api/email/auth/*`) and gates every other route behind a session
87
+ * cookie - the front door for an app exposed publicly (e.g. through a portr
88
+ * tunnel that bypasses the Databricks OAuth proxy). Reuses this plugin's
89
+ * transport to email the code. Omit or `enabled: false` to leave the app open.
90
+ */
91
+ auth?: AuthConfig;
92
+ }
93
+ /** Email-OTP access-gate configuration (see {@link EmailPluginConfig.auth}). */
94
+ export interface AuthConfig {
95
+ /** Turn the gate on. Falls back to `EMAIL_AUTH_ENABLED`. Default off. */
96
+ enabled?: boolean;
97
+ /**
98
+ * Who may request a code. Each entry is a domain shortcut (`databricks.com`
99
+ * or `@databricks.com`), a glob (`*.databricks.com`), or a `/regex/`. An
100
+ * EMPTY list allows nobody (fail closed). Falls back to `EMAIL_AUTH_ALLOW`
101
+ * (comma/space-separated).
102
+ */
103
+ allow?: string | string[];
104
+ /** Session lifetime (seconds). Falls back to `EMAIL_AUTH_SESSION_TTL`. Default 43200 (12h). */
105
+ sessionTtlSeconds?: number;
106
+ /** One-time-code lifetime (seconds). Falls back to `EMAIL_AUTH_CODE_TTL`. Default 600 (10m). */
107
+ codeTtlSeconds?: number;
108
+ /** Max verify attempts per issued code. Default 5. */
109
+ maxAttempts?: number;
84
110
  }
85
111
  /** Config shared by both resolved modes. */
86
112
  interface ResolvedSender {
@@ -121,6 +147,20 @@ export interface ResolvedFileConfig extends ResolvedSender {
121
147
  export type ResolvedEmailConfig = ResolvedSmtpConfig | ResolvedFileConfig;
122
148
  /** JSON Schema published on the manifest's `config.schema`. */
123
149
  export declare const EMAIL_CONFIG_SCHEMA: JSONSchema7;
150
+ /** Resolved email-OTP gate config, with env fallbacks applied (or `undefined` when off). */
151
+ export interface ResolvedAuthConfig {
152
+ readonly allow: string[];
153
+ readonly sessionTtlSeconds: number;
154
+ readonly codeTtlSeconds: number;
155
+ readonly maxAttempts: number;
156
+ }
157
+ /**
158
+ * Resolve {@link AuthConfig} against env, returning `undefined` when the gate is
159
+ * off. `enabled` gates everything; `allow` merges the config list + env
160
+ * (`parseList` handles a `string[]` or a delimited string). Empty `allow` is
161
+ * allowed here (the gate then denies everyone - a deliberate fail-closed state).
162
+ */
163
+ export declare function resolveAuthConfig(auth: AuthConfig | undefined): ResolvedAuthConfig | undefined;
124
164
  /**
125
165
  * Resolve plugin config over environment defaults.
126
166
  *
package/lib/src/config.js CHANGED
@@ -25,7 +25,7 @@
25
25
  */
26
26
  import { resolve } from "node:path";
27
27
  import { ConfigurationError, ValidationError } from "@databricks/appkit";
28
- import { object } from "@dbx-tools/shared-core";
28
+ import { object, string } from "@dbx-tools/shared-core";
29
29
  import { parseAllowedSenders } from "./sender.js";
30
30
  /** SMTP submission port used when none is configured. */
31
31
  export const DEFAULT_SMTP_PORT = 587;
@@ -104,8 +104,60 @@ export const EMAIL_CONFIG_SCHEMA = {
104
104
  },
105
105
  required: ["accent", "fontFamily"],
106
106
  },
107
+ auth: {
108
+ type: "object",
109
+ description: "Email-OTP access gate. When enabled, mounts a login flow at /api/email/auth/* and gates every other route behind a session cookie.",
110
+ properties: {
111
+ enabled: {
112
+ type: "boolean",
113
+ description: "Turn the gate on (env EMAIL_AUTH_ENABLED). Default off.",
114
+ },
115
+ allow: {
116
+ type: "array",
117
+ items: { type: "string" },
118
+ description: 'Allow-list of who may request a code: domain shortcut ("databricks.com"), glob ("*.databricks.com"), or "/regex/". Empty = nobody. Also accepts a comma/space-separated string. Env EMAIL_AUTH_ALLOW.',
119
+ },
120
+ sessionTtlSeconds: {
121
+ type: "number",
122
+ description: "Session lifetime in seconds (env EMAIL_AUTH_SESSION_TTL). Default 43200.",
123
+ },
124
+ codeTtlSeconds: {
125
+ type: "number",
126
+ description: "One-time-code lifetime in seconds (env EMAIL_AUTH_CODE_TTL). Default 600.",
127
+ },
128
+ maxAttempts: {
129
+ type: "number",
130
+ description: "Max verify attempts per issued code. Default 5.",
131
+ },
132
+ },
133
+ },
107
134
  },
108
135
  };
136
+ /**
137
+ * Resolve {@link AuthConfig} against env, returning `undefined` when the gate is
138
+ * off. `enabled` gates everything; `allow` merges the config list + env
139
+ * (`parseList` handles a `string[]` or a delimited string). Empty `allow` is
140
+ * allowed here (the gate then denies everyone - a deliberate fail-closed state).
141
+ */
142
+ export function resolveAuthConfig(auth) {
143
+ const enabled = auth?.enabled ?? object.toBoolean(process.env.EMAIL_AUTH_ENABLED) ?? false;
144
+ if (!enabled)
145
+ return undefined;
146
+ const allow = [
147
+ ...string.parseList(auth?.allow),
148
+ ...string.parseList(process.env.EMAIL_AUTH_ALLOW),
149
+ ];
150
+ const num = (value, env, fallback) => {
151
+ const raw = value ?? (env ? Number(env) : undefined);
152
+ return typeof raw === "number" && Number.isFinite(raw) && raw > 0 ? raw : fallback;
153
+ };
154
+ return {
155
+ allow,
156
+ sessionTtlSeconds: num(auth?.sessionTtlSeconds, process.env.EMAIL_AUTH_SESSION_TTL, 43200),
157
+ codeTtlSeconds: num(auth?.codeTtlSeconds, process.env.EMAIL_AUTH_CODE_TTL, 600),
158
+ maxAttempts: auth?.maxAttempts ?? 5,
159
+ };
160
+ }
109
161
  /** Parse the `SMTP_SECURE` env / config flag, defaulting by port. */
110
162
  function resolveSecure(flag, port) {
111
163
  if (typeof flag === "boolean")
@@ -209,4 +261,4 @@ export function resolveEmailConfig(config = {}) {
209
261
  const outDir = resolve(config.outDir ?? process.env.EMAIL_OUTBOX_DIR ?? resolve(process.cwd(), "tmp"));
210
262
  return { mode: "file", outDir, ...sender };
211
263
  }
212
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlnLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvbmZpZy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBd0JHO0FBQ0gsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUNwQyxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsZUFBZSxFQUF5QixNQUFNLG9CQUFvQixDQUFDO0FBQ2hHLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUdoRCxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFFbEQseURBQXlEO0FBQ3pELE1BQU0sQ0FBQyxNQUFNLGlCQUFpQixHQUFHLEdBQUcsQ0FBQztBQUVyQywyRUFBMkU7QUFDM0UsTUFBTSxDQUFDLE1BQU0sc0JBQXNCLEdBQUcsR0FBRyxDQUFDO0FBd0gxQywrREFBK0Q7QUFDL0QsTUFBTSxDQUFDLE1BQU0sbUJBQW1CLEdBQWdCO0lBQzlDLElBQUksRUFBRSxRQUFRO0lBQ2QsVUFBVSxFQUFFO1FBQ1YsSUFBSSxFQUFFO1lBQ0osSUFBSSxFQUFFLFFBQVE7WUFDZCxXQUFXLEVBQUUsMERBQTBEO1lBQ3ZFLFVBQVUsRUFBRTtnQkFDVixJQUFJLEVBQUUsRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLFdBQVcsRUFBRSxtQ0FBbUMsRUFBRTtnQkFDMUUsSUFBSSxFQUFFO29CQUNKLElBQUksRUFBRSxRQUFRO29CQUNkLFdBQVcsRUFBRSw2Q0FBNkMsaUJBQWlCLEdBQUc7aUJBQy9FO2dCQUNELE1BQU0sRUFBRTtvQkFDTixJQUFJLEVBQUUsU0FBUztvQkFDZixXQUFXLEVBQUUsNkRBQTZELHNCQUFzQixHQUFHO2lCQUNwRztnQkFDRCxJQUFJLEVBQUUsRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLFdBQVcsRUFBRSxpQ0FBaUMsRUFBRTtnQkFDeEUsUUFBUSxFQUFFO29CQUNSLElB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bmZpZ3VyYXRpb24gZm9yIHRoZSBlbWFpbCBwbHVnaW46IHRoZSB0eXBlZFxuICoge0BsaW5rIEVtYWlsUGx1Z2luQ29uZmlnfSAodGhlIHBsdWdpbidzIHNsaWNlIG9mIEFwcEtpdCBjb25maWcpLCB0aGVcbiAqIEpTT04gU2NoZW1hIHRoZSBtYW5pZmVzdCBwdWJsaXNoZXMgZm9yIGl0LCBhbmQge0BsaW5rIHJlc29sdmVFbWFpbENvbmZpZ31cbiAqIHdoaWNoIGxheWVycyB0aGF0IGNvbmZpZyBvdmVyIGVudmlyb25tZW50IGRlZmF1bHRzIGludG8gdGhlIGNvbmNyZXRlXG4gKiB7QGxpbmsgUmVzb2x2ZWRFbWFpbENvbmZpZ30gdGhlIHJ1bnRpbWUgbmVlZHMuXG4gKlxuICogVHdvIG1vZGVzIGZhbGwgb3V0IG9mIHRoZSByZXNvbHV0aW9uLiBXaGVuIFNNVFAgY3JlZGVudGlhbHMgKGhvc3QgK1xuICogdXNlciArIHBhc3N3b3JkKSBhcmUgYWxsIHByZXNlbnQgaXQgcmVzb2x2ZXMgdG8gYG1vZGU6IFwic210cFwiYCBhbmRcbiAqIG1haWwgaXMgc2VudCBmb3IgcmVhbC4gV2hlbiB0aGV5IGFyZSBhYnNlbnQgYW5kIGBFTUFJTF9PVVRCT1hfTU9ERWBcbiAqIGlzIGV4cGxpY2l0bHkgZW5hYmxlZCBpdCByZXNvbHZlcyB0byBgbW9kZTogXCJmaWxlXCJgIChhbiBcIm91dGJveFwiKVxuICogYW5kIGVhY2ggbWVzc2FnZSBpcyB3cml0dGVuIHRvIGRpc2sgYXMgSFRNTCBpbnN0ZWFkIG9mIHNlbnQuIEFueVxuICogcGFydGlhbCBTTVRQIGNvbmZpZ3VyYXRpb24gb3IgYSBzZW5kIGF0dGVtcHQgd2l0aCBubyBjcmVkZW50aWFscyBhbmRcbiAqIG5vIG91dGJveCBvcHQtaW4gdGhyb3dzLlxuICpcbiAqIFByZWNlZGVuY2UgcGVyIGZpZWxkOiBleHBsaWNpdCBwbHVnaW4gY29uZmlnIHdpbnMsIHRoZW4gdGhlIG1hdGNoaW5nXG4gKiBlbnZpcm9ubWVudCB2YXJpYWJsZS4gRW52IG5hbWVzIGFyZSB1bnByZWZpeGVkIGJlY2F1c2UgdGhlIGFwcCB0YWxrc1xuICogdG8gYSBzaW5nbGUgU01UUCBzZXJ2ZXIgKGUuZy4gU01UUDJHTyk6IGBTTVRQX0hPU1RgLCBgU01UUF9QT1JUYCxcbiAqIGBTTVRQX1NFQ1VSRWAsIGBTTVRQX1VTRVJgLCBgU01UUF9QQVNTV09SRGAsIHBsdXMgYEVNQUlMX0RPTUFJTmAgZm9yXG4gKiB0aGUgZGVyaXZlZCBzZW5kZXIncyBkb21haW4sIGBFTUFJTF9GUk9NYCBmb3IgYW4gZXhwbGljaXQgb3ZlcnJpZGUsXG4gKiBgRU1BSUxfU0VOREVSX1BPTElDWWAgZm9yIHRoZSBzZW5kZXIgcmVzdHJpY3Rpb24gbW9kZSwgYW5kXG4gKiBgRU1BSUxfT1VUQk9YX0RJUmAgZm9yIHRoZSBvdXRib3ggZGlyZWN0b3J5LlxuICpcbiAqIEBtb2R1bGVcbiAqL1xuaW1wb3J0IHsgcmVzb2x2ZSB9IGZyb20gXCJub2RlOnBhdGhcIjtcbmltcG9ydCB7IENvbmZpZ3VyYXRpb25FcnJvciwgVmFsaWRhdGlvbkVycm9yLCB0eXBlIEJhc2VQbHVnaW5Db25maWcgfSBmcm9tIFwiQGRhdGFicmlja3MvYXBwa2l0XCI7XG5pbXBvcnQgeyBvYmplY3QgfSBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtY29yZVwiO1xuaW1wb3J0IHR5cGUgeyBKU09OU2NoZW1hNyB9IGZyb20gXCJqc29uLXNjaGVtYVwiO1xuaW1wb3J0IHR5cGUgeyBFbWFpbEJyYW5kIH0gZnJvbSBcIi4vYnJhbmQudHNcIjtcbmltcG9ydCB7IHBhcnNlQWxsb3dlZFNlbmRlcnMgfSBmcm9tIFwiLi9zZW5kZXIudHNcIjtcblxuLyoqIFNNVFAgc3VibWlzc2lvbiBwb3J0IHVzZWQgd2hlbiBub25lIGlzIGNvbmZpZ3VyZWQuICovXG5leHBvcnQgY29uc3QgREVGQVVMVF9TTVRQX1BPUlQgPSA1ODc7XG5cbi8qKiBTTVRQIHBvcnQgdGhhdCBpbXBsaWVzIGEgVExTLW9uLWNvbm5lY3Qgc29ja2V0IHJhdGhlciB0aGFuIFNUQVJUVExTLiAqL1xuZXhwb3J0IGNvbnN0IElNUExJQ0lUX1RMU19TTVRQX1BPUlQgPSA0NjU7XG5cbi8qKlxuICogSG93IHRoZSBzZW5kZXIgKGBGcm9tYCkgYWRkcmVzcyBpcyByZXN0cmljdGVkLlxuICpcbiAqIGBcImFsbG93bGlzdFwiYCBpcyB0aGUgZGVmYXVsdCBhbmQgdGhlIGRlbnktYnktZGVmYXVsdCBwb3N0dXJlOiBhIHNlbmQgaXNcbiAqIHBlcm1pdHRlZCBvbmx5IGZyb20gYW4gYWRkcmVzcyB0aGUgY29uZmlndXJhdGlvbiBuYW1lcywgZWl0aGVyIHRocm91Z2hcbiAqIHtAbGluayBFbWFpbFBsdWdpbkNvbmZpZy5hbGxvd2VkU2VuZGVyc30gb3IsIHdoZW4gdGhhdCBpcyBlbXB0eSwgdGhyb3VnaFxuICogdGhlIGNvbmZpZ3VyZWQgc2VuZGVyIHNvdXJjZSAoe0BsaW5rIEVtYWlsUGx1Z2luQ29uZmlnLmZyb219IGFzIGFuIGV4YWN0XG4gKiBhZGRyZXNzLCB7QGxpbmsgRW1haWxQbHVnaW5Db25maWcuZG9tYWlufSBhcyBhIGAqQGRvbWFpbmAgd2lsZGNhcmQpLlxuICpcbiAqIGBcInVucmVzdHJpY3RlZFwiYCBpcyB0aGUgZXhwbGljaXQgb3B0LW91dDogYW55IGBGcm9tYCBhIGNhbGxlciBzdXBwbGllcyBpc1xuICogYWNjZXB0ZWQuIE9ubHkgcmVhY2ggZm9yIGl0IHdoZW4gYW4gdXBzdHJlYW0gc3lzdGVtIGFscmVhZHkgdmV0cyB0aGVcbiAqIHNlbmRlci5cbiAqL1xuZXhwb3J0IHR5cGUgU2VuZGVyUG9saWN5ID0gXCJhbGxvd2xpc3RcIiB8IFwidW5yZXN0cmljdGVkXCI7XG5cbi8qKiBTTVRQIGNvbm5lY3Rpb24gKyBjcmVkZW50aWFscy4gQWxsIGZpZWxkcyBmYWxsIGJhY2sgdG8gZW52IHdoZW4gdW5zZXQuICovXG5leHBvcnQgaW50ZXJmYWNlIFNtdHBDb25maWcge1xuICAvKiogU01UUCBzZXJ2ZXIgaG9zdG5hbWUgKGBTTVRQX0hPU1RgKS4gKi9cbiAgaG9zdD86IHN0cmluZztcbiAgLyoqIFNNVFAgc2VydmVyIHBvcnQgKGBTTVRQX1BPUlRgKS4gRGVmYXVsdHMgdG8ge0BsaW5rIERFRkFVTFRfU01UUF9QT1JUfS4gKi9cbiAgcG9ydD86IG51bWJlcjtcbiAgLyoqXG4gICAqIFVzZSBhIFRMUy1vbi1jb25uZWN0IHNvY2tldCAoYFNNVFBfU0VDVVJFYCkuIERlZmF1bHRzIHRvXG4gICAqIGBwb3J0ID09PSBgIHtAbGluayBJTVBMSUNJVF9UTFNfU01UUF9QT1JUfS5cbiAgICovXG4gIHNlY3VyZT86IGJvb2xlYW47XG4gIC8qKiBTTVRQIGF1dGggdXNlcm5hbWUgKGBTTVRQX1VTRVJgKS4gKi9cbiAgdXNlcj86IHN0cmluZztcbiAgLyoqIFNNVFAgYXV0aCBwYXNzd29yZCAvIEFQSSBrZXkgKGBTTVRQX1BBU1NXT1JEYCkuICovXG4gIHBhc3N3b3JkPzogc3RyaW5nO1xufVxuXG4vKiogQXBwS2l0IGNvbmZpZyBhY2NlcHRlZCBieSB0aGUgZW1haWwgcGx1Z2luLiAqL1xuZXhwb3J0IGludGVyZmFjZSBFbWFpbFBsdWdpbkNvbmZpZyBleHRlbmRzIEJhc2VQbHVnaW5Db25maWcge1xuICAvKiogU01UUCBjb25uZWN0aW9uICsgY3JlZGVudGlhbHMuIE9taXQgdG8gcnVuIGluIGZpbGUvb3V0Ym94IG1vZGUuICovXG4gIHNtdHA/OiBTbXRwQ29uZmlnO1xuICAvKipcbiAgICogRG9tYWluIHVzZWQgdG8gYnVpbGQgdGhlIHNlbmRlciBhZGRyZXNzIGZyb20gdGhlIG9uLWJlaGFsZi1vZiB1c2VyXG4gICAqIChgPGxvY2FsLXBhcnQ+QDxkb21haW4+YCkuIEZhbGxzIGJhY2sgdG8gYEVNQUlMX0RPTUFJTmAuIFJlcXVpcmVkIGluXG4gICAqIFNNVFAgbW9kZSB1bmxlc3Mge0BsaW5rIGZyb219IGlzIHNldDsgb3B0aW9uYWwgaW4gZmlsZSBtb2RlICh0aGVcbiAgICogb3V0Ym94IGZhbGxzIGJhY2sgdG8gdGhlIHVzZXIncyBvd24gZW1haWwgYWRkcmVzcykuXG4gICAqL1xuICBkb21haW4/OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBFeHBsaWNpdCBgRnJvbWAgYWRkcmVzcy4gV2hlbiBzZXQsIHRoZSBzZW5kZXIgaXMgdXNlZCB2ZXJiYXRpbSBhbmRcbiAgICogdGhlIHBlci11c2VyIGRlcml2YXRpb24gaXMgc2tpcHBlZC4gRmFsbHMgYmFjayB0byBgRU1BSUxfRlJPTWAuXG4gICAqL1xuICBmcm9tPzogc3RyaW5nO1xuICAvKipcbiAgICogRGlyZWN0b3J5IGZvciB0aGUgZmlsZS9vdXRib3ggZmFsbGJhY2suIEZhbGxzIGJhY2sgdG9cbiAgICogYEVNQUlMX09VVEJPWF9ESVJgLCB0aGVuIGA8Y3dkPi90bXBgLiBPbmx5IHVzZWQgd2hlbiBTTVRQXG4gICAqIGNyZWRlbnRpYWxzIGFyZSBhYnNlbnQuXG4gICAqL1xuICBvdXREaXI/OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBBbGxvdy1saXN0IHJlc3RyaWN0aW5nIHRoZSBzZW5kZXIgKGBGcm9tYCkgYWRkcmVzcy4gRWFjaCBlbnRyeSBpcyBhblxuICAgKiBleGFjdCBhZGRyZXNzIChgdXNlckBkb21haW4uY29tYCksIGEgZG9tYWluIHdpbGRjYXJkIChgKkBkb21haW4uY29tYFxuICAgKiBvciB0aGUgYmFyZSBgZG9tYWluLmNvbWAsIG1hdGNoaW5nIGFueSBsb2NhbCBwYXJ0IG9uIHRoYXQgZG9tYWluKSwgb3JcbiAgICogYCpgIChhbnkpLiBBIHJlc29sdmVkIC8gY2hvc2VuIHNlbmRlciB0aGF0IG1hdGNoZXMgbm8gZW50cnkgaXNcbiAgICogcmVqZWN0ZWQgYXQgc2VuZCB0aW1lLiBBY2NlcHRzIGEgYHN0cmluZ1tdYCBvciBhIHNpbmdsZSBjb21tYS0gL1xuICAgKiB3aGl0ZXNwYWNlLXNlcGFyYXRlZCBzdHJpbmc7IGZhbGxzIGJhY2sgdG8gYEVNQUlMX0FMTE9XRURfU0VOREVSU2AuXG4gICAqIFdoZW4gZW1wdHksIHRoZSB7QGxpbmsgc2VuZGVyUG9saWN5fSBkZWNpZGVzIHdoYXQgaXMgcGVybWl0dGVkLlxuICAgKi9cbiAgYWxsb3dlZFNlbmRlcnM/OiBzdHJpbmcgfCBzdHJpbmdbXTtcbiAgLyoqXG4gICAqIEhvdyB0aGUgc2VuZGVyIGFkZHJlc3MgaXMgcmVzdHJpY3RlZCB3aGVuIHtAbGluayBhbGxvd2VkU2VuZGVyc30gaXNcbiAgICogZW1wdHkgKGBFTUFJTF9TRU5ERVJfUE9MSUNZYCkuIERlZmF1bHRzIHRvIGBcImFsbG93bGlzdFwiYCwgd2hpY2hcbiAgICogbmFycm93cyBzZW5kcyB0byB0aGUgY29uZmlndXJlZCBzZW5kZXIgc291cmNlLiBTZWVcbiAgICoge0BsaW5rIFNlbmRlclBvbGljeX0uXG4gICAqL1xuICBzZW5kZXJQb2xpY3k/OiBTZW5kZXJQb2xpY3k7XG4gIC8qKlxuICAgKiBPcHRpb25hbCBicmFuZCBzdHlsaW5nIChhY2NlbnQsIGZvbnQsIGhlYWRlciBsb2dvKSBhcHBsaWVkIHRvIHRoZVxuICAgKiByZW5kZXJlZCBIVE1MIG9mIGV2ZXJ5IG1lc3NhZ2UuIE9taXQgZm9yIHRoZSBuZXV0cmFsIGRlZmF1bHQgbGF5b3V0LlxuICAgKiBQYXNzIHtAbGluayBlbWFpbEJyYW5kRnJvbUNvbnRleHR9IHRvIGRlcml2ZSBpdCBmcm9tIGEgc2hhcmVkXG4gICAqIGBCcmFuZENvbnRleHRgLlxuICAgKi9cbiAgYnJhbmQ/OiBFbWFpbEJyYW5kO1xufVxuXG4vKiogQ29uZmlnIHNoYXJlZCBieSBib3RoIHJlc29sdmVkIG1vZGVzLiAqL1xuaW50ZXJmYWNlIFJlc29sdmVkU2VuZGVyIHtcbiAgLyoqIFNlbmRlciBkb21haW47IHByZXNlbnQgd2hlbmV2ZXIge0BsaW5rIGZyb219IGlzIGFic2VudC4gKi9cbiAgZG9tYWluPzogc3RyaW5nO1xuICAvKiogRXhwbGljaXQgc2VuZGVyIG92ZXJyaWRlOyBwcmVzZW50IHNraXBzIHBlci11c2VyIGRlcml2YXRpb24uICovXG4gIGZyb20/OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBFZmZlY3RpdmUgc2VuZGVyIGFsbG93LWxpc3Q6IHRoZSBjb25maWd1cmVkIHBhdHRlcm5zIHdoZW4gYW55IHdlcmVcbiAgICogZ2l2ZW4sIGVsc2UgdGhlIHBhdHRlcm5zIGltcGxpZWQgYnkgdGhlIHNlbmRlciBzb3VyY2UgdW5kZXIgYW5cbiAgICogYFwiYWxsb3dsaXN0XCJgIHBvbGljeS4gRW1wdHkgbWVhbnMgdW5lbmZvcmNlYWJsZSAoYW4gYFwidW5yZXN0cmljdGVkXCJgXG4gICAqIHBvbGljeSwgb3IgYW4gb3V0Ym94IHdpdGggbm8gc2VuZGVyIHNvdXJjZSB0byBuYXJyb3cgdG8pLlxuICAgKi9cbiAgYWxsb3dlZFNlbmRlcnM6IHN0cmluZ1tdO1xuICAvKiogVGhlIHJlc3RyaWN0aW9uIG1vZGUgdGhlIGFsbG93LWxpc3Qgd2FzIHJlc29sdmVkIHVuZGVyLiAqL1xuICBzZW5kZXJQb2xpY3k6IFNlbmRlclBvbGljeTtcbiAgLyoqIEJyYW5kIHN0eWxpbmcgYXBwbGllZCB0byByZW5kZXJlZCBIVE1MOyBhYnNlbnQgZm9yIHRoZSBkZWZhdWx0IGxheW91dC4gKi9cbiAgYnJhbmQ/OiBFbWFpbEJyYW5kO1xufVxuXG4vKiogUmVzb2x2ZWQgY29uZmlnIGZvciByZWFsIFNNVFAgZGVsaXZlcnkuICovXG5leHBvcnQgaW50ZXJmYWNlIFJlc29sdmVkU210cENvbmZpZyBleHRlbmRzIFJlc29sdmVkU2VuZGVyIHtcbiAgbW9kZTogXCJzbXRwXCI7XG4gIGhvc3Q6IHN0cmluZztcbiAgcG9ydDogbnVtYmVyO1xuICBzZWN1cmU6IGJvb2xlYW47XG4gIGF1dGg6IHsgdXNlcjogc3RyaW5nOyBwYXNzOiBzdHJpbmcgfTtcbn1cblxuLyoqIFJlc29sdmVkIGNvbmZpZyBmb3IgdGhlIGZpbGUvb3V0Ym94IGZhbGxiYWNrIChubyBTTVRQIGNyZWRlbnRpYWxzKS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUmVzb2x2ZWRGaWxlQ29uZmlnIGV4dGVuZHMgUmVzb2x2ZWRTZW5kZXIge1xuICBtb2RlOiBcImZpbGVcIjtcbiAgLyoqIEFic29sdXRlIGRpcmVjdG9yeSBtZXNzYWdlcyBhcmUgd3JpdHRlbiB1bmRlci4gKi9cbiAgb3V0RGlyOiBzdHJpbmc7XG59XG5cbi8qKiBDb25jcmV0ZSwgdmFsaWRhdGVkIGNvbmZpZyB0aGUgcnVudGltZSBkaXNwYXRjaGVzIHRocm91Z2guICovXG5leHBvcnQgdHlwZSBSZXNvbHZlZEVtYWlsQ29uZmlnID0gUmVzb2x2ZWRTbXRwQ29uZmlnIHwgUmVzb2x2ZWRGaWxlQ29uZmlnO1xuXG4vKiogSlNPTiBTY2hlbWEgcHVibGlzaGVkIG9uIHRoZSBtYW5pZmVzdCdzIGBjb25maWcuc2NoZW1hYC4gKi9cbmV4cG9ydCBjb25zdCBFTUFJTF9DT05GSUdfU0NIRU1BOiBKU09OU2NoZW1hNyA9IHtcbiAgdHlwZTogXCJvYmplY3RcIixcbiAgcHJvcGVydGllczoge1xuICAgIHNtdHA6IHtcbiAgICAgIHR5cGU6IFwib2JqZWN0XCIsXG4gICAgICBkZXNjcmlwdGlvbjogXCJTTVRQIGNvbm5lY3Rpb24gYW5kIGNyZWRlbnRpYWxzIChlbnYgZmFsbGJhY2tzOiBTTVRQXyopLlwiLFxuICAgICAgcHJvcGVydGllczoge1xuICAgICAgICBob3N0OiB7IHR5cGU6IFwic3RyaW5nXCIsIGRlc2NyaXB0aW9uOiBcIlNNVFAgc2VydmVyIGhvc3RuYW1lIChTTVRQX0hPU1QpLlwiIH0sXG4gICAgICAgIHBvcnQ6IHtcbiAgICAgICAgICB0eXBlOiBcIm51bWJlclwiLFxuICAgICAgICAgIGRlc2NyaXB0aW9uOiBgU01UUCBzZXJ2ZXIgcG9ydCAoU01UUF9QT1JUKS4gRGVmYXVsdHMgdG8gJHtERUZBVUxUX1NNVFBfUE9SVH0uYCxcbiAgICAgICAgfSxcbiAgICAgICAgc2VjdXJlOiB7XG4gICAgICAgICAgdHlwZTogXCJib29sZWFuXCIsXG4gICAgICAgICAgZGVzY3JpcHRpb246IGBUTFMtb24tY29ubmVjdCBzb2NrZXQgKFNNVFBfU0VDVVJFKS4gRGVmYXVsdHMgdG8gcG9ydCA9PT0gJHtJTVBMSUNJVF9UTFNfU01UUF9QT1JUfS5gLFxuICAgICAgICB9LFxuICAgICAgICB1c2VyOiB7IHR5cGU6IFwic3RyaW5nXCIsIGRlc2NyaXB0aW9uOiBcIlNNVFAgYXV0aCB1c2VybmFtZSAoU01UUF9VU0VSKS5cIiB9LFxuICAgICAgICBwYXNzd29yZDoge1xuICAgICAgICAgIHR5cGU6IFwic3RyaW5nXCIsXG4gICAgICAgICAgZGVzY3JpcHRpb246IFwiU01UUCBhdXRoIHBhc3N3b3JkIC8gQVBJIGtleSAoU01UUF9QQVNTV09SRCkuXCIsXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgIH0sXG4gICAgZG9tYWluOiB7XG4gICAgICB0eXBlOiBcInN0cmluZ1wiLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgIFwiRG9tYWluIGZvciB0aGUgZGVyaXZlZCBzZW5kZXIgYWRkcmVzcyAoPHVzZXItbG9jYWwtcGFydD5APGRvbWFpbj4pLiBGYWxscyBiYWNrIHRvIEVNQUlMX0RPTUFJTi5cIixcbiAgICB9LFxuICAgIGZyb206IHtcbiAgICAgIHR5cGU6IFwic3RyaW5nXCIsXG4gICAgICBkZXNjcmlwdGlvbjogXCJFeHBsaWNpdCBGcm9tIGFkZHJlc3M7IHNraXBzIHBlci11c2VyIGRlcml2YXRpb24uIEZhbGxzIGJhY2sgdG8gRU1BSUxfRlJPTS5cIixcbiAgICB9LFxuICAgIG91dERpcjoge1xuICAgICAgdHlwZTogXCJzdHJpbmdcIixcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICBcIkRpcmVjdG9yeSBmb3IgdGhlIGZpbGUvb3V0Ym94IGZhbGxiYWNrIHdoZW4gU01UUCBpcyB1bmNvbmZpZ3VyZWQuIEZhbGxzIGJhY2sgdG8gRU1BSUxfT1VUQk9YX0RJUiwgdGhlbiA8Y3dkPi90bXAuXCIsXG4gICAgfSxcbiAgICBhbGxvd2VkU2VuZGVyczoge1xuICAgICAgdHlwZTogXCJhcnJheVwiLFxuICAgICAgaXRlbXM6IHsgdHlwZTogXCJzdHJpbmdcIiB9LFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdBbGxvdy1saXN0IG9mIHBlcm1pdHRlZCBzZW5kZXIgKEZyb20pIHBhdHRlcm5zOiBleGFjdCBhZGRyZXNzZXMgKFwidXNlckBkb21haW4uY29tXCIpLCBkb21haW4gd2lsZGNhcmRzIChcIipAZG9tYWluLmNvbVwiKSwgb3IgXCIqXCIuIEFsc28gYWNjZXB0cyBhIGNvbW1hL3NwYWNlLXNlcGFyYXRlZCBzdHJpbmcuIEZhbGxzIGJhY2sgdG8gRU1BSUxfQUxMT1dFRF9TRU5ERVJTLiBXaGVuIGVtcHR5LCBzZW5kZXJQb2xpY3kgZGVjaWRlcy4nLFxuICAgIH0sXG4gICAgc2VuZGVyUG9saWN5OiB7XG4gICAgICB0eXBlOiBcInN0cmluZ1wiLFxuICAgICAgZW51bTogW1wiYWxsb3dsaXN0XCIsIFwidW5yZXN0cmljdGVkXCJdLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdIb3cgdGhlIHNlbmRlciBpcyByZXN0cmljdGVkIHdoZW4gYWxsb3dlZFNlbmRlcnMgaXMgZW1wdHkgKEVNQUlMX1NFTkRFUl9QT0xJQ1kpLiBcImFsbG93bGlzdFwiIChkZWZhdWx0KSBuYXJyb3dzIHNlbmRzIHRvIHRoZSBjb25maWd1cmVkIHNlbmRlciBzb3VyY2U7IFwidW5yZXN0cmljdGVkXCIgYWNjZXB0cyBhbnkgRnJvbS4nLFxuICAgIH0sXG4gICAgYnJhbmQ6IHtcbiAgICAgIHR5cGU6IFwib2JqZWN0XCIsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgXCJCcmFuZCBzdHlsaW5nIGlubGluZWQgaW50byBldmVyeSByZW5kZXJlZCBtZXNzYWdlLiBPbWl0IGZvciB0aGUgbmV1dHJhbCBkZWZhdWx0IGxheW91dC5cIixcbiAgICAgIHByb3BlcnRpZXM6IHtcbiAgICAgICAgYWNjZW50OiB7XG4gICAgICAgICAgdHlwZTogXCJzdHJpbmdcIixcbiAgICAgICAgICBkZXNjcmlwdGlvbjogJ0hlYWRlci1iYW5kIGJhY2tncm91bmQgYW5kIGJvZHkgbGluayBjb2xvciAoZS5nLiBcIiNGRjM2MjFcIikuJyxcbiAgICAgICAgfSxcbiAgICAgICAgb25BY2NlbnQ6IHtcbiAgICAgICAgICB0eXBlOiBcInN0cmluZ1wiLFxuICAgICAgICAgIGRlc2NyaXB0aW9uOiBcIlRleHQgYW5kIGxvZ28gY29sb3IgcmVuZGVyZWQgb24gdGhlIGFjY2VudCBiYW5kLiBEZWZhdWx0cyB0byB3aGl0ZS5cIixcbiAgICAgICAgfSxcbiAgICAgICAgZm9udEZhbWlseToge1xuICAgICAgICAgIHR5cGU6IFwic3RyaW5nXCIsXG4gICAgICAgICAgZGVzY3JpcHRpb246ICdCb2R5IGZvbnQgc3RhY2sgKGUuZy4gXCJJbnRlciwgdWktc2Fucy1zZXJpZiwgc3lzdGVtLXVpLCBzYW5zLXNlcmlmXCIpLicsXG4gICAgICAgIH0sXG4gICAgICAgIG5hbWU6IHtcbiAgICAgICAgICB0eXBlOiBcInN0cmluZ1wiLFxuICAgICAgICAgIGRlc2NyaXB0aW9uOiBcIlByb2R1Y3QgLyBkaXNwbGF5IG5hbWUgdXNlZCBhcyB0aGUgaGVhZGVyIHRleHQgYW5kIHRoZSBsb2dvIGFsdCB0ZXh0LlwiLFxuICAgICAgICB9LFxuICAgICAgICBsb2dvVXJsOiB7XG4gICAgICAgICAgdHlwZTogXCJzdHJpbmdcIixcbiAgICAgICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgICAgIFwiTG9nbyBpbWFnZSBmb3IgdGhlIGhlYWRlciBiYW5kLiBPbmx5IGFuIGh0dHAocyk6IG9yIGRhdGE6IFVSTCByZW5kZXJzOyBvdGhlciB2YWx1ZXMgYXJlIGRyb3BwZWQgYmVjYXVzZSBhIG1haWwgY2xpZW50IGNhbm5vdCBsb2FkIHRoZW0uXCIsXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgICAgcmVxdWlyZWQ6IFtcImFjY2VudFwiLCBcImZvbnRGYW1pbHlcIl0sXG4gICAgfSxcbiAgfSxcbn07XG5cbi8qKiBQYXJzZSB0aGUgYFNNVFBfU0VDVVJFYCBlbnYgLyBjb25maWcgZmxhZywgZGVmYXVsdGluZyBieSBwb3J0LiAqL1xuZnVuY3Rpb24gcmVzb2x2ZVNlY3VyZShmbGFnOiBib29sZWFuIHwgdW5kZWZpbmVkLCBwb3J0OiBudW1iZXIpOiBib29sZWFuIHtcbiAgaWYgKHR5cGVvZiBmbGFnID09PSBcImJvb2xlYW5cIikgcmV0dXJuIGZsYWc7XG4gIHJldHVybiBvYmplY3QudG9Cb29sZWFuKHByb2Nlc3MuZW52LlNNVFBfU0VDVVJFKSA/PyBwb3J0ID09PSBJTVBMSUNJVF9UTFNfU01UUF9QT1JUO1xufVxuXG4vKiogUGFyc2UgdGhlIGBFTUFJTF9TRU5ERVJfUE9MSUNZYCBlbnYgLyBjb25maWcgdmFsdWUsIGRlZmF1bHRpbmcgdG8gZGVueS1ieS1kZWZhdWx0LiAqL1xuZnVuY3Rpb24gcmVzb2x2ZVNlbmRlclBvbGljeShwb2xpY3k6IFNlbmRlclBvbGljeSB8IHVuZGVmaW5lZCk6IFNlbmRlclBvbGljeSB7XG4gIGNvbnN0IHJhdyA9IHBvbGljeSA/PyBwcm9jZXNzLmVudi5FTUFJTF9TRU5ERVJfUE9MSUNZPy50cmltKCkudG9Mb3dlckNhc2UoKTtcbiAgaWYgKHJhdyA9PT0gXCJ1bnJlc3RyaWN0ZWRcIikgcmV0dXJuIFwidW5yZXN0cmljdGVkXCI7XG4gIGlmIChyYXcgPT09IHVuZGVmaW5lZCB8fCByYXcgPT09IFwiXCIgfHwgcmF3ID09PSBcImFsbG93bGlzdFwiKSByZXR1cm4gXCJhbGxvd2xpc3RcIjtcbiAgdGhyb3cgVmFsaWRhdGlvbkVycm9yLmludmFsaWRWYWx1ZShcInNlbmRlclBvbGljeVwiLCByYXcsICdcImFsbG93bGlzdFwiIG9yIFwidW5yZXN0cmljdGVkXCInKTtcbn1cblxuLyoqXG4gKiBFZmZlY3RpdmUgYWxsb3ctbGlzdCBmb3IgYW4gYFwiYWxsb3dsaXN0XCJgIHBvbGljeSB3aXRoIG5vIGV4cGxpY2l0IHBhdHRlcm5zOlxuICogdGhlIHNlbmRlciBzb3VyY2UgaXRzZWxmLCBzbyBhIGNvbmZpZ3VyZWQgZG9tYWluIG9yIGZpeGVkIGFkZHJlc3MgaXMgdGhlXG4gKiBib3VuZGFyeSByYXRoZXIgdGhhbiBcImFueXRoaW5nIGdvZXNcIi4gWWllbGRzIG5vdGhpbmcgd2hlbiBuZWl0aGVyIGlzIHNldCxcbiAqIHdoaWNoIG9ubHkgaGFwcGVucyBpbiBvdXRib3ggbW9kZSAod2hlcmUgdGhlIHNlbmRlciBmYWxscyBiYWNrIHRvIHRoZVxuICogb24tYmVoYWxmLW9mIHVzZXIncyBvd24gYWRkcmVzcyBhbmQgY2Fubm90IGJlIGVudW1lcmF0ZWQgdXAgZnJvbnQpLlxuICovXG5mdW5jdGlvbiBpbXBsaWVkU2VuZGVyUGF0dGVybnMoZG9tYWluOiBzdHJpbmcgfCB1bmRlZmluZWQsIGZyb206IHN0cmluZyB8IHVuZGVmaW5lZCk6IHN0cmluZ1tdIHtcbiAgY29uc3QgcGF0dGVybnM6IHN0cmluZ1tdID0gW107XG4gIGlmIChmcm9tKSBwYXR0ZXJucy5wdXNoKGZyb20udHJpbSgpLnRvTG93ZXJDYXNlKCkpO1xuICBpZiAoZG9tYWluKSBwYXR0ZXJucy5wdXNoKGAqQCR7ZG9tYWluLnRyaW0oKS50b0xvd2VyQ2FzZSgpfWApO1xuICByZXR1cm4gcGF0dGVybnM7XG59XG5cbi8qKiBXaGV0aGVyIGBFTUFJTF9PVVRCT1hfTU9ERWAgZXhwbGljaXRseSBvcHRzIGludG8gdGhlIGZpbGUvb3V0Ym94IGZhbGxiYWNrLiAqL1xuZnVuY3Rpb24gaXNPdXRib3hNb2RlRW5hYmxlZCgpOiBib29sZWFuIHtcbiAgcmV0dXJuIG9iamVjdC50b0Jvb2xlYW4ocHJvY2Vzcy5lbnYuRU1BSUxfT1VUQk9YX01PREUpID8/IGZhbHNlO1xufVxuXG5jb25zdCBTTVRQX1JFUVVJUkVEX0ZJRUxEUyA9IFtcIlNNVFBfSE9TVFwiLCBcIlNNVFBfVVNFUlwiLCBcIlNNVFBfUEFTU1dPUkRcIl0gYXMgY29uc3Q7XG5cbi8qKiBMaXN0IGVudiBrZXlzIGZvciBTTVRQIGZpZWxkcyB0aGF0IGFyZSB1bnNldCBpbiB0aGUgcmVzb2x2ZWQgY3JlZGVudGlhbCBzZXQuICovXG5mdW5jdGlvbiBtaXNzaW5nU210cEZpZWxkcyhcbiAgaG9zdDogc3RyaW5nIHwgdW5kZWZpbmVkLFxuICB1c2VyOiBzdHJpbmcgfCB1bmRlZmluZWQsXG4gIHBhc3M6IHN0cmluZyB8IHVuZGVmaW5lZCxcbik6IHN0cmluZ1tdIHtcbiAgY29uc3QgdmFsdWVzID0gW2hvc3QsIHVzZXIsIHBhc3NdIGFzIGNvbnN0O1xuICByZXR1cm4gU01UUF9SRVFVSVJFRF9GSUVMRFMuZmlsdGVyKChfLCBpbmRleCkgPT4gIXZhbHVlc1tpbmRleF0pO1xufVxuXG4vKipcbiAqIFJlc29sdmUgcGx1Z2luIGNvbmZpZyBvdmVyIGVudmlyb25tZW50IGRlZmF1bHRzLlxuICpcbiAqIFdoZW4gU01UUCBob3N0ICsgdXNlciArIHBhc3N3b3JkIGFyZSBhbGwgcHJlc2VudCwgcmV0dXJucyBgbW9kZTpcbiAqIFwic210cFwiYCBmb3IgcmVhbCBkZWxpdmVyeSAoYW5kIHRocm93cyBpZiBubyBzZW5kZXIgc291cmNlIC0gZG9tYWluIG9yXG4gKiBmcm9tIC0gaXMgY29uZmlndXJlZCwgc2luY2UgU01UUCBjYW4ndCBkZXJpdmUgb25lIGZyb20gbm90aGluZykuXG4gKiBXaGVuIGFsbCB0aHJlZSBhcmUgYWJzZW50IGFuZCBgRU1BSUxfT1VUQk9YX01PREVgIGlzIGVuYWJsZWQsIHJldHVybnNcbiAqIGBtb2RlOiBcImZpbGVcImAgc28gdGhlIHJ1bnRpbWUgd3JpdGVzIG1lc3NhZ2VzIHRvIHRoZSBvdXRib3ggZGlyZWN0b3J5XG4gKiBmb3IgbG9jYWwgdGVzdGluZzsgaW4gdGhhdCBtb2RlIGEgc2VuZGVyIHNvdXJjZSBpcyBvcHRpb25hbCAodGhlXG4gKiBvdXRib3ggZmFsbHMgYmFjayB0byB0aGUgT0JPIHVzZXIncyBvd24gYWRkcmVzcykuIFBhcnRpYWwgU01UUFxuICogY29uZmlndXJhdGlvbiBvciBhIHNlbmQgd2l0aCBubyBjcmVkZW50aWFscyBhbmQgbm8gb3V0Ym94IG9wdC1pblxuICogdGhyb3dzLlxuICpcbiAqIFRoZSBzZW5kZXIgYWxsb3ctbGlzdCBpcyByZXNvbHZlZCBoZXJlIHRvbzogdW5kZXIgdGhlIGRlZmF1bHRcbiAqIGBcImFsbG93bGlzdFwiYCBwb2xpY3kgYW4gZW1wdHkgbGlzdCBpcyBmaWxsZWQgaW4gZnJvbSB0aGUgc2VuZGVyIHNvdXJjZSxcbiAqIHNvIGEgZGVwbG95bWVudCB0aGF0IG9ubHkgc2V0cyBgRU1BSUxfRE9NQUlOYCBzdGlsbCByZWplY3RzIGEgYEZyb21gIG9uXG4gKiBhbnkgb3RoZXIgZG9tYWluLiBTZWUge0BsaW5rIFNlbmRlclBvbGljeX0uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXNvbHZlRW1haWxDb25maWcoY29uZmlnOiBFbWFpbFBsdWdpbkNvbmZpZyA9IHt9KTogUmVzb2x2ZWRFbWFpbENvbmZpZyB7XG4gIGNvbnN0IHNtdHAgPSBjb25maWcuc210cCA/PyB7fTtcbiAgY29uc3QgaG9zdCA9IHNtdHAuaG9zdCA/PyBwcm9jZXNzLmVudi5TTVRQX0hPU1Q7XG4gIGNvbnN0IHVzZXIgPSBzbXRwLnVzZXIgPz8gcHJvY2Vzcy5lbnYuU01UUF9VU0VSO1xuICBjb25zdCBwYXNzID0gc210cC5wYXNzd29yZCA/PyBwcm9jZXNzLmVudi5TTVRQX1BBU1NXT1JEO1xuICBjb25zdCBkb21haW4gPSBjb25maWcuZG9tYWluID8/IHByb2Nlc3MuZW52LkVNQUlMX0RPTUFJTjtcbiAgY29uc3QgZnJvbSA9IGNvbmZpZy5mcm9tID8/IHByb2Nlc3MuZW52LkVNQUlMX0ZST007XG4gIGNvbnN0IHNlbmRlclBvbGljeSA9IHJlc29sdmVTZW5kZXJQb2xpY3koY29uZmlnLnNlbmRlclBvbGljeSk7XG4gIGNvbnN0IGNvbmZpZ3VyZWRTZW5kZXJzID0gcGFyc2VBbGxvd2VkU2VuZGVycyhcbiAgICBjb25maWcuYWxsb3dlZFNlbmRlcnMgPz8gcHJvY2Vzcy5lbnYuRU1BSUxfQUxMT1dFRF9TRU5ERVJTLFxuICApO1xuICBjb25zdCBhbGxvd2VkU2VuZGVycyA9XG4gICAgY29uZmlndXJlZFNlbmRlcnMubGVuZ3RoID4gMCB8fCBzZW5kZXJQb2xpY3kgPT09IFwidW5yZXN0cmljdGVkXCJcbiAgICAgID8gY29uZmlndXJlZFNlbmRlcnNcbiAgICAgIDogaW1wbGllZFNlbmRlclBhdHRlcm5zKGRvbWFpbiwgZnJvbSk7XG4gIGNvbnN0IHNlbmRlcjogUmVzb2x2ZWRTZW5kZXIgPSB7XG4gICAgLi4uKGRvbWFpbiA/IHsgZG9tYWluIH0gOiB7fSksXG4gICAgLi4uKGZyb20gPyB7IGZyb20gfSA6IHt9KSxcbiAgICBhbGxvd2VkU2VuZGVycyxcbiAgICBzZW5kZXJQb2xpY3ksXG4gICAgLi4uKGNvbmZpZy5icmFuZCA/IHsgYnJhbmQ6IGNvbmZpZy5icmFuZCB9IDoge30pLFxuICB9O1xuXG4gIGNvbnN0IGhhc0FsbFNtdHAgPSBCb29sZWFuKGhvc3QgJiYgdXNlciAmJiBwYXNzKTtcbiAgY29uc3QgaGFzQW55U210cCA9IEJvb2xlYW4oaG9zdCB8fCB1c2VyIHx8IHBhc3MpO1xuXG4gIGlmIChoYXNBbnlTbXRwICYmICFoYXNBbGxTbXRwKSB7XG4gICAgdGhyb3cgVmFsaWRhdGlvbkVycm9yLm1pc3NpbmdFbnZWYXJzKG1pc3NpbmdTbXRwRmllbGRzKGhvc3QsIHVzZXIsIHBhc3MpKTtcbiAgfVxuXG4gIGlmIChoYXNBbGxTbXRwKSB7XG4gICAgaWYgKCFkb21haW4gJiYgIWZyb20pIHtcbiAgICAgIHRocm93IENvbmZpZ3VyYXRpb25FcnJvci5yZXNvdXJjZU5vdEZvdW5kKFxuICAgICAgICBcIkVtYWlsIHNlbmRlciBzb3VyY2VcIixcbiAgICAgICAgXCJTZXQgRU1BSUxfRE9NQUlOIHRvIGRlcml2ZSA8dXNlci1sb2NhbC1wYXJ0PkA8ZG9tYWluPiwgb3IgRU1BSUxfRlJPTSBmb3IgYSBmaXhlZCBhZGRyZXNzLlwiLFxuICAgICAgKTtcbiAgICB9XG4gICAgY29uc3QgcG9ydFJhdyA9IHNtdHAucG9ydCA/PyBOdW1iZXIocHJvY2Vzcy5lbnYuU01UUF9QT1JUKTtcbiAgICBjb25zdCBwb3J0ID0gTnVtYmVyLmlzRmluaXRlKHBvcnRSYXcpICYmIHBvcnRSYXcgPyBOdW1iZXIocG9ydFJhdykgOiBERUZBVUxUX1NNVFBfUE9SVDtcbiAgICByZXR1cm4ge1xuICAgICAgbW9kZTogXCJzbXRwXCIsXG4gICAgICBob3N0OiBob3N0ISxcbiAgICAgIHBvcnQsXG4gICAgICBzZWN1cmU6IHJlc29sdmVTZWN1cmUoc210cC5zZWN1cmUsIHBvcnQpLFxuICAgICAgYXV0aDogeyB1c2VyOiB1c2VyISwgcGFzczogcGFzcyEgfSxcbiAgICAgIC4uLnNlbmRlcixcbiAgICB9O1xuICB9XG5cbiAgaWYgKCFpc091dGJveE1vZGVFbmFibGVkKCkpIHtcbiAgICB0aHJvdyBDb25maWd1cmF0aW9uRXJyb3IuaW52YWxpZENvbm5lY3Rpb24oXG4gICAgICBcIlNNVFBcIixcbiAgICAgIGBTZXQgJHtTTVRQX1JFUVVJUkVEX0ZJRUxEUy5qb2luKFwiLCBcIil9LCBvciBFTUFJTF9PVVRCT1hfTU9ERT0xIHRvIHdyaXRlIG1lc3NhZ2VzIHRvIGEgbG9jYWwgb3V0Ym94IGluc3RlYWQuYCxcbiAgICApO1xuICB9XG5cbiAgY29uc3Qgb3V0RGlyID0gcmVzb2x2ZShcbiAgICBjb25maWcub3V0RGlyID8/IHByb2Nlc3MuZW52LkVNQUlMX09VVEJPWF9ESVIgPz8gcmVzb2x2ZShwcm9jZXNzLmN3ZCgpLCBcInRtcFwiKSxcbiAgKTtcbiAgcmV0dXJuIHsgbW9kZTogXCJmaWxlXCIsIG91dERpciwgLi4uc2VuZGVyIH07XG59XG4iXX0=
264
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlnLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvbmZpZy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBd0JHO0FBQ0gsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUNwQyxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsZUFBZSxFQUF5QixNQUFNLG9CQUFvQixDQUFDO0FBQ2hHLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFHeEQsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sYUFBYSxDQUFDO0FBRWxELHlEQUF5RDtBQUN6RCxNQUFNLENBQUMsTUFBTSxpQkFBaUIsR0FBRyxHQUFHLENBQUM7QUFFckMsMkVBQTJFO0FBQzNFLE1BQU0sQ0FBQyxNQUFNLHNCQUFzQixHQUFHLEdBQUcsQ0FBQztBQW1KMUMsK0RBQStEO0FBQy9ELE1BQU0sQ0FBQyxNQUFNLG1CQUFtQixHQUFnQjtJQUM5QyxJQUFJLEVBQUUsUUFBUTtJQUNkLFVBQVUsRUFBRTtRQUNWLElBQUksRUFBRTtZQUNKLElBQUksRUFBRSxRQUFRO1lBQ2QsV0FBVyxFQUFFLDBEQUEwRDtZQUN2RSxVQUFVLEVBQUU7Z0JBQ1YsSUFBSSxFQUFFLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxXQUFXLEVBQUUsbUNBQW1DLEVBQUU7Z0JBQzFFLElBQUksRUFBRTtvQkFDSixJQUFJLEVBQUUsUUFBUTtvQkFDZCxXQUFXLEVBQUUsNkNBQTZDLGlCQUFpQixHQUFHO2lCQUMvRTtnQkFDRCxNQUFNLEVBQUU7b0JBQ04sSUFBSSxFQUFFLFNBQVM7b0JBQ2YsV0FBVyxFQUFFLDZEQUE2RCxzQkFBc0IsR0FBRztpQkFDcEc7Z0JBQ0QsSUFBSSxFQUFFLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxXQUFXLEVBQUUsaUNBQWlDLEVBQUU7Z0JBQ3hFLFFBQVEsRUFB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QyxJQUFJLEVBQUUsRUFBRSxJQUFJLEVBQUUsSUFBSyxFQUFFLElBQUksRUFBRSxJQUFLLEVBQUU7WUFDbEMsR0FBRyxNQUFNO1NBQ1YsQ0FBQztJQUNKLENBQUM7SUFFRCxJQUFJLENBQUMsbUJBQW1CLEVBQUUsRUFBRSxDQUFDO1FBQzNCLE1BQU0sa0JBQWtCLENBQUMsaUJBQWlCLENBQ3hDLE1BQU0sRUFDTixPQUFPLG9CQUFvQixDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsdUVBQXVFLENBQzlHLENBQUM7SUFDSixDQUFDO0lBRUQsTUFBTSxNQUFNLEdBQUcsT0FBTyxDQUNwQixNQUFNLENBQUMsTUFBTSxJQUFJLE9BQU8sQ0FBQyxHQUFHLENBQUMsZ0JBQWdCLElBQUksT0FBTyxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUUsRUFBRSxLQUFLLENBQUMsQ0FDL0UsQ0FBQztJQUNGLE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxHQUFHLE1BQU0sRUFBRSxDQUFDO0FBQzdDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFNNVFAgY29uZmlndXJhdGlvbiBmb3IgdGhlIGVtYWlsIHBsdWdpbjogdGhlIHR5cGVkXG4gKiB7QGxpbmsgRW1haWxQbHVnaW5Db25maWd9ICh0aGUgcGx1Z2luJ3Mgc2xpY2Ugb2YgQXBwS2l0IGNvbmZpZyksIHRoZVxuICogSlNPTiBTY2hlbWEgdGhlIG1hbmlmZXN0IHB1Ymxpc2hlcyBmb3IgaXQsIGFuZCB7QGxpbmsgcmVzb2x2ZUVtYWlsQ29uZmlnfVxuICogd2hpY2ggbGF5ZXJzIHRoYXQgY29uZmlnIG92ZXIgZW52aXJvbm1lbnQgZGVmYXVsdHMgaW50byB0aGUgY29uY3JldGVcbiAqIHtAbGluayBSZXNvbHZlZEVtYWlsQ29uZmlnfSB0aGUgcnVudGltZSBuZWVkcy5cbiAqXG4gKiBUd28gbW9kZXMgZmFsbCBvdXQgb2YgdGhlIHJlc29sdXRpb24uIFdoZW4gU01UUCBjcmVkZW50aWFscyAoaG9zdCArXG4gKiB1c2VyICsgcGFzc3dvcmQpIGFyZSBhbGwgcHJlc2VudCBpdCByZXNvbHZlcyB0byBgbW9kZTogXCJzbXRwXCJgIGFuZFxuICogbWFpbCBpcyBzZW50IGZvciByZWFsLiBXaGVuIHRoZXkgYXJlIGFic2VudCBhbmQgYEVNQUlMX09VVEJPWF9NT0RFYFxuICogaXMgZXhwbGljaXRseSBlbmFibGVkIGl0IHJlc29sdmVzIHRvIGBtb2RlOiBcImZpbGVcImAgKGFuIFwib3V0Ym94XCIpXG4gKiBhbmQgZWFjaCBtZXNzYWdlIGlzIHdyaXR0ZW4gdG8gZGlzayBhcyBIVE1MIGluc3RlYWQgb2Ygc2VudC4gQW55XG4gKiBwYXJ0aWFsIFNNVFAgY29uZmlndXJhdGlvbiBvciBhIHNlbmQgYXR0ZW1wdCB3aXRoIG5vIGNyZWRlbnRpYWxzIGFuZFxuICogbm8gb3V0Ym94IG9wdC1pbiB0aHJvd3MuXG4gKlxuICogUHJlY2VkZW5jZSBwZXIgZmllbGQ6IGV4cGxpY2l0IHBsdWdpbiBjb25maWcgd2lucywgdGhlbiB0aGUgbWF0Y2hpbmdcbiAqIGVudmlyb25tZW50IHZhcmlhYmxlLiBFbnYgbmFtZXMgYXJlIHVucHJlZml4ZWQgYmVjYXVzZSB0aGUgYXBwIHRhbGtzXG4gKiB0byBhIHNpbmdsZSBTTVRQIHNlcnZlciAoZS5nLiBTTVRQMkdPKTogYFNNVFBfSE9TVGAsIGBTTVRQX1BPUlRgLFxuICogYFNNVFBfU0VDVVJFYCwgYFNNVFBfVVNFUmAsIGBTTVRQX1BBU1NXT1JEYCwgcGx1cyBgRU1BSUxfRE9NQUlOYCBmb3JcbiAqIHRoZSBkZXJpdmVkIHNlbmRlcidzIGRvbWFpbiwgYEVNQUlMX0ZST01gIGZvciBhbiBleHBsaWNpdCBvdmVycmlkZSxcbiAqIGBFTUFJTF9TRU5ERVJfUE9MSUNZYCBmb3IgdGhlIHNlbmRlciByZXN0cmljdGlvbiBtb2RlLCBhbmRcbiAqIGBFTUFJTF9PVVRCT1hfRElSYCBmb3IgdGhlIG91dGJveCBkaXJlY3RvcnkuXG4gKlxuICogQG1vZHVsZVxuICovXG5pbXBvcnQgeyByZXNvbHZlIH0gZnJvbSBcIm5vZGU6cGF0aFwiO1xuaW1wb3J0IHsgQ29uZmlndXJhdGlvbkVycm9yLCBWYWxpZGF0aW9uRXJyb3IsIHR5cGUgQmFzZVBsdWdpbkNvbmZpZyB9IGZyb20gXCJAZGF0YWJyaWNrcy9hcHBraXRcIjtcbmltcG9ydCB7IG9iamVjdCwgc3RyaW5nIH0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLWNvcmVcIjtcbmltcG9ydCB0eXBlIHsgSlNPTlNjaGVtYTcgfSBmcm9tIFwianNvbi1zY2hlbWFcIjtcbmltcG9ydCB0eXBlIHsgRW1haWxCcmFuZCB9IGZyb20gXCIuL2JyYW5kLnRzXCI7XG5pbXBvcnQgeyBwYXJzZUFsbG93ZWRTZW5kZXJzIH0gZnJvbSBcIi4vc2VuZGVyLnRzXCI7XG5cbi8qKiBTTVRQIHN1Ym1pc3Npb24gcG9ydCB1c2VkIHdoZW4gbm9uZSBpcyBjb25maWd1cmVkLiAqL1xuZXhwb3J0IGNvbnN0IERFRkFVTFRfU01UUF9QT1JUID0gNTg3O1xuXG4vKiogU01UUCBwb3J0IHRoYXQgaW1wbGllcyBhIFRMUy1vbi1jb25uZWN0IHNvY2tldCByYXRoZXIgdGhhbiBTVEFSVFRMUy4gKi9cbmV4cG9ydCBjb25zdCBJTVBMSUNJVF9UTFNfU01UUF9QT1JUID0gNDY1O1xuXG4vKipcbiAqIEhvdyB0aGUgc2VuZGVyIChgRnJvbWApIGFkZHJlc3MgaXMgcmVzdHJpY3RlZC5cbiAqXG4gKiBgXCJhbGxvd2xpc3RcImAgaXMgdGhlIGRlZmF1bHQgYW5kIHRoZSBkZW55LWJ5LWRlZmF1bHQgcG9zdHVyZTogYSBzZW5kIGlzXG4gKiBwZXJtaXR0ZWQgb25seSBmcm9tIGFuIGFkZHJlc3MgdGhlIGNvbmZpZ3VyYXRpb24gbmFtZXMsIGVpdGhlciB0aHJvdWdoXG4gKiB7QGxpbmsgRW1haWxQbHVnaW5Db25maWcuYWxsb3dlZFNlbmRlcnN9IG9yLCB3aGVuIHRoYXQgaXMgZW1wdHksIHRocm91Z2hcbiAqIHRoZSBjb25maWd1cmVkIHNlbmRlciBzb3VyY2UgKHtAbGluayBFbWFpbFBsdWdpbkNvbmZpZy5mcm9tfSBhcyBhbiBleGFjdFxuICogYWRkcmVzcywge0BsaW5rIEVtYWlsUGx1Z2luQ29uZmlnLmRvbWFpbn0gYXMgYSBgKkBkb21haW5gIHdpbGRjYXJkKS5cbiAqXG4gKiBgXCJ1bnJlc3RyaWN0ZWRcImAgaXMgdGhlIGV4cGxpY2l0IG9wdC1vdXQ6IGFueSBgRnJvbWAgYSBjYWxsZXIgc3VwcGxpZXMgaXNcbiAqIGFjY2VwdGVkLiBPbmx5IHJlYWNoIGZvciBpdCB3aGVuIGFuIHVwc3RyZWFtIHN5c3RlbSBhbHJlYWR5IHZldHMgdGhlXG4gKiBzZW5kZXIuXG4gKi9cbmV4cG9ydCB0eXBlIFNlbmRlclBvbGljeSA9IFwiYWxsb3dsaXN0XCIgfCBcInVucmVzdHJpY3RlZFwiO1xuXG4vKiogU01UUCBjb25uZWN0aW9uICsgY3JlZGVudGlhbHMuIEFsbCBmaWVsZHMgZmFsbCBiYWNrIHRvIGVudiB3aGVuIHVuc2V0LiAqL1xuZXhwb3J0IGludGVyZmFjZSBTbXRwQ29uZmlnIHtcbiAgLyoqIFNNVFAgc2VydmVyIGhvc3RuYW1lIChgU01UUF9IT1NUYCkuICovXG4gIGhvc3Q/OiBzdHJpbmc7XG4gIC8qKiBTTVRQIHNlcnZlciBwb3J0IChgU01UUF9QT1JUYCkuIERlZmF1bHRzIHRvIHtAbGluayBERUZBVUxUX1NNVFBfUE9SVH0uICovXG4gIHBvcnQ/OiBudW1iZXI7XG4gIC8qKlxuICAgKiBVc2UgYSBUTFMtb24tY29ubmVjdCBzb2NrZXQgKGBTTVRQX1NFQ1VSRWApLiBEZWZhdWx0cyB0b1xuICAgKiBgcG9ydCA9PT0gYCB7QGxpbmsgSU1QTElDSVRfVExTX1NNVFBfUE9SVH0uXG4gICAqL1xuICBzZWN1cmU/OiBib29sZWFuO1xuICAvKiogU01UUCBhdXRoIHVzZXJuYW1lIChgU01UUF9VU0VSYCkuICovXG4gIHVzZXI/OiBzdHJpbmc7XG4gIC8qKiBTTVRQIGF1dGggcGFzc3dvcmQgLyBBUEkga2V5IChgU01UUF9QQVNTV09SRGApLiAqL1xuICBwYXNzd29yZD86IHN0cmluZztcbn1cblxuLyoqIEFwcEtpdCBjb25maWcgYWNjZXB0ZWQgYnkgdGhlIGVtYWlsIHBsdWdpbi4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgRW1haWxQbHVnaW5Db25maWcgZXh0ZW5kcyBCYXNlUGx1Z2luQ29uZmlnIHtcbiAgLyoqIFNNVFAgY29ubmVjdGlvbiArIGNyZWRlbnRpYWxzLiBPbWl0IHRvIHJ1biBpbiBmaWxlL291dGJveCBtb2RlLiAqL1xuICBzbXRwPzogU210cENvbmZpZztcbiAgLyoqXG4gICAqIERvbWFpbiB1c2VkIHRvIGJ1aWxkIHRoZSBzZW5kZXIgYWRkcmVzcyBmcm9tIHRoZSBvbi1iZWhhbGYtb2YgdXNlclxuICAgKiAoYDxsb2NhbC1wYXJ0PkA8ZG9tYWluPmApLiBGYWxscyBiYWNrIHRvIGBFTUFJTF9ET01BSU5gLiBSZXF1aXJlZCBpblxuICAgKiBTTVRQIG1vZGUgdW5sZXNzIHtAbGluayBmcm9tfSBpcyBzZXQ7IG9wdGlvbmFsIGluIGZpbGUgbW9kZSAodGhlXG4gICAqIG91dGJveCBmYWxscyBiYWNrIHRvIHRoZSB1c2VyJ3Mgb3duIGVtYWlsIGFkZHJlc3MpLlxuICAgKi9cbiAgZG9tYWluPzogc3RyaW5nO1xuICAvKipcbiAgICogRXhwbGljaXQgYEZyb21gIGFkZHJlc3MuIFdoZW4gc2V0LCB0aGUgc2VuZGVyIGlzIHVzZWQgdmVyYmF0aW0gYW5kXG4gICAqIHRoZSBwZXItdXNlciBkZXJpdmF0aW9uIGlzIHNraXBwZWQuIEZhbGxzIGJhY2sgdG8gYEVNQUlMX0ZST01gLlxuICAgKi9cbiAgZnJvbT86IHN0cmluZztcbiAgLyoqXG4gICAqIERpcmVjdG9yeSBmb3IgdGhlIGZpbGUvb3V0Ym94IGZhbGxiYWNrLiBGYWxscyBiYWNrIHRvXG4gICAqIGBFTUFJTF9PVVRCT1hfRElSYCwgdGhlbiBgPGN3ZD4vdG1wYC4gT25seSB1c2VkIHdoZW4gU01UUFxuICAgKiBjcmVkZW50aWFscyBhcmUgYWJzZW50LlxuICAgKi9cbiAgb3V0RGlyPzogc3RyaW5nO1xuICAvKipcbiAgICogQWxsb3ctbGlzdCByZXN0cmljdGluZyB0aGUgc2VuZGVyIChgRnJvbWApIGFkZHJlc3MuIEVhY2ggZW50cnkgaXMgYW5cbiAgICogZXhhY3QgYWRkcmVzcyAoYHVzZXJAZG9tYWluLmNvbWApLCBhIGRvbWFpbiB3aWxkY2FyZCAoYCpAZG9tYWluLmNvbWBcbiAgICogb3IgdGhlIGJhcmUgYGRvbWFpbi5jb21gLCBtYXRjaGluZyBhbnkgbG9jYWwgcGFydCBvbiB0aGF0IGRvbWFpbiksIG9yXG4gICAqIGAqYCAoYW55KS4gQSByZXNvbHZlZCAvIGNob3NlbiBzZW5kZXIgdGhhdCBtYXRjaGVzIG5vIGVudHJ5IGlzXG4gICAqIHJlamVjdGVkIGF0IHNlbmQgdGltZS4gQWNjZXB0cyBhIGBzdHJpbmdbXWAgb3IgYSBzaW5nbGUgY29tbWEtIC9cbiAgICogd2hpdGVzcGFjZS1zZXBhcmF0ZWQgc3RyaW5nOyBmYWxscyBiYWNrIHRvIGBFTUFJTF9BTExPV0VEX1NFTkRFUlNgLlxuICAgKiBXaGVuIGVtcHR5LCB0aGUge0BsaW5rIHNlbmRlclBvbGljeX0gZGVjaWRlcyB3aGF0IGlzIHBlcm1pdHRlZC5cbiAgICovXG4gIGFsbG93ZWRTZW5kZXJzPzogc3RyaW5nIHwgc3RyaW5nW107XG4gIC8qKlxuICAgKiBIb3cgdGhlIHNlbmRlciBhZGRyZXNzIGlzIHJlc3RyaWN0ZWQgd2hlbiB7QGxpbmsgYWxsb3dlZFNlbmRlcnN9IGlzXG4gICAqIGVtcHR5IChgRU1BSUxfU0VOREVSX1BPTElDWWApLiBEZWZhdWx0cyB0byBgXCJhbGxvd2xpc3RcImAsIHdoaWNoXG4gICAqIG5hcnJvd3Mgc2VuZHMgdG8gdGhlIGNvbmZpZ3VyZWQgc2VuZGVyIHNvdXJjZS4gU2VlXG4gICAqIHtAbGluayBTZW5kZXJQb2xpY3l9LlxuICAgKi9cbiAgc2VuZGVyUG9saWN5PzogU2VuZGVyUG9saWN5O1xuICAvKipcbiAgICogT3B0aW9uYWwgYnJhbmQgc3R5bGluZyAoYWNjZW50LCBmb250LCBoZWFkZXIgbG9nbykgYXBwbGllZCB0byB0aGVcbiAgICogcmVuZGVyZWQgSFRNTCBvZiBldmVyeSBtZXNzYWdlLiBPbWl0IGZvciB0aGUgbmV1dHJhbCBkZWZhdWx0IGxheW91dC5cbiAgICogUGFzcyB7QGxpbmsgZW1haWxCcmFuZEZyb21Db250ZXh0fSB0byBkZXJpdmUgaXQgZnJvbSBhIHNoYXJlZFxuICAgKiBgQnJhbmRDb250ZXh0YC5cbiAgICovXG4gIGJyYW5kPzogRW1haWxCcmFuZDtcbiAgLyoqXG4gICAqIE9wdGlvbmFsIGVtYWlsLU9UUCBBQ0NFU1MgR0FURS4gV2hlbiBgZW5hYmxlZGAsIHRoZSBwbHVnaW4gbW91bnRzIGEgbG9naW5cbiAgICogZmxvdyAoYC9hcGkvZW1haWwvYXV0aC8qYCkgYW5kIGdhdGVzIGV2ZXJ5IG90aGVyIHJvdXRlIGJlaGluZCBhIHNlc3Npb25cbiAgICogY29va2llIC0gdGhlIGZyb250IGRvb3IgZm9yIGFuIGFwcCBleHBvc2VkIHB1YmxpY2x5IChlLmcuIHRocm91Z2ggYSBwb3J0clxuICAgKiB0dW5uZWwgdGhhdCBieXBhc3NlcyB0aGUgRGF0YWJyaWNrcyBPQXV0aCBwcm94eSkuIFJldXNlcyB0aGlzIHBsdWdpbidzXG4gICAqIHRyYW5zcG9ydCB0byBlbWFpbCB0aGUgY29kZS4gT21pdCBvciBgZW5hYmxlZDogZmFsc2VgIHRvIGxlYXZlIHRoZSBhcHAgb3Blbi5cbiAgICovXG4gIGF1dGg/OiBBdXRoQ29uZmlnO1xufVxuXG4vKiogRW1haWwtT1RQIGFjY2Vzcy1nYXRlIGNvbmZpZ3VyYXRpb24gKHNlZSB7QGxpbmsgRW1haWxQbHVnaW5Db25maWcuYXV0aH0pLiAqL1xuZXhwb3J0IGludGVyZmFjZSBBdXRoQ29uZmlnIHtcbiAgLyoqIFR1cm4gdGhlIGdhdGUgb24uIEZhbGxzIGJhY2sgdG8gYEVNQUlMX0FVVEhfRU5BQkxFRGAuIERlZmF1bHQgb2ZmLiAqL1xuICBlbmFibGVkPzogYm9vbGVhbjtcbiAgLyoqXG4gICAqIFdobyBtYXkgcmVxdWVzdCBhIGNvZGUuIEVhY2ggZW50cnkgaXMgYSBkb21haW4gc2hvcnRjdXQgKGBkYXRhYnJpY2tzLmNvbWBcbiAgICogb3IgYEBkYXRhYnJpY2tzLmNvbWApLCBhIGdsb2IgKGAqLmRhdGFicmlja3MuY29tYCksIG9yIGEgYC9yZWdleC9gLiBBblxuICAgKiBFTVBUWSBsaXN0IGFsbG93cyBub2JvZHkgKGZhaWwgY2xvc2VkKS4gRmFsbHMgYmFjayB0byBgRU1BSUxfQVVUSF9BTExPV2BcbiAgICogKGNvbW1hL3NwYWNlLXNlcGFyYXRlZCkuXG4gICAqL1xuICBhbGxvdz86IHN0cmluZyB8IHN0cmluZ1tdO1xuICAvKiogU2Vzc2lvbiBsaWZldGltZSAoc2Vjb25kcykuIEZhbGxzIGJhY2sgdG8gYEVNQUlMX0FVVEhfU0VTU0lPTl9UVExgLiBEZWZhdWx0IDQzMjAwICgxMmgpLiAqL1xuICBzZXNzaW9uVHRsU2Vjb25kcz86IG51bWJlcjtcbiAgLyoqIE9uZS10aW1lLWNvZGUgbGlmZXRpbWUgKHNlY29uZHMpLiBGYWxscyBiYWNrIHRvIGBFTUFJTF9BVVRIX0NPREVfVFRMYC4gRGVmYXVsdCA2MDAgKDEwbSkuICovXG4gIGNvZGVUdGxTZWNvbmRzPzogbnVtYmVyO1xuICAvKiogTWF4IHZlcmlmeSBhdHRlbXB0cyBwZXIgaXNzdWVkIGNvZGUuIERlZmF1bHQgNS4gKi9cbiAgbWF4QXR0ZW1wdHM/OiBudW1iZXI7XG59XG5cbi8qKiBDb25maWcgc2hhcmVkIGJ5IGJvdGggcmVzb2x2ZWQgbW9kZXMuICovXG5pbnRlcmZhY2UgUmVzb2x2ZWRTZW5kZXIge1xuICAvKiogU2VuZGVyIGRvbWFpbjsgcHJlc2VudCB3aGVuZXZlciB7QGxpbmsgZnJvbX0gaXMgYWJzZW50LiAqL1xuICBkb21haW4/OiBzdHJpbmc7XG4gIC8qKiBFeHBsaWNpdCBzZW5kZXIgb3ZlcnJpZGU7IHByZXNlbnQgc2tpcHMgcGVyLXVzZXIgZGVyaXZhdGlvbi4gKi9cbiAgZnJvbT86IHN0cmluZztcbiAgLyoqXG4gICAqIEVmZmVjdGl2ZSBzZW5kZXIgYWxsb3ctbGlzdDogdGhlIGNvbmZpZ3VyZWQgcGF0dGVybnMgd2hlbiBhbnkgd2VyZVxuICAgKiBnaXZlbiwgZWxzZSB0aGUgcGF0dGVybnMgaW1wbGllZCBieSB0aGUgc2VuZGVyIHNvdXJjZSB1bmRlciBhblxuICAgKiBgXCJhbGxvd2xpc3RcImAgcG9saWN5LiBFbXB0eSBtZWFucyB1bmVuZm9yY2VhYmxlIChhbiBgXCJ1bnJlc3RyaWN0ZWRcImBcbiAgICogcG9saWN5LCBvciBhbiBvdXRib3ggd2l0aCBubyBzZW5kZXIgc291cmNlIHRvIG5hcnJvdyB0bykuXG4gICAqL1xuICBhbGxvd2VkU2VuZGVyczogc3RyaW5nW107XG4gIC8qKiBUaGUgcmVzdHJpY3Rpb24gbW9kZSB0aGUgYWxsb3ctbGlzdCB3YXMgcmVzb2x2ZWQgdW5kZXIuICovXG4gIHNlbmRlclBvbGljeTogU2VuZGVyUG9saWN5O1xuICAvKiogQnJhbmQgc3R5bGluZyBhcHBsaWVkIHRvIHJlbmRlcmVkIEhUTUw7IGFic2VudCBmb3IgdGhlIGRlZmF1bHQgbGF5b3V0LiAqL1xuICBicmFuZD86IEVtYWlsQnJhbmQ7XG59XG5cbi8qKiBSZXNvbHZlZCBjb25maWcgZm9yIHJlYWwgU01UUCBkZWxpdmVyeS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUmVzb2x2ZWRTbXRwQ29uZmlnIGV4dGVuZHMgUmVzb2x2ZWRTZW5kZXIge1xuICBtb2RlOiBcInNtdHBcIjtcbiAgaG9zdDogc3RyaW5nO1xuICBwb3J0OiBudW1iZXI7XG4gIHNlY3VyZTogYm9vbGVhbjtcbiAgYXV0aDogeyB1c2VyOiBzdHJpbmc7IHBhc3M6IHN0cmluZyB9O1xufVxuXG4vKiogUmVzb2x2ZWQgY29uZmlnIGZvciB0aGUgZmlsZS9vdXRib3ggZmFsbGJhY2sgKG5vIFNNVFAgY3JlZGVudGlhbHMpLiAqL1xuZXhwb3J0IGludGVyZmFjZSBSZXNvbHZlZEZpbGVDb25maWcgZXh0ZW5kcyBSZXNvbHZlZFNlbmRlciB7XG4gIG1vZGU6IFwiZmlsZVwiO1xuICAvKiogQWJzb2x1dGUgZGlyZWN0b3J5IG1lc3NhZ2VzIGFyZSB3cml0dGVuIHVuZGVyLiAqL1xuICBvdXREaXI6IHN0cmluZztcbn1cblxuLyoqIENvbmNyZXRlLCB2YWxpZGF0ZWQgY29uZmlnIHRoZSBydW50aW1lIGRpc3BhdGNoZXMgdGhyb3VnaC4gKi9cbmV4cG9ydCB0eXBlIFJlc29sdmVkRW1haWxDb25maWcgPSBSZXNvbHZlZFNtdHBDb25maWcgfCBSZXNvbHZlZEZpbGVDb25maWc7XG5cbi8qKiBKU09OIFNjaGVtYSBwdWJsaXNoZWQgb24gdGhlIG1hbmlmZXN0J3MgYGNvbmZpZy5zY2hlbWFgLiAqL1xuZXhwb3J0IGNvbnN0IEVNQUlMX0NPTkZJR19TQ0hFTUE6IEpTT05TY2hlbWE3ID0ge1xuICB0eXBlOiBcIm9iamVjdFwiLFxuICBwcm9wZXJ0aWVzOiB7XG4gICAgc210cDoge1xuICAgICAgdHlwZTogXCJvYmplY3RcIixcbiAgICAgIGRlc2NyaXB0aW9uOiBcIlNNVFAgY29ubmVjdGlvbiBhbmQgY3JlZGVudGlhbHMgKGVudiBmYWxsYmFja3M6IFNNVFBfKikuXCIsXG4gICAgICBwcm9wZXJ0aWVzOiB7XG4gICAgICAgIGhvc3Q6IHsgdHlwZTogXCJzdHJpbmdcIiwgZGVzY3JpcHRpb246IFwiU01UUCBzZXJ2ZXIgaG9zdG5hbWUgKFNNVFBfSE9TVCkuXCIgfSxcbiAgICAgICAgcG9ydDoge1xuICAgICAgICAgIHR5cGU6IFwibnVtYmVyXCIsXG4gICAgICAgICAgZGVzY3JpcHRpb246IGBTTVRQIHNlcnZlciBwb3J0IChTTVRQX1BPUlQpLiBEZWZhdWx0cyB0byAke0RFRkFVTFRfU01UUF9QT1JUfS5gLFxuICAgICAgICB9LFxuICAgICAgICBzZWN1cmU6IHtcbiAgICAgICAgICB0eXBlOiBcImJvb2xlYW5cIixcbiAgICAgICAgICBkZXNjcmlwdGlvbjogYFRMUy1vbi1jb25uZWN0IHNvY2tldCAoU01UUF9TRUNVUkUpLiBEZWZhdWx0cyB0byBwb3J0ID09PSAke0lNUExJQ0lUX1RMU19TTVRQX1BPUlR9LmAsXG4gICAgICAgIH0sXG4gICAgICAgIHVzZXI6IHsgdHlwZTogXCJzdHJpbmdcIiwgZGVzY3JpcHRpb246IFwiU01UUCBhdXRoIHVzZXJuYW1lIChTTVRQX1VTRVIpLlwiIH0sXG4gICAgICAgIHBhc3N3b3JkOiB7XG4gICAgICAgICAgdHlwZTogXCJzdHJpbmdcIixcbiAgICAgICAgICBkZXNjcmlwdGlvbjogXCJTTVRQIGF1dGggcGFzc3dvcmQgLyBBUEkga2V5IChTTVRQX1BBU1NXT1JEKS5cIixcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgfSxcbiAgICBkb21haW46IHtcbiAgICAgIHR5cGU6IFwic3RyaW5nXCIsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgXCJEb21haW4gZm9yIHRoZSBkZXJpdmVkIHNlbmRlciBhZGRyZXNzICg8dXNlci1sb2NhbC1wYXJ0PkA8ZG9tYWluPikuIEZhbGxzIGJhY2sgdG8gRU1BSUxfRE9NQUlOLlwiLFxuICAgIH0sXG4gICAgZnJvbToge1xuICAgICAgdHlwZTogXCJzdHJpbmdcIixcbiAgICAgIGRlc2NyaXB0aW9uOiBcIkV4cGxpY2l0IEZyb20gYWRkcmVzczsgc2tpcHMgcGVyLXVzZXIgZGVyaXZhdGlvbi4gRmFsbHMgYmFjayB0byBFTUFJTF9GUk9NLlwiLFxuICAgIH0sXG4gICAgb3V0RGlyOiB7XG4gICAgICB0eXBlOiBcInN0cmluZ1wiLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgIFwiRGlyZWN0b3J5IGZvciB0aGUgZmlsZS9vdXRib3ggZmFsbGJhY2sgd2hlbiBTTVRQIGlzIHVuY29uZmlndXJlZC4gRmFsbHMgYmFjayB0byBFTUFJTF9PVVRCT1hfRElSLCB0aGVuIDxjd2Q+L3RtcC5cIixcbiAgICB9LFxuICAgIGFsbG93ZWRTZW5kZXJzOiB7XG4gICAgICB0eXBlOiBcImFycmF5XCIsXG4gICAgICBpdGVtczogeyB0eXBlOiBcInN0cmluZ1wiIH0sXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0FsbG93LWxpc3Qgb2YgcGVybWl0dGVkIHNlbmRlciAoRnJvbSkgcGF0dGVybnM6IGV4YWN0IGFkZHJlc3NlcyAoXCJ1c2VyQGRvbWFpbi5jb21cIiksIGRvbWFpbiB3aWxkY2FyZHMgKFwiKkBkb21haW4uY29tXCIpLCBvciBcIipcIi4gQWxzbyBhY2NlcHRzIGEgY29tbWEvc3BhY2Utc2VwYXJhdGVkIHN0cmluZy4gRmFsbHMgYmFjayB0byBFTUFJTF9BTExPV0VEX1NFTkRFUlMuIFdoZW4gZW1wdHksIHNlbmRlclBvbGljeSBkZWNpZGVzLicsXG4gICAgfSxcbiAgICBzZW5kZXJQb2xpY3k6IHtcbiAgICAgIHR5cGU6IFwic3RyaW5nXCIsXG4gICAgICBlbnVtOiBbXCJhbGxvd2xpc3RcIiwgXCJ1bnJlc3RyaWN0ZWRcIl0sXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0hvdyB0aGUgc2VuZGVyIGlzIHJlc3RyaWN0ZWQgd2hlbiBhbGxvd2VkU2VuZGVycyBpcyBlbXB0eSAoRU1BSUxfU0VOREVSX1BPTElDWSkuIFwiYWxsb3dsaXN0XCIgKGRlZmF1bHQpIG5hcnJvd3Mgc2VuZHMgdG8gdGhlIGNvbmZpZ3VyZWQgc2VuZGVyIHNvdXJjZTsgXCJ1bnJlc3RyaWN0ZWRcIiBhY2NlcHRzIGFueSBGcm9tLicsXG4gICAgfSxcbiAgICBicmFuZDoge1xuICAgICAgdHlwZTogXCJvYmplY3RcIixcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICBcIkJyYW5kIHN0eWxpbmcgaW5saW5lZCBpbnRvIGV2ZXJ5IHJlbmRlcmVkIG1lc3NhZ2UuIE9taXQgZm9yIHRoZSBuZXV0cmFsIGRlZmF1bHQgbGF5b3V0LlwiLFxuICAgICAgcHJvcGVydGllczoge1xuICAgICAgICBhY2NlbnQ6IHtcbiAgICAgICAgICB0eXBlOiBcInN0cmluZ1wiLFxuICAgICAgICAgIGRlc2NyaXB0aW9uOiAnSGVhZGVyLWJhbmQgYmFja2dyb3VuZCBhbmQgYm9keSBsaW5rIGNvbG9yIChlLmcuIFwiI0ZGMzYyMVwiKS4nLFxuICAgICAgICB9LFxuICAgICAgICBvbkFjY2VudDoge1xuICAgICAgICAgIHR5cGU6IFwic3RyaW5nXCIsXG4gICAgICAgICAgZGVzY3JpcHRpb246IFwiVGV4dCBhbmQgbG9nbyBjb2xvciByZW5kZXJlZCBvbiB0aGUgYWNjZW50IGJhbmQuIERlZmF1bHRzIHRvIHdoaXRlLlwiLFxuICAgICAgICB9LFxuICAgICAgICBmb250RmFtaWx5OiB7XG4gICAgICAgICAgdHlwZTogXCJzdHJpbmdcIixcbiAgICAgICAgICBkZXNjcmlwdGlvbjogJ0JvZHkgZm9udCBzdGFjayAoZS5nLiBcIkludGVyLCB1aS1zYW5zLXNlcmlmLCBzeXN0ZW0tdWksIHNhbnMtc2VyaWZcIikuJyxcbiAgICAgICAgfSxcbiAgICAgICAgbmFtZToge1xuICAgICAgICAgIHR5cGU6IFwic3RyaW5nXCIsXG4gICAgICAgICAgZGVzY3JpcHRpb246IFwiUHJvZHVjdCAvIGRpc3BsYXkgbmFtZSB1c2VkIGFzIHRoZSBoZWFkZXIgdGV4dCBhbmQgdGhlIGxvZ28gYWx0IHRleHQuXCIsXG4gICAgICAgIH0sXG4gICAgICAgIGxvZ29Vcmw6IHtcbiAgICAgICAgICB0eXBlOiBcInN0cmluZ1wiLFxuICAgICAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAgICAgXCJMb2dvIGltYWdlIGZvciB0aGUgaGVhZGVyIGJhbmQuIE9ubHkgYW4gaHR0cChzKTogb3IgZGF0YTogVVJMIHJlbmRlcnM7IG90aGVyIHZhbHVlcyBhcmUgZHJvcHBlZCBiZWNhdXNlIGEgbWFpbCBjbGllbnQgY2Fubm90IGxvYWQgdGhlbS5cIixcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgICByZXF1aXJlZDogW1wiYWNjZW50XCIsIFwiZm9udEZhbWlseVwiXSxcbiAgICB9LFxuICAgIGF1dGg6IHtcbiAgICAgIHR5cGU6IFwib2JqZWN0XCIsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgXCJFbWFpbC1PVFAgYWNjZXNzIGdhdGUuIFdoZW4gZW5hYmxlZCwgbW91bnRzIGEgbG9naW4gZmxvdyBhdCAvYXBpL2VtYWlsL2F1dGgvKiBhbmQgZ2F0ZXMgZXZlcnkgb3RoZXIgcm91dGUgYmVoaW5kIGEgc2Vzc2lvbiBjb29raWUuXCIsXG4gICAgICBwcm9wZXJ0aWVzOiB7XG4gICAgICAgIGVuYWJsZWQ6IHtcbiAgICAgICAgICB0eXBlOiBcImJvb2xlYW5cIixcbiAgICAgICAgICBkZXNjcmlwdGlvbjogXCJUdXJuIHRoZSBnYXRlIG9uIChlbnYgRU1BSUxfQVVUSF9FTkFCTEVEKS4gRGVmYXVsdCBvZmYuXCIsXG4gICAgICAgIH0sXG4gICAgICAgIGFsbG93OiB7XG4gICAgICAgICAgdHlwZTogXCJhcnJheVwiLFxuICAgICAgICAgIGl0ZW1zOiB7IHR5cGU6IFwic3RyaW5nXCIgfSxcbiAgICAgICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgICAgICdBbGxvdy1saXN0IG9mIHdobyBtYXkgcmVxdWVzdCBhIGNvZGU6IGRvbWFpbiBzaG9ydGN1dCAoXCJkYXRhYnJpY2tzLmNvbVwiKSwgZ2xvYiAoXCIqLmRhdGFicmlja3MuY29tXCIpLCBvciBcIi9yZWdleC9cIi4gRW1wdHkgPSBub2JvZHkuIEFsc28gYWNjZXB0cyBhIGNvbW1hL3NwYWNlLXNlcGFyYXRlZCBzdHJpbmcuIEVudiBFTUFJTF9BVVRIX0FMTE9XLicsXG4gICAgICAgIH0sXG4gICAgICAgIHNlc3Npb25UdGxTZWNvbmRzOiB7XG4gICAgICAgICAgdHlwZTogXCJudW1iZXJcIixcbiAgICAgICAgICBkZXNjcmlwdGlvbjogXCJTZXNzaW9uIGxpZmV0aW1lIGluIHNlY29uZHMgKGVudiBFTUFJTF9BVVRIX1NFU1NJT05fVFRMKS4gRGVmYXVsdCA0MzIwMC5cIixcbiAgICAgICAgfSxcbiAgICAgICAgY29kZVR0bFNlY29uZHM6IHtcbiAgICAgICAgICB0eXBlOiBcIm51bWJlclwiLFxuICAgICAgICAgIGRlc2NyaXB0aW9uOiBcIk9uZS10aW1lLWNvZGUgbGlmZXRpbWUgaW4gc2Vjb25kcyAoZW52IEVNQUlMX0FVVEhfQ09ERV9UVEwpLiBEZWZhdWx0IDYwMC5cIixcbiAgICAgICAgfSxcbiAgICAgICAgbWF4QXR0ZW1wdHM6IHtcbiAgICAgICAgICB0eXBlOiBcIm51bWJlclwiLFxuICAgICAgICAgIGRlc2NyaXB0aW9uOiBcIk1heCB2ZXJpZnkgYXR0ZW1wdHMgcGVyIGlzc3VlZCBjb2RlLiBEZWZhdWx0IDUuXCIsXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgIH0sXG4gIH0sXG59O1xuXG4vKiogUmVzb2x2ZWQgZW1haWwtT1RQIGdhdGUgY29uZmlnLCB3aXRoIGVudiBmYWxsYmFja3MgYXBwbGllZCAob3IgYHVuZGVmaW5lZGAgd2hlbiBvZmYpLiAqL1xuZXhwb3J0IGludGVyZmFjZSBSZXNvbHZlZEF1dGhDb25maWcge1xuICByZWFkb25seSBhbGxvdzogc3RyaW5nW107XG4gIHJlYWRvbmx5IHNlc3Npb25UdGxTZWNvbmRzOiBudW1iZXI7XG4gIHJlYWRvbmx5IGNvZGVUdGxTZWNvbmRzOiBudW1iZXI7XG4gIHJlYWRvbmx5IG1heEF0dGVtcHRzOiBudW1iZXI7XG59XG5cbi8qKlxuICogUmVzb2x2ZSB7QGxpbmsgQXV0aENvbmZpZ30gYWdhaW5zdCBlbnYsIHJldHVybmluZyBgdW5kZWZpbmVkYCB3aGVuIHRoZSBnYXRlIGlzXG4gKiBvZmYuIGBlbmFibGVkYCBnYXRlcyBldmVyeXRoaW5nOyBgYWxsb3dgIG1lcmdlcyB0aGUgY29uZmlnIGxpc3QgKyBlbnZcbiAqIChgcGFyc2VMaXN0YCBoYW5kbGVzIGEgYHN0cmluZ1tdYCBvciBhIGRlbGltaXRlZCBzdHJpbmcpLiBFbXB0eSBgYWxsb3dgIGlzXG4gKiBhbGxvd2VkIGhlcmUgKHRoZSBnYXRlIHRoZW4gZGVuaWVzIGV2ZXJ5b25lIC0gYSBkZWxpYmVyYXRlIGZhaWwtY2xvc2VkIHN0YXRlKS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlc29sdmVBdXRoQ29uZmlnKGF1dGg6IEF1dGhDb25maWcgfCB1bmRlZmluZWQpOiBSZXNvbHZlZEF1dGhDb25maWcgfCB1bmRlZmluZWQge1xuICBjb25zdCBlbmFibGVkID0gYXV0aD8uZW5hYmxlZCA/PyBvYmplY3QudG9Cb29sZWFuKHByb2Nlc3MuZW52LkVNQUlMX0FVVEhfRU5BQkxFRCkgPz8gZmFsc2U7XG4gIGlmICghZW5hYmxlZCkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgY29uc3QgYWxsb3cgPSBbXG4gICAgLi4uc3RyaW5nLnBhcnNlTGlzdChhdXRoPy5hbGxvdyksXG4gICAgLi4uc3RyaW5nLnBhcnNlTGlzdChwcm9jZXNzLmVudi5FTUFJTF9BVVRIX0FMTE9XKSxcbiAgXTtcbiAgY29uc3QgbnVtID0gKHZhbHVlOiBudW1iZXIgfCB1bmRlZmluZWQsIGVudjogc3RyaW5nIHwgdW5kZWZpbmVkLCBmYWxsYmFjazogbnVtYmVyKTogbnVtYmVyID0+IHtcbiAgICBjb25zdCByYXcgPSB2YWx1ZSA/PyAoZW52ID8gTnVtYmVyKGVudikgOiB1bmRlZmluZWQpO1xuICAgIHJldHVybiB0eXBlb2YgcmF3ID09PSBcIm51bWJlclwiICYmIE51bWJlci5pc0Zpbml0ZShyYXcpICYmIHJhdyA+IDAgPyByYXcgOiBmYWxsYmFjaztcbiAgfTtcbiAgcmV0dXJuIHtcbiAgICBhbGxvdyxcbiAgICBzZXNzaW9uVHRsU2Vjb25kczogbnVtKGF1dGg/LnNlc3Npb25UdGxTZWNvbmRzLCBwcm9jZXNzLmVudi5FTUFJTF9BVVRIX1NFU1NJT05fVFRMLCA0MzIwMCksXG4gICAgY29kZVR0bFNlY29uZHM6IG51bShhdXRoPy5jb2RlVHRsU2Vjb25kcywgcHJvY2Vzcy5lbnYuRU1BSUxfQVVUSF9DT0RFX1RUTCwgNjAwKSxcbiAgICBtYXhBdHRlbXB0czogYXV0aD8ubWF4QXR0ZW1wdHMgPz8gNSxcbiAgfTtcbn1cblxuLyoqIFBhcnNlIHRoZSBgU01UUF9TRUNVUkVgIGVudiAvIGNvbmZpZyBmbGFnLCBkZWZhdWx0aW5nIGJ5IHBvcnQuICovXG5mdW5jdGlvbiByZXNvbHZlU2VjdXJlKGZsYWc6IGJvb2xlYW4gfCB1bmRlZmluZWQsIHBvcnQ6IG51bWJlcik6IGJvb2xlYW4ge1xuICBpZiAodHlwZW9mIGZsYWcgPT09IFwiYm9vbGVhblwiKSByZXR1cm4gZmxhZztcbiAgcmV0dXJuIG9iamVjdC50b0Jvb2xlYW4ocHJvY2Vzcy5lbnYuU01UUF9TRUNVUkUpID8/IHBvcnQgPT09IElNUExJQ0lUX1RMU19TTVRQX1BPUlQ7XG59XG5cbi8qKiBQYXJzZSB0aGUgYEVNQUlMX1NFTkRFUl9QT0xJQ1lgIGVudiAvIGNvbmZpZyB2YWx1ZSwgZGVmYXVsdGluZyB0byBkZW55LWJ5LWRlZmF1bHQuICovXG5mdW5jdGlvbiByZXNvbHZlU2VuZGVyUG9saWN5KHBvbGljeTogU2VuZGVyUG9saWN5IHwgdW5kZWZpbmVkKTogU2VuZGVyUG9saWN5IHtcbiAgY29uc3QgcmF3ID0gcG9saWN5ID8/IHByb2Nlc3MuZW52LkVNQUlMX1NFTkRFUl9QT0xJQ1k/LnRyaW0oKS50b0xvd2VyQ2FzZSgpO1xuICBpZiAocmF3ID09PSBcInVucmVzdHJpY3RlZFwiKSByZXR1cm4gXCJ1bnJlc3RyaWN0ZWRcIjtcbiAgaWYgKHJhdyA9PT0gdW5kZWZpbmVkIHx8IHJhdyA9PT0gXCJcIiB8fCByYXcgPT09IFwiYWxsb3dsaXN0XCIpIHJldHVybiBcImFsbG93bGlzdFwiO1xuICB0aHJvdyBWYWxpZGF0aW9uRXJyb3IuaW52YWxpZFZhbHVlKFwic2VuZGVyUG9saWN5XCIsIHJhdywgJ1wiYWxsb3dsaXN0XCIgb3IgXCJ1bnJlc3RyaWN0ZWRcIicpO1xufVxuXG4vKipcbiAqIEVmZmVjdGl2ZSBhbGxvdy1saXN0IGZvciBhbiBgXCJhbGxvd2xpc3RcImAgcG9saWN5IHdpdGggbm8gZXhwbGljaXQgcGF0dGVybnM6XG4gKiB0aGUgc2VuZGVyIHNvdXJjZSBpdHNlbGYsIHNvIGEgY29uZmlndXJlZCBkb21haW4gb3IgZml4ZWQgYWRkcmVzcyBpcyB0aGVcbiAqIGJvdW5kYXJ5IHJhdGhlciB0aGFuIFwiYW55dGhpbmcgZ29lc1wiLiBZaWVsZHMgbm90aGluZyB3aGVuIG5laXRoZXIgaXMgc2V0LFxuICogd2hpY2ggb25seSBoYXBwZW5zIGluIG91dGJveCBtb2RlICh3aGVyZSB0aGUgc2VuZGVyIGZhbGxzIGJhY2sgdG8gdGhlXG4gKiBvbi1iZWhhbGYtb2YgdXNlcidzIG93biBhZGRyZXNzIGFuZCBjYW5ub3QgYmUgZW51bWVyYXRlZCB1cCBmcm9udCkuXG4gKi9cbmZ1bmN0aW9uIGltcGxpZWRTZW5kZXJQYXR0ZXJucyhkb21haW46IHN0cmluZyB8IHVuZGVmaW5lZCwgZnJvbTogc3RyaW5nIHwgdW5kZWZpbmVkKTogc3RyaW5nW10ge1xuICBjb25zdCBwYXR0ZXJuczogc3RyaW5nW10gPSBbXTtcbiAgaWYgKGZyb20pIHBhdHRlcm5zLnB1c2goZnJvbS50cmltKCkudG9Mb3dlckNhc2UoKSk7XG4gIGlmIChkb21haW4pIHBhdHRlcm5zLnB1c2goYCpAJHtkb21haW4udHJpbSgpLnRvTG93ZXJDYXNlKCl9YCk7XG4gIHJldHVybiBwYXR0ZXJucztcbn1cblxuLyoqIFdoZXRoZXIgYEVNQUlMX09VVEJPWF9NT0RFYCBleHBsaWNpdGx5IG9wdHMgaW50byB0aGUgZmlsZS9vdXRib3ggZmFsbGJhY2suICovXG5mdW5jdGlvbiBpc091dGJveE1vZGVFbmFibGVkKCk6IGJvb2xlYW4ge1xuICByZXR1cm4gb2JqZWN0LnRvQm9vbGVhbihwcm9jZXNzLmVudi5FTUFJTF9PVVRCT1hfTU9ERSkgPz8gZmFsc2U7XG59XG5cbmNvbnN0IFNNVFBfUkVRVUlSRURfRklFTERTID0gW1wiU01UUF9IT1NUXCIsIFwiU01UUF9VU0VSXCIsIFwiU01UUF9QQVNTV09SRFwiXSBhcyBjb25zdDtcblxuLyoqIExpc3QgZW52IGtleXMgZm9yIFNNVFAgZmllbGRzIHRoYXQgYXJlIHVuc2V0IGluIHRoZSByZXNvbHZlZCBjcmVkZW50aWFsIHNldC4gKi9cbmZ1bmN0aW9uIG1pc3NpbmdTbXRwRmllbGRzKFxuICBob3N0OiBzdHJpbmcgfCB1bmRlZmluZWQsXG4gIHVzZXI6IHN0cmluZyB8IHVuZGVmaW5lZCxcbiAgcGFzczogc3RyaW5nIHwgdW5kZWZpbmVkLFxuKTogc3RyaW5nW10ge1xuICBjb25zdCB2YWx1ZXMgPSBbaG9zdCwgdXNlciwgcGFzc10gYXMgY29uc3Q7XG4gIHJldHVybiBTTVRQX1JFUVVJUkVEX0ZJRUxEUy5maWx0ZXIoKF8sIGluZGV4KSA9PiAhdmFsdWVzW2luZGV4XSk7XG59XG5cbi8qKlxuICogUmVzb2x2ZSBwbHVnaW4gY29uZmlnIG92ZXIgZW52aXJvbm1lbnQgZGVmYXVsdHMuXG4gKlxuICogV2hlbiBTTVRQIGhvc3QgKyB1c2VyICsgcGFzc3dvcmQgYXJlIGFsbCBwcmVzZW50LCByZXR1cm5zIGBtb2RlOlxuICogXCJzbXRwXCJgIGZvciByZWFsIGRlbGl2ZXJ5IChhbmQgdGhyb3dzIGlmIG5vIHNlbmRlciBzb3VyY2UgLSBkb21haW4gb3JcbiAqIGZyb20gLSBpcyBjb25maWd1cmVkLCBzaW5jZSBTTVRQIGNhbid0IGRlcml2ZSBvbmUgZnJvbSBub3RoaW5nKS5cbiAqIFdoZW4gYWxsIHRocmVlIGFyZSBhYnNlbnQgYW5kIGBFTUFJTF9PVVRCT1hfTU9ERWAgaXMgZW5hYmxlZCwgcmV0dXJuc1xuICogYG1vZGU6IFwiZmlsZVwiYCBzbyB0aGUgcnVudGltZSB3cml0ZXMgbWVzc2FnZXMgdG8gdGhlIG91dGJveCBkaXJlY3RvcnlcbiAqIGZvciBsb2NhbCB0ZXN0aW5nOyBpbiB0aGF0IG1vZGUgYSBzZW5kZXIgc291cmNlIGlzIG9wdGlvbmFsICh0aGVcbiAqIG91dGJveCBmYWxscyBiYWNrIHRvIHRoZSBPQk8gdXNlcidzIG93biBhZGRyZXNzKS4gUGFydGlhbCBTTVRQXG4gKiBjb25maWd1cmF0aW9uIG9yIGEgc2VuZCB3aXRoIG5vIGNyZWRlbnRpYWxzIGFuZCBubyBvdXRib3ggb3B0LWluXG4gKiB0aHJvd3MuXG4gKlxuICogVGhlIHNlbmRlciBhbGxvdy1saXN0IGlzIHJlc29sdmVkIGhlcmUgdG9vOiB1bmRlciB0aGUgZGVmYXVsdFxuICogYFwiYWxsb3dsaXN0XCJgIHBvbGljeSBhbiBlbXB0eSBsaXN0IGlzIGZpbGxlZCBpbiBmcm9tIHRoZSBzZW5kZXIgc291cmNlLFxuICogc28gYSBkZXBsb3ltZW50IHRoYXQgb25seSBzZXRzIGBFTUFJTF9ET01BSU5gIHN0aWxsIHJlamVjdHMgYSBgRnJvbWAgb25cbiAqIGFueSBvdGhlciBkb21haW4uIFNlZSB7QGxpbmsgU2VuZGVyUG9saWN5fS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlc29sdmVFbWFpbENvbmZpZyhjb25maWc6IEVtYWlsUGx1Z2luQ29uZmlnID0ge30pOiBSZXNvbHZlZEVtYWlsQ29uZmlnIHtcbiAgY29uc3Qgc210cCA9IGNvbmZpZy5zbXRwID8/IHt9O1xuICBjb25zdCBob3N0ID0gc210cC5ob3N0ID8/IHByb2Nlc3MuZW52LlNNVFBfSE9TVDtcbiAgY29uc3QgdXNlciA9IHNtdHAudXNlciA/PyBwcm9jZXNzLmVudi5TTVRQX1VTRVI7XG4gIGNvbnN0IHBhc3MgPSBzbXRwLnBhc3N3b3JkID8/IHByb2Nlc3MuZW52LlNNVFBfUEFTU1dPUkQ7XG4gIGNvbnN0IGRvbWFpbiA9IGNvbmZpZy5kb21haW4gPz8gcHJvY2Vzcy5lbnYuRU1BSUxfRE9NQUlOO1xuICBjb25zdCBmcm9tID0gY29uZmlnLmZyb20gPz8gcHJvY2Vzcy5lbnYuRU1BSUxfRlJPTTtcbiAgY29uc3Qgc2VuZGVyUG9saWN5ID0gcmVzb2x2ZVNlbmRlclBvbGljeShjb25maWcuc2VuZGVyUG9saWN5KTtcbiAgY29uc3QgY29uZmlndXJlZFNlbmRlcnMgPSBwYXJzZUFsbG93ZWRTZW5kZXJzKFxuICAgIGNvbmZpZy5hbGxvd2VkU2VuZGVycyA/PyBwcm9jZXNzLmVudi5FTUFJTF9BTExPV0VEX1NFTkRFUlMsXG4gICk7XG4gIGNvbnN0IGFsbG93ZWRTZW5kZXJzID1cbiAgICBjb25maWd1cmVkU2VuZGVycy5sZW5ndGggPiAwIHx8IHNlbmRlclBvbGljeSA9PT0gXCJ1bnJlc3RyaWN0ZWRcIlxuICAgICAgPyBjb25maWd1cmVkU2VuZGVyc1xuICAgICAgOiBpbXBsaWVkU2VuZGVyUGF0dGVybnMoZG9tYWluLCBmcm9tKTtcbiAgY29uc3Qgc2VuZGVyOiBSZXNvbHZlZFNlbmRlciA9IHtcbiAgICAuLi4oZG9tYWluID8geyBkb21haW4gfSA6IHt9KSxcbiAgICAuLi4oZnJvbSA/IHsgZnJvbSB9IDoge30pLFxuICAgIGFsbG93ZWRTZW5kZXJzLFxuICAgIHNlbmRlclBvbGljeSxcbiAgICAuLi4oY29uZmlnLmJyYW5kID8geyBicmFuZDogY29uZmlnLmJyYW5kIH0gOiB7fSksXG4gIH07XG5cbiAgY29uc3QgaGFzQWxsU210cCA9IEJvb2xlYW4oaG9zdCAmJiB1c2VyICYmIHBhc3MpO1xuICBjb25zdCBoYXNBbnlTbXRwID0gQm9vbGVhbihob3N0IHx8IHVzZXIgfHwgcGFzcyk7XG5cbiAgaWYgKGhhc0FueVNtdHAgJiYgIWhhc0FsbFNtdHApIHtcbiAgICB0aHJvdyBWYWxpZGF0aW9uRXJyb3IubWlzc2luZ0VudlZhcnMobWlzc2luZ1NtdHBGaWVsZHMoaG9zdCwgdXNlciwgcGFzcykpO1xuICB9XG5cbiAgaWYgKGhhc0FsbFNtdHApIHtcbiAgICBpZiAoIWRvbWFpbiAmJiAhZnJvbSkge1xuICAgICAgdGhyb3cgQ29uZmlndXJhdGlvbkVycm9yLnJlc291cmNlTm90Rm91bmQoXG4gICAgICAgIFwiRW1haWwgc2VuZGVyIHNvdXJjZVwiLFxuICAgICAgICBcIlNldCBFTUFJTF9ET01BSU4gdG8gZGVyaXZlIDx1c2VyLWxvY2FsLXBhcnQ+QDxkb21haW4+LCBvciBFTUFJTF9GUk9NIGZvciBhIGZpeGVkIGFkZHJlc3MuXCIsXG4gICAgICApO1xuICAgIH1cbiAgICBjb25zdCBwb3J0UmF3ID0gc210cC5wb3J0ID8/IE51bWJlcihwcm9jZXNzLmVudi5TTVRQX1BPUlQpO1xuICAgIGNvbnN0IHBvcnQgPSBOdW1iZXIuaXNGaW5pdGUocG9ydFJhdykgJiYgcG9ydFJhdyA/IE51bWJlcihwb3J0UmF3KSA6IERFRkFVTFRfU01UUF9QT1JUO1xuICAgIHJldHVybiB7XG4gICAgICBtb2RlOiBcInNtdHBcIixcbiAgICAgIGhvc3Q6IGhvc3QhLFxuICAgICAgcG9ydCxcbiAgICAgIHNlY3VyZTogcmVzb2x2ZVNlY3VyZShzbXRwLnNlY3VyZSwgcG9ydCksXG4gICAgICBhdXRoOiB7IHVzZXI6IHVzZXIhLCBwYXNzOiBwYXNzISB9LFxuICAgICAgLi4uc2VuZGVyLFxuICAgIH07XG4gIH1cblxuICBpZiAoIWlzT3V0Ym94TW9kZUVuYWJsZWQoKSkge1xuICAgIHRocm93IENvbmZpZ3VyYXRpb25FcnJvci5pbnZhbGlkQ29ubmVjdGlvbihcbiAgICAgIFwiU01UUFwiLFxuICAgICAgYFNldCAke1NNVFBfUkVRVUlSRURfRklFTERTLmpvaW4oXCIsIFwiKX0sIG9yIEVNQUlMX09VVEJPWF9NT0RFPTEgdG8gd3JpdGUgbWVzc2FnZXMgdG8gYSBsb2NhbCBvdXRib3ggaW5zdGVhZC5gLFxuICAgICk7XG4gIH1cblxuICBjb25zdCBvdXREaXIgPSByZXNvbHZlKFxuICAgIGNvbmZpZy5vdXREaXIgPz8gcHJvY2Vzcy5lbnYuRU1BSUxfT1VUQk9YX0RJUiA/PyByZXNvbHZlKHByb2Nlc3MuY3dkKCksIFwidG1wXCIpLFxuICApO1xuICByZXR1cm4geyBtb2RlOiBcImZpbGVcIiwgb3V0RGlyLCAuLi5zZW5kZXIgfTtcbn1cbiJdfQ==
@@ -47,6 +47,8 @@ import { type EmailPluginConfig } from "./config.ts";
47
47
  * ```
48
48
  */
49
49
  export declare class EmailPlugin extends Plugin<EmailPluginConfig> implements ToolProvider {
50
+ /** The email-OTP access gate, constructed in {@link setup} when `auth.enabled`. */
51
+ private authGate?;
50
52
  static manifest: {
51
53
  name: "email";
52
54
  displayName: string;
@@ -101,6 +103,15 @@ export declare class EmailPlugin extends Plugin<EmailPluginConfig> implements To
101
103
  * local part.
102
104
  */
103
105
  injectRoutes(router: IAppRouter): void;
106
+ /**
107
+ * Mount the email-OTP login flow under `/api/email/auth/*` when the gate is
108
+ * enabled. These routes are the ONLY ones the gate middleware leaves open (see
109
+ * {@link AuthGate.middleware}); everything else requires the session cookie
110
+ * they establish. No-op when auth is off.
111
+ */
112
+ private injectAuthRoutes;
113
+ /** Client IP for rate-limiting, honoring the Apps ingress `x-forwarded-for`. */
114
+ private clientIp;
104
115
  exports(): {
105
116
  /**
106
117
  * Send a message immediately from `from` through the shared
@@ -129,6 +140,18 @@ export declare class EmailPlugin extends Plugin<EmailPluginConfig> implements To
129
140
  * not wrap it again.
130
141
  */
131
142
  private send;
143
+ /**
144
+ * Build the email-OTP access gate when `auth.enabled`, wiring its code
145
+ * delivery through this plugin's own transport. Called from {@link setup}; a
146
+ * no-op (leaves {@link authGate} undefined) when the gate is off.
147
+ */
148
+ private setupAuthGate;
149
+ /**
150
+ * Deliver a one-time code to `email` through this plugin's transport. Throws
151
+ * on failure (the gate swallows it, so a delivery error never leaks whether
152
+ * the address was allow-listed).
153
+ */
154
+ private sendOtpEmail;
132
155
  /** Run the sender-options lookup through the plugin's interceptor chain. */
133
156
  private executeListSenders;
134
157
  /**