@forestadmin/workflow-executor 1.12.0 → 1.14.0
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 +4 -0
- package/dist/adapters/agent-client-agent-port.d.ts +1 -1
- package/dist/adapters/agent-client-agent-port.js +3 -3
- package/dist/adapters/ai-client-adapter.d.ts +5 -1
- package/dist/adapters/ai-client-adapter.js +4 -1
- package/dist/adapters/always-error-ai-model-port.d.ts +5 -1
- package/dist/adapters/always-error-ai-model-port.js +6 -1
- package/dist/adapters/server-ai-adapter.d.ts +5 -1
- package/dist/adapters/server-ai-adapter.js +4 -1
- package/dist/adapters/step-outcome-to-update-step-mapper.js +4 -1
- package/dist/build-workflow-executor.js +87 -2
- package/dist/crypto/credential-encryption.d.ts +10 -0
- package/dist/crypto/credential-encryption.js +75 -0
- package/dist/defaults.d.ts +1 -0
- package/dist/defaults.js +5 -2
- package/dist/errors.d.ts +18 -0
- package/dist/errors.js +50 -2
- package/dist/executors/mcp-step-executor.d.ts +7 -2
- package/dist/executors/mcp-step-executor.js +78 -14
- package/dist/executors/step-executor-factory.d.ts +1 -1
- package/dist/executors/step-executor-factory.js +24 -3
- package/dist/executors/trigger-record-action-step-executor.js +10 -4
- package/dist/http/executor-http-server.d.ts +12 -0
- package/dist/http/executor-http-server.js +90 -1
- package/dist/http/mcp-oauth-credentials.d.ts +24 -0
- package/dist/http/mcp-oauth-credentials.js +77 -0
- package/dist/index.d.ts +7 -1
- package/dist/index.js +10 -3
- package/dist/oauth/keyed-mutex.d.ts +5 -0
- package/dist/oauth/keyed-mutex.js +27 -0
- package/dist/oauth/refresh-grant.d.ts +15 -0
- package/dist/oauth/refresh-grant.js +112 -0
- package/dist/oauth/token-endpoint-url.d.ts +2 -0
- package/dist/oauth/token-endpoint-url.js +103 -0
- package/dist/oauth/token-service.d.ts +34 -0
- package/dist/oauth/token-service.js +172 -0
- package/dist/ports/agent-port.d.ts +1 -0
- package/dist/ports/ai-model-port.d.ts +5 -1
- package/dist/ports/mcp-oauth-credentials-store.d.ts +24 -0
- package/dist/ports/mcp-oauth-credentials-store.js +3 -0
- package/dist/ports/run-store.d.ts +1 -0
- package/dist/remote-tool-fetcher.d.ts +7 -2
- package/dist/remote-tool-fetcher.js +53 -6
- package/dist/runner.d.ts +2 -0
- package/dist/runner.js +3 -3
- package/dist/stores/database-mcp-oauth-credentials-store.d.ts +22 -0
- package/dist/stores/database-mcp-oauth-credentials-store.js +188 -0
- package/dist/stores/database-store.d.ts +1 -1
- package/dist/stores/database-store.js +17 -50
- package/dist/stores/in-memory-mcp-oauth-credentials-store.d.ts +13 -0
- package/dist/stores/in-memory-mcp-oauth-credentials-store.js +44 -0
- package/dist/stores/in-memory-store.d.ts +1 -0
- package/dist/stores/in-memory-store.js +6 -1
- package/dist/stores/schema-migrations.d.ts +19 -0
- package/dist/stores/schema-migrations.js +69 -0
- package/dist/types/validated/execution.d.ts +6 -0
- package/dist/types/validated/step-outcome.d.ts +10 -0
- package/dist/types/validated/step-outcome.js +7 -2
- package/package.json +4 -4
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.default = assertSafeTokenEndpoint;
|
|
7
|
+
const net_1 = __importDefault(require("net"));
|
|
8
|
+
const errors_1 = require("../errors");
|
|
9
|
+
// The token endpoint comes from the deposit body, and the executor POSTs the refresh grant (with
|
|
10
|
+
// client credentials) to it — so an unconstrained value is an SSRF vector. The guard rejects hosts
|
|
11
|
+
// that are never a legitimate endpoint but are prime SSRF targets (loopback, link-local /
|
|
12
|
+
// cloud-metadata) and requires TLS, while deliberately allowing private (RFC1918) hosts: a private
|
|
13
|
+
// OAuth provider reached over the internal network is a supported deployment, so blocking it would
|
|
14
|
+
// break a real use case. http and loopback are relaxed only when NODE_ENV explicitly opts in
|
|
15
|
+
// (development/test) — see isRelaxedEnv. Only IP literals are inspected — resolving a hostname here
|
|
16
|
+
// would be racy (it can resolve to a different address at fetch time), not safer.
|
|
17
|
+
// Fail closed: the strict rules (https + no loopback) apply everywhere UNLESS NODE_ENV explicitly
|
|
18
|
+
// opts into the local-dev relaxation. An unset or misspelled NODE_ENV stays strict, so a
|
|
19
|
+
// misconfigured deploy can't silently allow loopback targets or cleartext http.
|
|
20
|
+
function isRelaxedEnv() {
|
|
21
|
+
return process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test';
|
|
22
|
+
}
|
|
23
|
+
function unbracket(hostname) {
|
|
24
|
+
return hostname.startsWith('[') && hostname.endsWith(']') ? hostname.slice(1, -1) : hostname;
|
|
25
|
+
}
|
|
26
|
+
function classifyIpv4(host) {
|
|
27
|
+
const [a, b] = host.split('.').map(Number);
|
|
28
|
+
return {
|
|
29
|
+
loopback: a === 127, // 127.0.0.0/8
|
|
30
|
+
linkLocal: a === 169 && b === 254, // 169.254.0.0/16
|
|
31
|
+
unspecified: a === 0, // 0.0.0.0/8 — "this host"; connects to loopback on Linux
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
// Returns the embedded IPv4 of an IPv4-mapped IPv6 address (otherwise null). The WHATWG URL parser
|
|
35
|
+
// normalizes `::ffff:127.0.0.1` to the hex form `::ffff:7f00:1`, which would otherwise dodge the
|
|
36
|
+
// IPv4 loopback/link-local checks and still reach the executor's loopback / metadata interface.
|
|
37
|
+
function embeddedIpv4(host) {
|
|
38
|
+
const tail = host.toLowerCase().match(/^::ffff:(.+)$/)?.[1];
|
|
39
|
+
if (!tail)
|
|
40
|
+
return null;
|
|
41
|
+
if (net_1.default.isIPv4(tail))
|
|
42
|
+
return tail;
|
|
43
|
+
const hex = tail.match(/^([0-9a-f]{1,4}):([0-9a-f]{1,4})$/);
|
|
44
|
+
if (!hex)
|
|
45
|
+
return null;
|
|
46
|
+
const hi = parseInt(hex[1], 16); // high 16 bits → first two octets
|
|
47
|
+
const lo = parseInt(hex[2], 16); // low 16 bits → last two octets
|
|
48
|
+
return `${Math.floor(hi / 256)}.${hi % 256}.${Math.floor(lo / 256)}.${lo % 256}`;
|
|
49
|
+
}
|
|
50
|
+
function classify(host) {
|
|
51
|
+
const kind = net_1.default.isIP(host);
|
|
52
|
+
if (kind === 4)
|
|
53
|
+
return classifyIpv4(host);
|
|
54
|
+
if (kind === 6) {
|
|
55
|
+
const mapped = embeddedIpv4(host);
|
|
56
|
+
if (mapped)
|
|
57
|
+
return classifyIpv4(mapped);
|
|
58
|
+
const normalized = host.toLowerCase().split('%')[0]; // drop any zone id
|
|
59
|
+
const firstHextet = normalized.split(':')[0];
|
|
60
|
+
return {
|
|
61
|
+
loopback: normalized === '::1' || normalized === '0:0:0:0:0:0:0:1',
|
|
62
|
+
linkLocal: /^fe[89ab]/.test(firstHextet), // fe80::/10
|
|
63
|
+
unspecified: normalized === '::' || normalized === '0:0:0:0:0:0:0:0',
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
// Not an IP literal. Reject the reserved loopback names — bare `localhost`, the `.localhost` TLD
|
|
67
|
+
// (RFC 6761), and their trailing-dot FQDN forms — since they resolve to loopback. Other hostnames
|
|
68
|
+
// are left to the scheme rule; their DNS is not resolved here (a hostname pointed at an internal
|
|
69
|
+
// IP is the filtering-agent's job, not this string check).
|
|
70
|
+
return {
|
|
71
|
+
loopback: /^localhost\.?$|\.localhost\.?$/.test(host.toLowerCase()),
|
|
72
|
+
linkLocal: false,
|
|
73
|
+
unspecified: false,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
function assertSafeTokenEndpoint(raw) {
|
|
77
|
+
let url;
|
|
78
|
+
try {
|
|
79
|
+
url = new URL(raw);
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
throw new errors_1.InvalidTokenEndpointError('it is not a valid absolute URL');
|
|
83
|
+
}
|
|
84
|
+
if (url.protocol !== 'https:' && url.protocol !== 'http:') {
|
|
85
|
+
throw new errors_1.InvalidTokenEndpointError('it must use http or https');
|
|
86
|
+
}
|
|
87
|
+
const { loopback, linkLocal, unspecified } = classify(unbracket(url.hostname));
|
|
88
|
+
if (unspecified) {
|
|
89
|
+
throw new errors_1.InvalidTokenEndpointError('it points at the unspecified address (0.0.0.0 / ::)');
|
|
90
|
+
}
|
|
91
|
+
if (linkLocal) {
|
|
92
|
+
throw new errors_1.InvalidTokenEndpointError('it points at a link-local / metadata address');
|
|
93
|
+
}
|
|
94
|
+
if (!isRelaxedEnv()) {
|
|
95
|
+
if (url.protocol !== 'https:') {
|
|
96
|
+
throw new errors_1.InvalidTokenEndpointError('it must use https');
|
|
97
|
+
}
|
|
98
|
+
if (loopback) {
|
|
99
|
+
throw new errors_1.InvalidTokenEndpointError('it points at the executor host (loopback)');
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9rZW4tZW5kcG9pbnQtdXJsLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL29hdXRoL3Rva2VuLWVuZHBvaW50LXVybC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQW9GQSwwQ0FnQ0M7QUFwSEQsOENBQXNCO0FBRXRCLHNDQUFzRDtBQUV0RCxpR0FBaUc7QUFDakcsbUdBQW1HO0FBQ25HLDBGQUEwRjtBQUMxRixtR0FBbUc7QUFDbkcsbUdBQW1HO0FBQ25HLDZGQUE2RjtBQUM3RixvR0FBb0c7QUFDcEcsa0ZBQWtGO0FBRWxGLGtHQUFrRztBQUNsRyx5RkFBeUY7QUFDekYsZ0ZBQWdGO0FBQ2hGLFNBQVMsWUFBWTtJQUNuQixPQUFPLE9BQU8sQ0FBQyxHQUFHLENBQUMsUUFBUSxLQUFLLGFBQWEsSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLFFBQVEsS0FBSyxNQUFNLENBQUM7QUFDbkYsQ0FBQztBQUVELFNBQVMsU0FBUyxDQUFDLFFBQWdCO0lBQ2pDLE9BQU8sUUFBUSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsSUFBSSxRQUFRLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUM7QUFDL0YsQ0FBQztBQUlELFNBQVMsWUFBWSxDQUFDLElBQVk7SUFDaEMsTUFBTSxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUUzQyxPQUFPO1FBQ0wsUUFBUSxFQUFFLENBQUMsS0FBSyxHQUFHLEVBQUUsY0FBYztRQUNuQyxTQUFTLEVBQUUsQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLEtBQUssR0FBRyxFQUFFLGlCQUFpQjtRQUNwRCxXQUFXLEVBQUUsQ0FBQyxL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
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { RefreshGrantParams, RefreshGrantResult } from './refresh-grant';
|
|
2
|
+
import type CredentialEncryption from '../crypto/credential-encryption';
|
|
3
|
+
import type { Logger } from '../ports/logger-port';
|
|
4
|
+
import type { McpOAuthCredentialsStore } from '../ports/mcp-oauth-credentials-store';
|
|
5
|
+
export interface OAuthTokenServiceOptions {
|
|
6
|
+
store: McpOAuthCredentialsStore;
|
|
7
|
+
encryption: CredentialEncryption;
|
|
8
|
+
logger?: Logger;
|
|
9
|
+
expirySkewS?: number;
|
|
10
|
+
refreshAccessToken?: (params: RefreshGrantParams) => Promise<RefreshGrantResult>;
|
|
11
|
+
now?: () => number;
|
|
12
|
+
}
|
|
13
|
+
export default class OAuthTokenService {
|
|
14
|
+
private readonly store;
|
|
15
|
+
private readonly encryption;
|
|
16
|
+
private readonly logger?;
|
|
17
|
+
private readonly expirySkewMs;
|
|
18
|
+
private readonly refreshAccessToken;
|
|
19
|
+
private readonly now;
|
|
20
|
+
private readonly cache;
|
|
21
|
+
private readonly mutex;
|
|
22
|
+
private readonly evictionEpoch;
|
|
23
|
+
constructor(options: OAuthTokenServiceOptions);
|
|
24
|
+
getAccessToken(userId: number, mcpServerId: string, options?: {
|
|
25
|
+
forceRefresh?: boolean;
|
|
26
|
+
}): Promise<string>;
|
|
27
|
+
evict(userId: number, mcpServerId: string): void;
|
|
28
|
+
private readCache;
|
|
29
|
+
private refreshAndCache;
|
|
30
|
+
private runGrantWithRotationRetry;
|
|
31
|
+
private toGrantParams;
|
|
32
|
+
private persistRotatedRefreshToken;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=token-service.d.ts.map
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const defaults_1 = require("../defaults");
|
|
7
|
+
const errors_1 = require("../errors");
|
|
8
|
+
const keyed_mutex_1 = __importDefault(require("./keyed-mutex"));
|
|
9
|
+
const refresh_grant_1 = __importDefault(require("./refresh-grant"));
|
|
10
|
+
// Acquires an MCP OAuth access token for a (user, server): serves a cached token until it nears
|
|
11
|
+
// expiry, otherwise runs the refresh-token grant under a per-key mutex (one in-flight refresh per
|
|
12
|
+
// user+server in this process) and recovers from a concurrent refresh-token rotation via a single
|
|
13
|
+
// re-read + retry. A missing credential or a genuinely rejected refresh raises
|
|
14
|
+
// OAuthReauthRequiredError so the step pauses for re-authentication.
|
|
15
|
+
class OAuthTokenService {
|
|
16
|
+
constructor(options) {
|
|
17
|
+
this.cache = new Map();
|
|
18
|
+
this.mutex = new keyed_mutex_1.default();
|
|
19
|
+
// Bumped on evict() so a refresh already in flight for a key can detect a disconnect that landed
|
|
20
|
+
// mid-refresh and skip repopulating the cache for the now-deleted credential.
|
|
21
|
+
this.evictionEpoch = new Map();
|
|
22
|
+
this.store = options.store;
|
|
23
|
+
this.encryption = options.encryption;
|
|
24
|
+
this.logger = options.logger;
|
|
25
|
+
this.expirySkewMs = (options.expirySkewS ?? defaults_1.DEFAULT_OAUTH_EXPIRY_SKEW_S) * 1000;
|
|
26
|
+
this.refreshAccessToken = options.refreshAccessToken ?? refresh_grant_1.default;
|
|
27
|
+
this.now = options.now ?? Date.now;
|
|
28
|
+
}
|
|
29
|
+
async getAccessToken(userId, mcpServerId, options) {
|
|
30
|
+
const key = `${userId}:${mcpServerId}`;
|
|
31
|
+
const forceRefresh = options?.forceRefresh ?? false;
|
|
32
|
+
if (!forceRefresh) {
|
|
33
|
+
const cached = this.readCache(key);
|
|
34
|
+
if (cached)
|
|
35
|
+
return cached;
|
|
36
|
+
}
|
|
37
|
+
return this.mutex.runExclusive(key, async () => {
|
|
38
|
+
// Re-check inside the lock: a concurrent caller may have just refreshed for this key.
|
|
39
|
+
if (!forceRefresh) {
|
|
40
|
+
const cached = this.readCache(key);
|
|
41
|
+
if (cached)
|
|
42
|
+
return cached;
|
|
43
|
+
}
|
|
44
|
+
return this.refreshAndCache(userId, mcpServerId, key);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
// Drop the cached access token for a (user, server). Called on credential delete so a disconnect
|
|
48
|
+
// takes effect immediately, instead of the executor serving the cached token until it expires.
|
|
49
|
+
evict(userId, mcpServerId) {
|
|
50
|
+
const key = `${userId}:${mcpServerId}`;
|
|
51
|
+
this.cache.delete(key);
|
|
52
|
+
this.evictionEpoch.set(key, (this.evictionEpoch.get(key) ?? 0) + 1);
|
|
53
|
+
}
|
|
54
|
+
readCache(key) {
|
|
55
|
+
const entry = this.cache.get(key);
|
|
56
|
+
if (!entry)
|
|
57
|
+
return undefined;
|
|
58
|
+
if (this.now() >= entry.expiresAtMs - this.expirySkewMs) {
|
|
59
|
+
// Drop expired entries on read so the cache can't grow without bound across many keys.
|
|
60
|
+
this.cache.delete(key);
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
return entry.accessToken;
|
|
64
|
+
}
|
|
65
|
+
async refreshAndCache(userId, mcpServerId, key) {
|
|
66
|
+
const epochAtStart = this.evictionEpoch.get(key) ?? 0;
|
|
67
|
+
const credential = await this.store.get(userId, mcpServerId);
|
|
68
|
+
if (!credential)
|
|
69
|
+
throw new errors_1.OAuthReauthRequiredError(mcpServerId);
|
|
70
|
+
const { result, credential: grantedCredential } = await this.runGrantWithRotationRetry(credential, userId, mcpServerId);
|
|
71
|
+
const evictedDuringRefresh = (this.evictionEpoch.get(key) ?? 0) !== epochAtStart;
|
|
72
|
+
// Skip caching if the credential was disconnected mid-refresh (would serve a token for a deleted
|
|
73
|
+
// credential) or the grant carried no expiry (never servable); the in-flight caller still gets it.
|
|
74
|
+
if (!evictedDuringRefresh && result.expiresInS !== undefined) {
|
|
75
|
+
this.cache.set(key, {
|
|
76
|
+
accessToken: result.accessToken,
|
|
77
|
+
expiresAtMs: this.now() + result.expiresInS * 1000,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
this.cache.delete(key);
|
|
82
|
+
}
|
|
83
|
+
if (result.refreshToken) {
|
|
84
|
+
await this.persistRotatedRefreshToken(grantedCredential, result.refreshToken);
|
|
85
|
+
}
|
|
86
|
+
return result.accessToken;
|
|
87
|
+
}
|
|
88
|
+
// On invalid_grant a peer instance likely rotated the refresh token out from under us: re-read the
|
|
89
|
+
// row and retry once with the current token; a second invalid_grant (or an unchanged token) is a
|
|
90
|
+
// genuine revocation and forces re-auth. Returns the credential whose token produced the grant so
|
|
91
|
+
// the caller writes the rotated token back onto that (current) row, not the stale one.
|
|
92
|
+
async runGrantWithRotationRetry(credential, userId, mcpServerId) {
|
|
93
|
+
try {
|
|
94
|
+
const result = await this.refreshAccessToken(this.toGrantParams(credential));
|
|
95
|
+
return { result, credential };
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
if (!(error instanceof errors_1.OAuthInvalidGrantError))
|
|
99
|
+
throw error;
|
|
100
|
+
// A peer rotated the refresh token iff the stored value changed since we read it.
|
|
101
|
+
const latest = await this.store.get(userId, mcpServerId);
|
|
102
|
+
const wasRotated = latest !== null &&
|
|
103
|
+
latest.refreshTokenEnc.toString('base64') !== credential.refreshTokenEnc.toString('base64');
|
|
104
|
+
if (!latest || !wasRotated) {
|
|
105
|
+
throw new errors_1.OAuthReauthRequiredError(mcpServerId);
|
|
106
|
+
}
|
|
107
|
+
try {
|
|
108
|
+
const result = await this.refreshAccessToken(this.toGrantParams(latest));
|
|
109
|
+
return { result, credential: latest };
|
|
110
|
+
}
|
|
111
|
+
catch (retryError) {
|
|
112
|
+
if (retryError instanceof errors_1.OAuthInvalidGrantError) {
|
|
113
|
+
throw new errors_1.OAuthReauthRequiredError(mcpServerId);
|
|
114
|
+
}
|
|
115
|
+
throw retryError;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// Decrypt happens here. A decrypt failure with the key PRESENT (auth-tag mismatch — the row was
|
|
120
|
+
// encrypted under a since-rotated/hard-swapped key, or is corrupt) is recoverable: re-consent
|
|
121
|
+
// re-deposits under the current key, so surface it as needs-oauth-reauth. A missing key
|
|
122
|
+
// (ExecutorEncryptionKeyMissingError) is an operator misconfig, not re-consent-resolvable, so it
|
|
123
|
+
// propagates as a terminal error (a re-deposit would just 503 at the deposit endpoint).
|
|
124
|
+
toGrantParams(credential) {
|
|
125
|
+
try {
|
|
126
|
+
return {
|
|
127
|
+
tokenEndpoint: credential.tokenEndpoint,
|
|
128
|
+
refreshToken: this.encryption.decrypt(credential.refreshTokenEnc),
|
|
129
|
+
clientId: credential.clientId,
|
|
130
|
+
clientSecret: credential.clientSecretEnc
|
|
131
|
+
? this.encryption.decrypt(credential.clientSecretEnc)
|
|
132
|
+
: null,
|
|
133
|
+
tokenEndpointAuthMethod: credential.tokenEndpointAuthMethod,
|
|
134
|
+
scopes: credential.scopes,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
if (error instanceof errors_1.ExecutorEncryptionKeyMissingError)
|
|
139
|
+
throw error;
|
|
140
|
+
throw new errors_1.OAuthReauthRequiredError(credential.mcpServerId);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
async persistRotatedRefreshToken(credential, refreshToken) {
|
|
144
|
+
try {
|
|
145
|
+
const encrypted = this.encryption.encrypt(refreshToken);
|
|
146
|
+
// Id-scoped so a disconnect (or disconnect + re-authorize) after the grant read leaves an
|
|
147
|
+
// absent or different row — the rotated-token write-back then can't resurrect or clobber it.
|
|
148
|
+
await this.store.updateIfPresent(credential.id, {
|
|
149
|
+
userId: credential.userId,
|
|
150
|
+
mcpServerId: credential.mcpServerId,
|
|
151
|
+
refreshTokenEnc: encrypted.ciphertext,
|
|
152
|
+
clientId: credential.clientId,
|
|
153
|
+
clientSecretEnc: credential.clientSecretEnc,
|
|
154
|
+
clientSecretExpiresAt: credential.clientSecretExpiresAt,
|
|
155
|
+
tokenEndpoint: credential.tokenEndpoint,
|
|
156
|
+
tokenEndpointAuthMethod: credential.tokenEndpointAuthMethod,
|
|
157
|
+
scopes: credential.scopes,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
catch (error) {
|
|
161
|
+
// A failed write-back is not fatal: the access token just obtained is valid for this call.
|
|
162
|
+
// The rotated refresh token is lost, so a later refresh forces re-authentication — the safe
|
|
163
|
+
// fallback, and better than failing the current operation over a transient write error.
|
|
164
|
+
this.logger?.('Error', 'Failed to persist rotated MCP OAuth refresh token', {
|
|
165
|
+
mcpServerId: credential.mcpServerId,
|
|
166
|
+
error: error instanceof Error ? error.message : String(error),
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
exports.default = OAuthTokenService;
|
|
172
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9rZW4tc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9vYXV0aC90b2tlbi1zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBUUEsMENBQTBEO0FBQzFELHNDQUltQjtBQUNuQixnRUFBdUM7QUFDdkMsb0VBQXdEO0FBZ0J4RCxnR0FBZ0c7QUFDaEcsa0dBQWtHO0FBQ2xHLGtHQUFrRztBQUNsRywrRUFBK0U7QUFDL0UscUVBQXFFO0FBQ3JFLE1BQXFCLGlCQUFpQjtJQWFwQyxZQUFZLE9BQWlDO1FBTjVCLFVBQUssR0FBRyxJQUFJLEdBQUcsRUFBdUIsQ0FBQztRQUN2QyxVQUFLLEdBQUcsSUFBSSxxQkFBVSxFQUFFLENBQUM7UUFDMUMsaUdBQWlHO1FBQ2pHLDhFQUE4RTtRQUM3RCxrQkFBYSxHQUFHLElBQUksR0FBRyxFQUFrQixDQUFDO1FBR3pELElBQUksQ0FBQyxLQUFLLEdBQUcsT0FBTyxDQUFDLEtBQUssQ0FBQztRQUMzQixJQUFJLENBQUMsVUFBVSxHQUFHLE9BQU8sQ0FBQyxVQUFVLENBQUM7UUFDckMsSUFBSSxDQUFDLE1BQU0sR0FBRyxPQUFPLENBQUMsTUFBTSxDQUFDO1FBQzdCLElBQUksQ0FBQyxZQUFZLEdBQUcsQ0FBQyxPQUFPLENBQUMsV0FBVyxJQUFJLHNDQUEyQixDQUFDLEdBQUcsSUFBSSxDQUFDO1FBQ2hGLElBQUksQ0FBQyxrQkFBa0IsR0FBRyxPQUFPLENBQUMsa0JBQWtCLElBQUksdUJBQXlCLENBQUM7UUFDbEYsSUFBSSxDQUFDLEdBQUcsR0FBRyxPQUFPLENBQUMsR0FBRyxJQUFJLElBQUksQ0FBQyxHQUFHLENBQUM7SUFDckMsQ0FBQztJQUVELEtBQUssQ0FBQyxjQUFjLENBQ2xCLE1BQWMsRUFDZCxXQUFtQixFQUNuQixPQUFvQztRQUVwQyxNQUFNLEdBQUcsR0FBRyxHQUFHLE1BQU0sSUFBSSxXQUFXLEVBQUUsQ0FBQztRQUN2QyxNQUFNLFlBQVksR0FB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
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { BaseChatModel, RemoteTool, ToolConfig } from '@forestadmin/ai-proxy';
|
|
1
|
+
import type { BaseChatModel, McpServerLoadFailure, RemoteTool, ToolConfig } from '@forestadmin/ai-proxy';
|
|
2
2
|
export interface GetModelOptions {
|
|
3
3
|
aiConfigName?: string;
|
|
4
4
|
userId?: number;
|
|
@@ -6,6 +6,10 @@ export interface GetModelOptions {
|
|
|
6
6
|
export interface AiModelPort {
|
|
7
7
|
getModel(options?: GetModelOptions): BaseChatModel;
|
|
8
8
|
loadRemoteTools(configs: Record<string, ToolConfig>): Promise<RemoteTool[]>;
|
|
9
|
+
loadRemoteToolsWithFailures(configs: Record<string, ToolConfig>): Promise<{
|
|
10
|
+
tools: RemoteTool[];
|
|
11
|
+
failures: McpServerLoadFailure[];
|
|
12
|
+
}>;
|
|
9
13
|
closeConnections(): Promise<void>;
|
|
10
14
|
}
|
|
11
15
|
//# sourceMappingURL=ai-model-port.d.ts.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Logger } from './logger-port';
|
|
2
|
+
export interface McpOAuthCredentialInput {
|
|
3
|
+
userId: number;
|
|
4
|
+
mcpServerId: string;
|
|
5
|
+
refreshTokenEnc: Buffer;
|
|
6
|
+
clientId?: string | null;
|
|
7
|
+
clientSecretEnc?: Buffer | null;
|
|
8
|
+
clientSecretExpiresAt?: Date | null;
|
|
9
|
+
tokenEndpoint: string;
|
|
10
|
+
tokenEndpointAuthMethod?: string | null;
|
|
11
|
+
scopes?: string | null;
|
|
12
|
+
}
|
|
13
|
+
export interface StoredMcpOAuthCredential extends McpOAuthCredentialInput {
|
|
14
|
+
id: number;
|
|
15
|
+
}
|
|
16
|
+
export interface McpOAuthCredentialsStore {
|
|
17
|
+
init(logger?: Logger): Promise<void>;
|
|
18
|
+
close(logger?: Logger): Promise<void>;
|
|
19
|
+
get(userId: number, mcpServerId: string): Promise<StoredMcpOAuthCredential | null>;
|
|
20
|
+
upsert(credential: McpOAuthCredentialInput): Promise<void>;
|
|
21
|
+
updateIfPresent(id: number, credential: McpOAuthCredentialInput): Promise<void>;
|
|
22
|
+
delete(userId: number, mcpServerId: string): Promise<void>;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=mcp-oauth-credentials-store.d.ts.map
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWNwLW9hdXRoLWNyZWRlbnRpYWxzLXN0b3JlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3BvcnRzL21jcC1vYXV0aC1jcmVkZW50aWFscy1zdG9yZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIn0=
|
|
@@ -5,5 +5,6 @@ export interface RunStore {
|
|
|
5
5
|
close(logger?: Logger): Promise<void>;
|
|
6
6
|
getStepExecutions(runId: string): Promise<StepExecutionData[]>;
|
|
7
7
|
saveStepExecution(runId: string, stepExecution: StepExecutionData): Promise<void>;
|
|
8
|
+
deleteStepExecution(runId: string, stepIndex: number): Promise<void>;
|
|
8
9
|
}
|
|
9
10
|
//# sourceMappingURL=run-store.d.ts.map
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type OAuthTokenService from './oauth/token-service';
|
|
1
2
|
import type { AiModelPort } from './ports/ai-model-port';
|
|
2
3
|
import type { Logger } from './ports/logger-port';
|
|
3
4
|
import type { WorkflowPort } from './ports/workflow-port';
|
|
@@ -6,13 +7,17 @@ export declare function scopeConfigsToServer(configs: Record<string, ToolConfig>
|
|
|
6
7
|
export interface FetchRemoteToolsResult {
|
|
7
8
|
tools: RemoteTool[];
|
|
8
9
|
mcpServerName?: string;
|
|
10
|
+
loadFailed?: boolean;
|
|
11
|
+
reloadWithFreshAuth?: () => Promise<RemoteTool[]>;
|
|
9
12
|
}
|
|
10
13
|
export default class RemoteToolFetcher {
|
|
11
14
|
private readonly workflowPort;
|
|
12
15
|
private readonly aiModelPort;
|
|
13
16
|
private readonly logger;
|
|
14
|
-
|
|
15
|
-
|
|
17
|
+
private readonly oauthTokenService;
|
|
18
|
+
constructor(workflowPort: WorkflowPort, aiModelPort: AiModelPort, logger: Logger, oauthTokenService: OAuthTokenService);
|
|
19
|
+
fetch(mcpServerId: string, userId: number): Promise<FetchRemoteToolsResult>;
|
|
20
|
+
private fetchOAuthTools;
|
|
16
21
|
private warnMissingTargetServer;
|
|
17
22
|
private errorOnPartialLoadFailure;
|
|
18
23
|
}
|
|
@@ -1,26 +1,72 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.scopeConfigsToServer = scopeConfigsToServer;
|
|
4
|
+
const ai_proxy_1 = require("@forestadmin/ai-proxy");
|
|
5
|
+
const errors_1 = require("./errors");
|
|
6
|
+
const OAUTH2_AUTH_TYPE = 'oauth2';
|
|
4
7
|
// Match by config.id, not by Record key: server names can collide across configs.
|
|
5
8
|
function scopeConfigsToServer(configs, mcpServerId) {
|
|
6
9
|
return Object.fromEntries(Object.entries(configs).filter(([, cfg]) => cfg.id === mcpServerId));
|
|
7
10
|
}
|
|
11
|
+
function readAuthType(config) {
|
|
12
|
+
return config?.authType;
|
|
13
|
+
}
|
|
8
14
|
class RemoteToolFetcher {
|
|
9
|
-
constructor(workflowPort, aiModelPort, logger) {
|
|
15
|
+
constructor(workflowPort, aiModelPort, logger, oauthTokenService) {
|
|
16
|
+
// Fail loudly here instead of a cryptic undefined dereference at the first OAuth fetch —
|
|
17
|
+
// Runner/RunnerConfig are public API, so a JS caller can bypass the compile-time check.
|
|
18
|
+
if (!oauthTokenService) {
|
|
19
|
+
throw new Error('RemoteToolFetcher requires an OAuth token service (mcpOAuthTokenService)');
|
|
20
|
+
}
|
|
10
21
|
this.workflowPort = workflowPort;
|
|
11
22
|
this.aiModelPort = aiModelPort;
|
|
12
23
|
this.logger = logger;
|
|
24
|
+
this.oauthTokenService = oauthTokenService;
|
|
13
25
|
}
|
|
14
|
-
async fetch(mcpServerId) {
|
|
26
|
+
async fetch(mcpServerId, userId) {
|
|
15
27
|
const configs = await this.workflowPort.getMcpServerConfigs();
|
|
16
28
|
const scoped = scopeConfigsToServer(configs, mcpServerId);
|
|
17
29
|
const [mcpServerName] = Object.keys(scoped);
|
|
18
30
|
this.warnMissingTargetServer(configs, scoped, mcpServerId, mcpServerName);
|
|
19
31
|
if (Object.keys(scoped).length === 0)
|
|
20
32
|
return { tools: [], mcpServerName };
|
|
33
|
+
if (readAuthType(scoped[mcpServerName]) === OAUTH2_AUTH_TYPE) {
|
|
34
|
+
return this.fetchOAuthTools(scoped, mcpServerName, mcpServerId, userId);
|
|
35
|
+
}
|
|
21
36
|
const tools = await this.aiModelPort.loadRemoteTools(scoped);
|
|
22
|
-
this.errorOnPartialLoadFailure(scoped, tools, mcpServerId, mcpServerName);
|
|
23
|
-
return { tools, mcpServerName };
|
|
37
|
+
const loadFailed = this.errorOnPartialLoadFailure(scoped, tools, mcpServerId, mcpServerName);
|
|
38
|
+
return { tools, mcpServerName, loadFailed };
|
|
39
|
+
}
|
|
40
|
+
// OAuth2 path: acquire a per-user access token, inject it as a Bearer header, then list tools.
|
|
41
|
+
// Tool listing is the first authenticated call, so an auth failure here forces one token refresh
|
|
42
|
+
// and a single retry; a still-failing load is a genuine re-auth case.
|
|
43
|
+
async fetchOAuthTools(scoped, mcpServerName, mcpServerId, userId) {
|
|
44
|
+
const tokenService = this.oauthTokenService;
|
|
45
|
+
const attemptLoad = async (forceRefresh) => {
|
|
46
|
+
const token = await tokenService.getAccessToken(userId, mcpServerId, { forceRefresh });
|
|
47
|
+
const bearer = `Bearer ${token}`;
|
|
48
|
+
// All scoped configs share this mcpServerId, so inject the token for every one — not just the
|
|
49
|
+
// first key — or extra same-id servers load unauthenticated and report spurious auth failures.
|
|
50
|
+
const injected = (0, ai_proxy_1.injectOauthTokens)({
|
|
51
|
+
configs: scoped,
|
|
52
|
+
tokensByMcpServerName: Object.fromEntries(Object.keys(scoped).map(name => [name, bearer])),
|
|
53
|
+
}) ?? scoped;
|
|
54
|
+
const { tools, failures } = await this.aiModelPort.loadRemoteToolsWithFailures(injected);
|
|
55
|
+
return { tools, hasAuthFailure: failures.some(failure => failure.kind === 'auth') };
|
|
56
|
+
};
|
|
57
|
+
const reloadWithFreshAuth = async () => {
|
|
58
|
+
const attempt = await attemptLoad(true);
|
|
59
|
+
if (attempt.hasAuthFailure)
|
|
60
|
+
throw new errors_1.OAuthReauthRequiredError(mcpServerId);
|
|
61
|
+
this.errorOnPartialLoadFailure(scoped, attempt.tools, mcpServerId, mcpServerName);
|
|
62
|
+
return attempt.tools;
|
|
63
|
+
};
|
|
64
|
+
const initial = await attemptLoad(false);
|
|
65
|
+
if (initial.hasAuthFailure) {
|
|
66
|
+
return { tools: await reloadWithFreshAuth(), mcpServerName, reloadWithFreshAuth };
|
|
67
|
+
}
|
|
68
|
+
const loadFailed = this.errorOnPartialLoadFailure(scoped, initial.tools, mcpServerId, mcpServerName);
|
|
69
|
+
return { tools: initial.tools, mcpServerName, reloadWithFreshAuth, loadFailed };
|
|
24
70
|
}
|
|
25
71
|
// Distinguish "no configs at all" (deployment misconfig) from "configs exist but none match"
|
|
26
72
|
// (orchestrator/executor drift on server id) — both yield zero tools, but ops need to know
|
|
@@ -44,13 +90,14 @@ class RemoteToolFetcher {
|
|
|
44
90
|
.filter(([, cfg]) => !loadedMcpServerIds.has(cfg.id))
|
|
45
91
|
.map(([name]) => name);
|
|
46
92
|
if (failedConfigNames.length === 0)
|
|
47
|
-
return;
|
|
93
|
+
return false;
|
|
48
94
|
this.logger('Error', 'MCP servers failed to load tools', {
|
|
49
95
|
requestedMcpServerId: mcpServerId,
|
|
50
96
|
mcpServerName,
|
|
51
97
|
failedConfigNames,
|
|
52
98
|
});
|
|
99
|
+
return true;
|
|
53
100
|
}
|
|
54
101
|
}
|
|
55
102
|
exports.default = RemoteToolFetcher;
|
|
56
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
103
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVtb3RlLXRvb2wtZmV0Y2hlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9yZW1vdGUtdG9vbC1mZXRjaGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBYUEsb0RBS0M7QUFaRCxvREFBMEQ7QUFFMUQscUNBQW9EO0FBRXBELE1BQU0sZ0JBQWdCLEdBQUcsUUFBUSxDQUFDO0FBRWxDLGtGQUFrRjtBQUNsRixTQUFnQixvQkFBb0IsQ0FDbEMsT0FBbUMsRUFDbkMsV0FBbUI7SUFFbkIsT0FBTyxNQUFNLENBQUMsV0FBVyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxLQUFLLFdBQVcsQ0FBQyxDQUFDLENBQUM7QUFDakcsQ0FBQztBQUVELFNBQVMsWUFBWSxDQUFDLE1BQThCO0lBQ2xELE9BQVEsTUFBNEMsRUFBRSxRQUFRLENBQUM7QUFDakUsQ0FBQztBQWNELE1BQXFCLGlCQUFpQjtJQU1wQyxZQUNFLFlBQTBCLEVBQzFCLFdBQXdCLEVBQ3hCLE1BQWMsRUFDZCxpQkFBb0M7UUFFcEMseUZBQXlGO1FBQ3pGLHdGQUF3RjtRQUN4RixJQUFJLENBQUMsaUJBQWlCLEVBQUUsQ0FBQztZQUN2QixNQUFNLElBQUksS0FBSyxDQUFDLDBFQUEwRSxDQUFDLENBQUM7UUFDOUYsQ0FBQztRQUVELElBQUksQ0FBQyxZQUFZLEdBQUcsWUFBWSxDQUFDO1FBQ2pDLElBQUksQ0FBQyxXQUFXLEdBQUcsV0FBVyxDQUFDO1FBQy9CLElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDO1FBQ3JCLElBQUksQ0FBQyxpQkFBaUIsR0FBRyxpQkFBaUIsQ0FBQztJQUM3QyxDQUFDO0lBRUQsS0FBSyxDQUFDLEtBQUssQ0FBQyxXQUFtQixFQUFFLE1BQWM7UUFDN0MsTUFBTSxPQUFPLEdBQUcsTUFBTSxJ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
|
package/dist/runner.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type OAuthTokenService from './oauth/token-service';
|
|
1
2
|
import type { ActivityLogPortFactory } from './ports/activity-log-port';
|
|
2
3
|
import type { AgentPort } from './ports/agent-port';
|
|
3
4
|
import type { AiModelPort } from './ports/ai-model-port';
|
|
@@ -22,6 +23,7 @@ export interface RunnerConfig {
|
|
|
22
23
|
stepTimeoutS?: number;
|
|
23
24
|
aiInvokeTimeoutS?: number;
|
|
24
25
|
maxChainDepth?: number;
|
|
26
|
+
mcpOAuthTokenService: OAuthTokenService;
|
|
25
27
|
}
|
|
26
28
|
export default class Runner {
|
|
27
29
|
private readonly config;
|
package/dist/runner.js
CHANGED
|
@@ -20,7 +20,7 @@ class Runner {
|
|
|
20
20
|
this._state = 'idle';
|
|
21
21
|
this.config = config;
|
|
22
22
|
this.logger = config.logger ?? (0, console_logger_1.default)();
|
|
23
|
-
this.remoteToolFetcher = new remote_tool_fetcher_1.default(config.workflowPort, config.aiModelPort, this.logger);
|
|
23
|
+
this.remoteToolFetcher = new remote_tool_fetcher_1.default(config.workflowPort, config.aiModelPort, this.logger, config.mcpOAuthTokenService);
|
|
24
24
|
}
|
|
25
25
|
get state() {
|
|
26
26
|
return this._state;
|
|
@@ -216,7 +216,7 @@ class Runner {
|
|
|
216
216
|
while (true) {
|
|
217
217
|
let result;
|
|
218
218
|
try {
|
|
219
|
-
const executor = await step_executor_factory_1.default.create(currentStep, this.contextConfig, this.config.activityLogPortFactory.forRun(currentToken), mcpServerId => this.remoteToolFetcher.fetch(mcpServerId), currentIncomingData, currentToken);
|
|
219
|
+
const executor = await step_executor_factory_1.default.create(currentStep, this.contextConfig, this.config.activityLogPortFactory.forRun(currentToken), (mcpServerId, userId) => this.remoteToolFetcher.fetch(mcpServerId, userId), currentIncomingData, currentToken);
|
|
220
220
|
result = await executor.execute();
|
|
221
221
|
}
|
|
222
222
|
catch (error) {
|
|
@@ -333,4 +333,4 @@ class Runner {
|
|
|
333
333
|
}
|
|
334
334
|
}
|
|
335
335
|
exports.default = Runner;
|
|
336
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVubmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3J1bm5lci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQVlBLCtFQUE0RDtBQUM1RCx5Q0FBNkU7QUFDN0UscUNBT2tCO0FBQ2xCLDhGQUFvRTtBQUNwRSxzRkFBMkQ7QUFDM0QsZ0ZBQXNEO0FBQ3RELGlFQUF1RTtBQUN2RSwwRUFBaUQ7QUE0QmpELHlHQUF5RztBQUN6RyxNQUFNLEVBQUUsT0FBTyxFQUFFLGdCQUFnQixFQUFFLEdBQUcsT0FBTyxDQUFDLGlCQUFpQixDQUF3QixDQUFDO0FBRXhGLE1BQXFCLE1BQU07SUFRekIsWUFBWSxNQUFvQjtRQU54QixpQkFBWSxHQUEwQixJQUFJLENBQUM7UUFDbEMsaUJBQVksR0FBRyxJQUFJLGdDQUFtQixFQUFFLENBQUM7UUFHbEQsV0FBTSxHQUFnQixNQUFNLENBQUM7UUFHbkMsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUM7UUFDckIsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUMsTUFBTSxJQUFJLElBQUEsd0JBQW1CLEdBQUUsQ0FBQztRQUNyRCxJQUFJLENBQUMsaUJBQWlCLEdBQUcsSUFBSSw2QkFBaUIsQ0FDNUMsTUFBTSxDQUFDLFlBQVksRUFDbkIsTUFBTSxDQUFDLFdBQVcsRUFDbEIsSUFBSSxDQUFDLE1BQU0sQ0FDWixDQUFDO0lBQ0osQ0FBQztJQUVELElBQUksS0FBSztRQUNQLE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQztJQUNyQixDQUFDO0lBRUQsS0FBSyxDQUFDLEtBQUs7UUFDVCxJQUFJLElBQUksQ0FBQyxNQUFNLEtBQUssU0FBUyxJQUFJLElBQUksQ0FBQyxNQUFNLEtBQUssVUFBVSxFQUFFLENBQUM7WUFDNUQsTUFBTSxJQUFJLEtBQUssQ0FBQyxpREFBaUQsQ0FBQyxDQUFDO1FBQ3JFLENBQUM7UUFFRCxJQUFJLElBQUksQ0FBQyxNQUFNLEtBQUssU0FBUztZQUFFLE9BQU87UUFFdEMsSUFBQSwwQkFBZSxFQUFDLEVBQUUsU0FBUyxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxFQUFFLFVBQVUsRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLFVBQVUsRUFBRSxDQUFDLENBQUM7UUFFMUYseUZBQXlGO1FBQ3pGLE1BQU0sSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDcEMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEVBQUUsb0JBQW9CLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFDOUMsTUFBTSxJQUFJLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBRTdDLElBQUksQ0FBQyxNQUFNLEdBQUcsU0FBUyxDQUFDO1FBRXhCLElBQUksQ0FBQywwQkFBMEIsRUFBRSxDQUFDO1FBQ2xDLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQztJQUN0QixDQUFDO0lBRUQsS0FBSyxDQUFDLElBQUk7UUFDUixJQUFJLElBQUksQ0FBQyxNQUFNLEtBQUssTUFBTSxJQUFJLElBQUksQ0FBQyxNQUFNLEtBQUssU0FBUyxJQUFJLElBQUksQ0FBQyxNQUFNLEtBQUssVUFBVTtZQUFFLE9BQU87UUFFOUYsSUFBSSxDQUFDLE1BQU0sR0FBRyxVQUFVLENBQUM7UUFDekIsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEVBQUUsNkJBQTZCLEVBQUUsRUFBRSxZQUFZLEVBQUUsSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDO1FBRTdGLElBQUksSUFBSSxDQUFDLFlBQVksS0FBSyxJQUFJLEVBQUUsQ0FBQztZQUMvQixZQUFZLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxDQUFDO1lBQ2hDLElBQUksQ0FBQyxZQUFZLEdBQUcsSUFBSSxDQUFDO1FBQzNCLENBQUM7UUFFRCxJQUFJLENBQUM7WUFDSCxrRUFBa0U7WUFDbEUsSUFBSSxJQUFJLENBQUMsWUFBWSxDQUFDLElBQUksR0FBRyxDQUFDLEVBQUUsQ0FBQztnQkFDL0IsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEVBQUUseUJBQXlCLEVBQUU7b0JBQzdDLEtBQUssRUFBRSxJQUFJLENBQUMsWUFBWSxDQUFDLElBQUk7b0JBQzdCLElBQUksRUFBRSxDQUFDLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLEVBQUUsQ0FBQztpQkFDcEMsQ0FBQyxDQUFDO2dCQUVILE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsWUFBWSxJQUFJLGlDQUFzQixDQUFDO2dCQUNwRSxJQUFJLFVBQXNDLENBQUM7Z0JBQzNDLE1BQU0sV0FBVyxHQUFHLE1BQU0sT0FBTyxDQUFDLElBQUksQ0FBQztvQkFDckMsSUFBSSxDQUFDLFlBQVksQ0FBQyxLQUFLLEVBQUUsQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFO3dCQUNsQyxJQUFJLFVBQVU7NEJBQUUsWUFBWSxDQUFDLFVBQVUsQ0FBQyxDQUFDO3dCQUV6QyxPQUFPLFNBQWtCLENBQUM7b0JBQzVCLENBQUMsQ0FBQztvQkFDRixJQUFJLE9BQU8sQ0FBWSxPQUFPLENBQUMsRUFBRTt3QkFDL0IsVUFBVSxHQUFHLFVBQVUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLEVBQUUsUUFBUSxHQUFHLElBQUksQ0FBQyxDQUFDO29CQUNyRSxDQUFDLENBQUM7aUJBQ0gsQ0FBQyxDQUFDO2dCQUVILElBQUksV0FBVyxLQUFLLFNBQVMsRUFBRSxDQUFDO29CQUM5QixJQUFJLENBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRSxzQ0FBc0MsRUFBRTt3QkFDM0QsYUFBYSxFQUFFLENBQUMsR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDLElBQUksRUFBRSxDQUFDO3dCQUM1QyxRQUFRO3FCQUNULENBQUMsQ0FBQztnQkFDTCxDQUFDO3FCQUFNLENBQUM7b0JBQ04sSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEVBQUUsNEJBQTRCLEVBQUUsRUFBRSxDQUFDLENBQUM7Z0JBQ3hELENBQUM7WUFDSCxDQUFDO1lBRUQseUZBQXlGO1lBQ3pGLDJEQUEyRDtZQUMzRCxNQUFNLElBQUksQ0FBQyxNQUFNLENBQUMsc0JBQXNCLENBQUMsS0FBSyxFQUFFLENBQUM7WUFFakQsTUFBTSxPQUFPLEdBQUcsTUFBTSxPQUFPLENBQUMsVUFBVSxDQUFDO2dCQUN2QyxJQUFJLENBQUMsTUFBTSxDQUFDLFdBQVcsQ0FBQyxnQkFBZ0IsRUFBRTtnQkFDMUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUM7YUFDeEMsQ0FBQyxDQUFDO1lBRUgsS0FBSyxNQUFNLE1BQU0sSUFBSSxPQUFPLEVBQUUsQ0FBQztnQkFDN0IsSUFBSSxNQUFNLENBQUMsTUFBTSxLQUFLLFVBQVUsRUFBRSxDQUFDO29CQUNqQyxJQUFJLENBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRSx5Q0FBeUMsRUFBRTt3QkFDOUQsS0FBSyxFQUFFLE1BQU0sQ0FBQyxNQUFNLFlBQVksS0FBSyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUM7cUJBQ3RGLENBQUMsQ0FBQztnQkFDTCxDQUFDO1lBQ0gsQ0FBQztRQUNILENBQUM7Z0JBQVMsQ0FBQztZQUNULElBQUksQ0FBQyxNQUFNLEdBQUcsU0FBUyxDQUFDO1lBQ3hCLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxFQUFFLDJCQUEyQixFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQ3ZELENBQUM7SUFDSCxDQUFDO0lBRUQsS0FBSyxDQUFDLG9CQUFvQixDQUFDLEtBQWE7UUFDdEMsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxpQkFBaUIsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUN2RCxDQUFDO0lBRUQsS0FBSyxDQUFDLFdBQVcsQ0FDZixLQUFhLEVBQ2IsT0FBMEQ7UUFFMUQsMEZBQTBGO1FBQzFGLDhGQUE4RjtRQUM5Rix5RkFBeUY7UUFDekYsNEZBQTRGO1FBQzVGLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUVqQyxJQUFJLFFBQXFDLENBQUM7UUFFMUMsSUFBSSxDQUFDO1lBQ0gsUUFBUSxHQUFHLE1BQU0sSUFBSSxDQUFDLE1BQU0sQ0FBQyxZQUFZLENBQUMsZUFBZSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ25FLENBQUM7UUFBQyxPQUFPLEdBQUcsRUFBRSxDQUFDO1lBQ2IsSUFBSSxHQUFHLFlBQVksMEJBQWlCLEVBQUUsQ0FBQztnQkFDckMsTUFBTSxJQUFJLENBQUMsa0JBQWtCLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQzFDLENBQUM7WUFFRCxNQUFNLEdBQUcsQ0FBQztRQUNaLENBQUM7UUFFRCxJQUFJLENBQUMsUUFBUTtZQUFFLE1BQU0sSUFBSSx5QkFBZ0IsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUVqRCxNQUFNLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxHQUFHLFFBQVEsQ0FBQztRQUVoQyxJQUFJLE9BQU8sRUFBRSxZQUFZLEtBQUssU0FBUyxJQUFJLElBQUksQ0FBQyxJQUFJLENBQUMsRUFBRSxLQUFLLE9BQU8sQ0FBQyxZQUFZLEVBQUUsQ0FBQztZQUNqRixNQUFNLElBQUksMEJBQWlCLENBQUMsS0FBSyxFQUFFLE9BQU8sQ0FBQyxZQUFZLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUN6RSxDQUFDO1FBRUQsTUFBTSxJQUFJLENBQUMsV0FBVyxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsaUJBQWlCLEVBQUUsT0FBTyxFQUFFLFdBQVcsQ0FBQyxDQUFDO0lBQzdFLENBQUM7SUFFTyxvQkFBb0IsQ0FBQyxLQUFhO1FBQ3hDLElBQUksSUFBSSxDQUFDLFlBQVksQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUNqQyxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sRUFBRSx5Q0FBeUMsRUFBRSxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUM7WUFFMUUsTUFBTSxJQUFJLGdDQUF1QixDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzNDLENBQUM7SUFDSCxDQUFDO0lBRU8sWUFBWTtRQUNsQixJQUFJLElBQUksQ0FBQyxNQUFNLEtBQUssU0FBUztZQUFFLE9BQU87UUFDdEMsSUFBSSxDQUFDLFlBQVksR0FBRyxVQUFVLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLFlBQVksRUFBRSxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsZ0JBQWdCLEdBQUcsSUFBSSxDQUFDLENBQUM7SUFDakcsQ0FBQztJQUVPLEtBQUssQ0FBQyxZQUFZO1FBQ3hCLElBQUksQ0FBQztZQUNILE1BQU0sRUFBRSxPQUFPLEVBQUUsU0FBUyxFQUFFLEdBQUcsTUFBTSxJQUFJLENBQUMsTUFBTSxDQUFDLFlBQVksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO1lBQ2pGLDBGQUEwRjtZQUMxRixNQUFNLE9BQU8sQ0FBQyxVQUFVLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFFL0UsTUFBTSxZQUFZLEdBQUcsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO1lBQy9FLE1BQU0sUUFBUSxHQUFHLE1BQU0sQ0FBQyxrQkFBa0IsQ0FBQztnQkFDekMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxNQUFNO2dCQUN2QixVQUFVLEVBQUUsWUFBWSxDQUFDLE1BQU07Z0JBQy9CLFNBQVMsRUFBRSxTQUFTLENBQUMsTUFBTTthQUM1QixDQUFDLENBQUM7WUFDSCxJQUFJLENBQUMsTUFBTSxDQUFDLFFBQVEsRUFBRSxzQkFBc0IsRUFBRTtnQkFDNUMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxNQUFNO2dCQUN2QixXQUFXLEVBQUUsWUFBWSxDQUFDLE1BQU07Z0JBQ2hDLFNBQVMsRUFBRSxTQUFTLENBQUMsTUFBTTthQUM1QixDQUFDLENBQUM7WUFDSCxNQUFNLE9BQU8sQ0FBQyxVQUFVLENBQ3RCLFlBQVksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDLENBQzFFLENBQUM7UUFDSixDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLElBQUksQ0FBQyxNQUFNLENBQUMsT0FBTyxFQUFFLG1CQUFtQixFQUFFO2dCQUN4QyxLQUFLLEVBQUUsSUFBQSw0QkFBbUIsRUFBQyxLQUFLLENBQUM7Z0JBQ2pDLEtBQUssRUFBRSxLQUFLLFlBQVksS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxTQUFTO2FBQ3hELENBQUMsQ0FBQztRQUNMLENBQUM7Z0JBQVMsQ0FBQztZQUNULElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQztRQUN0QixDQUFDO0lBQ0gsQ0FBQztJQUVELCtGQUErRjtJQUMvRiw4RkFBOEY7SUFDOUYsZ0NBQWdDO0lBQ3hCLEtBQUssQ0FBQyxrQkFBa0IsQ0FBQyxJQUFzQjtRQUNyRCxJQUFJLElBQUksQ0FBQyxNQUFNLEtBQUssSUFBSSxJQUFJLElBQUksQ0FBQyxTQUFTLEtBQUssSUFBSSxFQUFFLENBQUM7WUFDcEQsSUFBSSxDQUFDLE1BQU0sQ0FBQyxPQUFPLEVBQUUsaUVBQWlFLEVBQUU7Z0JBQ3RGLEtBQUssRUFBRSxJQUFJLENBQUMsS0FBSztnQkFDakIsS0FBSyxFQUFFLElBQUksQ0FBQyxnQkFBZ0I7YUFDN0IsQ0FBQyxDQUFDO1lBRUgsT0FBTztRQUNULENBQUM7UUFFRCxJQUFJLENBQUM7WUFDSCxNQUFNLElBQUksQ0FBQyxNQUFNLENBQUMsWUFBWSxDQUFDLG1CQUFtQixDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUU7Z0JBQzdELElBQUksRUFBRSxRQUFRO2dCQUNkLE1BQU0sRUFBRSxJQUFJLENBQUMsTUFBTTtnQkFDbkIsU0FBUyxFQUFFLElBQUksQ0FBQyxTQUFTO2dCQUN6QixNQUFNLEVBQUUsT0FBTztnQkFDZixLQUFLLEVBQUUsSUFBSSxDQUFDLFdBQVc7YUFDeEIsQ0FBQyxDQUFDO1lBQ0gsSUFBSSxDQUFDLE1BQU0sQ0FBQyxPQUFPLEVBQUUsaUNBQWlDLEVBQUU7Z0JBQ3RELEtBQUssRUFBRSxJQUFJLENBQUMsS0FBSztnQkFDakIsU0FBUyxFQUFFLElBQUksQ0FBQyxTQUFTO2dCQUN6QixLQUFLLEVBQUUsSUFBSSxDQUFDLGdCQUFnQjthQUM3QixDQUFDLENBQUM7UUFDTCxDQUFDO1FBQUMsT0FBTyxTQUFTLEVBQUUsQ0FBQztZQUNuQixJQUFJLENBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRSx1Q0FBdUMsRUFBRTtnQkFDNUQsS0FBSyxFQUFFLElBQUksQ0FBQyxLQUFLO2dCQUNqQixZQUFZLEVBQUUsSUFBSSxDQUFDLGdCQUFnQjtnQkFDbkMsV0FBVyxFQUFFLElBQUEsNEJBQW1CLEVBQUMsU0FBUyxDQUFDO2FBQzVDLENBQUMsQ0FBQztRQUNMLENBQUM7SUFDSCxDQUFDO0lBRU8sV0FBVyxDQUNqQixJQUE0QixFQUM1QixpQkFBeUIsRUFDekIsbUJBQTZCO1FBRTdCLHVGQUF1RjtRQUN2Rix5RkFBeUY7UUFDekYsNEZBQTRGO1FBQzVGLDhCQUE4QjtRQUM5QixPQUFPLElBQUksQ0FBQyxZQUFZLENBQUMsS0FBSyxDQUM1QixJQUFJLENBQUMsS0FBSyxFQUNWLElBQUksQ0FBQyxhQUFhLENBQUMsSUFBSSxFQUFFLGlCQUFpQixFQUFFLG1CQUFtQixDQUFDLENBQ2pFLENBQUM7SUFDSixDQUFDO0lBRU8sS0FBSyxDQUFDLGFBQWEsQ0FDekIsSUFBNEIsRUFDNUIsaUJBQXlCLEVBQ3pCLG1CQUE2QjtRQUU3QixJQUFJLFdBQVcsR0FBRyxJQUFJLENBQUM7UUFDdkIsSUFBSSxZQUFZLEdBQUcsaUJBQWlCLENBQUM7UUFDckMsSUFBSSxtQkFBbUIsR0FBRyxtQkFBbUIsQ0FBQztRQUM5QyxJQUFJLFlBQVksR0FBRyxDQUFDLENBQUMsQ0FBQyxpREFBaUQ7UUFDdkUsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxhQUFhLElBQUksa0NBQXVCLENBQUM7UUFFdEUsMkZBQTJGO1FBQzNGLGdFQUFnRTtRQUNoRSw0REFBNEQ7UUFDNUQsT0FBTyxJQUFJLEVBQUUsQ0FBQztZQUNaLElBQUksTUFBMkIsQ0FBQztZQUVoQyxJQUFJLENBQUM7Z0JBQ0gsTUFBTSxRQUFRLEdBQUcsTUFBTSwrQkFBbUIsQ0FBQyxNQUFNLENBQy9DLFdBQVcsRUFDWCxJQUFJLENBQUMsYUFBYSxFQUNsQixJQUFJLENBQUMsTUFBTSxDQUFDLHNCQUFzQixDQUFDLE1BQU0sQ0FBQyxZQUFZLENBQUMsRUFDdkQsV0FBVyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsaUJBQWlCLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxFQUN4RCxtQkFBbUIsRUFDbkIsWUFBWSxDQUNiLENBQUM7Z0JBQ0YsTUFBTSxHQUFHLE1BQU0sUUFBUSxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQ3BDLENBQUM7WUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO2dCQUNmLElBQUksQ0FBQyxNQUFNLENBQ1QsT0FBTyxFQUNQLHVFQUF1RSxFQUN2RTtvQkFDRSxLQUFLLEVBQUUsV0FBVyxDQUFDLEtBQUs7b0JBQ3hCLE1BQU0sRUFBRSxXQUFXLENBQUMsTUFBTTtvQkFDMUIsU0FBUyxFQUFFLFdBQVcsQ0FBQyxTQUFTO29CQUNoQyxLQUFLLEVBQUUsSUFBQSw0QkFBbUIsRUFBQyxLQUFLLENBQUM7aUJBQ2xDLENBQ0YsQ0FBQztnQkFFRixzRkFBc0Y7Z0JBQ3RGLDRFQUE0RTtnQkFDNUUsTUFBTSxnQkFBZ0IsR0FBZ0I7b0JBQ3BDLElBQUksRUFBRSxJQUFBLG9DQUFxQixFQUFDLFdBQVcsQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDO29CQUM1RCxNQUFNLEVBQUUsV0FBVyxDQUFDLE1BQU07b0JBQzFCLFNBQVMsRUFBRSxXQUFXLENBQUMsU0FBUztvQkFDaEMsTUFBTSxFQUFFLE9BQU87b0JBQ2YsS0FBSyxFQUFFLCtCQUErQjtpQkFDdkMsQ0FBQztnQkFFRixJQUFJLENBQUM7b0JBQ0gsTUFBTSxJQUFJLENBQUMsTUFBTSxDQUFDLFlBQVksQ0FBQyxtQkFBbUIsQ0FBQyxXQUFXLENBQUMsS0FBSyxFQUFFLGdCQUFnQixDQUFDLENBQUM7Z0JBQzFGLENBQUM7Z0JBQUMsT0FBTyxTQUFTLEVBQUUsQ0FBQztvQkFDbkIsSUFBSSxDQUFDLE1BQU0sQ0FBQyxPQUFPLEVBQUUsc0RBQXNELEVBQUU7d0JBQzNFLEtBQUssRUFBRSxXQUFXLENBQUMsS0FBSzt3QkFDeEIsTUFBTSxFQUFFLFdBQVcsQ0FBQyxNQUFNO3dCQUMxQixXQUFXLEVBQUUsSUFBQSw0QkFBbUIsRUFBQyxTQUFTLENBQUM7cUJBQzVDLENBQUMsQ0FBQztnQkFDTCxDQUFDO2dCQUVELE9BQU87WUFDVCxDQUFDO1lBRUQsSUFBSSxZQUF5QyxDQUFDO1lBRTlDLElBQUksQ0FBQztnQkFDSCxZQUFZLEdBQUcsTUFBTSxJQUFJLENBQUMsTUFBTSxDQUFDLFlBQVksQ0FBQyxtQkFBbUIsQ0FDL0QsV0FBVyxDQUFDLEtBQUssRUFDakIsTUFBTSxDQUFDLFdBQVcsQ0FDbkIsQ0FBQztZQUNKLENBQUM7WUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO2dCQUNmLElBQUksQ0FBQyxNQUFNLENBQUMsT0FBTyxFQUFFLCtCQUErQixFQUFFO29CQUNwRCxLQUFLLEVBQUUsV0FBVyxDQUFDLEtBQUs7b0JBQ3hCLE1BQU0sRUFBRSxXQUFXLENBQUMsTUFBTTtvQkFDMUIsU0FBUyxFQUFFLFdBQVcsQ0FBQyxTQUFTO29CQUNoQyxLQUFLLEVBQUUsSUFBQSw0QkFBbUIsRUFBQyxLQUFLLENBQUM7b0JBQ2pDLEtBQUssRUFBRSxJQUFBLHFCQUFZLEVBQUMsS0FBSyxDQUFDO29CQUMxQixLQUFLLEVBQUUsS0FBSyxZQUFZLEtBQUssQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsU0FBUztpQkFDeEQsQ0FBQyxDQUFDO2dCQUVILE9BQU87WUFDVCxDQUFDO1lBRUQsSUFBSSxZQUFZLEtBQUssSUFBSSxFQUFFLENBQUM7Z0JBQzFCLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxFQUFFLHlEQUF5RCxFQUFFO29CQUM3RSxLQUFLLEVBQUUsV0FBVyxDQUFDLEtBQUs7b0JBQ3hCLFNBQVMsRUFBRSxXQUFXLENBQUMsU0FBUztpQkFDakMsQ0FBQyxDQUFDO2dCQUVILE9BQU87WUFDVCxDQUFDO1lBRUQsNEZBQTRGO1lBQzVGLDBGQUEwRjtZQUMxRixzRkFBc0Y7WUFDdEYscUVBQXFFO1lBQ3JFLElBQ0UsWUFBWSxDQUFDLElBQUksQ0FBQyxLQUFLLEtBQUssV0FBVyxDQUFDLEtBQUs7Z0JBQzdDLFlBQVksQ0FBQyxJQUFJLENBQUMsU0FBUyxJQUFJLFdBQVcsQ0FBQyxTQUFTLEVBQ3BELENBQUM7Z0JBQ0QsSUFBSSxDQUFDLE1BQU0sQ0FBQyxPQUFPLEVBQUUsMkRBQTJELEVBQUU7b0JBQ2hGLEtBQUssRUFBRSxXQUFXLENBQUMsS0FBSztvQkFDeEIsZ0JBQWdCLEVBQUUsV0FBVyxDQUFDLFNBQVM7b0JBQ3ZDLGFBQWEsRUFBRSxZQUFZLENBQUMsSUFBSSxDQUFDLEtBQUs7b0JBQ3RDLGlCQUFpQixFQUFFLFlBQVksQ0FBQyxJQUFJLENBQUMsU0FBUztpQkFDL0MsQ0FBQyxDQUFDO2dCQUVILE9BQU87WUFDVCxDQUFDO1lBRUQsMkZBQTJGO1lBQzNGLGdGQUFnRjtZQUNoRixJQUFJLFlBQVksSUFBSSxRQUFRLEVBQUUsQ0FBQztnQkFDN0IsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEVBQUUsaURBQWlELEVBQUU7b0JBQ3JFLEtBQUssRUFBRSxXQUFXLENBQUMsS0FBSztvQkFDeEIsU0FBUyxFQUFFLFdBQVcsQ0FBQyxTQUFTO29CQUNoQyxRQUFRO2lCQUNULENBQUMsQ0FBQztnQkFFSCxPQUFPO1lBQ1QsQ0FBQztZQUVELGtGQUFrRjtZQUNsRixJQUFJLElBQUksQ0FBQyxNQUFNLEtBQUssVUFBVSxFQUFFLENBQUM7Z0JBQy9CLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxFQUFFLHdDQUF3QyxFQUFFO29CQUM1RCxLQUFLLEVBQUUsV0FBVyxDQUFDLEtBQUs7b0JBQ3hCLFNBQVMsRUFBRSxXQUFXLENBQUMsU0FBUztpQkFDakMsQ0FBQyxDQUFDO2dCQUVILE9BQU87WUFDVCxDQUFDO1lBRUQsWUFBWSxJQUFJLENBQUMsQ0FBQztZQUNsQixXQUFXLEdBQUcsWUFBWSxDQUFDLElBQUksQ0FBQztZQUNoQyxZQUFZLEdBQUcsWUFBWSxDQUFDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQztZQUNuRCxtQkFBbUIsR0FBRyxTQUFTLENBQUMsQ0FBQyx5Q0FBeUM7UUFDNUUsQ0FBQztRQUNELDJEQUEyRDtJQUM3RCxDQUFDO0lBRUQsSUFBWSxhQUFhO1FBQ3ZCLE9BQU87WUFDTCxXQUFXLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxXQUFXO1lBQ3BDLFNBQVMsRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLFNBQVM7WUFDaEMsWUFBWSxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsWUFBWTtZQUN0QyxRQUFRLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxRQUFRO1lBQzlCLFdBQVcsRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLFdBQVc7WUFDcEMsTUFBTSxFQUFFLElBQUksQ0FBQyxNQUFNO1lBQ25CLFlBQVksRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLFlBQVk7WUFDdEMsZ0JBQWdCLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxnQkFBZ0I7U0FDL0MsQ0FBQztJQUNKLENBQUM7SUFFTyxNQUFNLENBQUMsa0JBQWtCLENBQUMsRUFDaEMsT0FBTyxFQUNQLFVBQVUsRUFDVixTQUFTLEdBS1Y7UUFDQyxPQUFPLE9BQU8sS0FBSyxDQUFDLElBQUksVUFBVSxLQUFLLENBQUMsSUFBSSxTQUFTLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQztJQUNqRixDQUFDO0lBRU8sMEJBQTBCO1FBQ2hDLElBQUksQ0FBQyxNQUFNLENBQUMsWUFBWSxDQUFDLHNCQUFzQixDQUFDLEVBQUUsT0FBTyxFQUFFLGdCQUFnQixFQUFFLENBQUMsQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLEVBQUU7WUFDM0YsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEVBQUUsbURBQW1ELEVBQUU7Z0JBQ3ZFLE9BQU8sRUFBRSxnQkFBZ0I7Z0JBQ3pCLEtBQUssRUFBRSxLQUFLLFlBQVksS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDO2FBQzlELENBQUMsQ0FBQztRQUNMLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztDQUNGO0FBeFpELHlCQXdaQyJ9
|
|
336
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVubmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3J1bm5lci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQWFBLCtFQUE0RDtBQUM1RCx5Q0FBNkU7QUFDN0UscUNBT2tCO0FBQ2xCLDhGQUFvRTtBQUNwRSxzRkFBMkQ7QUFDM0QsZ0ZBQXNEO0FBQ3RELGlFQUF1RTtBQUN2RSwwRUFBaUQ7QUErQmpELHlHQUF5RztBQUN6RyxNQUFNLEVBQUUsT0FBTyxFQUFFLGdCQUFnQixFQUFFLEdBQUcsT0FBTyxDQUFDLGlCQUFpQixDQUF3QixDQUFDO0FBRXhGLE1BQXFCLE1BQU07SUFRekIsWUFBWSxNQUFvQjtRQU54QixpQkFBWSxHQUEwQixJQUFJLENBQUM7UUFDbEMsaUJBQVksR0FBRyxJQUFJLGdDQUFtQixFQUFFLENBQUM7UUFHbEQsV0FBTSxHQUFnQixNQUFNLENBQUM7UUFHbkMsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUM7UUFDckIsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUMsTUFBTSxJQUFJLElBQUEsd0JBQW1CLEdBQUUsQ0FBQztRQUNyRCxJQUFJLENBQUMsaUJBQWlCLEdBQUcsSUFBSSw2QkFBaUIsQ0FDNUMsTUFBTSxDQUFDLFlBQVksRUFDbkIsTUFBTSxDQUFDLFdBQVcsRUFDbEIsSUFBSSxDQUFDLE1BQU0sRUFDWCxNQUFNLENBQUMsb0JBQW9CLENBQzVCLENBQUM7SUFDSixDQUFDO0lBRUQsSUFBSSxLQUFLO1FBQ1AsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDO0lBQ3JCLENBQUM7SUFFRCxLQUFLLENBQUMsS0FBSztRQUNULElBQUksSUFBSSxDQUFDLE1BQU0sS0FBSyxTQUFTLElBQUksSUFBSSxDQUFDLE1BQU0sS0FBSyxVQUFVLEVBQUUsQ0FBQztZQUM1RCxNQUFNLElBQUksS0FBSyxDQUFDLGlEQUFpRCxDQUFDLENBQUM7UUFDckUsQ0FBQztRQUVELElBQUksSUFBSSxDQUFDLE1B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
|