@dbx-tools/appkit-mastra 0.5.0 → 0.6.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.
@@ -10,6 +10,20 @@ import { RequestContext } from "@mastra/core/request-context";
10
10
  import { MastraServer as MastraServerExpress } from "@mastra/express";
11
11
  import type express from "express";
12
12
  import { type MastraPluginConfig } from "./config.ts";
13
+ /**
14
+ * Who a turn is ATTRIBUTED to, independent of which Databricks credential runs
15
+ * its calls. Supplied by the HTTP middleware from the forwarded user headers so
16
+ * that in `service-principal` mode - where every request shares the app SP's
17
+ * client - the memory thread, per-user cache namespace, and trace metadata
18
+ * still key off the real caller. Ignored in an OBO (user) context, whose own
19
+ * user id / email are authoritative.
20
+ */
21
+ export interface AttributedIdentity {
22
+ /** Forwarded `x-forwarded-user` id, used when the client is the service principal. */
23
+ userId?: string | undefined;
24
+ /** Forwarded `x-forwarded-email`, used for trace metadata under the service principal. */
25
+ email?: string | undefined;
26
+ }
13
27
  /**
14
28
  * Stamp the AppKit user (plus the resource id and trace metadata) onto
15
29
  * `requestContext`.
@@ -22,10 +36,14 @@ import { type MastraPluginConfig } from "./config.ts";
22
36
  * callers build a context with {@link createRequestContext} instead of a
23
37
  * request.
24
38
  *
39
+ * The Databricks credential always comes from the ambient execution context;
40
+ * `attributed` only changes WHO the turn is attributed to when that context is
41
+ * the service principal (see {@link AttributedIdentity}).
42
+ *
25
43
  * Idempotent: returns immediately when the user and resource id are already
26
44
  * present, so the middleware can call it over a context another layer stamped.
27
45
  */
28
- export declare function stampRequestContextUser(requestContext: RequestContext): Promise<void>;
46
+ export declare function stampRequestContextUser(requestContext: RequestContext, attributed?: AttributedIdentity): Promise<void>;
29
47
  /**
30
48
  * Build the `RequestContext` a NON-HTTP agent turn needs.
31
49
  *
@@ -58,7 +76,7 @@ export declare class MastraServer extends MastraServerExpress {
58
76
  private feedbackEnabled;
59
77
  constructor(config: MastraPluginConfig, ...args: ConstructorParameters<typeof MastraServerExpress>);
60
78
  registerAuthMiddleware(): void;
61
- configureRequestContextUser(requestContext: RequestContext): Promise<void>;
79
+ configureRequestContextUser(req: express.Request, requestContext: RequestContext): Promise<void>;
62
80
  /**
63
81
  * Stamp a per-request id and echo it on the response so an upstream
64
82
  * proxy / curl client / browser-side log line can pair its view of
package/lib/src/server.js CHANGED
@@ -13,6 +13,7 @@ import { MASTRA_RESOURCE_ID_KEY, MASTRA_THREAD_ID_KEY, RequestContext, } from "@
13
13
  import { MastraServer as MastraServerExpress } from "@mastra/express";
14
14
  import { trace } from "@opentelemetry/api";
15
15
  import { executionContextUserId, MASTRA_REQUEST_ID_KEY, MASTRA_SCOPES_KEY, MASTRA_USER_EMAIL_KEY, MASTRA_USER_KEY, MASTRA_USER_NAME_KEY, } from "./config.js";
16
+ import { requestUserEmail, requestUserId } from "./identity.js";
16
17
  import { resolveFeedbackEnabled } from "./mlflow.js";
17
18
  import { extractModelOverride, MASTRA_MODEL_OVERRIDE_KEY, resolveServingConfig, } from "./serving.js";
18
19
  /**
@@ -34,28 +35,40 @@ const INVALID_TRACE_ID = "0".repeat(32);
34
35
  * callers build a context with {@link createRequestContext} instead of a
35
36
  * request.
36
37
  *
38
+ * The Databricks credential always comes from the ambient execution context;
39
+ * `attributed` only changes WHO the turn is attributed to when that context is
40
+ * the service principal (see {@link AttributedIdentity}).
41
+ *
37
42
  * Idempotent: returns immediately when the user and resource id are already
38
43
  * present, so the middleware can call it over a context another layer stamped.
39
44
  */
40
- export async function stampRequestContextUser(requestContext) {
45
+ export async function stampRequestContextUser(requestContext, attributed = {}) {
41
46
  if ([MASTRA_USER_KEY, MASTRA_RESOURCE_ID_KEY].every((key) => requestContext.get(key)))
42
47
  return;
43
48
  const executionContext = getExecutionContext();
44
- const user = {
45
- id: executionContextUserId(executionContext),
46
- executionContext,
47
- };
49
+ const isUserContext = "isUserContext" in executionContext;
50
+ // The Databricks CREDENTIAL is always the ambient execution context's client
51
+ // (OBO in a user context, the service principal otherwise). WHO the turn is
52
+ // attributed to can differ: in `service-principal` mode every request shares
53
+ // the SP client, but the forwarded user id must still key the memory thread
54
+ // and the per-user cache namespace so two callers don't share a conversation.
55
+ // Prefer the OBO context's own user id, then the forwarded id, then the SP id.
56
+ const id = (isUserContext ? executionContextUserId(executionContext) : attributed.userId) ??
57
+ executionContextUserId(executionContext);
58
+ const user = { id, executionContext };
48
59
  requestContext.set(MASTRA_USER_KEY, user);
49
60
  requestContext.set(MASTRA_RESOURCE_ID_KEY, user.id);
50
61
  // AppKit's `UserContext` surfaces display name / email only on
51
62
  // OBO requests. Service-context calls (background tasks, server
52
63
  // start-up) leave these undefined and we skip the stamp so
53
- // downstream trace metadata stays absent rather than empty.
64
+ // downstream trace metadata stays absent rather than empty. In
65
+ // `service-principal` mode the forwarded email still identifies the caller,
66
+ // so it is used for trace metadata even though the client is the SP.
54
67
  let userName;
55
- let email;
56
- if ("isUserContext" in executionContext) {
68
+ let email = attributed.email;
69
+ if (isUserContext) {
57
70
  userName = executionContext.userName;
58
- email = executionContext.userEmail;
71
+ email = executionContext.userEmail ?? email;
59
72
  }
60
73
  else if (process.env.NODE_ENV === "development") {
61
74
  const currentUser = await executionContext.client.currentUser.me();
@@ -117,7 +130,7 @@ export class MastraServer extends MastraServerExpress {
117
130
  super.registerAuthMiddleware();
118
131
  this.app.use(async (req, res, next) => {
119
132
  const requestContext = res.locals.requestContext;
120
- await this.configureRequestContextUser(requestContext);
133
+ await this.configureRequestContextUser(req, requestContext);
121
134
  this.configureRequestContextThreadId(req, res, requestContext);
122
135
  this.configureRequestContextModelOverride(req, requestContext);
123
136
  this.configureRequestContextRequestId(req, res, requestContext);
@@ -139,8 +152,14 @@ export class MastraServer extends MastraServerExpress {
139
152
  next();
140
153
  });
141
154
  }
142
- async configureRequestContextUser(requestContext) {
143
- await stampRequestContextUser(requestContext);
155
+ async configureRequestContextUser(req, requestContext) {
156
+ // Pass the forwarded caller identity so `service-principal` mode still keys
157
+ // memory / cache / traces per user even though the client is the app SP.
158
+ // In an OBO context these are ignored in favor of the context's own user.
159
+ await stampRequestContextUser(requestContext, {
160
+ userId: requestUserId(req),
161
+ email: requestUserEmail(req),
162
+ });
144
163
  }
145
164
  /**
146
165
  * Stamp a per-request id and echo it on the response so an upstream
@@ -333,4 +352,4 @@ export function attachRoutePatchMiddleware(app) {
333
352
  next();
334
353
  });
335
354
  }
336
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NlcnZlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7OztHQU9HO0FBRUgsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDekQsT0FBTyxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsR0FBRyxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDaEYsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUM1RCxPQUFPLEVBQ0wsc0JBQXNCLEVBQ3RCLG9CQUFvQixFQUNwQixjQUFjLEdBQ2YsTUFBTSw4QkFBOEIsQ0FBQztBQUN0QyxPQUFPLEVBQUUsWUFBWSxJQUFJLG1CQUFtQixFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDdEUsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBRzNDLE9BQU8sRUFDTCxzQkFBc0IsRUFDdEIscUJBQXFCLEVBQ3JCLGlCQUFpQixFQUNqQixxQkFBcUIsRUFDckIsZUFBZSxFQUNmLG9CQUFvQixHQUdyQixNQUFNLGFBQWEsQ0FBQztBQUNyQixPQUFPLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFFckQsT0FBTyxFQUNMLG9CQUFvQixFQUNwQix5QkFBeUIsRUFDekIsb0JBQW9CLEdBQ3JCLE1BQU0sY0FBYyxDQUFDO0FBQ3RCOzs7OztHQUtHO0FBQ0gsTUFBTSxnQkFBZ0IsR0FBRyxHQUFHLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0FBRXhDOzs7Ozs7Ozs7Ozs7OztHQWNHO0FBQ0gsTUFBTSxDQUFDLEtBQUssVUFBVSx1QkFBdUIsQ0FBQyxjQUE4QjtJQUMxRSxJQUFJLENBQUMsZUFBZSxFQUFFLHNCQUFzQixDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxjQUFjLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQUUsT0FBTztJQUM5RixNQUFNLGdCQUFnQixHQUFHLG1CQUFtQixFQUFFLENBQUM7SUFDL0MsTUFBTSxJQUFJLEdBQVM7UUFDakIsRUFBRSxFQUFFLHNCQUFzQixDQUFDLGdCQUFnQixDQUFDO1FBQzVDLGdCQUFnQjtLQUNqQixDQUFDO0lBQ0YsY0FBYyxDQUFDLEdBQUcsQ0FBQyxlQUFlLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDMUMsY0FBYyxDQUFDLEdBQUcsQ0FBQyxzQkFBc0IsRUFBRSxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDcEQsK0RBQStEO0lBQy9ELGdFQUFnRTtJQUNoRSwyREFBMkQ7SUFDM0QsNERBQTREO0lBQzVELElBQUksUUFBNEIsQ0FBQztJQUNqQyxJQUFJLEtBQXlCLENBQUM7SUFDOUIsSUFBSSxlQUFlLElBQUksZ0JBQWdCLEVBQUUsQ0FBQztRQUN4QyxRQUFRLEdBQUcsZ0JBQWdCLENBQUMsUUFBUSxDQUFDO1FBQ3JDLEtBQUssR0FBRyxnQkFBZ0IsQ0FBQyxTQUFTLENBQUM7SUFDckMsQ0FBQztTQUFNLElBQUksT0FBTyxDQUFDLEdBQUcsQ0FBQyxRQUFRLEtBQUssYUFBYSxFQUFFLENBQUM7UUFDbEQsTUFBTSxXQUFXLEdBQUcsTUFBTSxnQkFBZ0IsQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDLEVBQUUsRUFBRSxDQUFDO1FBQ25FLFFBQVEsR0FBRyxXQUFXLEVBQUUsUUFBUSxDQUFDO1FBQ2pDLEtBQUssR0FBRyxXQUFXLEVBQUUsTUFBTSxFQUFFLE1BQU0sQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQztZQUN4RixFQUFFLEtBQWUsQ0FBQztJQUN0QixDQUFDO0lBQ0QsSUFBSSxRQUFRLEVBQUUsQ0FBQztRQUNiLGNBQWMsQ0FBQyxHQUFHLENBQUMsb0JBQW9CLEVBQUUsUUFBUSxDQUFDLENBQUM7SUFDckQsQ0FBQztJQUNELElBQUksS0FBSyxFQUFFLENBQUM7UUFDVixjQUFjLENBQUMsR0FBRyxDQUFDLHFCQUFxQixFQUFFLEtBQUssQ0FBQyxDQUFDO0lBQ25ELENBQUM7QUFDSCxDQUFDO0FBRUQ7Ozs7Ozs7Ozs7O0dBV0c7QUFDSCxNQUFNLENBQUMsS0FBSyxVQUFVLG9CQUFvQixDQUN4QyxVQUEwRSxFQUFFO0lBRTVFLE1BQU0sY0FBYyxHQUFHLElBQUksY0FBYyxFQUFFLENBQUM7SUFDNUMsTUFBTSx1QkFBdUIsQ0FBQyxjQUFjLENBQUMsQ0FBQztJQUM5QyxJQUFJLE9BQU8sQ0FBQyxRQUFRO1FBQUUsY0FBYyxDQUFDLEdBQUcsQ0FBQyxvQkFBb0IsRUFBRSxPQUFPLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDakYsNEVBQTRFO0lBQzVFLHlFQUF5RTtJQUN6RSxJQUFJLE9BQU8sQ0FBQyxVQUFVO1FBQUUsY0FBYyxDQUFDLEdBQUcsQ0FBQyxzQkFBc0IsRUFBRSxPQUFPLENBQUMsVUFBVSxDQUFDLENBQUM7SUFDdkYsY0FBYyxDQUFDLEdBQUcsQ0FBQyxxQkFBcUIsRUFBRSxPQUFPLENBQUMsU0FBUyxJQUFJLElBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQzFFLE9BQU8sY0FBYyxDQUFDO0FBQ3hCLENBQUM7QUFFRDs7OztHQUlHO0FBQ0gsTUFBTSxPQUFPLFlBQWEsU0FBUSxtQkFBbUI7SUFTekM7SUFSRixHQUFHLENBQWE7SUFDeEI7OztPQUdHO0lBQ0ssZUFBZSxDQUFVO0lBRWpDLFlBQ1UsTUFBMEIsRUFDbEMsR0FBRyxJQUF1RDtRQUUxRCxLQUFLLENBQUMsR0FBRyxJQUFJLENBQUMsQ0FBQztRQUhQLFdBQU0sR0FBTixNQUFNLENBQW9CO1FBSWxDLElBQUksQ0FBQyxHQUFHLEdBQUcsR0FBRyxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUM5QixJQUFJLENBQUMsZUFBZSxHQUFHLHNCQUFzQixDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUNqRSxDQUFDO0lBRVEsc0JBQXNCO1FBQzdCLEtBQUssQ0FBQyxzQkFBc0IsRUFBRSxDQUFDO1FBQy9CLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLEtBQUssRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLElBQUksRUFBRSxFQUFFO1lBQ3BDLE1BQU0sY0FBYyxHQUFHLEdBQUcsQ0FBQyxNQUFNLENBQUMsY0FBaUMsQ0FBQztZQUNwRSxNQUFNLElBQUksQ0FBQywyQkFBMkIsQ0FBQyxjQUFjLENBQUMsQ0FBQztZQUN2RCxJQUFJLENBQUMsK0JBQStCLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRSxjQUFjLENBQUMsQ0FBQztZQUMvRCxJQUFJLENBQUMsb0NBQW9DLENBQUMsR0FBRyxFQUFFLGNBQWMsQ0FBQyxDQUFDO1lBQy9ELElBQUksQ0FBQyxnQ0FBZ0MsQ0FBQyxHQUFHLEVBQUUsR0FBRyxFQUFFLGNBQWMsQ0FBQyxDQUFDO1lBQ2hFLElBQUksQ0FBQyw2QkFBNkIsQ0FBQyxHQUFHLEVBQUUsY0FBYyxDQUFDLENBQUM7WUFFeEQsSUFBSSxDQUFDLHNCQUFzQixDQUFDLEdBQUcsQ0FBQyxDQUFDO1lBQ2pDLElBQUksQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLGlCQUFpQixFQUFFO2dCQUNoQyxNQUFNLEVBQUUsR0FBRyxDQUFDLE1BQU07Z0JBQ2xCLElBQUksRUFBRSxHQUFHLENBQUMsSUFBSTtnQkFDZCxTQUFTLEVBQUUsY0FBYyxDQUFDLEdBQUcsQ0FBQyxxQkFBcUIsQ0FBQztnQkFDcEQsUUFBUSxFQUFFLGNBQWMsQ0FBQyxHQUFHLENBQUMsb0JBQW9CLENBQUM7Z0JBQ2xELFVBQVUsRUFBRSxjQUFjLENBQUMsR0FBRyxDQUFDLHNCQUFzQixDQUFDO2dCQUN0RCxRQUFRLEVBQUUsY0FBYyxDQUFDLEdBQUcsQ0FBQyxvQkFBb0IsQ0FBQztnQkFDbEQsU0FBUyxFQUFFLGNBQWMsQ0FBQyxHQUFHLENBQUMscUJBQXFCLENBQUM7Z0JBQ3BELGFBQWEsRUFBRSxjQUFjLENBQUMsR0FBRztnQkFDL0Isc0RBQXNEO2dCQUN0RCx5REFBeUQ7Z0JBQ3pELHdCQUF3QixDQUN6QjthQUNGLENBQUMsQ0FBQztZQUNILElBQUksRUFBRSxDQUFDO1FBQ1QsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQsS0FBSyxDQUFDLDJCQUEyQixDQUFDLGNBQThCO1FBQzlELE1BQU0sdUJBQXVCLENBQUMsY0FBYyxDQUFDLENBQUM7SUFDaEQsQ0FBQztJQUVEOzs7Ozs7Ozs7O09BVUc7SUFDSCxnQ0FBZ0MsQ0FDOUIsR0FBb0IsRUFDcEIsR0FBcUIsRUFDckIsY0FBOEI7UUFFOUIsSUFBSSxjQUFjLENBQUMsR0FBRyxDQUFDLHFCQUFxQixDQUFDO1lBQUUsT0FBTztRQUN0RCxNQUFNLFdBQVcsR0FBRyxHQUFHLENBQUMsT0FBTyxDQUFDLGNBQWMsQ0FBQyxDQUFDO1FBQ2hELE1BQU0sUUFBUSxHQUFHLEtBQUssQ0FBQyxPQUFPLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsV0FBVyxDQUFDO1FBQzNFLE1BQU0sU0FBUyxHQUFHLFFBQVEsRUFBRSxJQUFJLEVBQUUsSUFBSSxJQUFJLENBQUMsRUFBRSxFQUFFLENBQUM7UUFDaEQsY0FBYyxDQUFDLEdBQUcsQ0FBQyxxQkFBcUIsRUFBRSxTQUFTLENBQUMsQ0FBQztRQUNyRCxHQUFHLENBQUMsU0FBUyxDQUFDLGNBQWMsRUFBRSxTQUFTLENBQUMsQ0FBQztJQUMzQyxDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsNkJBQTZCLENBQUMsR0FBb0IsRUFBRSxjQUE4QjtRQUNoRixNQUFNLE1BQU0sR0FBRztZQUNiLEdBQUcsTUFBTTtpQkFDTixRQUFRLENBQUMsS0FBSyxDQUFDLG9CQUFvQixDQUFDLEdBQUcsQ0FBQyxFQUFFLEtBQUssQ0FBQyxvQkFBb0IsQ0FBQyxHQUFHLEVBQUUsZUFBZSxDQUFDLENBQUM7aUJBQzNGLFFBQVEsRUFBRTtTQUNkLENBQUM7UUFDRixjQUFjLENBQUMsR0FBRyxDQUFDLGlCQUFpQixFQUFFLE1BQU0sQ0FBQyxDQUFDO0lBQ2hELENBQUM7SUFFRDs7Ozs7Ozs7Ozs7O09BWUc7SUFDSCxzQkFBc0IsQ0FBQyxHQUFxQjtRQUMxQyxJQUFJLENBQUMsSUFBSSxDQUFDLGVBQWUsSUFBSSxHQUFHLENBQUMsV0FBVztZQUFFLE9BQU87UUFDckQsTUFBTSxPQUFPLEdBQUcsS0FBSyxDQUFDLGFBQWEsRUFBRSxFQUFFLFdBQVcsRUFBRSxDQUFDLE9BQU8sQ0FBQztRQUM3RCxJQUFJLENBQUMsT0FBTyxJQUFJLE9BQU8sS0FBSyxnQkFBZ0I7WUFBRSxPQUFPO1FBQ3JELEdBQUcsQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDLHNCQUFzQixFQUFFLE1BQU0sT0FBTyxFQUFFLENBQUMsQ0FBQztJQUNsRSxDQUFDO0lBRUQ7Ozs7Ozs7Ozs7Ozs7Ozs7O09BaUJHO0lBQ0gsK0JBQStCLENBQzdCLEdBQW9CLEVBQ3BCLEdBQXFCLEVBQ3JCLGNBQThCO1FBRTlCLElBQUksY0FBYyxDQUFDLEdBQUcsQ0FBQyxvQkFBb0IsQ0FBQztZQUFFLE9BQU87UUFDckQsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLHFCQUFxQixDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ2xELElBQUksU0FBUyxFQUFFLENBQUM7WUFDZCxjQUFjLENBQUMsR0FBRyxDQUFDLG9CQUFvQixFQUFFLFNBQVMsQ0FBQyxDQUFDO1lBQ3BELE9BQU87UUFDVCxDQUFDO1FBQ0QsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ3RELE1BQU0sVUFBVSxHQUFHLE1BQU0sQ0FBQyx1QkFBdUIsQ0FDL0MsRUFBRSxTQUFTLEVBQUUsR0FBRyxFQUFFLFFBQVEsRUFBRSxJQUFJLEVBQUUsRUFDbEMsUUFBUSxFQUNSLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSyxFQUNqQixXQUFXLENBQ1osQ0FBQztRQUNGLElBQUksU0FBUyxHQUFHLE9BQU8sQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUNwQyxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7WUFDZixTQUFTLEdBQUcsSUFBSSxDQUFDLEVBQUUsRUFBRSxDQUFDO1lBQ3RCLEdBQUcsQ0FBQyxNQUFNLENBQUMsVUFBVSxFQUFFLFNBQVMsRUFBRTtnQkFDaEMsUUFBUSxFQUFFLElBQUk7Z0JBQ2QsUUFBUSxFQUFFLEtBQUs7Z0JBQ2YsTUFBTSxFQUFFLEdBQUcsQ0FBQyxNQUFNO2dCQUNsQixJQUFJLEVBQUUsR0FBRzthQUNWLENBQUMsQ0FBQztRQUNMLENBQUM7UUFDRCxjQUFjLENBQUMsR0FBRyxDQUFDLG9CQUFvQixFQUFFLFNBQVMsQ0FBQyxDQUFDO0lBQ3RELENBQUM7SUFFRDs7Ozs7T0FLRztJQUNLLHFCQUFxQixDQUFDLEdBQW9CO1FBQ2hELE1BQU0sV0FBVyxHQUFHLEdBQUcsQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLGdCQUFnQixDQUFDLENBQUM7UUFDekQsTUFBTSxVQUFVLEdBQUcsR0FBRyxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsZUFBZSxDQUFDLENBQUM7UUFDckQsT0FBTyxDQUNMLE1BQU0sQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxXQUFXLENBQUM7WUFDNUUsTUFBTSxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxDQUMxRSxDQUFDO0lBQ0osQ0FBQztJQUVELG9DQUFvQyxDQUFDLEdBQW9CLEVBQUUsY0FBOEI7UUFDdkYsMkRBQTJEO1FBQzNELHFEQUFxRDtRQUNyRCwwREFBMEQ7UUFDMUQsMENBQTBDO1FBQzFDLE1BQU0sT0FBTyxHQUFHLG9CQUFvQixDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUNsRCxJQUFJLE9BQU8sQ0FBQyxhQUFhLEVBQUUsQ0FBQztZQUMxQixNQUFNLFFBQVEsR0FBRyxvQkFBb0IsQ0FBQztnQkFDcEMsT0FBTyxFQUFFLEdBQUcsQ0FBQyxPQUF3RDtnQkFDckUsS0FBSyxFQUFFLEdBQUcsQ0FBQyxLQUFnQztnQkFDM0MsSUFBSSxFQUFFLEdBQUcsQ0FBQyxJQUFJO2FBQ2YsQ0FBQyxDQUFDO1lBQ0gsSUFBSSxRQUFRO2dCQUFFLGNBQWMsQ0FBQyxHQUFHLENBQUMseUJBQXlCLEVBQUUsUUFBUSxDQUFDLENBQUM7UUFDeEUsQ0FBQztJQUNILENBQUM7Q0FDRjtBQVVEOzs7Ozs7Ozs7Ozs7O0dBYUc7QUFDSCxNQUFNLGVBQWUsR0FDbkIsb0pBQW9KLENBQUM7QUFFdkosMEVBQTBFO0FBQzFFLE1BQU0sY0FBYyxHQUFHLHNCQUFzQixDQUFDO0FBRTlDOzs7Ozs7Ozs7OztHQVdHO0FBQ0gsTUFBTSxVQUFVLHNCQUFzQixDQUNwQyxNQUFjLEVBQ2QsSUFBWSxFQUNaLElBQTBCO0lBRTFCLElBQUksSUFBSSxDQUFDLE1BQU0sS0FBSyxNQUFNO1FBQUUsT0FBTyxJQUFJLENBQUM7SUFDeEMsTUFBTSxDQUFDLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLElBQUksRUFBRSxDQUFDO0lBQ25ELDREQUE0RDtJQUM1RCwwRUFBMEU7SUFDMUUsSUFBSSxDQUFDLEtBQUssUUFBUSxJQUFJLENBQUMsQ0FBQyxVQUFVLENBQUMsU0FBUyxDQUFDO1FBQUUsT0FBTyxJQUFJLENBQUM7SUFDM0QsSUFBSSxJQUFJLENBQUMsVUFBVSxJQUFJLENBQUMsQ0FBQyxLQUFLLE1BQU0sSUFBSSxDQUFDLENBQUMsVUFBVSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQUUsT0FBTyxJQUFJLENBQUM7SUFDNUUsTUFBTSxDQUFDLEdBQUcsTUFBTSxDQUFDLFdBQVcsRUFBRSxDQUFDO0lBQy9CLElBQUksQ0FBQyxLQUFLLE1BQU0sSUFBSSxlQUFlLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztRQUFFLE9BQU8sSUFBSSxDQUFDO0lBQ3pELElBQUksQ0FBQyxLQUFLLEtBQUssSUFBSSxjQUFjLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztRQUFFLE9BQU8sSUFBSSxDQUFDO0lBQ3ZELE9BQU8sS0FBSyxDQUFDO0FBQ2YsQ0FBQztBQUVEOzs7Ozs7Ozs7Ozs7O0dBYUc7QUFDSCxNQUFNLFVBQVUsMEJBQTBCLENBQUMsR0FBb0I7SUFDN0QsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLEVBQUU7UUFDMUIsTUFBTSxhQUFhLEdBQUcsR0FBRyxDQUFDLElBQUksS0FBSyxRQUFRLElBQUksR0FBRyxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDOUUsSUFBSSxDQUFDLGFBQWE7WUFBRSxPQUFPLElBQUksRUFBRSxDQUFDO1FBQ2xDLEdBQUcsQ0FBQyxXQUFXLEdBQUcsR0FBRyxDQUFDLElBQUksQ0FBQztRQUMzQixJQUFJLEVBQUUsQ0FBQztJQUNULENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogRXhwcmVzcy1sYXllciBwbHVtYmluZyBmb3IgdGhlIE1hc3RyYSBwbHVnaW46IGEgYE1hc3RyYVNlcnZlcmAgdGhhdFxuICogc3RhbXBzIHRoZSBwZXItcmVxdWVzdCBgUmVxdWVzdENvbnRleHRgLCBhbmQgYSByb3V0ZS1wYXRjaCBtaWRkbGV3YXJlXG4gKiB0aGF0IGxldHMgdGhlIHBsdWdpbidzIGN1c3RvbSBBUEkgcm91dGVzIChlLmcuIGBoaXN0b3J5Um91dGVgKSB3b3JrXG4gKiBiZWhpbmQgYW4gRXhwcmVzcyBtb3VudCBwb2ludC5cbiAqXG4gKiBAbW9kdWxlXG4gKi9cblxuaW1wb3J0IHsgZ2V0RXhlY3V0aW9uQ29udGV4dCB9IGZyb20gXCJAZGF0YWJyaWNrcy9hcHBraXRcIjtcbmltcG9ydCB7IGhhc2gsIGh0dHAsIGxvZywgb2JqZWN0LCBzdHJpbmcsIHRva2VuIH0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLWNvcmVcIjtcbmltcG9ydCB7IGZlZWRiYWNrLCB0aHJlYWQgfSBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtbWFzdHJhXCI7XG5pbXBvcnQge1xuICBNQVNUUkFfUkVTT1VSQ0VfSURfS0VZLFxuICBNQVNUUkFfVEhSRUFEX0lEX0tFWSxcbiAgUmVxdWVzdENvbnRleHQsXG59IGZyb20gXCJAbWFzdHJhL2NvcmUvcmVxdWVzdC1jb250ZXh0XCI7XG5pbXBvcnQgeyBNYXN0cmFTZXJ2ZXIgYXMgTWFzdHJhU2VydmVyRXhwcmVzcyB9IGZyb20gXCJAbWFzdHJhL2V4cHJlc3NcIjtcbmltcG9ydCB7IHRyYWNlIH0gZnJvbSBcIkBvcGVudGVsZW1ldHJ5L2FwaVwiO1xuaW1wb3J0IHR5cGUgZXhwcmVzcyBmcm9tIFwiZXhwcmVzc1wiO1xuXG5pbXBvcnQge1xuICBleGVjdXRpb25Db250ZXh0VXNlcklkLFxuICBNQVNUUkFfUkVRVUVTVF9JRF9LRVksXG4gIE1BU1RSQV9TQ09QRVNfS0VZLFxuICBNQVNUUkFfVVNFUl9FTUFJTF9LRVksXG4gIE1BU1RSQV9VU0VSX0tFWSxcbiAgTUFTVFJBX1VTRVJfTkFNRV9LRVksXG4gIHR5cGUgTWFzdHJhUGx1Z2luQ29uZmlnLFxuICB0eXBlIFVzZXIsXG59IGZyb20gXCIuL2NvbmZpZy50c1wiO1xuaW1wb3J0IHsgcmVzb2x2ZUZlZWRiYWNrRW5hYmxlZCB9IGZyb20gXCIuL21sZmxvdy50c1wiO1xuXG5pbXBvcnQge1xuICBleHRyYWN0TW9kZWxPdmVycmlkZSxcbiAgTUFTVFJBX01PREVMX09WRVJSSURFX0tFWSxcbiAgcmVzb2x2ZVNlcnZpbmdDb25maWcsXG59IGZyb20gXCIuL3NlcnZpbmcudHNcIjtcbi8qKlxuICogT3BlblRlbGVtZXRyeSdzIHNlbnRpbmVsIGZvciBcIm5vIHZhbGlkIHRyYWNlXCIgLSAzMiB6ZXJvIGhleCBjaGFycy5cbiAqIGB0cmFjZS5nZXRBY3RpdmVTcGFuKClgIHJldHVybnMgYSBub24tcmVjb3JkaW5nIHNwYW4gd2l0aCB0aGlzIGlkXG4gKiB3aGVuIG5vIFNESyBpcyByZWdpc3RlcmVkLCB3aGljaCBtdXN0IG5ldmVyIGJlIHN1cmZhY2VkIGFzIGEgdHJhY2UgdG9cbiAqIGF0dGFjaCBmZWVkYmFjayB0by5cbiAqL1xuY29uc3QgSU5WQUxJRF9UUkFDRV9JRCA9IFwiMFwiLnJlcGVhdCgzMik7XG5cbi8qKlxuICogU3RhbXAgdGhlIEFwcEtpdCB1c2VyIChwbHVzIHRoZSByZXNvdXJjZSBpZCBhbmQgdHJhY2UgbWV0YWRhdGEpIG9udG9cbiAqIGByZXF1ZXN0Q29udGV4dGAuXG4gKlxuICogU3BsaXQgb3V0IG9mIHtAbGluayBNYXN0cmFTZXJ2ZXJ9IGJlY2F1c2UgdGhlIEhUVFAgbWlkZGxld2FyZSBpcyBub3QgdGhlIG9ubHlcbiAqIGNhbGxlciB0aGF0IG5lZWRzIGl0OiBhbiBvdXQtb2YtYmFuZCB0dXJuIChhIFRlYW1zIGFjdGl2aXR5IGFycml2aW5nIG9uXG4gKiBhbm90aGVyIHBsdWdpbidzIHJvdXRlLCBhIHNjaGVkdWxlZCBqb2IpIGRyaXZlcyBgYWdlbnQuZ2VuZXJhdGVgIGRpcmVjdGx5LCBhbmRcbiAqIHdpdGhvdXQgdGhpcyBzdGFtcCBldmVyeSB1c2VyLXNjb3BlZCB0b29sIC0gYGFza19nZW5pZWAgYWJvdmUgYWxsIC0gZmFpbHMgd2l0aFxuICogXCJpbnZva2UgdGhlIHRvb2wgZnJvbSBhbiBhZ2VudCB0dXJuIHNlcnZlZCBieSB0aGUgbWFzdHJhIHBsdWdpblwiLiBUaG9zZVxuICogY2FsbGVycyBidWlsZCBhIGNvbnRleHQgd2l0aCB7QGxpbmsgY3JlYXRlUmVxdWVzdENvbnRleHR9IGluc3RlYWQgb2YgYVxuICogcmVxdWVzdC5cbiAqXG4gKiBJZGVtcG90ZW50OiByZXR1cm5zIGltbWVkaWF0ZWx5IHdoZW4gdGhlIHVzZXIgYW5kIHJlc291cmNlIGlkIGFyZSBhbHJlYWR5XG4gKiBwcmVzZW50LCBzbyB0aGUgbWlkZGxld2FyZSBjYW4gY2FsbCBpdCBvdmVyIGEgY29udGV4dCBhbm90aGVyIGxheWVyIHN0YW1wZWQuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzdGFtcFJlcXVlc3RDb250ZXh0VXNlcihyZXF1ZXN0Q29udGV4dDogUmVxdWVzdENvbnRleHQpOiBQcm9taXNlPHZvaWQ+IHtcbiAgaWYgKFtNQVNUUkFfVVNFUl9LRVksIE1BU1RSQV9SRVNPVVJDRV9JRF9LRVldLmV2ZXJ5KChrZXkpID0+IHJlcXVlc3RDb250ZXh0LmdldChrZXkpKSkgcmV0dXJuO1xuICBjb25zdCBleGVjdXRpb25Db250ZXh0ID0gZ2V0RXhlY3V0aW9uQ29udGV4dCgpO1xuICBjb25zdCB1c2VyOiBVc2VyID0ge1xuICAgIGlkOiBleGVjdXRpb25Db250ZXh0VXNlcklkKGV4ZWN1dGlvbkNvbnRleHQpLFxuICAgIGV4ZWN1dGlvbkNvbnRleHQsXG4gIH07XG4gIHJlcXVlc3RDb250ZXh0LnNldChNQVNUUkFfVVNFUl9LRVksIHVzZXIpO1xuICByZXF1ZXN0Q29udGV4dC5zZXQoTUFTVFJBX1JFU09VUkNFX0lEX0tFWSwgdXNlci5pZCk7XG4gIC8vIEFwcEtpdCdzIGBVc2VyQ29udGV4dGAgc3VyZmFjZXMgZGlzcGxheSBuYW1lIC8gZW1haWwgb25seSBvblxuICAvLyBPQk8gcmVxdWVzdHMuIFNlcnZpY2UtY29udGV4dCBjYWxscyAoYmFja2dyb3VuZCB0YXNrcywgc2VydmVyXG4gIC8vIHN0YXJ0LXVwKSBsZWF2ZSB0aGVzZSB1bmRlZmluZWQgYW5kIHdlIHNraXAgdGhlIHN0YW1wIHNvXG4gIC8vIGRvd25zdHJlYW0gdHJhY2UgbWV0YWRhdGEgc3RheXMgYWJzZW50IHJhdGhlciB0aGFuIGVtcHR5LlxuICBsZXQgdXNlck5hbWU6IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgbGV0IGVtYWlsOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gIGlmIChcImlzVXNlckNvbnRleHRcIiBpbiBleGVjdXRpb25Db250ZXh0KSB7XG4gICAgdXNlck5hbWUgPSBleGVjdXRpb25Db250ZXh0LnVzZXJOYW1lO1xuICAgIGVtYWlsID0gZXhlY3V0aW9uQ29udGV4dC51c2VyRW1haWw7XG4gIH0gZWxzZSBpZiAocHJvY2Vzcy5lbnYuTk9ERV9FTlYgPT09IFwiZGV2ZWxvcG1lbnRcIikge1xuICAgIGNvbnN0IGN1cnJlbnRVc2VyID0gYXdhaXQgZXhlY3V0aW9uQ29udGV4dC5jbGllbnQuY3VycmVudFVzZXIubWUoKTtcbiAgICB1c2VyTmFtZSA9IGN1cnJlbnRVc2VyPy51c2VyTmFtZTtcbiAgICBlbWFpbCA9IGN1cnJlbnRVc2VyPy5lbWFpbHM/LmZpbHRlcigoZW1haWwpID0+IGVtYWlsLnByaW1hcnkpLmZpbmQoKGVtYWlsKSA9PiBlbWFpbC52YWx1ZSlcbiAgICAgID8udmFsdWUgYXMgc3RyaW5nO1xuICB9XG4gIGlmICh1c2VyTmFtZSkge1xuICAgIHJlcXVlc3RDb250ZXh0LnNldChNQVNUUkFfVVNFUl9OQU1FX0tFWSwgdXNlck5hbWUpO1xuICB9XG4gIGlmIChlbWFpbCkge1xuICAgIHJlcXVlc3RDb250ZXh0LnNldChNQVNUUkFfVVNFUl9FTUFJTF9LRVksIGVtYWlsKTtcbiAgfVxufVxuXG4vKipcbiAqIEJ1aWxkIHRoZSBgUmVxdWVzdENvbnRleHRgIGEgTk9OLUhUVFAgYWdlbnQgdHVybiBuZWVkcy5cbiAqXG4gKiBFdmVyeXRoaW5nIE1hc3RyYSdzIHRvb2xzIHJlYWQgb2ZmIHRoZSBjb250ZXh0IGlzIHN0YW1wZWQgdGhlIHNhbWUgd2F5IHRoZVxuICogcmVxdWVzdCBtaWRkbGV3YXJlIHN0YW1wcyBpdCAtIHRoZSBBcHBLaXQgdXNlciAoc28gYGFza19nZW5pZWAgYW5kIHRoZSBtb2RlbFxuICogcmVzb2x2ZXIgY2FuIG1pbnQgdXNlci1zY29wZWQgdG9rZW5zKSwgdGhlIG1lbW9yeSB0aHJlYWQgLyByZXNvdXJjZSBwYWlyLCBhbmRcbiAqIGEgcmVxdWVzdCBpZCBzbyB0aGUgdHVybidzIHNwYW5zIGpvaW4gdXAgaW4gdHJhY2VzLiBUaGUgcmVzdWx0IGlzIHBhc3NlZCBhc1xuICogYHJlcXVlc3RDb250ZXh0YCB0byBgYWdlbnQuZ2VuZXJhdGVgIC8gYGFnZW50LnN0cmVhbWAuXG4gKlxuICogVGhpcyBpcyB3aGF0IG1ha2VzIGEgY2FyZCB0dXJuIGFuc3dlciB3aXRoIHRoZSBTQU1FIGRhdGEgYSBjaGF0IHR1cm4gZG9lczogdGhlXG4gKiBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIHR3byBlbmRwb2ludHMgaXMgcHJlc2VudGF0aW9uLCBub3QgY2FwYWJpbGl0eS5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNyZWF0ZVJlcXVlc3RDb250ZXh0KFxuICBvcHRpb25zOiB7IHRocmVhZElkPzogc3RyaW5nOyByZXNvdXJjZUlkPzogc3RyaW5nOyByZXF1ZXN0SWQ/OiBzdHJpbmcgfSA9IHt9LFxuKTogUHJvbWlzZTxSZXF1ZXN0Q29udGV4dD4ge1xuICBjb25zdCByZXF1ZXN0Q29udGV4dCA9IG5ldyBSZXF1ZXN0Q29udGV4dCgpO1xuICBhd2FpdCBzdGFtcFJlcXVlc3RDb250ZXh0VXNlcihyZXF1ZXN0Q29udGV4dCk7XG4gIGlmIChvcHRpb25zLnRocmVhZElkKSByZXF1ZXN0Q29udGV4dC5zZXQoTUFTVFJBX1RIUkVBRF9JRF9LRVksIG9wdGlvbnMudGhyZWFkSWQpO1xuICAvLyBTdGFtcGVkIEFGVEVSIHRoZSB1c2VyIHNvIGFuIGV4cGxpY2l0IHJlc291cmNlIGlkIChhIGNoYW5uZWwgbWVtYmVyLCBzYXkpXG4gIC8vIHdpbnMgb3ZlciB0aGUgYW1iaWVudCBpZGVudGl0eSBgc3RhbXBSZXF1ZXN0Q29udGV4dFVzZXJgIGRlZmF1bHRlZCB0by5cbiAgaWYgKG9wdGlvbnMucmVzb3VyY2VJZCkgcmVxdWVzdENvbnRleHQuc2V0KE1BU1RSQV9SRVNPVVJDRV9JRF9LRVksIG9wdGlvbnMucmVzb3VyY2VJZCk7XG4gIHJlcXVlc3RDb250ZXh0LnNldChNQVNUUkFfUkVRVUVTVF9JRF9LRVksIG9wdGlvbnMucmVxdWVzdElkID8/IGhhc2guaWQoKSk7XG4gIHJldHVybiByZXF1ZXN0Q29udGV4dDtcbn1cblxuLyoqXG4gKiBgQG1hc3RyYS9leHByZXNzYCBzdWJjbGFzcyB0aGF0IHN0YW1wcyBgUmVxdWVzdENvbnRleHRgIHdpdGggdGhlXG4gKiBBcHBLaXQgdXNlciwgcmVzb3VyY2UgaWQsIGFuZCBhIHRocmVhZCBpZCBiYWNrZWQgYnkgYW4gSFRUUC1vbmx5XG4gKiBzZXNzaW9uIGNvb2tpZSAoYGFwcGtpdF88cGx1Z2luLW5hbWU+X3Nlc3Npb25faWRgKS5cbiAqL1xuZXhwb3J0IGNsYXNzIE1hc3RyYVNlcnZlciBleHRlbmRzIE1hc3RyYVNlcnZlckV4cHJlc3Mge1xuICBwcml2YXRlIGxvZzogbG9nLkxvZ2dlcjtcbiAgLyoqXG4gICAqIFdoZXRoZXIgdG8gc3RhbXAgdGhlIE1MZmxvdyB0cmFjZS1pZCBoZWFkZXIgb24gcmVzcG9uc2VzLiBTaGFyZXMgdGhlXG4gICAqIHBsdWdpbidzIGZlZWRiYWNrIGdhdGUgdmlhIHtAbGluayByZXNvbHZlRmVlZGJhY2tFbmFibGVkfS5cbiAgICovXG4gIHByaXZhdGUgZmVlZGJhY2tFbmFibGVkOiBib29sZWFuO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgY29uZmlnOiBNYXN0cmFQbHVnaW5Db25maWcsXG4gICAgLi4uYXJnczogQ29uc3RydWN0b3JQYXJhbWV0ZXJzPHR5cGVvZiBNYXN0cmFTZXJ2ZXJFeHByZXNzPlxuICApIHtcbiAgICBzdXBlciguLi5hcmdzKTtcbiAgICB0aGlzLmxvZyA9IGxvZy5sb2dnZXIoY29uZmlnKTtcbiAgICB0aGlzLmZlZWRiYWNrRW5hYmxlZCA9IHJlc29sdmVGZWVkYmFja0VuYWJsZWQoY29uZmlnLmZlZWRiYWNrKTtcbiAgfVxuXG4gIG92ZXJyaWRlIHJlZ2lzdGVyQXV0aE1pZGRsZXdhcmUoKTogdm9pZCB7XG4gICAgc3VwZXIucmVnaXN0ZXJBdXRoTWlkZGxld2FyZSgpO1xuICAgIHRoaXMuYXBwLnVzZShhc3luYyAocmVxLCByZXMsIG5leHQpID0+IHtcbiAgICAgIGNvbnN0IHJlcXVlc3RDb250ZXh0ID0gcmVzLmxvY2Fscy5yZXF1ZXN0Q29udGV4dCEgYXMgUmVxdWVzdENvbnRleHQ7XG4gICAgICBhd2FpdCB0aGlzLmNvbmZpZ3VyZVJlcXVlc3RDb250ZXh0VXNlcihyZXF1ZXN0Q29udGV4dCk7XG4gICAgICB0aGlzLmNvbmZpZ3VyZVJlcXVlc3RDb250ZXh0VGhyZWFkSWQocmVxLCByZXMsIHJlcXVlc3RDb250ZXh0KTtcbiAgICAgIHRoaXMuY29uZmlndXJlUmVxdWVzdENvbnRleHRNb2RlbE92ZXJyaWRlKHJlcSwgcmVxdWVzdENvbnRleHQpO1xuICAgICAgdGhpcy5jb25maWd1cmVSZXF1ZXN0Q29udGV4dFJlcXVlc3RJZChyZXEsIHJlcywgcmVxdWVzdENvbnRleHQpO1xuICAgICAgdGhpcy5jb25maWd1cmVSZXF1ZXN0Q29udGV4dFNjb3BlcyhyZXEsIHJlcXVlc3RDb250ZXh0KTtcblxuICAgICAgdGhpcy5jb25maWd1cmVNbGZsb3dUcmFjZUlkKHJlcyk7XG4gICAgICB0aGlzLmxvZy5kZWJ1ZyhcImF1dGg6bWlkZGxld2FyZVwiLCB7XG4gICAgICAgIG1ldGhvZDogcmVxLm1ldGhvZCxcbiAgICAgICAgcGF0aDogcmVxLnBhdGgsXG4gICAgICAgIHJlcXVlc3RJZDogcmVxdWVzdENvbnRleHQuZ2V0KE1BU1RSQV9SRVFVRVNUX0lEX0tFWSksXG4gICAgICAgIHRocmVhZElkOiByZXF1ZXN0Q29udGV4dC5nZXQoTUFTVFJBX1RIUkVBRF9JRF9LRVkpLFxuICAgICAgICByZXNvdXJjZUlkOiByZXF1ZXN0Q29udGV4dC5nZXQoTUFTVFJBX1JFU09VUkNFX0lEX0tFWSksXG4gICAgICAgIHVzZXJOYW1lOiByZXF1ZXN0Q29udGV4dC5nZXQoTUFTVFJBX1VTRVJfTkFNRV9LRVkpLFxuICAgICAgICB1c2VyRW1haWw6IHJlcXVlc3RDb250ZXh0LmdldChNQVNUUkFfVVNFUl9FTUFJTF9LRVkpLFxuICAgICAgICBtb2RlbE92ZXJyaWRlOiByZXF1ZXN0Q29udGV4dC5nZXQoXG4gICAgICAgICAgLy8gaW1wb3J0ZWQgYmVsb3c7IGxvZ2dlZCBzbyBhIG1pc3JvdXRlZCByZXF1ZXN0IHNob3dzXG4gICAgICAgICAgLy8gdXAgYWxvbmdzaWRlIGl0cyBtb2RlbCBzZWxlY3Rpb24gaW4gYExPR19MRVZFTD1kZWJ1Z2AuXG4gICAgICAgICAgXCJtYXN0cmFfX21vZGVsX292ZXJyaWRlXCIsXG4gICAgICAgICksXG4gICAgICB9KTtcbiAgICAgIG5leHQoKTtcbiAgICB9KTtcbiAgfVxuXG4gIGFzeW5jIGNvbmZpZ3VyZVJlcXVlc3RDb250ZXh0VXNlcihyZXF1ZXN0Q29udGV4dDogUmVxdWVzdENvbnRleHQpIHtcbiAgICBhd2FpdCBzdGFtcFJlcXVlc3RDb250ZXh0VXNlcihyZXF1ZXN0Q29udGV4dCk7XG4gIH1cblxuICAvKipcbiAgICogU3RhbXAgYSBwZXItcmVxdWVzdCBpZCBhbmQgZWNobyBpdCBvbiB0aGUgcmVzcG9uc2Ugc28gYW4gdXBzdHJlYW1cbiAgICogcHJveHkgLyBjdXJsIGNsaWVudCAvIGJyb3dzZXItc2lkZSBsb2cgbGluZSBjYW4gcGFpciBpdHMgdmlldyBvZlxuICAgKiB0aGUgcmVxdWVzdCB3aXRoIHRoZSBtYXRjaGluZyB0cmFjZSBzcGFuLiBSZXVzZXMgYFgtUmVxdWVzdC1JZGBcbiAgICogd2hlbiB0aGUgdXBzdHJlYW0gYWxyZWFkeSBzdXBwbGllcyBvbmUgc28gbXVsdGktaG9wIHRyYWNlcyBzdGF5XG4gICAqIGpvaW5lZDsgb3RoZXJ3aXNlIG1pbnRzIGEgVVVJRHY0LlxuICAgKlxuICAgKiBUaGUgaWQgaXMgc3VyZmFjZWQgYXMgYG1hc3RyYV9fcmVxdWVzdElkYCBzcGFuIG1ldGFkYXRhIHZpYVxuICAgKiB7QGxpbmsgVFJBQ0VfUkVRVUVTVF9DT05URVhUX0tFWVN9IGFuZCBhcyB0aGUgYFgtUmVxdWVzdC1JZGBcbiAgICogcmVzcG9uc2UgaGVhZGVyIHNvIGRldiB0b29scyBjYW4gY29weSBpdCBmcm9tIGVpdGhlciBzaWRlLlxuICAgKi9cbiAgY29uZmlndXJlUmVxdWVzdENvbnRleHRSZXF1ZXN0SWQoXG4gICAgcmVxOiBleHByZXNzLlJlcXVlc3QsXG4gICAgcmVzOiBleHByZXNzLlJlc3BvbnNlLFxuICAgIHJlcXVlc3RDb250ZXh0OiBSZXF1ZXN0Q29udGV4dCxcbiAgKSB7XG4gICAgaWYgKHJlcXVlc3RDb250ZXh0LmdldChNQVNUUkFfUkVRVUVTVF9JRF9LRVkpKSByZXR1cm47XG4gICAgY29uc3QgaGVhZGVyVmFsdWUgPSByZXEuaGVhZGVyc1tcIngtcmVxdWVzdC1pZFwiXTtcbiAgICBjb25zdCB1cHN0cmVhbSA9IEFycmF5LmlzQXJyYXkoaGVhZGVyVmFsdWUpID8gaGVhZGVyVmFsdWVbMF0gOiBoZWFkZXJWYWx1ZTtcbiAgICBjb25zdCByZXF1ZXN0SWQgPSB1cHN0cmVhbT8udHJpbSgpIHx8IGhhc2guaWQoKTtcbiAgICByZXF1ZXN0Q29udGV4dC5zZXQoTUFTVFJBX1JFUVVFU1RfSURfS0VZLCByZXF1ZXN0SWQpO1xuICAgIHJlcy5zZXRIZWFkZXIoXCJYLVJlcXVlc3QtSWRcIiwgcmVxdWVzdElkKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTdGFtcCBPQXV0aCBzY29wZXMgZnJvbSB0aGUgZm9yd2FyZGVkIGFjY2VzcyB0b2tlbiBvblxuICAgKiB7QGxpbmsgTUFTVFJBX1NDT1BFU19LRVl9IGZvciB3b3Jrc3BhY2UgbW91bnQgZ2F0aW5nLlxuICAgKi9cbiAgY29uZmlndXJlUmVxdWVzdENvbnRleHRTY29wZXMocmVxOiBleHByZXNzLlJlcXVlc3QsIHJlcXVlc3RDb250ZXh0OiBSZXF1ZXN0Q29udGV4dCkge1xuICAgIGNvbnN0IHNjb3BlcyA9IFtcbiAgICAgIC4uLm9iamVjdFxuICAgICAgICAuc2VxdWVuY2UodG9rZW4uZ2V0QWNjZXNzVG9rZW5TY29wZXMocmVxKSwgdG9rZW4uZ2V0QWNjZXNzVG9rZW5TY29wZXMocmVxLCBcImF1dGhvcml6YXRpb25cIikpXG4gICAgICAgIC5kaXN0aW5jdCgpLFxuICAgIF07XG4gICAgcmVxdWVzdENvbnRleHQuc2V0KE1BU1RSQV9TQ09QRVNfS0VZLCBzY29wZXMpO1xuICB9XG5cbiAgLyoqXG4gICAqIFN0YW1wIHRoZSB0dXJuJ3MgTUxmbG93IHRyYWNlIGlkIG9uIHRoZSByZXNwb25zZSBzbyB0aGUgY2hhdCBjbGllbnRcbiAgICogY2FuIGF0dGFjaCB0aHVtYnMgLyBjb21tZW50IGZlZWRiYWNrIHRvIGl0IGxhdGVyLiBNTGZsb3cgZGVyaXZlc1xuICAgKiBpdHMgdHJhY2UgaWQgZnJvbSB0aGUgT3BlblRlbGVtZXRyeSB0cmFjZSBpZCAoYHRyLTxoZXg+YCksIGFuZCBldmVyeVxuICAgKiBNYXN0cmEgc3BhbiBmb3IgdGhpcyByZXF1ZXN0IGluaGVyaXRzIHRoZSBhbWJpZW50IE9UZWwgY29udGV4dCAoc2VlXG4gICAqIGBvYnNlcnZhYmlsaXR5LnRzYCksIHNvIHRoZSBhY3RpdmUgc3BhbidzIHRyYWNlIGlkIGhlcmUgaXMgdGhlIGlkXG4gICAqIE1MZmxvdyB3aWxsIHJlY29yZCBmb3IgdGhlIHR1cm4uXG4gICAqXG4gICAqIE5vLW9wIHVubGVzcyBmZWVkYmFjayBpcyBlbmFibGVkLCBhbmQgd2hlbiBubyBsaXZlIE9UZWwgc3BhbiBpc1xuICAgKiBhY3RpdmUgKGUuZy4gdGhlIE9UTFAgU0RLIGlzbid0IHJlZ2lzdGVyZWQpOiBpbiB0aGF0IGNhc2UgdGhlIGhlYWRlclxuICAgKiBpcyBzaW1wbHkgYWJzZW50IGFuZCB0aGUgY2xpZW50IGhpZGVzIGZlZWRiYWNrIGZvciB0aGF0IG1lc3NhZ2UsXG4gICAqIGRlZ3JhZGluZyBncmFjZWZ1bGx5IHJhdGhlciB0aGFuIGVtaXR0aW5nIGEgYm9ndXMgdHJhY2UgaWQuXG4gICAqL1xuICBjb25maWd1cmVNbGZsb3dUcmFjZUlkKHJlczogZXhwcmVzcy5SZXNwb25zZSkge1xuICAgIGlmICghdGhpcy5mZWVkYmFja0VuYWJsZWQgfHwgcmVzLmhlYWRlcnNTZW50KSByZXR1cm47XG4gICAgY29uc3QgdHJhY2VJZCA9IHRyYWNlLmdldEFjdGl2ZVNwYW4oKT8uc3BhbkNvbnRleHQoKS50cmFjZUlkO1xuICAgIGlmICghdHJhY2VJZCB8fCB0cmFjZUlkID09PSBJTlZBTElEX1RSQUNFX0lEKSByZXR1cm47XG4gICAgcmVzLnNldEhlYWRlcihmZWVkYmFjay5NTEZMT1dfVFJBQ0VfSURfSEVBREVSLCBgdHItJHt0cmFjZUlkfWApO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlc29sdmUgdGhlIHRocmVhZCBpZCB0aGlzIHJlcXVlc3QgdGFyZ2V0cyBhbmQgcGluIGl0IG9uXG4gICAqIGBSZXF1ZXN0Q29udGV4dGAgKGNvbnN1bWVkIGJ5IHRoZSBhZ2VudCBzdHJlYW0gZm9yIHBlcnNpc3RlbmNlIGFuZFxuICAgKiBieSB0aGUgaGlzdG9yeSAvIHRocmVhZHMgcm91dGVzKS4gUmVzb2x1dGlvbiBvcmRlcjpcbiAgICpcbiAgICogICAxLiBBIGNsaWVudC1zdXBwbGllZCB0aHJlYWQgaWQgKHRoZSB0aHJlYWQtc2VsZWN0aW9uIGhlYWRlciAvXG4gICAqICAgICAgYD90aHJlYWRJZD1gIHF1ZXJ5KS4gVGhpcyBpcyBob3cgdGhlIGNoYXQgVUkgcmVmZXJlbmNlcyBhXG4gICAqICAgICAgc3BlY2lmaWMgY29udmVyc2F0aW9uIGFtb25nIHRoZSBtYW55IGEgdXNlciBvd25zIC0gaXQgcGlja3MgYVxuICAgKiAgICAgIHRocmVhZCBpZCBmcm9tIHRoZSBgL3RocmVhZHNgIGxpc3RpbmcgKG9yIG1pbnRzIG9uZSBmb3IgYSBuZXdcbiAgICogICAgICBjb252ZXJzYXRpb24pIGFuZCBzdGFtcHMgaXQgaGVyZS4gVGhlIGlkIGlzIHNjb3BlZCB0byB0aGVcbiAgICogICAgICBjYWxsZXIncyByZXNvdXJjZSBieSB0aGUgcmVjYWxsIC8gbGlzdCByb3V0ZXMsIHNvIGEgY2xpZW50XG4gICAqICAgICAgY2FuIG9ubHkgZXZlciByZWFkIG9yIHdyaXRlIGl0cyBvd24gdGhyZWFkcy5cbiAgICogICAyLiBUaGUgcGVyLXNlc3Npb24gY29va2llIChgYXBwa2l0XzxwbHVnaW4tbmFtZT5fc2Vzc2lvbl9pZGApLFxuICAgKiAgICAgIG1pbnRlZCBvbiBmaXJzdCBjb250YWN0LiBUaGlzIGlzIHRoZSBkZWZhdWx0IHNpbmdsZS10aHJlYWRcbiAgICogICAgICBmYWxsYmFjayBmb3IgY2xpZW50cyB0aGF0IGRvbid0IG1hbmFnZSB0aHJlYWRzIGV4cGxpY2l0bHksIHNvXG4gICAqICAgICAgZXhpc3RpbmcgZW1iZWRzIGtlZXAgb25lIHN0YWJsZSBjb252ZXJzYXRpb24gcGVyIHNlc3Npb24gd2l0aFxuICAgKiAgICAgIG5vIGNsaWVudCBjaGFuZ2VzLlxuICAgKi9cbiAgY29uZmlndXJlUmVxdWVzdENvbnRleHRUaHJlYWRJZChcbiAgICByZXE6IGV4cHJlc3MuUmVxdWVzdCxcbiAgICByZXM6IGV4cHJlc3MuUmVzcG9uc2UsXG4gICAgcmVxdWVzdENvbnRleHQ6IFJlcXVlc3RDb250ZXh0LFxuICApIHtcbiAgICBpZiAocmVxdWVzdENvbnRleHQuZ2V0KE1BU1RSQV9USFJFQURfSURfS0VZKSkgcmV0dXJuO1xuICAgIGNvbnN0IHJlcXVlc3RlZCA9IHRoaXMucmVhZFJlcXVlc3RlZFRocmVhZElkKHJlcSk7XG4gICAgaWYgKHJlcXVlc3RlZCkge1xuICAgICAgcmVxdWVzdENvbnRleHQuc2V0KE1BU1RSQV9USFJFQURfSURfS0VZLCByZXF1ZXN0ZWQpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCBjb29raWVzID0gaHR0cC5wYXJzZUNvb2tpZXMocmVxLmhlYWRlcnMuY29va2llKTtcbiAgICBjb25zdCBjb29raWVOYW1lID0gc3RyaW5nLnRvSWRlbnRpZmllcldpdGhPcHRpb25zKFxuICAgICAgeyBkZWxpbWl0ZXI6IFwiX1wiLCBkaXN0aW5jdDogdHJ1ZSB9LFxuICAgICAgXCJhcHBraXRcIixcbiAgICAgIHRoaXMuY29uZmlnLm5hbWUhLFxuICAgICAgXCJzZXNzaW9uSWRcIixcbiAgICApO1xuICAgIGxldCBzZXNzaW9uSWQgPSBjb29raWVzW2Nvb2tpZU5hbWVdO1xuICAgIGlmICghc2Vzc2lvbklkKSB7XG4gICAgICBzZXNzaW9uSWQgPSBoYXNoLmlkKCk7XG4gICAgICByZXMuY29va2llKGNvb2tpZU5hbWUsIHNlc3Npb25JZCwge1xuICAgICAgICBodHRwT25seTogdHJ1ZSxcbiAgICAgICAgc2FtZVNpdGU6IFwibGF4XCIsXG4gICAgICAgIHNlY3VyZTogcmVxLnNlY3VyZSxcbiAgICAgICAgcGF0aDogXCIvXCIsXG4gICAgICB9KTtcbiAgICB9XG4gICAgcmVxdWVzdENvbnRleHQuc2V0KE1BU1RSQV9USFJFQURfSURfS0VZLCBzZXNzaW9uSWQpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlYWQgdGhlIGNsaWVudC1zZWxlY3RlZCB0aHJlYWQgaWQgZnJvbSB0aGUgcmVxdWVzdCwgcHJlZmVycmluZ1xuICAgKiB0aGUgdGhyZWFkLXNlbGVjdGlvbiBoZWFkZXIgb3ZlciB0aGUgYD90aHJlYWRJZD1gIHF1ZXJ5LiBSZXR1cm5zXG4gICAqIGBudWxsYCB3aGVuIG5laXRoZXIgY2FycmllcyBhIG5vbi1lbXB0eSB2YWx1ZSBzbyB0aGUgY2FsbGVyIGZhbGxzXG4gICAqIGJhY2sgdG8gdGhlIHNlc3Npb24gY29va2llLlxuICAgKi9cbiAgcHJpdmF0ZSByZWFkUmVxdWVzdGVkVGhyZWFkSWQocmVxOiBleHByZXNzLlJlcXVlc3QpOiBzdHJpbmcgfCBudWxsIHtcbiAgICBjb25zdCBoZWFkZXJWYWx1ZSA9IHJlcS5oZWFkZXJzW3RocmVhZC5USFJFQURfSURfSEVBREVSXTtcbiAgICBjb25zdCBxdWVyeVZhbHVlID0gcmVxLnF1ZXJ5W3RocmVhZC5USFJFQURfSURfUVVFUlldO1xuICAgIHJldHVybiAoXG4gICAgICBzdHJpbmcudHJpbVRvTnVsbChBcnJheS5pc0FycmF5KGhlYWRlclZhbHVlKSA/IGhlYWRlclZhbHVlWzBdIDogaGVhZGVyVmFsdWUpID8/XG4gICAgICBzdHJpbmcudHJpbVRvTnVsbChBcnJheS5pc0FycmF5KHF1ZXJ5VmFsdWUpID8gcXVlcnlWYWx1ZVswXSA6IHF1ZXJ5VmFsdWUpXG4gICAgKTtcbiAgfVxuXG4gIGNvbmZpZ3VyZVJlcXVlc3RDb250ZXh0TW9kZWxPdmVycmlkZShyZXE6IGV4cHJlc3MuUmVxdWVzdCwgcmVxdWVzdENvbnRleHQ6IFJlcXVlc3RDb250ZXh0KSB7XG4gICAgLy8gUGVyLXJlcXVlc3QgbW9kZWwgb3ZlcnJpZGU6IG9ubHkgaG9ub3JlZCB3aGVuIHRoZSBwbHVnaW5cbiAgICAvLyBvcHRzIGluIChkZWZhdWx0KS4gU291cmNlcywgaW4gcHJpb3JpdHkgb3JkZXIsIGFyZVxuICAgIC8vIGBYLU1hc3RyYS1Nb2RlbGAgaGVhZGVyLCBgP21vZGVsPWAgcXVlcnksIGFuZCBgbW9kZWxgIC9cbiAgICAvLyBgbW9kZWxJZGAgYm9keSBmaWVsZDsgc2VlIGBzZXJ2aW5nLnRzYC5cbiAgICBjb25zdCBzZXJ2aW5nID0gcmVzb2x2ZVNlcnZpbmdDb25maWcodGhpcy5jb25maWcpO1xuICAgIGlmIChzZXJ2aW5nLmFsbG93T3ZlcnJpZGUpIHtcbiAgICAgIGNvbnN0IG92ZXJyaWRlID0gZXh0cmFjdE1vZGVsT3ZlcnJpZGUoe1xuICAgICAgICBoZWFkZXJzOiByZXEuaGVhZGVycyBhcyBSZWNvcmQ8c3RyaW5nLCBzdHJpbmcgfCBzdHJpbmdbXSB8IHVuZGVmaW5lZD4sXG4gICAgICAgIHF1ZXJ5OiByZXEucXVlcnkgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4sXG4gICAgICAgIGJvZHk6IHJlcS5ib2R5LFxuICAgICAgfSk7XG4gICAgICBpZiAob3ZlcnJpZGUpIHJlcXVlc3RDb250ZXh0LnNldChNQVNUUkFfTU9ERUxfT1ZFUlJJREVfS0VZLCBvdmVycmlkZSk7XG4gICAgfVxuICB9XG59XG5cbi8qKiBJbnB1dHMgZm9yIHtAbGluayBpc01hc3RyYVJlcXVlc3RBbGxvd2VkfS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTWFzdHJhQXBpR2F0ZU9wdGlvbnMge1xuICAvKiogYGNvbmZpZy5hcGlBY2Nlc3NgOyBgXCJmdWxsXCJgIHNob3J0LWNpcmN1aXRzIHRvIGFsbG93IGV2ZXJ5dGhpbmcuICovXG4gIGFjY2VzczogXCJzY29wZWRcIiB8IFwiZnVsbFwiO1xuICAvKiogV2hldGhlciB0aGUgTUNQIHRyYW5zcG9ydCBpcyBtb3VudGVkIChzbyBgL21jcC8qYCBpcyBsZWdpdGltYXRlKS4gKi9cbiAgbWNwRW5hYmxlZDogYm9vbGVhbjtcbn1cblxuLyoqXG4gKiBNb3VudC1yZWxhdGl2ZSBhZ2VudCBpbmZlcmVuY2UgcGF0aHMgKGAvYWdlbnRzLzppZC88dmVyYj4uLi5gKS4gTWF0Y2hlZFxuICogYnkgcHJlZml4IG9uIHRoZSB2ZXJiIHNvIGZ1dHVyZSB2YXJpYW50cyAoYHN0cmVhbVZOZXh0YCwgYHN0cmVhbS92bmV4dGAsXG4gKiBgZ2VuZXJhdGVWTmV4dGApIHN0YXkgY292ZXJlZCB3aXRob3V0IGEgY29kZSBjaGFuZ2UuXG4gKlxuICogQ292ZXJzIHRoZSBwbGFpbiBpbmZlcmVuY2UgdmVyYnMgKGBzdHJlYW1gIC8gYGdlbmVyYXRlYCAvIGBuZXR3b3JrYCkgcGx1c1xuICogdGhlIGh1bWFuLWluLXRoZS1sb29wIHJlc3VtZSB2ZXJicyBhIHBhdXNlZCBgcmVxdWlyZUFwcHJvdmFsYCB0b29sIG5lZWRzXG4gKiB0byBjb250aW51ZTogYGFwcHJvdmUtdG9vbC1jYWxsYCAvIGBkZWNsaW5lLXRvb2wtY2FsbGAgKHN0cmVhbWluZywgYW5kIHZpYVxuICogcHJlZml4IHRoZWlyIGAtZ2VuZXJhdGVgIG5vbi1zdHJlYW1pbmcgdmFyaWFudHMpLCB0aGUgYC1uZXR3b3JrLWAgdmFyaWFudHMsXG4gKiBhbmQgYHJlc3VtZS1zdHJlYW1gIChjb3ZlcnMgYHJlc3VtZS1zdHJlYW0tdW50aWwtaWRsZWApLiBXaXRob3V0IHRoZXNlIGFuXG4gKiBhcHByb3ZhbC1nYXRlZCB0b29sIChlLmcuIGBzZW5kX2VtYWlsYCkgY2FuIGJlIHJlcXVlc3RlZCBidXQgbmV2ZXIgYXBwcm92ZWRcbiAqIGZyb20gdGhlIGJyb3dzZXIgLSB0aGUgcmVzdW1lIGBQT1NUYCA0MDNzIHVuZGVyIHNjb3BlZCBtb2RlLiBUaGVzZSBhcmUgdGhlXG4gKiBvbmx5ICp3cml0ZXMqIHRoZSBicm93c2VyIGNsaWVudCBpcyBhbGxvd2VkIHRvIG1ha2UgYWdhaW5zdCBzdG9jayBNYXN0cmEuXG4gKi9cbmNvbnN0IEFHRU5UX0lORkVSRU5DRSA9XG4gIC9eXFwvYWdlbnRzXFwvW14vXStcXC8oc3RyZWFtfGdlbmVyYXRlfG5ldHdvcmt8cmVzdW1lLXN0cmVhbXxhcHByb3ZlLXRvb2wtY2FsbHxkZWNsaW5lLXRvb2wtY2FsbHxhcHByb3ZlLW5ldHdvcmstdG9vbC1jYWxsfGRlY2xpbmUtbmV0d29yay10b29sLWNhbGwpL2k7XG5cbi8qKiBNb3VudC1yZWxhdGl2ZSByZWFkLW9ubHkgYWdlbnQgbWV0YWRhdGEgKGAvYWdlbnRzYCwgYC9hZ2VudHMvOmlkYCkuICovXG5jb25zdCBBR0VOVF9NRVRBREFUQSA9IC9eXFwvYWdlbnRzKFxcL1teL10rKT8kLztcblxuLyoqXG4gKiBXaGV0aGVyIGEgcmVxdWVzdCB0byB0aGUgc3RvY2sgYEBtYXN0cmEvZXhwcmVzc2Agc3ViLWFwcCBzaG91bGQgYmVcbiAqIGRpc3BhdGNoZWQsIGdpdmVuIHRoZSBjb25maWd1cmVkIHtAbGluayBNYXN0cmFBcGlHYXRlT3B0aW9ucy5hY2Nlc3N9LlxuICpcbiAqIGBwYXRoYCBpcyBtb3VudC1yZWxhdGl2ZSAod2hhdCB0aGUgcGx1Z2luJ3MgY2F0Y2gtYWxsIHNlZXMsIGUuZy5cbiAqIGAvYWdlbnRzL3gvc3RyZWFtYCwgYC9yb3V0ZS9oaXN0b3J5L3hgLCBgL21jcC8uLi5gKS4gSW4gYFwic2NvcGVkXCJgXG4gKiBtb2RlIHRoZSBhbGxvd2xpc3QgaXMgZGVsaWJlcmF0ZWx5IHRpZ2h0IC0gdGhlIGNoYXQgY2xpZW50IG9ubHkgZXZlclxuICogbmVlZHMgYWdlbnQgaW5mZXJlbmNlLCByZWFkLW9ubHkgYWdlbnQgbWV0YWRhdGEsIHRoaXMgcGx1Z2luJ3Mgb3duXG4gKiBPQk8vcmVzb3VyY2Utc2NvcGVkIGAvcm91dGUvKmAgcm91dGVzLCBhbmQgKHdoZW4gZW5hYmxlZCkgTUNQIC0gc28gdGhlXG4gKiB3aG9sZSBhZG1pbiAvIG11dGF0aW5nIC8gYnVsay1leHBvcnQgc3VyZmFjZSBNYXN0cmEgYWxzbyBleHBvc2VzIGlzXG4gKiBkZW5pZWQgYnkgZGVmYXVsdCByYXRoZXIgdGhhbiBlbnVtZXJhdGVkLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNNYXN0cmFSZXF1ZXN0QWxsb3dlZChcbiAgbWV0aG9kOiBzdHJpbmcsXG4gIHBhdGg6IHN0cmluZyxcbiAgb3B0czogTWFzdHJhQXBpR2F0ZU9wdGlvbnMsXG4pOiBib29sZWFuIHtcbiAgaWYgKG9wdHMuYWNjZXNzID09PSBcImZ1bGxcIikgcmV0dXJuIHRydWU7XG4gIGNvbnN0IHAgPSBwYXRoLnN0YXJ0c1dpdGgoXCIvXCIpID8gcGF0aCA6IGAvJHtwYXRofWA7XG4gIC8vIFRoaXMgcGx1Z2luJ3Mgb3duIGN1c3RvbSByb3V0ZXMgYXJlIGluZGl2aWR1YWxseSBPQk8tIGFuZFxuICAvLyByZXNvdXJjZS1zY29wZWQgKHNlZSBoaXN0b3J5LnRzIC8gdGhyZWFkcy50cyksIHNvIGV2ZXJ5IG1ldGhvZCBpcyBzYWZlLlxuICBpZiAocCA9PT0gXCIvcm91dGVcIiB8fCBwLnN0YXJ0c1dpdGgoXCIvcm91dGUvXCIpKSByZXR1cm4gdHJ1ZTtcbiAgaWYgKG9wdHMubWNwRW5hYmxlZCAmJiAocCA9PT0gXCIvbWNwXCIgfHwgcC5zdGFydHNXaXRoKFwiL21jcC9cIikpKSByZXR1cm4gdHJ1ZTtcbiAgY29uc3QgbSA9IG1ldGhvZC50b1VwcGVyQ2FzZSgpO1xuICBpZiAobSA9PT0gXCJQT1NUXCIgJiYgQUdFTlRfSU5GRVJFTkNFLnRlc3QocCkpIHJldHVybiB0cnVlO1xuICBpZiAobSA9PT0gXCJHRVRcIiAmJiBBR0VOVF9NRVRBREFUQS50ZXN0KHApKSByZXR1cm4gdHJ1ZTtcbiAgcmV0dXJuIGZhbHNlO1xufVxuXG4vKipcbiAqIFBhdGNoZXMgYXJvdW5kIGBAbWFzdHJhL2V4cHJlc3NgJ3MgY3VzdG9tLXJvdXRlIGRpc3BhdGNoZXIgc28gdGhlXG4gKiBwbHVnaW4ncyBjdXN0b20gQVBJIHJvdXRlcyAoZS5nLiBgaGlzdG9yeVJvdXRlYCkgd29yayB3aGVuXG4gKiBgTWFzdHJhU2VydmVyYCBpcyBob3N0ZWQgb24gYW4gRXhwcmVzcyBzdWJhcHAgbW91bnRlZCB1bmRlciBhIHBhcmVudFxuICogcGF0aCAoZS5nLiBgL2FwaS9tYXN0cmFgKS5cbiAqXG4gKiBUaGUgYWRhcHRlcidzIGByZWdpc3RlckN1c3RvbUFwaVJvdXRlc2AgbWF0Y2hlcyBhZ2FpbnN0IGByZXEucGF0aGBcbiAqIChtb3VudC1yZWxhdGl2ZSwgY29ycmVjdCkgYnV0IGRpc3BhdGNoZXMgdG8gaXRzIGludGVybmFsIEhvbm9cbiAqIG1pbmktYXBwIHVzaW5nIGByZXEub3JpZ2luYWxVcmxgLCB3aGljaCBzdGlsbCBjb250YWlucyB0aGUgcGFyZW50XG4gKiBtb3VudCBwcmVmaXguIFRoZSBIb25vIGFwcCByZWdpc3RlcnMgdGhlIGxpdGVyYWwgcm91dGUgcGF0aHNcbiAqIChmb3IgZXhhbXBsZSBgL3JvdXRlL2hpc3RvcnlgKSwgc28gdGhlIGFic29sdXRlIFVSTCBuZXZlciBtYXRjaGVzXG4gKiB1bnRpbCB3ZSBvdmVyd3JpdGUgYG9yaWdpbmFsVXJsYCBmb3IgYC9yb3V0ZWAgYW5kIGAvcm91dGUvKmAgdG8gdGhlXG4gKiBtb3VudC1yZWxhdGl2ZSBwYXRoLlxuICovXG5leHBvcnQgZnVuY3Rpb24gYXR0YWNoUm91dGVQYXRjaE1pZGRsZXdhcmUoYXBwOiBleHByZXNzLkV4cHJlc3MpOiB2b2lkIHtcbiAgYXBwLnVzZSgocmVxLCBfcmVzLCBuZXh0KSA9PiB7XG4gICAgY29uc3QgaXNDdXN0b21Sb3V0ZSA9IHJlcS5wYXRoID09PSBcIi9yb3V0ZVwiIHx8IHJlcS5wYXRoLnN0YXJ0c1dpdGgoXCIvcm91dGUvXCIpO1xuICAgIGlmICghaXNDdXN0b21Sb3V0ZSkgcmV0dXJuIG5leHQoKTtcbiAgICByZXEub3JpZ2luYWxVcmwgPSByZXEucGF0aDtcbiAgICBuZXh0KCk7XG4gIH0pO1xufVxuIl19
355
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NlcnZlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7OztHQU9HO0FBRUgsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDekQsT0FBTyxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsR0FBRyxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDaEYsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUM1RCxPQUFPLEVBQ0wsc0JBQXNCLEVBQ3RCLG9CQUFvQixFQUNwQixjQUFjLEdBQ2YsTUFBTSw4QkFBOEIsQ0FBQztBQUN0QyxPQUFPLEVBQUUsWUFBWSxJQUFJLG1CQUFtQixFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDdEUsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBRzNDLE9BQU8sRUFDTCxzQkFBc0IsRUFDdEIscUJBQXFCLEVBQ3JCLGlCQUFpQixFQUNqQixxQkFBcUIsRUFDckIsZUFBZSxFQUNmLG9CQUFvQixHQUdyQixNQUFNLGFBQWEsQ0FBQztBQUNyQixPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsYUFBYSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ2hFLE9BQU8sRUFBRSxzQkFBc0IsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUVyRCxPQUFPLEVBQ0wsb0JBQW9CLEVBQ3BCLHlCQUF5QixFQUN6QixvQkFBb0IsR0FDckIsTUFBTSxjQUFjLENBQUM7QUFDdEI7Ozs7O0dBS0c7QUFDSCxNQUFNLGdCQUFnQixHQUFHLEdBQUcsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLENBQUM7QUFpQnhDOzs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FrQkc7QUFDSCxNQUFNLENBQUMsS0FBSyxVQUFVLHVCQUF1QixDQUMzQyxjQUE4QixFQUM5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LENBQUM7UUFDOUUsSUFBSSxDQUFDLGFBQWE7WUFBRSxPQUFPLElBQUksRUFBRSxDQUFDO1FBQ2xDLEdBQUcsQ0FBQyxXQUFXLEdBQUcsR0FBRyxDQUFDLElBQUksQ0FBQztRQUMzQixJQUFJLEVBQUUsQ0FBQztJQUNULENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogRXhwcmVzcy1sYXllciBwbHVtYmluZyBmb3IgdGhlIE1hc3RyYSBwbHVnaW46IGEgYE1hc3RyYVNlcnZlcmAgdGhhdFxuICogc3RhbXBzIHRoZSBwZXItcmVxdWVzdCBgUmVxdWVzdENvbnRleHRgLCBhbmQgYSByb3V0ZS1wYXRjaCBtaWRkbGV3YXJlXG4gKiB0aGF0IGxldHMgdGhlIHBsdWdpbidzIGN1c3RvbSBBUEkgcm91dGVzIChlLmcuIGBoaXN0b3J5Um91dGVgKSB3b3JrXG4gKiBiZWhpbmQgYW4gRXhwcmVzcyBtb3VudCBwb2ludC5cbiAqXG4gKiBAbW9kdWxlXG4gKi9cblxuaW1wb3J0IHsgZ2V0RXhlY3V0aW9uQ29udGV4dCB9IGZyb20gXCJAZGF0YWJyaWNrcy9hcHBraXRcIjtcbmltcG9ydCB7IGhhc2gsIGh0dHAsIGxvZywgb2JqZWN0LCBzdHJpbmcsIHRva2VuIH0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLWNvcmVcIjtcbmltcG9ydCB7IGZlZWRiYWNrLCB0aHJlYWQgfSBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtbWFzdHJhXCI7XG5pbXBvcnQge1xuICBNQVNUUkFfUkVTT1VSQ0VfSURfS0VZLFxuICBNQVNUUkFfVEhSRUFEX0lEX0tFWSxcbiAgUmVxdWVzdENvbnRleHQsXG59IGZyb20gXCJAbWFzdHJhL2NvcmUvcmVxdWVzdC1jb250ZXh0XCI7XG5pbXBvcnQgeyBNYXN0cmFTZXJ2ZXIgYXMgTWFzdHJhU2VydmVyRXhwcmVzcyB9IGZyb20gXCJAbWFzdHJhL2V4cHJlc3NcIjtcbmltcG9ydCB7IHRyYWNlIH0gZnJvbSBcIkBvcGVudGVsZW1ldHJ5L2FwaVwiO1xuaW1wb3J0IHR5cGUgZXhwcmVzcyBmcm9tIFwiZXhwcmVzc1wiO1xuXG5pbXBvcnQge1xuICBleGVjdXRpb25Db250ZXh0VXNlcklkLFxuICBNQVNUUkFfUkVRVUVTVF9JRF9LRVksXG4gIE1BU1RSQV9TQ09QRVNfS0VZLFxuICBNQVNUUkFfVVNFUl9FTUFJTF9LRVksXG4gIE1BU1RSQV9VU0VSX0tFWSxcbiAgTUFTVFJBX1VTRVJfTkFNRV9LRVksXG4gIHR5cGUgTWFzdHJhUGx1Z2luQ29uZmlnLFxuICB0eXBlIFVzZXIsXG59IGZyb20gXCIuL2NvbmZpZy50c1wiO1xuaW1wb3J0IHsgcmVxdWVzdFVzZXJFbWFpbCwgcmVxdWVzdFVzZXJJZCB9IGZyb20gXCIuL2lkZW50aXR5LnRzXCI7XG5pbXBvcnQgeyByZXNvbHZlRmVlZGJhY2tFbmFibGVkIH0gZnJvbSBcIi4vbWxmbG93LnRzXCI7XG5cbmltcG9ydCB7XG4gIGV4dHJhY3RNb2RlbE92ZXJyaWRlLFxuICBNQVNUUkFfTU9ERUxfT1ZFUlJJREVfS0VZLFxuICByZXNvbHZlU2VydmluZ0NvbmZpZyxcbn0gZnJvbSBcIi4vc2VydmluZy50c1wiO1xuLyoqXG4gKiBPcGVuVGVsZW1ldHJ5J3Mgc2VudGluZWwgZm9yIFwibm8gdmFsaWQgdHJhY2VcIiAtIDMyIHplcm8gaGV4IGNoYXJzLlxuICogYHRyYWNlLmdldEFjdGl2ZVNwYW4oKWAgcmV0dXJucyBhIG5vbi1yZWNvcmRpbmcgc3BhbiB3aXRoIHRoaXMgaWRcbiAqIHdoZW4gbm8gU0RLIGlzIHJlZ2lzdGVyZWQsIHdoaWNoIG11c3QgbmV2ZXIgYmUgc3VyZmFjZWQgYXMgYSB0cmFjZSB0b1xuICogYXR0YWNoIGZlZWRiYWNrIHRvLlxuICovXG5jb25zdCBJTlZBTElEX1RSQUNFX0lEID0gXCIwXCIucmVwZWF0KDMyKTtcblxuLyoqXG4gKiBXaG8gYSB0dXJuIGlzIEFUVFJJQlVURUQgdG8sIGluZGVwZW5kZW50IG9mIHdoaWNoIERhdGFicmlja3MgY3JlZGVudGlhbCBydW5zXG4gKiBpdHMgY2FsbHMuIFN1cHBsaWVkIGJ5IHRoZSBIVFRQIG1pZGRsZXdhcmUgZnJvbSB0aGUgZm9yd2FyZGVkIHVzZXIgaGVhZGVycyBzb1xuICogdGhhdCBpbiBgc2VydmljZS1wcmluY2lwYWxgIG1vZGUgLSB3aGVyZSBldmVyeSByZXF1ZXN0IHNoYXJlcyB0aGUgYXBwIFNQJ3NcbiAqIGNsaWVudCAtIHRoZSBtZW1vcnkgdGhyZWFkLCBwZXItdXNlciBjYWNoZSBuYW1lc3BhY2UsIGFuZCB0cmFjZSBtZXRhZGF0YVxuICogc3RpbGwga2V5IG9mZiB0aGUgcmVhbCBjYWxsZXIuIElnbm9yZWQgaW4gYW4gT0JPICh1c2VyKSBjb250ZXh0LCB3aG9zZSBvd25cbiAqIHVzZXIgaWQgLyBlbWFpbCBhcmUgYXV0aG9yaXRhdGl2ZS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBBdHRyaWJ1dGVkSWRlbnRpdHkge1xuICAvKiogRm9yd2FyZGVkIGB4LWZvcndhcmRlZC11c2VyYCBpZCwgdXNlZCB3aGVuIHRoZSBjbGllbnQgaXMgdGhlIHNlcnZpY2UgcHJpbmNpcGFsLiAqL1xuICB1c2VySWQ/OiBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gIC8qKiBGb3J3YXJkZWQgYHgtZm9yd2FyZGVkLWVtYWlsYCwgdXNlZCBmb3IgdHJhY2UgbWV0YWRhdGEgdW5kZXIgdGhlIHNlcnZpY2UgcHJpbmNpcGFsLiAqL1xuICBlbWFpbD86IHN0cmluZyB8IHVuZGVmaW5lZDtcbn1cblxuLyoqXG4gKiBTdGFtcCB0aGUgQXBwS2l0IHVzZXIgKHBsdXMgdGhlIHJlc291cmNlIGlkIGFuZCB0cmFjZSBtZXRhZGF0YSkgb250b1xuICogYHJlcXVlc3RDb250ZXh0YC5cbiAqXG4gKiBTcGxpdCBvdXQgb2Yge0BsaW5rIE1hc3RyYVNlcnZlcn0gYmVjYXVzZSB0aGUgSFRUUCBtaWRkbGV3YXJlIGlzIG5vdCB0aGUgb25seVxuICogY2FsbGVyIHRoYXQgbmVlZHMgaXQ6IGFuIG91dC1vZi1iYW5kIHR1cm4gKGEgVGVhbXMgYWN0aXZpdHkgYXJyaXZpbmcgb25cbiAqIGFub3RoZXIgcGx1Z2luJ3Mgcm91dGUsIGEgc2NoZWR1bGVkIGpvYikgZHJpdmVzIGBhZ2VudC5nZW5lcmF0ZWAgZGlyZWN0bHksIGFuZFxuICogd2l0aG91dCB0aGlzIHN0YW1wIGV2ZXJ5IHVzZXItc2NvcGVkIHRvb2wgLSBgYXNrX2dlbmllYCBhYm92ZSBhbGwgLSBmYWlscyB3aXRoXG4gKiBcImludm9rZSB0aGUgdG9vbCBmcm9tIGFuIGFnZW50IHR1cm4gc2VydmVkIGJ5IHRoZSBtYXN0cmEgcGx1Z2luXCIuIFRob3NlXG4gKiBjYWxsZXJzIGJ1aWxkIGEgY29udGV4dCB3aXRoIHtAbGluayBjcmVhdGVSZXF1ZXN0Q29udGV4dH0gaW5zdGVhZCBvZiBhXG4gKiByZXF1ZXN0LlxuICpcbiAqIFRoZSBEYXRhYnJpY2tzIGNyZWRlbnRpYWwgYWx3YXlzIGNvbWVzIGZyb20gdGhlIGFtYmllbnQgZXhlY3V0aW9uIGNvbnRleHQ7XG4gKiBgYXR0cmlidXRlZGAgb25seSBjaGFuZ2VzIFdITyB0aGUgdHVybiBpcyBhdHRyaWJ1dGVkIHRvIHdoZW4gdGhhdCBjb250ZXh0IGlzXG4gKiB0aGUgc2VydmljZSBwcmluY2lwYWwgKHNlZSB7QGxpbmsgQXR0cmlidXRlZElkZW50aXR5fSkuXG4gKlxuICogSWRlbXBvdGVudDogcmV0dXJucyBpbW1lZGlhdGVseSB3aGVuIHRoZSB1c2VyIGFuZCByZXNvdXJjZSBpZCBhcmUgYWxyZWFkeVxuICogcHJlc2VudCwgc28gdGhlIG1pZGRsZXdhcmUgY2FuIGNhbGwgaXQgb3ZlciBhIGNvbnRleHQgYW5vdGhlciBsYXllciBzdGFtcGVkLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc3RhbXBSZXF1ZXN0Q29udGV4dFVzZXIoXG4gIHJlcXVlc3RDb250ZXh0OiBSZXF1ZXN0Q29udGV4dCxcbiAgYXR0cmlidXRlZDogQXR0cmlidXRlZElkZW50aXR5ID0ge30sXG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgaWYgKFtNQVNUUkFfVVNFUl9LRVksIE1BU1RSQV9SRVNPVVJDRV9JRF9LRVldLmV2ZXJ5KChrZXkpID0+IHJlcXVlc3RDb250ZXh0LmdldChrZXkpKSkgcmV0dXJuO1xuICBjb25zdCBleGVjdXRpb25Db250ZXh0ID0gZ2V0RXhlY3V0aW9uQ29udGV4dCgpO1xuICBjb25zdCBpc1VzZXJDb250ZXh0ID0gXCJpc1VzZXJDb250ZXh0XCIgaW4gZXhlY3V0aW9uQ29udGV4dDtcbiAgLy8gVGhlIERhdGFicmlja3MgQ1JFREVOVElBTCBpcyBhbHdheXMgdGhlIGFtYmllbnQgZXhlY3V0aW9uIGNvbnRleHQncyBjbGllbnRcbiAgLy8gKE9CTyBpbiBhIHVzZXIgY29udGV4dCwgdGhlIHNlcnZpY2UgcHJpbmNpcGFsIG90aGVyd2lzZSkuIFdITyB0aGUgdHVybiBpc1xuICAvLyBhdHRyaWJ1dGVkIHRvIGNhbiBkaWZmZXI6IGluIGBzZXJ2aWNlLXByaW5jaXBhbGAgbW9kZSBldmVyeSByZXF1ZXN0IHNoYXJlc1xuICAvLyB0aGUgU1AgY2xpZW50LCBidXQgdGhlIGZvcndhcmRlZCB1c2VyIGlkIG11c3Qgc3RpbGwga2V5IHRoZSBtZW1vcnkgdGhyZWFkXG4gIC8vIGFuZCB0aGUgcGVyLXVzZXIgY2FjaGUgbmFtZXNwYWNlIHNvIHR3byBjYWxsZXJzIGRvbid0IHNoYXJlIGEgY29udmVyc2F0aW9uLlxuICAvLyBQcmVmZXIgdGhlIE9CTyBjb250ZXh0J3Mgb3duIHVzZXIgaWQsIHRoZW4gdGhlIGZvcndhcmRlZCBpZCwgdGhlbiB0aGUgU1AgaWQuXG4gIGNvbnN0IGlkID1cbiAgICAoaXNVc2VyQ29udGV4dCA/IGV4ZWN1dGlvbkNvbnRleHRVc2VySWQoZXhlY3V0aW9uQ29udGV4dCkgOiBhdHRyaWJ1dGVkLnVzZXJJZCkgPz9cbiAgICBleGVjdXRpb25Db250ZXh0VXNlcklkKGV4ZWN1dGlvbkNvbnRleHQpO1xuICBjb25zdCB1c2VyOiBVc2VyID0geyBpZCwgZXhlY3V0aW9uQ29udGV4dCB9O1xuICByZXF1ZXN0Q29udGV4dC5zZXQoTUFTVFJBX1VTRVJfS0VZLCB1c2VyKTtcbiAgcmVxdWVzdENvbnRleHQuc2V0KE1BU1RSQV9SRVNPVVJDRV9JRF9LRVksIHVzZXIuaWQpO1xuICAvLyBBcHBLaXQncyBgVXNlckNvbnRleHRgIHN1cmZhY2VzIGRpc3BsYXkgbmFtZSAvIGVtYWlsIG9ubHkgb25cbiAgLy8gT0JPIHJlcXVlc3RzLiBTZXJ2aWNlLWNvbnRleHQgY2FsbHMgKGJhY2tncm91bmQgdGFza3MsIHNlcnZlclxuICAvLyBzdGFydC11cCkgbGVhdmUgdGhlc2UgdW5kZWZpbmVkIGFuZCB3ZSBza2lwIHRoZSBzdGFtcCBzb1xuICAvLyBkb3duc3RyZWFtIHRyYWNlIG1ldGFkYXRhIHN0YXlzIGFic2VudCByYXRoZXIgdGhhbiBlbXB0eS4gSW5cbiAgLy8gYHNlcnZpY2UtcHJpbmNpcGFsYCBtb2RlIHRoZSBmb3J3YXJkZWQgZW1haWwgc3RpbGwgaWRlbnRpZmllcyB0aGUgY2FsbGVyLFxuICAvLyBzbyBpdCBpcyB1c2VkIGZvciB0cmFjZSBtZXRhZGF0YSBldmVuIHRob3VnaCB0aGUgY2xpZW50IGlzIHRoZSBTUC5cbiAgbGV0IHVzZXJOYW1lOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gIGxldCBlbWFpbDogc3RyaW5nIHwgdW5kZWZpbmVkID0gYXR0cmlidXRlZC5lbWFpbDtcbiAgaWYgKGlzVXNlckNvbnRleHQpIHtcbiAgICB1c2VyTmFtZSA9IGV4ZWN1dGlvbkNvbnRleHQudXNlck5hbWU7XG4gICAgZW1haWwgPSBleGVjdXRpb25Db250ZXh0LnVzZXJFbWFpbCA/PyBlbWFpbDtcbiAgfSBlbHNlIGlmIChwcm9jZXNzLmVudi5OT0RFX0VOViA9PT0gXCJkZXZlbG9wbWVudFwiKSB7XG4gICAgY29uc3QgY3VycmVudFVzZXIgPSBhd2FpdCBleGVjdXRpb25Db250ZXh0LmNsaWVudC5jdXJyZW50VXNlci5tZSgpO1xuICAgIHVzZXJOYW1lID0gY3VycmVudFVzZXI/LnVzZXJOYW1lO1xuICAgIGVtYWlsID0gY3VycmVudFVzZXI/LmVtYWlscz8uZmlsdGVyKChlbWFpbCkgPT4gZW1haWwucHJpbWFyeSkuZmluZCgoZW1haWwpID0+IGVtYWlsLnZhbHVlKVxuICAgICAgPy52YWx1ZSBhcyBzdHJpbmc7XG4gIH1cbiAgaWYgKHVzZXJOYW1lKSB7XG4gICAgcmVxdWVzdENvbnRleHQuc2V0KE1BU1RSQV9VU0VSX05BTUVfS0VZLCB1c2VyTmFtZSk7XG4gIH1cbiAgaWYgKGVtYWlsKSB7XG4gICAgcmVxdWVzdENvbnRleHQuc2V0KE1BU1RSQV9VU0VSX0VNQUlMX0tFWSwgZW1haWwpO1xuICB9XG59XG5cbi8qKlxuICogQnVpbGQgdGhlIGBSZXF1ZXN0Q29udGV4dGAgYSBOT04tSFRUUCBhZ2VudCB0dXJuIG5lZWRzLlxuICpcbiAqIEV2ZXJ5dGhpbmcgTWFzdHJhJ3MgdG9vbHMgcmVhZCBvZmYgdGhlIGNvbnRleHQgaXMgc3RhbXBlZCB0aGUgc2FtZSB3YXkgdGhlXG4gKiByZXF1ZXN0IG1pZGRsZXdhcmUgc3RhbXBzIGl0IC0gdGhlIEFwcEtpdCB1c2VyIChzbyBgYXNrX2dlbmllYCBhbmQgdGhlIG1vZGVsXG4gKiByZXNvbHZlciBjYW4gbWludCB1c2VyLXNjb3BlZCB0b2tlbnMpLCB0aGUgbWVtb3J5IHRocmVhZCAvIHJlc291cmNlIHBhaXIsIGFuZFxuICogYSByZXF1ZXN0IGlkIHNvIHRoZSB0dXJuJ3Mgc3BhbnMgam9pbiB1cCBpbiB0cmFjZXMuIFRoZSByZXN1bHQgaXMgcGFzc2VkIGFzXG4gKiBgcmVxdWVzdENvbnRleHRgIHRvIGBhZ2VudC5nZW5lcmF0ZWAgLyBgYWdlbnQuc3RyZWFtYC5cbiAqXG4gKiBUaGlzIGlzIHdoYXQgbWFrZXMgYSBjYXJkIHR1cm4gYW5zd2VyIHdpdGggdGhlIFNBTUUgZGF0YSBhIGNoYXQgdHVybiBkb2VzOiB0aGVcbiAqIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgdHdvIGVuZHBvaW50cyBpcyBwcmVzZW50YXRpb24sIG5vdCBjYXBhYmlsaXR5LlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY3JlYXRlUmVxdWVzdENvbnRleHQoXG4gIG9wdGlvbnM6IHsgdGhyZWFkSWQ/OiBzdHJpbmc7IHJlc291cmNlSWQ/OiBzdHJpbmc7IHJlcXVlc3RJZD86IHN0cmluZyB9ID0ge30sXG4pOiBQcm9taXNlPFJlcXVlc3RDb250ZXh0PiB7XG4gIGNvbnN0IHJlcXVlc3RDb250ZXh0ID0gbmV3IFJlcXVlc3RDb250ZXh0KCk7XG4gIGF3YWl0IHN0YW1wUmVxdWVzdENvbnRleHRVc2VyKHJlcXVlc3RDb250ZXh0KTtcbiAgaWYgKG9wdGlvbnMudGhyZWFkSWQpIHJlcXVlc3RDb250ZXh0LnNldChNQVNUUkFfVEhSRUFEX0lEX0tFWSwgb3B0aW9ucy50aHJlYWRJZCk7XG4gIC8vIFN0YW1wZWQgQUZURVIgdGhlIHVzZXIgc28gYW4gZXhwbGljaXQgcmVzb3VyY2UgaWQgKGEgY2hhbm5lbCBtZW1iZXIsIHNheSlcbiAgLy8gd2lucyBvdmVyIHRoZSBhbWJpZW50IGlkZW50aXR5IGBzdGFtcFJlcXVlc3RDb250ZXh0VXNlcmAgZGVmYXVsdGVkIHRvLlxuICBpZiAob3B0aW9ucy5yZXNvdXJjZUlkKSByZXF1ZXN0Q29udGV4dC5zZXQoTUFTVFJBX1JFU09VUkNFX0lEX0tFWSwgb3B0aW9ucy5yZXNvdXJjZUlkKTtcbiAgcmVxdWVzdENvbnRleHQuc2V0KE1BU1RSQV9SRVFVRVNUX0lEX0tFWSwgb3B0aW9ucy5yZXF1ZXN0SWQgPz8gaGFzaC5pZCgpKTtcbiAgcmV0dXJuIHJlcXVlc3RDb250ZXh0O1xufVxuXG4vKipcbiAqIGBAbWFzdHJhL2V4cHJlc3NgIHN1YmNsYXNzIHRoYXQgc3RhbXBzIGBSZXF1ZXN0Q29udGV4dGAgd2l0aCB0aGVcbiAqIEFwcEtpdCB1c2VyLCByZXNvdXJjZSBpZCwgYW5kIGEgdGhyZWFkIGlkIGJhY2tlZCBieSBhbiBIVFRQLW9ubHlcbiAqIHNlc3Npb24gY29va2llIChgYXBwa2l0XzxwbHVnaW4tbmFtZT5fc2Vzc2lvbl9pZGApLlxuICovXG5leHBvcnQgY2xhc3MgTWFzdHJhU2VydmVyIGV4dGVuZHMgTWFzdHJhU2VydmVyRXhwcmVzcyB7XG4gIHByaXZhdGUgbG9nOiBsb2cuTG9nZ2VyO1xuICAvKipcbiAgICogV2hldGhlciB0byBzdGFtcCB0aGUgTUxmbG93IHRyYWNlLWlkIGhlYWRlciBvbiByZXNwb25zZXMuIFNoYXJlcyB0aGVcbiAgICogcGx1Z2luJ3MgZmVlZGJhY2sgZ2F0ZSB2aWEge0BsaW5rIHJlc29sdmVGZWVkYmFja0VuYWJsZWR9LlxuICAgKi9cbiAgcHJpdmF0ZSBmZWVkYmFja0VuYWJsZWQ6IGJvb2xlYW47XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSBjb25maWc6IE1hc3RyYVBsdWdpbkNvbmZpZyxcbiAgICAuLi5hcmdzOiBDb25zdHJ1Y3RvclBhcmFtZXRlcnM8dHlwZW9mIE1hc3RyYVNlcnZlckV4cHJlc3M+XG4gICkge1xuICAgIHN1cGVyKC4uLmFyZ3MpO1xuICAgIHRoaXMubG9nID0gbG9nLmxvZ2dlcihjb25maWcpO1xuICAgIHRoaXMuZmVlZGJhY2tFbmFibGVkID0gcmVzb2x2ZUZlZWRiYWNrRW5hYmxlZChjb25maWcuZmVlZGJhY2spO1xuICB9XG5cbiAgb3ZlcnJpZGUgcmVnaXN0ZXJBdXRoTWlkZGxld2FyZSgpOiB2b2lkIHtcbiAgICBzdXBlci5yZWdpc3RlckF1dGhNaWRkbGV3YXJlKCk7XG4gICAgdGhpcy5hcHAudXNlKGFzeW5jIChyZXEsIHJlcywgbmV4dCkgPT4ge1xuICAgICAgY29uc3QgcmVxdWVzdENvbnRleHQgPSByZXMubG9jYWxzLnJlcXVlc3RDb250ZXh0ISBhcyBSZXF1ZXN0Q29udGV4dDtcbiAgICAgIGF3YWl0IHRoaXMuY29uZmlndXJlUmVxdWVzdENvbnRleHRVc2VyKHJlcSwgcmVxdWVzdENvbnRleHQpO1xuICAgICAgdGhpcy5jb25maWd1cmVSZXF1ZXN0Q29udGV4dFRocmVhZElkKHJlcSwgcmVzLCByZXF1ZXN0Q29udGV4dCk7XG4gICAgICB0aGlzLmNvbmZpZ3VyZVJlcXVlc3RDb250ZXh0TW9kZWxPdmVycmlkZShyZXEsIHJlcXVlc3RDb250ZXh0KTtcbiAgICAgIHRoaXMuY29uZmlndXJlUmVxdWVzdENvbnRleHRSZXF1ZXN0SWQocmVxLCByZXMsIHJlcXVlc3RDb250ZXh0KTtcbiAgICAgIHRoaXMuY29uZmlndXJlUmVxdWVzdENvbnRleHRTY29wZXMocmVxLCByZXF1ZXN0Q29udGV4dCk7XG5cbiAgICAgIHRoaXMuY29uZmlndXJlTWxmbG93VHJhY2VJZChyZXMpO1xuICAgICAgdGhpcy5sb2cuZGVidWcoXCJhdXRoOm1pZGRsZXdhcmVcIiwge1xuICAgICAgICBtZXRob2Q6IHJlcS5tZXRob2QsXG4gICAgICAgIHBhdGg6IHJlcS5wYXRoLFxuICAgICAgICByZXF1ZXN0SWQ6IHJlcXVlc3RDb250ZXh0LmdldChNQVNUUkFfUkVRVUVTVF9JRF9LRVkpLFxuICAgICAgICB0aHJlYWRJZDogcmVxdWVzdENvbnRleHQuZ2V0KE1BU1RSQV9USFJFQURfSURfS0VZKSxcbiAgICAgICAgcmVzb3VyY2VJZDogcmVxdWVzdENvbnRleHQuZ2V0KE1BU1RSQV9SRVNPVVJDRV9JRF9LRVkpLFxuICAgICAgICB1c2VyTmFtZTogcmVxdWVzdENvbnRleHQuZ2V0KE1BU1RSQV9VU0VSX05BTUVfS0VZKSxcbiAgICAgICAgdXNlckVtYWlsOiByZXF1ZXN0Q29udGV4dC5nZXQoTUFTVFJBX1VTRVJfRU1BSUxfS0VZKSxcbiAgICAgICAgbW9kZWxPdmVycmlkZTogcmVxdWVzdENvbnRleHQuZ2V0KFxuICAgICAgICAgIC8vIGltcG9ydGVkIGJlbG93OyBsb2dnZWQgc28gYSBtaXNyb3V0ZWQgcmVxdWVzdCBzaG93c1xuICAgICAgICAgIC8vIHVwIGFsb25nc2lkZSBpdHMgbW9kZWwgc2VsZWN0aW9uIGluIGBMT0dfTEVWRUw9ZGVidWdgLlxuICAgICAgICAgIFwibWFzdHJhX19tb2RlbF9vdmVycmlkZVwiLFxuICAgICAgICApLFxuICAgICAgfSk7XG4gICAgICBuZXh0KCk7XG4gICAgfSk7XG4gIH1cblxuICBhc3luYyBjb25maWd1cmVSZXF1ZXN0Q29udGV4dFVzZXIocmVxOiBleHByZXNzLlJlcXVlc3QsIHJlcXVlc3RDb250ZXh0OiBSZXF1ZXN0Q29udGV4dCkge1xuICAgIC8vIFBhc3MgdGhlIGZvcndhcmRlZCBjYWxsZXIgaWRlbnRpdHkgc28gYHNlcnZpY2UtcHJpbmNpcGFsYCBtb2RlIHN0aWxsIGtleXNcbiAgICAvLyBtZW1vcnkgLyBjYWNoZSAvIHRyYWNlcyBwZXIgdXNlciBldmVuIHRob3VnaCB0aGUgY2xpZW50IGlzIHRoZSBhcHAgU1AuXG4gICAgLy8gSW4gYW4gT0JPIGNvbnRleHQgdGhlc2UgYXJlIGlnbm9yZWQgaW4gZmF2b3Igb2YgdGhlIGNvbnRleHQncyBvd24gdXNlci5cbiAgICBhd2FpdCBzdGFtcFJlcXVlc3RDb250ZXh0VXNlcihyZXF1ZXN0Q29udGV4dCwge1xuICAgICAgdXNlcklkOiByZXF1ZXN0VXNlcklkKHJlcSksXG4gICAgICBlbWFpbDogcmVxdWVzdFVzZXJFbWFpbChyZXEpLFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFN0YW1wIGEgcGVyLXJlcXVlc3QgaWQgYW5kIGVjaG8gaXQgb24gdGhlIHJlc3BvbnNlIHNvIGFuIHVwc3RyZWFtXG4gICAqIHByb3h5IC8gY3VybCBjbGllbnQgLyBicm93c2VyLXNpZGUgbG9nIGxpbmUgY2FuIHBhaXIgaXRzIHZpZXcgb2ZcbiAgICogdGhlIHJlcXVlc3Qgd2l0aCB0aGUgbWF0Y2hpbmcgdHJhY2Ugc3Bhbi4gUmV1c2VzIGBYLVJlcXVlc3QtSWRgXG4gICAqIHdoZW4gdGhlIHVwc3RyZWFtIGFscmVhZHkgc3VwcGxpZXMgb25lIHNvIG11bHRpLWhvcCB0cmFjZXMgc3RheVxuICAgKiBqb2luZWQ7IG90aGVyd2lzZSBtaW50cyBhIFVVSUR2NC5cbiAgICpcbiAgICogVGhlIGlkIGlzIHN1cmZhY2VkIGFzIGBtYXN0cmFfX3JlcXVlc3RJZGAgc3BhbiBtZXRhZGF0YSB2aWFcbiAgICoge0BsaW5rIFRSQUNFX1JFUVVFU1RfQ09OVEVYVF9LRVlTfSBhbmQgYXMgdGhlIGBYLVJlcXVlc3QtSWRgXG4gICAqIHJlc3BvbnNlIGhlYWRlciBzbyBkZXYgdG9vbHMgY2FuIGNvcHkgaXQgZnJvbSBlaXRoZXIgc2lkZS5cbiAgICovXG4gIGNvbmZpZ3VyZVJlcXVlc3RDb250ZXh0UmVxdWVzdElkKFxuICAgIHJlcTogZXhwcmVzcy5SZXF1ZXN0LFxuICAgIHJlczogZXhwcmVzcy5SZXNwb25zZSxcbiAgICByZXF1ZXN0Q29udGV4dDogUmVxdWVzdENvbnRleHQsXG4gICkge1xuICAgIGlmIChyZXF1ZXN0Q29udGV4dC5nZXQoTUFTVFJBX1JFUVVFU1RfSURfS0VZKSkgcmV0dXJuO1xuICAgIGNvbnN0IGhlYWRlclZhbHVlID0gcmVxLmhlYWRlcnNbXCJ4LXJlcXVlc3QtaWRcIl07XG4gICAgY29uc3QgdXBzdHJlYW0gPSBBcnJheS5pc0FycmF5KGhlYWRlclZhbHVlKSA/IGhlYWRlclZhbHVlWzBdIDogaGVhZGVyVmFsdWU7XG4gICAgY29uc3QgcmVxdWVzdElkID0gdXBzdHJlYW0/LnRyaW0oKSB8fCBoYXNoLmlkKCk7XG4gICAgcmVxdWVzdENvbnRleHQuc2V0KE1BU1RSQV9SRVFVRVNUX0lEX0tFWSwgcmVxdWVzdElkKTtcbiAgICByZXMuc2V0SGVhZGVyKFwiWC1SZXF1ZXN0LUlkXCIsIHJlcXVlc3RJZCk7XG4gIH1cblxuICAvKipcbiAgICogU3RhbXAgT0F1dGggc2NvcGVzIGZyb20gdGhlIGZvcndhcmRlZCBhY2Nlc3MgdG9rZW4gb25cbiAgICoge0BsaW5rIE1BU1RSQV9TQ09QRVNfS0VZfSBmb3Igd29ya3NwYWNlIG1vdW50IGdhdGluZy5cbiAgICovXG4gIGNvbmZpZ3VyZVJlcXVlc3RDb250ZXh0U2NvcGVzKHJlcTogZXhwcmVzcy5SZXF1ZXN0LCByZXF1ZXN0Q29udGV4dDogUmVxdWVzdENvbnRleHQpIHtcbiAgICBjb25zdCBzY29wZXMgPSBbXG4gICAgICAuLi5vYmplY3RcbiAgICAgICAgLnNlcXVlbmNlKHRva2VuLmdldEFjY2Vzc1Rva2VuU2NvcGVzKHJlcSksIHRva2VuLmdldEFjY2Vzc1Rva2VuU2NvcGVzKHJlcSwgXCJhdXRob3JpemF0aW9uXCIpKVxuICAgICAgICAuZGlzdGluY3QoKSxcbiAgICBdO1xuICAgIHJlcXVlc3RDb250ZXh0LnNldChNQVNUUkFfU0NPUEVTX0tFWSwgc2NvcGVzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTdGFtcCB0aGUgdHVybidzIE1MZmxvdyB0cmFjZSBpZCBvbiB0aGUgcmVzcG9uc2Ugc28gdGhlIGNoYXQgY2xpZW50XG4gICAqIGNhbiBhdHRhY2ggdGh1bWJzIC8gY29tbWVudCBmZWVkYmFjayB0byBpdCBsYXRlci4gTUxmbG93IGRlcml2ZXNcbiAgICogaXRzIHRyYWNlIGlkIGZyb20gdGhlIE9wZW5UZWxlbWV0cnkgdHJhY2UgaWQgKGB0ci08aGV4PmApLCBhbmQgZXZlcnlcbiAgICogTWFzdHJhIHNwYW4gZm9yIHRoaXMgcmVxdWVzdCBpbmhlcml0cyB0aGUgYW1iaWVudCBPVGVsIGNvbnRleHQgKHNlZVxuICAgKiBgb2JzZXJ2YWJpbGl0eS50c2ApLCBzbyB0aGUgYWN0aXZlIHNwYW4ncyB0cmFjZSBpZCBoZXJlIGlzIHRoZSBpZFxuICAgKiBNTGZsb3cgd2lsbCByZWNvcmQgZm9yIHRoZSB0dXJuLlxuICAgKlxuICAgKiBOby1vcCB1bmxlc3MgZmVlZGJhY2sgaXMgZW5hYmxlZCwgYW5kIHdoZW4gbm8gbGl2ZSBPVGVsIHNwYW4gaXNcbiAgICogYWN0aXZlIChlLmcuIHRoZSBPVExQIFNESyBpc24ndCByZWdpc3RlcmVkKTogaW4gdGhhdCBjYXNlIHRoZSBoZWFkZXJcbiAgICogaXMgc2ltcGx5IGFic2VudCBhbmQgdGhlIGNsaWVudCBoaWRlcyBmZWVkYmFjayBmb3IgdGhhdCBtZXNzYWdlLFxuICAgKiBkZWdyYWRpbmcgZ3JhY2VmdWxseSByYXRoZXIgdGhhbiBlbWl0dGluZyBhIGJvZ3VzIHRyYWNlIGlkLlxuICAgKi9cbiAgY29uZmlndXJlTWxmbG93VHJhY2VJZChyZXM6IGV4cHJlc3MuUmVzcG9uc2UpIHtcbiAgICBpZiAoIXRoaXMuZmVlZGJhY2tFbmFibGVkIHx8IHJlcy5oZWFkZXJzU2VudCkgcmV0dXJuO1xuICAgIGNvbnN0IHRyYWNlSWQgPSB0cmFjZS5nZXRBY3RpdmVTcGFuKCk/LnNwYW5Db250ZXh0KCkudHJhY2VJZDtcbiAgICBpZiAoIXRyYWNlSWQgfHwgdHJhY2VJZCA9PT0gSU5WQUxJRF9UUkFDRV9JRCkgcmV0dXJuO1xuICAgIHJlcy5zZXRIZWFkZXIoZmVlZGJhY2suTUxGTE9XX1RSQUNFX0lEX0hFQURFUiwgYHRyLSR7dHJhY2VJZH1gKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXNvbHZlIHRoZSB0aHJlYWQgaWQgdGhpcyByZXF1ZXN0IHRhcmdldHMgYW5kIHBpbiBpdCBvblxuICAgKiBgUmVxdWVzdENvbnRleHRgIChjb25zdW1lZCBieSB0aGUgYWdlbnQgc3RyZWFtIGZvciBwZXJzaXN0ZW5jZSBhbmRcbiAgICogYnkgdGhlIGhpc3RvcnkgLyB0aHJlYWRzIHJvdXRlcykuIFJlc29sdXRpb24gb3JkZXI6XG4gICAqXG4gICAqICAgMS4gQSBjbGllbnQtc3VwcGxpZWQgdGhyZWFkIGlkICh0aGUgdGhyZWFkLXNlbGVjdGlvbiBoZWFkZXIgL1xuICAgKiAgICAgIGA/dGhyZWFkSWQ9YCBxdWVyeSkuIFRoaXMgaXMgaG93IHRoZSBjaGF0IFVJIHJlZmVyZW5jZXMgYVxuICAgKiAgICAgIHNwZWNpZmljIGNvbnZlcnNhdGlvbiBhbW9uZyB0aGUgbWFueSBhIHVzZXIgb3ducyAtIGl0IHBpY2tzIGFcbiAgICogICAgICB0aHJlYWQgaWQgZnJvbSB0aGUgYC90aHJlYWRzYCBsaXN0aW5nIChvciBtaW50cyBvbmUgZm9yIGEgbmV3XG4gICAqICAgICAgY29udmVyc2F0aW9uKSBhbmQgc3RhbXBzIGl0IGhlcmUuIFRoZSBpZCBpcyBzY29wZWQgdG8gdGhlXG4gICAqICAgICAgY2FsbGVyJ3MgcmVzb3VyY2UgYnkgdGhlIHJlY2FsbCAvIGxpc3Qgcm91dGVzLCBzbyBhIGNsaWVudFxuICAgKiAgICAgIGNhbiBvbmx5IGV2ZXIgcmVhZCBvciB3cml0ZSBpdHMgb3duIHRocmVhZHMuXG4gICAqICAgMi4gVGhlIHBlci1zZXNzaW9uIGNvb2tpZSAoYGFwcGtpdF88cGx1Z2luLW5hbWU+X3Nlc3Npb25faWRgKSxcbiAgICogICAgICBtaW50ZWQgb24gZmlyc3QgY29udGFjdC4gVGhpcyBpcyB0aGUgZGVmYXVsdCBzaW5nbGUtdGhyZWFkXG4gICAqICAgICAgZmFsbGJhY2sgZm9yIGNsaWVudHMgdGhhdCBkb24ndCBtYW5hZ2UgdGhyZWFkcyBleHBsaWNpdGx5LCBzb1xuICAgKiAgICAgIGV4aXN0aW5nIGVtYmVkcyBrZWVwIG9uZSBzdGFibGUgY29udmVyc2F0aW9uIHBlciBzZXNzaW9uIHdpdGhcbiAgICogICAgICBubyBjbGllbnQgY2hhbmdlcy5cbiAgICovXG4gIGNvbmZpZ3VyZVJlcXVlc3RDb250ZXh0VGhyZWFkSWQoXG4gICAgcmVxOiBleHByZXNzLlJlcXVlc3QsXG4gICAgcmVzOiBleHByZXNzLlJlc3BvbnNlLFxuICAgIHJlcXVlc3RDb250ZXh0OiBSZXF1ZXN0Q29udGV4dCxcbiAgKSB7XG4gICAgaWYgKHJlcXVlc3RDb250ZXh0LmdldChNQVNUUkFfVEhSRUFEX0lEX0tFWSkpIHJldHVybjtcbiAgICBjb25zdCByZXF1ZXN0ZWQgPSB0aGlzLnJlYWRSZXF1ZXN0ZWRUaHJlYWRJZChyZXEpO1xuICAgIGlmIChyZXF1ZXN0ZWQpIHtcbiAgICAgIHJlcXVlc3RDb250ZXh0LnNldChNQVNUUkFfVEhSRUFEX0lEX0tFWSwgcmVxdWVzdGVkKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgY29va2llcyA9IGh0dHAucGFyc2VDb29raWVzKHJlcS5oZWFkZXJzLmNvb2tpZSk7XG4gICAgY29uc3QgY29va2llTmFtZSA9IHN0cmluZy50b0lkZW50aWZpZXJXaXRoT3B0aW9ucyhcbiAgICAgIHsgZGVsaW1pdGVyOiBcIl9cIiwgZGlzdGluY3Q6IHRydWUgfSxcbiAgICAgIFwiYXBwa2l0XCIsXG4gICAgICB0aGlzLmNvbmZpZy5uYW1lISxcbiAgICAgIFwic2Vzc2lvbklkXCIsXG4gICAgKTtcbiAgICBsZXQgc2Vzc2lvbklkID0gY29va2llc1tjb29raWVOYW1lXTtcbiAgICBpZiAoIXNlc3Npb25JZCkge1xuICAgICAgc2Vzc2lvbklkID0gaGFzaC5pZCgpO1xuICAgICAgcmVzLmNvb2tpZShjb29raWVOYW1lLCBzZXNzaW9uSWQsIHtcbiAgICAgICAgaHR0cE9ubHk6IHRydWUsXG4gICAgICAgIHNhbWVTaXRlOiBcImxheFwiLFxuICAgICAgICBzZWN1cmU6IHJlcS5zZWN1cmUsXG4gICAgICAgIHBhdGg6IFwiL1wiLFxuICAgICAgfSk7XG4gICAgfVxuICAgIHJlcXVlc3RDb250ZXh0LnNldChNQVNUUkFfVEhSRUFEX0lEX0tFWSwgc2Vzc2lvbklkKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZWFkIHRoZSBjbGllbnQtc2VsZWN0ZWQgdGhyZWFkIGlkIGZyb20gdGhlIHJlcXVlc3QsIHByZWZlcnJpbmdcbiAgICogdGhlIHRocmVhZC1zZWxlY3Rpb24gaGVhZGVyIG92ZXIgdGhlIGA/dGhyZWFkSWQ9YCBxdWVyeS4gUmV0dXJuc1xuICAgKiBgbnVsbGAgd2hlbiBuZWl0aGVyIGNhcnJpZXMgYSBub24tZW1wdHkgdmFsdWUgc28gdGhlIGNhbGxlciBmYWxsc1xuICAgKiBiYWNrIHRvIHRoZSBzZXNzaW9uIGNvb2tpZS5cbiAgICovXG4gIHByaXZhdGUgcmVhZFJlcXVlc3RlZFRocmVhZElkKHJlcTogZXhwcmVzcy5SZXF1ZXN0KTogc3RyaW5nIHwgbnVsbCB7XG4gICAgY29uc3QgaGVhZGVyVmFsdWUgPSByZXEuaGVhZGVyc1t0aHJlYWQuVEhSRUFEX0lEX0hFQURFUl07XG4gICAgY29uc3QgcXVlcnlWYWx1ZSA9IHJlcS5xdWVyeVt0aHJlYWQuVEhSRUFEX0lEX1FVRVJZXTtcbiAgICByZXR1cm4gKFxuICAgICAgc3RyaW5nLnRyaW1Ub051bGwoQXJyYXkuaXNBcnJheShoZWFkZXJWYWx1ZSkgPyBoZWFkZXJWYWx1ZVswXSA6IGhlYWRlclZhbHVlKSA/P1xuICAgICAgc3RyaW5nLnRyaW1Ub051bGwoQXJyYXkuaXNBcnJheShxdWVyeVZhbHVlKSA/IHF1ZXJ5VmFsdWVbMF0gOiBxdWVyeVZhbHVlKVxuICAgICk7XG4gIH1cblxuICBjb25maWd1cmVSZXF1ZXN0Q29udGV4dE1vZGVsT3ZlcnJpZGUocmVxOiBleHByZXNzLlJlcXVlc3QsIHJlcXVlc3RDb250ZXh0OiBSZXF1ZXN0Q29udGV4dCkge1xuICAgIC8vIFBlci1yZXF1ZXN0IG1vZGVsIG92ZXJyaWRlOiBvbmx5IGhvbm9yZWQgd2hlbiB0aGUgcGx1Z2luXG4gICAgLy8gb3B0cyBpbiAoZGVmYXVsdCkuIFNvdXJjZXMsIGluIHByaW9yaXR5IG9yZGVyLCBhcmVcbiAgICAvLyBgWC1NYXN0cmEtTW9kZWxgIGhlYWRlciwgYD9tb2RlbD1gIHF1ZXJ5LCBhbmQgYG1vZGVsYCAvXG4gICAgLy8gYG1vZGVsSWRgIGJvZHkgZmllbGQ7IHNlZSBgc2VydmluZy50c2AuXG4gICAgY29uc3Qgc2VydmluZyA9IHJlc29sdmVTZXJ2aW5nQ29uZmlnKHRoaXMuY29uZmlnKTtcbiAgICBpZiAoc2VydmluZy5hbGxvd092ZXJyaWRlKSB7XG4gICAgICBjb25zdCBvdmVycmlkZSA9IGV4dHJhY3RNb2RlbE92ZXJyaWRlKHtcbiAgICAgICAgaGVhZGVyczogcmVxLmhlYWRlcnMgYXMgUmVjb3JkPHN0cmluZywgc3RyaW5nIHwgc3RyaW5nW10gfCB1bmRlZmluZWQ+LFxuICAgICAgICBxdWVyeTogcmVxLnF1ZXJ5IGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+LFxuICAgICAgICBib2R5OiByZXEuYm9keSxcbiAgICAgIH0pO1xuICAgICAgaWYgKG92ZXJyaWRlKSByZXF1ZXN0Q29udGV4dC5zZXQoTUFTVFJBX01PREVMX09WRVJSSURFX0tFWSwgb3ZlcnJpZGUpO1xuICAgIH1cbiAgfVxufVxuXG4vKiogSW5wdXRzIGZvciB7QGxpbmsgaXNNYXN0cmFSZXF1ZXN0QWxsb3dlZH0uICovXG5leHBvcnQgaW50ZXJmYWNlIE1hc3RyYUFwaUdhdGVPcHRpb25zIHtcbiAgLyoqIGBjb25maWcuYXBpQWNjZXNzYDsgYFwiZnVsbFwiYCBzaG9ydC1jaXJjdWl0cyB0byBhbGxvdyBldmVyeXRoaW5nLiAqL1xuICBhY2Nlc3M6IFwic2NvcGVkXCIgfCBcImZ1bGxcIjtcbiAgLyoqIFdoZXRoZXIgdGhlIE1DUCB0cmFuc3BvcnQgaXMgbW91bnRlZCAoc28gYC9tY3AvKmAgaXMgbGVnaXRpbWF0ZSkuICovXG4gIG1jcEVuYWJsZWQ6IGJvb2xlYW47XG59XG5cbi8qKlxuICogTW91bnQtcmVsYXRpdmUgYWdlbnQgaW5mZXJlbmNlIHBhdGhzIChgL2FnZW50cy86aWQvPHZlcmI+Li4uYCkuIE1hdGNoZWRcbiAqIGJ5IHByZWZpeCBvbiB0aGUgdmVyYiBzbyBmdXR1cmUgdmFyaWFudHMgKGBzdHJlYW1WTmV4dGAsIGBzdHJlYW0vdm5leHRgLFxuICogYGdlbmVyYXRlVk5leHRgKSBzdGF5IGNvdmVyZWQgd2l0aG91dCBhIGNvZGUgY2hhbmdlLlxuICpcbiAqIENvdmVycyB0aGUgcGxhaW4gaW5mZXJlbmNlIHZlcmJzIChgc3RyZWFtYCAvIGBnZW5lcmF0ZWAgLyBgbmV0d29ya2ApIHBsdXNcbiAqIHRoZSBodW1hbi1pbi10aGUtbG9vcCByZXN1bWUgdmVyYnMgYSBwYXVzZWQgYHJlcXVpcmVBcHByb3ZhbGAgdG9vbCBuZWVkc1xuICogdG8gY29udGludWU6IGBhcHByb3ZlLXRvb2wtY2FsbGAgLyBgZGVjbGluZS10b29sLWNhbGxgIChzdHJlYW1pbmcsIGFuZCB2aWFcbiAqIHByZWZpeCB0aGVpciBgLWdlbmVyYXRlYCBub24tc3RyZWFtaW5nIHZhcmlhbnRzKSwgdGhlIGAtbmV0d29yay1gIHZhcmlhbnRzLFxuICogYW5kIGByZXN1bWUtc3RyZWFtYCAoY292ZXJzIGByZXN1bWUtc3RyZWFtLXVudGlsLWlkbGVgKS4gV2l0aG91dCB0aGVzZSBhblxuICogYXBwcm92YWwtZ2F0ZWQgdG9vbCAoZS5nLiBgc2VuZF9lbWFpbGApIGNhbiBiZSByZXF1ZXN0ZWQgYnV0IG5ldmVyIGFwcHJvdmVkXG4gKiBmcm9tIHRoZSBicm93c2VyIC0gdGhlIHJlc3VtZSBgUE9TVGAgNDAzcyB1bmRlciBzY29wZWQgbW9kZS4gVGhlc2UgYXJlIHRoZVxuICogb25seSAqd3JpdGVzKiB0aGUgYnJvd3NlciBjbGllbnQgaXMgYWxsb3dlZCB0byBtYWtlIGFnYWluc3Qgc3RvY2sgTWFzdHJhLlxuICovXG5jb25zdCBBR0VOVF9JTkZFUkVOQ0UgPVxuICAvXlxcL2FnZW50c1xcL1teL10rXFwvKHN0cmVhbXxnZW5lcmF0ZXxuZXR3b3JrfHJlc3VtZS1zdHJlYW18YXBwcm92ZS10b29sLWNhbGx8ZGVjbGluZS10b29sLWNhbGx8YXBwcm92ZS1uZXR3b3JrLXRvb2wtY2FsbHxkZWNsaW5lLW5ldHdvcmstdG9vbC1jYWxsKS9pO1xuXG4vKiogTW91bnQtcmVsYXRpdmUgcmVhZC1vbmx5IGFnZW50IG1ldGFkYXRhIChgL2FnZW50c2AsIGAvYWdlbnRzLzppZGApLiAqL1xuY29uc3QgQUdFTlRfTUVUQURBVEEgPSAvXlxcL2FnZW50cyhcXC9bXi9dKyk/JC87XG5cbi8qKlxuICogV2hldGhlciBhIHJlcXVlc3QgdG8gdGhlIHN0b2NrIGBAbWFzdHJhL2V4cHJlc3NgIHN1Yi1hcHAgc2hvdWxkIGJlXG4gKiBkaXNwYXRjaGVkLCBnaXZlbiB0aGUgY29uZmlndXJlZCB7QGxpbmsgTWFzdHJhQXBpR2F0ZU9wdGlvbnMuYWNjZXNzfS5cbiAqXG4gKiBgcGF0aGAgaXMgbW91bnQtcmVsYXRpdmUgKHdoYXQgdGhlIHBsdWdpbidzIGNhdGNoLWFsbCBzZWVzLCBlLmcuXG4gKiBgL2FnZW50cy94L3N0cmVhbWAsIGAvcm91dGUvaGlzdG9yeS94YCwgYC9tY3AvLi4uYCkuIEluIGBcInNjb3BlZFwiYFxuICogbW9kZSB0aGUgYWxsb3dsaXN0IGlzIGRlbGliZXJhdGVseSB0aWdodCAtIHRoZSBjaGF0IGNsaWVudCBvbmx5IGV2ZXJcbiAqIG5lZWRzIGFnZW50IGluZmVyZW5jZSwgcmVhZC1vbmx5IGFnZW50IG1ldGFkYXRhLCB0aGlzIHBsdWdpbidzIG93blxuICogT0JPL3Jlc291cmNlLXNjb3BlZCBgL3JvdXRlLypgIHJvdXRlcywgYW5kICh3aGVuIGVuYWJsZWQpIE1DUCAtIHNvIHRoZVxuICogd2hvbGUgYWRtaW4gLyBtdXRhdGluZyAvIGJ1bGstZXhwb3J0IHN1cmZhY2UgTWFzdHJhIGFsc28gZXhwb3NlcyBpc1xuICogZGVuaWVkIGJ5IGRlZmF1bHQgcmF0aGVyIHRoYW4gZW51bWVyYXRlZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzTWFzdHJhUmVxdWVzdEFsbG93ZWQoXG4gIG1ldGhvZDogc3RyaW5nLFxuICBwYXRoOiBzdHJpbmcsXG4gIG9wdHM6IE1hc3RyYUFwaUdhdGVPcHRpb25zLFxuKTogYm9vbGVhbiB7XG4gIGlmIChvcHRzLmFjY2VzcyA9PT0gXCJmdWxsXCIpIHJldHVybiB0cnVlO1xuICBjb25zdCBwID0gcGF0aC5zdGFydHNXaXRoKFwiL1wiKSA/IHBhdGggOiBgLyR7cGF0aH1gO1xuICAvLyBUaGlzIHBsdWdpbidzIG93biBjdXN0b20gcm91dGVzIGFyZSBpbmRpdmlkdWFsbHkgT0JPLSBhbmRcbiAgLy8gcmVzb3VyY2Utc2NvcGVkIChzZWUgaGlzdG9yeS50cyAvIHRocmVhZHMudHMpLCBzbyBldmVyeSBtZXRob2QgaXMgc2FmZS5cbiAgaWYgKHAgPT09IFwiL3JvdXRlXCIgfHwgcC5zdGFydHNXaXRoKFwiL3JvdXRlL1wiKSkgcmV0dXJuIHRydWU7XG4gIGlmIChvcHRzLm1jcEVuYWJsZWQgJiYgKHAgPT09IFwiL21jcFwiIHx8IHAuc3RhcnRzV2l0aChcIi9tY3AvXCIpKSkgcmV0dXJuIHRydWU7XG4gIGNvbnN0IG0gPSBtZXRob2QudG9VcHBlckNhc2UoKTtcbiAgaWYgKG0gPT09IFwiUE9TVFwiICYmIEFHRU5UX0lORkVSRU5DRS50ZXN0KHApKSByZXR1cm4gdHJ1ZTtcbiAgaWYgKG0gPT09IFwiR0VUXCIgJiYgQUdFTlRfTUVUQURBVEEudGVzdChwKSkgcmV0dXJuIHRydWU7XG4gIHJldHVybiBmYWxzZTtcbn1cblxuLyoqXG4gKiBQYXRjaGVzIGFyb3VuZCBgQG1hc3RyYS9leHByZXNzYCdzIGN1c3RvbS1yb3V0ZSBkaXNwYXRjaGVyIHNvIHRoZVxuICogcGx1Z2luJ3MgY3VzdG9tIEFQSSByb3V0ZXMgKGUuZy4gYGhpc3RvcnlSb3V0ZWApIHdvcmsgd2hlblxuICogYE1hc3RyYVNlcnZlcmAgaXMgaG9zdGVkIG9uIGFuIEV4cHJlc3Mgc3ViYXBwIG1vdW50ZWQgdW5kZXIgYSBwYXJlbnRcbiAqIHBhdGggKGUuZy4gYC9hcGkvbWFzdHJhYCkuXG4gKlxuICogVGhlIGFkYXB0ZXIncyBgcmVnaXN0ZXJDdXN0b21BcGlSb3V0ZXNgIG1hdGNoZXMgYWdhaW5zdCBgcmVxLnBhdGhgXG4gKiAobW91bnQtcmVsYXRpdmUsIGNvcnJlY3QpIGJ1dCBkaXNwYXRjaGVzIHRvIGl0cyBpbnRlcm5hbCBIb25vXG4gKiBtaW5pLWFwcCB1c2luZyBgcmVxLm9yaWdpbmFsVXJsYCwgd2hpY2ggc3RpbGwgY29udGFpbnMgdGhlIHBhcmVudFxuICogbW91bnQgcHJlZml4LiBUaGUgSG9ubyBhcHAgcmVnaXN0ZXJzIHRoZSBsaXRlcmFsIHJvdXRlIHBhdGhzXG4gKiAoZm9yIGV4YW1wbGUgYC9yb3V0ZS9oaXN0b3J5YCksIHNvIHRoZSBhYnNvbHV0ZSBVUkwgbmV2ZXIgbWF0Y2hlc1xuICogdW50aWwgd2Ugb3ZlcndyaXRlIGBvcmlnaW5hbFVybGAgZm9yIGAvcm91dGVgIGFuZCBgL3JvdXRlLypgIHRvIHRoZVxuICogbW91bnQtcmVsYXRpdmUgcGF0aC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGF0dGFjaFJvdXRlUGF0Y2hNaWRkbGV3YXJlKGFwcDogZXhwcmVzcy5FeHByZXNzKTogdm9pZCB7XG4gIGFwcC51c2UoKHJlcSwgX3JlcywgbmV4dCkgPT4ge1xuICAgIGNvbnN0IGlzQ3VzdG9tUm91dGUgPSByZXEucGF0aCA9PT0gXCIvcm91dGVcIiB8fCByZXEucGF0aC5zdGFydHNXaXRoKFwiL3JvdXRlL1wiKTtcbiAgICBpZiAoIWlzQ3VzdG9tUm91dGUpIHJldHVybiBuZXh0KCk7XG4gICAgcmVxLm9yaWdpbmFsVXJsID0gcmVxLnBhdGg7XG4gICAgbmV4dCgpO1xuICB9KTtcbn1cbiJdfQ==
@@ -1 +1 @@
1
- {"root":["../src/agents.ts","../src/chart.ts","../src/config.ts","../src/defaults.ts","../src/filesystems.ts","../src/genie.ts","../src/history.ts","../src/mcp.ts","../src/memory.ts","../src/mlflow.ts","../src/model.ts","../src/observability.ts","../src/pagination.ts","../src/plugin.ts","../src/processors.ts","../src/rest.ts","../src/server.ts","../src/serving-sanitize.ts","../src/serving.ts","../src/statement.ts","../src/storage-schema.ts","../src/summarize.ts","../src/threads.ts","../src/validation.ts","../src/workspaces.ts","../src/writer.ts","../index.ts"],"version":"5.9.3"}
1
+ {"root":["../src/agents.ts","../src/chart.ts","../src/config.ts","../src/defaults.ts","../src/filesystems.ts","../src/genie.ts","../src/history.ts","../src/identity.ts","../src/mcp.ts","../src/memory.ts","../src/mlflow.ts","../src/model.ts","../src/observability.ts","../src/pagination.ts","../src/plugin.ts","../src/processors.ts","../src/rest.ts","../src/server.ts","../src/serving-sanitize.ts","../src/serving.ts","../src/statement.ts","../src/storage-schema.ts","../src/summarize.ts","../src/threads.ts","../src/validation.ts","../src/workspaces.ts","../src/writer.ts","../index.ts"],"version":"5.9.3"}
package/package.json CHANGED
@@ -28,21 +28,21 @@
28
28
  "express": "^5.1.0",
29
29
  "pg": "^8.22.0",
30
30
  "zod": "4.3.6",
31
- "@dbx-tools/appkit": "0.5.0",
32
- "@dbx-tools/core": "0.5.0",
33
- "@dbx-tools/model": "0.5.0",
34
- "@dbx-tools/shared-core": "0.5.0",
35
- "@dbx-tools/shared-model": "0.5.0",
36
- "@dbx-tools/genie": "0.5.0",
37
- "@dbx-tools/shared-mastra": "0.5.0",
38
- "@dbx-tools/shared-genie": "0.5.0"
31
+ "@dbx-tools/core": "0.6.0",
32
+ "@dbx-tools/genie": "0.6.0",
33
+ "@dbx-tools/appkit": "0.6.0",
34
+ "@dbx-tools/shared-core": "0.6.0",
35
+ "@dbx-tools/model": "0.6.0",
36
+ "@dbx-tools/shared-genie": "0.6.0",
37
+ "@dbx-tools/shared-mastra": "0.6.0",
38
+ "@dbx-tools/shared-model": "0.6.0"
39
39
  },
40
40
  "main": "./lib/index.js",
41
41
  "license": "UNLICENSED",
42
42
  "publishConfig": {
43
43
  "access": "public"
44
44
  },
45
- "version": "0.5.0",
45
+ "version": "0.6.0",
46
46
  "types": "./lib/index.d.ts",
47
47
  "type": "module",
48
48
  "exports": {
package/src/config.ts CHANGED
@@ -24,6 +24,7 @@ import type { PgVectorConfig, PostgresStoreConfig } from "@mastra/pg";
24
24
 
25
25
  import type { MastraAgentDefinition, MastraTools } from "./agents.ts";
26
26
  import type { GenieSpacesConfig } from "./genie.ts";
27
+ import type { MastraIdentityMode } from "./identity.ts";
27
28
 
28
29
  /**
29
30
  * `RequestContext` key under which {@link MastraServer} stores the
@@ -479,6 +480,38 @@ export interface MastraPluginConfig extends BasePluginConfig {
479
480
  * surface.
480
481
  */
481
482
  apiAccess?: "scoped" | "full";
483
+ /**
484
+ * Which Databricks identity the agents' workspace calls run as: the
485
+ * serving-endpoint catalogue behind the model picker, Genie suggestions,
486
+ * `ask_genie`, and the Statement Execution fetch behind a `[data:<id>]`
487
+ * embed. Falls back to `MASTRA_GENIE_IDENTITY`, then `"user"`.
488
+ *
489
+ * On-behalf-of (OBO) auth requires the caller to be a member of the
490
+ * WORKSPACE, not just of the Databricks account. An app shared with an
491
+ * account-level group can be opened by someone whose token is valid but whose
492
+ * every workspace call fails with `Unauthorized access to Org: <id>` - and
493
+ * granting workspace membership is not always possible, since a workspace
494
+ * caps membership well below the size of a large account's user group. The
495
+ * app's service principal already holds the grants the app was deployed with.
496
+ *
497
+ * - `"user"` (default): always OBO. Per-user attribution, and Genie / Unity
498
+ * Catalog row filters apply per user. Correct when every caller is a
499
+ * workspace member, and unchanged from before this option existed.
500
+ * - `"service-principal"`: always the app service principal. Needs no OBO
501
+ * scopes and works for any caller who can open the app, at the cost of
502
+ * per-user attribution in Genie / Unity Catalog.
503
+ *
504
+ * `"service-principal"` changes only the Databricks CREDENTIAL. Memory
505
+ * threads, the per-user cache namespace, and trace metadata still key off the
506
+ * forwarded user, so callers sharing the service principal's data access keep
507
+ * separate conversations and cannot read each other's threads or charts.
508
+ *
509
+ * @example An app any account user can open
510
+ * ```ts
511
+ * mastra({ genieIdentity: "service-principal", genieSpaces: { default: spaceId } });
512
+ * ```
513
+ */
514
+ genieIdentity?: MastraIdentityMode;
482
515
  /**
483
516
  * Optional brand context applied to charts produced by the built-in
484
517
  * `render_data` / `prepare_chart` tools. When set, the chart planner's
@@ -598,6 +631,12 @@ export const MASTRA_CONFIG_SCHEMA: ConfigSchema = {
598
631
  description:
599
632
  "Expose the registered agents over MCP. Defaults to agents-only; an object tunes the server id, advertised metadata, and whether ambient tools are exposed.",
600
633
  },
634
+ genieIdentity: {
635
+ type: "string",
636
+ enum: ["user", "service-principal"],
637
+ description:
638
+ 'Which Databricks identity the agents\' workspace calls (serving catalogue, Genie, statement execution) run as. "user" (default) is always OBO, so callers must be workspace members; "service-principal" always uses the app service principal, so any caller who can open the app works, at the cost of per-user attribution. Falls back to MASTRA_GENIE_IDENTITY.',
639
+ },
601
640
  apiAccess: {
602
641
  type: "string",
603
642
  enum: ["scoped", "full"],
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Which Databricks identity a chat turn's workspace calls run as.
3
+ *
4
+ * Every Databricks call a turn makes - the `/serving-endpoints` catalogue the
5
+ * model picker reads, Genie suggestions, `ask_genie`, and the Statement
6
+ * Execution fetch behind a `[data:<id>]` embed - goes through the workspace
7
+ * client on the ambient AppKit execution context. That context is user-scoped
8
+ * (OBO) whenever the plugin enters `asUser(req)` and the app's service principal
9
+ * otherwise, so ONE decision - do we enter that scope for this request - moves
10
+ * every call site together. This module owns that decision.
11
+ *
12
+ * Why the option exists: OBO requires the caller to be a member of the
13
+ * WORKSPACE, not merely of the Databricks account. An app shared with an
14
+ * account-level group can therefore be opened by someone whose OBO token is
15
+ * perfectly valid but whose every workspace call fails with `Unauthorized
16
+ * access to Org: <workspace-id>`, and granting workspace membership is not
17
+ * always available - a workspace caps membership far below the size of a large
18
+ * account's user group. The app's own service principal already holds the Genie
19
+ * / warehouse / serving / Unity Catalog grants the app was deployed with, and
20
+ * works for every caller.
21
+ *
22
+ * The two modes, from `config.genieIdentity` (env: {@link IDENTITY_ENV}):
23
+ *
24
+ * - `"user"` (default): always OBO. Calls are attributed per user and Genie /
25
+ * Unity Catalog row filters apply per user. Correct whenever every caller is
26
+ * a workspace member. This is the historical behavior, so the option is
27
+ * purely additive - an app that never sets it is unchanged.
28
+ * - `"service-principal"`: always the app service principal. Needs no OBO
29
+ * scopes and works for any caller who can open the app, at the cost of
30
+ * per-user attribution in Genie / Unity Catalog.
31
+ *
32
+ * What `"service-principal"` does NOT change is WHO the turn belongs to. The
33
+ * memory thread's `resourceId`, the per-user cache namespace, and the user
34
+ * metadata on traces still come from the forwarded request headers, so two
35
+ * account users sharing the service principal's data access still get separate
36
+ * conversations and cannot read each other's threads or cached charts. Only the
37
+ * Databricks credential is shared.
38
+ *
39
+ * @module
40
+ */
41
+
42
+ import { ConfigurationError } from "@databricks/appkit";
43
+ import { string } from "@dbx-tools/shared-core";
44
+ import type express from "express";
45
+
46
+ /** Identity a chat turn's Databricks calls run as. See the module docs. */
47
+ export type MastraIdentityMode = "user" | "service-principal";
48
+
49
+ /** Environment fallback for `config.genieIdentity`. */
50
+ export const IDENTITY_ENV = "MASTRA_GENIE_IDENTITY";
51
+
52
+ /** Every accepted {@link MastraIdentityMode}. */
53
+ export const IDENTITY_MODES: readonly MastraIdentityMode[] = ["user", "service-principal"];
54
+
55
+ /**
56
+ * Default mode. `"user"` keeps OBO the only identity unless an app opts in, so
57
+ * adopting this option can never silently widen an existing app's data access.
58
+ */
59
+ export const DEFAULT_IDENTITY_MODE: MastraIdentityMode = "user";
60
+
61
+ /**
62
+ * Resolve the configured mode: explicit plugin config, then {@link IDENTITY_ENV},
63
+ * then {@link DEFAULT_IDENTITY_MODE}.
64
+ *
65
+ * An unrecognized value throws rather than falling back, since falling back
66
+ * would silently keep serving OBO - and the 500s it produces - to exactly the
67
+ * callers the option was set to accommodate.
68
+ */
69
+ export function resolveIdentityMode(configured: string | undefined): MastraIdentityMode {
70
+ const raw = string.trimToNull(configured) ?? string.trimToNull(process.env[IDENTITY_ENV]);
71
+ if (raw === null) return DEFAULT_IDENTITY_MODE;
72
+ const mode = raw.toLowerCase() as MastraIdentityMode;
73
+ if (!IDENTITY_MODES.includes(mode)) {
74
+ throw new ConfigurationError(
75
+ `genieIdentity must be one of ${IDENTITY_MODES.join(" | ")} (env: ${IDENTITY_ENV})`,
76
+ { context: { field: "genieIdentity", envVar: IDENTITY_ENV, received: raw } },
77
+ );
78
+ }
79
+ return mode;
80
+ }
81
+
82
+ /** Header Databricks Apps forward the signed-in user's id on. */
83
+ export const USER_ID_HEADER = "x-forwarded-user";
84
+
85
+ /** Header Databricks Apps forward the signed-in user's email on. */
86
+ export const USER_EMAIL_HEADER = "x-forwarded-email";
87
+
88
+ /**
89
+ * The forwarded user id on `req`, or `undefined`. Used to attribute a turn to
90
+ * the real caller in `service-principal` mode, where the Databricks client is
91
+ * the app SP but memory / cache / traces must still key off the user.
92
+ */
93
+ export function requestUserId(req: express.Request): string | undefined {
94
+ return string.trimToNull(req.header(USER_ID_HEADER)) ?? undefined;
95
+ }
96
+
97
+ /** The forwarded user email on `req`, or `undefined`. */
98
+ export function requestUserEmail(req: express.Request): string | undefined {
99
+ return string.trimToNull(req.header(USER_EMAIL_HEADER)) ?? undefined;
100
+ }
101
+
102
+ /**
103
+ * Whether this request should run its Databricks calls as the app service
104
+ * principal rather than OBO. `"service-principal"` always does; `"user"` never
105
+ * does. The request is accepted for symmetry and to leave room for
106
+ * request-scoped policy later; it is unused today.
107
+ */
108
+ export function useServicePrincipal(mode: MastraIdentityMode, _req?: express.Request): boolean {
109
+ return mode === "service-principal";
110
+ }
package/src/plugin.ts CHANGED
@@ -86,6 +86,7 @@ import {
86
86
  } from "./defaults.ts";
87
87
  import { collectSpaceSuggestions, resolveGenieSpaces } from "./genie.ts";
88
88
  import { historyRoute } from "./history.ts";
89
+ import { resolveIdentityMode, useServicePrincipal, type MastraIdentityMode } from "./identity.ts";
89
90
  import { buildMcpServer, type ResolvedMcp } from "./mcp.ts";
90
91
  import { createMemoryBuilder, createServicePrincipalPool, needsLakebase } from "./memory.ts";
91
92
  import { logFeedback, resolveFeedbackEnabled } from "./mlflow.ts";
@@ -217,6 +218,12 @@ export class MastraPlugin extends Plugin<MastraPluginConfig> {
217
218
  * {@link buildAgentAndServer} and registered on the Mastra instance.
218
219
  */
219
220
  private mcp: ResolvedMcp | null = null;
221
+ /**
222
+ * Resolved {@link MastraIdentityMode}: the identity the chat path's Databricks
223
+ * calls run as. Read once at setup so an invalid `genieIdentity` fails the app
224
+ * boot rather than the first request, and so every request agrees.
225
+ */
226
+ private identityMode: MastraIdentityMode = "user";
220
227
  /**
221
228
  * Dedicated service-principal Lakebase pool backing Mastra memory /
222
229
  * storage. Built once in {@link buildAgentAndServer} (outside any
@@ -227,6 +234,9 @@ export class MastraPlugin extends Plugin<MastraPluginConfig> {
227
234
  private servicePrincipalPool: Pool | null = null;
228
235
 
229
236
  override async setup(): Promise<void> {
237
+ // Resolve the identity mode up front so an invalid `genieIdentity` fails the
238
+ // app boot with a clear message rather than 500-ing the first chat request.
239
+ this.identityMode = resolveIdentityMode(this.config.genieIdentity);
230
240
  // Wait until sibling plugins (e.g. `lakebase`) finish `setup()` so
231
241
  // the lakebase pool is valid when storage/memory are enabled.
232
242
  this.context?.onLifecycle("setup:complete", async () => {
@@ -235,6 +245,25 @@ export class MastraPlugin extends Plugin<MastraPluginConfig> {
235
245
  });
236
246
  }
237
247
 
248
+ /**
249
+ * The plugin instance the chat path's Databricks calls should run through for
250
+ * `req`, honoring {@link identityMode}.
251
+ *
252
+ * In `"user"` mode (the default) this is `this.asUser(req)` - AppKit's own
253
+ * proxy that runs every call inside `runInUserContext`, so `getExecutionContext()`
254
+ * returns the caller's OBO client, exactly as before this option existed. In
255
+ * `"service-principal"` mode it is `this` unwrapped, so the same methods run in
256
+ * the ambient service context and `getExecutionContext()` returns the app
257
+ * service principal's client - the same "just don't enter `asUser`" pattern
258
+ * AppKit's own service-context calls use. One helper covers every workspace
259
+ * call the chat path makes (serving catalogue, Genie suggestions, `ask_genie`
260
+ * via the dispatched agent turn, statement fetch, feedback), so the identity
261
+ * decision lives in one place.
262
+ */
263
+ private scopedSelf(req: express.Request): this {
264
+ return useServicePrincipal(this.identityMode, req) ? this : this.asUser(req);
265
+ }
266
+
238
267
  /**
239
268
  * When the `lakebase` plugin is registered, auto-enable `storage`
240
269
  * and `memory` unless the caller opted out explicitly (`false` or a
@@ -402,6 +431,10 @@ export class MastraPlugin extends Plugin<MastraPluginConfig> {
402
431
  defaultAgent: this.built?.defaultAgentId ?? FALLBACK_AGENT_ID,
403
432
  agents: Object.keys(this.built?.agents ?? {}),
404
433
  feedbackEnabled: this.feedbackEnabled(),
434
+ // In `service-principal` mode the chat works for any caller who can open
435
+ // the app, so a UI that hides chat behind an OBO-token probe should show
436
+ // it regardless. `"user"` mode keeps the OBO-gated behavior.
437
+ chatAlwaysAvailable: this.identityMode === "service-principal",
405
438
  };
406
439
  return config as unknown as Record<string, unknown>;
407
440
  }
@@ -446,7 +479,7 @@ export class MastraPlugin extends Plugin<MastraPluginConfig> {
446
479
  method: "get",
447
480
  path: routes.MASTRA_ROUTES.models,
448
481
  handler: async (req, res) => {
449
- const result = await this.asUser(req).listModelsResult();
482
+ const result = await this.scopedSelf(req).listModelsResult();
450
483
  if (!result.ok) {
451
484
  this.sendFailure(res, result, "models", MODEL_CATALOGUE_FAILED_MESSAGE);
452
485
  return;
@@ -532,14 +565,14 @@ export class MastraPlugin extends Plugin<MastraPluginConfig> {
532
565
  const embedResolvers: Record<string, EmbedResolver> = {
533
566
  chart: (req, id, signal) => {
534
567
  const timeoutMs = parseTimeoutMs(req.query.timeoutMs);
535
- return this.asUser(req).fetchChartEntry(id, {
568
+ return this.scopedSelf(req).fetchChartEntry(id, {
536
569
  ...(timeoutMs !== undefined ? { timeoutMs } : {}),
537
570
  signal,
538
571
  });
539
572
  },
540
573
  data: (req, id, signal) => {
541
574
  const limit = parseStatementLimit(req.query.limit);
542
- return this.asUser(req).fetchStatement(id, {
575
+ return this.scopedSelf(req).fetchStatement(id, {
543
576
  ...(limit !== undefined ? { limit } : {}),
544
577
  signal,
545
578
  });
@@ -599,7 +632,7 @@ export class MastraPlugin extends Plugin<MastraPluginConfig> {
599
632
  ): Promise<void> => {
600
633
  const controller = new AbortController();
601
634
  req.on("close", () => controller.abort());
602
- const result = await this.asUser(req).fetchSuggestions(controller.signal);
635
+ const result = await this.scopedSelf(req).fetchSuggestions(controller.signal);
603
636
  if (controller.signal.aborted) return;
604
637
  if (!result.ok) {
605
638
  // Suggestions are a non-critical enhancement; a lookup failure should
@@ -658,7 +691,7 @@ export class MastraPlugin extends Plugin<MastraPluginConfig> {
658
691
  });
659
692
  return;
660
693
  }
661
- const result = await this.asUser(req).logFeedback(parsed.data);
694
+ const result = await this.scopedSelf(req).logFeedback(parsed.data);
662
695
  if (!result.ok) {
663
696
  this.sendFailure(res, result, "feedback", "Feedback could not be recorded");
664
697
  return;
@@ -700,10 +733,10 @@ export class MastraPlugin extends Plugin<MastraPluginConfig> {
700
733
  // and BIND is one), not `Function.prototype.bind` - so binding it through
701
734
  // the proxy registers a bogus route and crashes `pathToRegexp`
702
735
  // ("path must be a string ..."). This only manifests in production where
703
- // an OBO token makes `userScopedSelf` return the proxy. `dispatchMastra`
736
+ // an OBO token makes `scopedSelf` return the proxy. `dispatchMastra`
704
737
  // is a plain method (its `.bind` is the normal one) and invokes
705
738
  // `this.mastraApp` off the real target, keeping the OBO scope active.
706
- return this.asUser(req).dispatchMastra(req, res, next);
739
+ return this.scopedSelf(req).dispatchMastra(req, res, next);
707
740
  });
708
741
  }
709
742