@dbx-tools/appkit-mastra 0.6.3 → 0.6.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/src/server.js CHANGED
@@ -12,7 +12,7 @@ import { feedback, thread } from "@dbx-tools/shared-mastra";
12
12
  import { MASTRA_RESOURCE_ID_KEY, MASTRA_THREAD_ID_KEY, RequestContext, } from "@mastra/core/request-context";
13
13
  import { MastraServer as MastraServerExpress } from "@mastra/express";
14
14
  import { trace } from "@opentelemetry/api";
15
- import { executionContextUserId, MASTRA_REQUEST_ID_KEY, MASTRA_SCOPES_KEY, MASTRA_USER_EMAIL_KEY, MASTRA_USER_KEY, MASTRA_USER_NAME_KEY, } from "./config.js";
15
+ import { attributedUserId, MASTRA_REQUEST_ID_KEY, MASTRA_SCOPES_KEY, MASTRA_USER_EMAIL_KEY, MASTRA_USER_KEY, MASTRA_USER_NAME_KEY, } from "./config.js";
16
16
  import { requestUserEmail, requestUserId } from "./identity.js";
17
17
  import { resolveFeedbackEnabled } from "./mlflow.js";
18
18
  import { extractModelOverride, MASTRA_MODEL_OVERRIDE_KEY, resolveServingConfig, } from "./serving.js";
@@ -52,10 +52,10 @@ export async function stampRequestContextUser(requestContext, attributed = {}) {
52
52
  // attributed to can differ: in `service-principal` mode every request shares
53
53
  // the SP client, but the forwarded user id must still key the memory thread
54
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 };
55
+ const user = {
56
+ id: attributedUserId(executionContext, attributed.userId),
57
+ executionContext,
58
+ };
59
59
  requestContext.set(MASTRA_USER_KEY, user);
60
60
  requestContext.set(MASTRA_RESOURCE_ID_KEY, user.id);
61
61
  // AppKit's `UserContext` surfaces display name / email only on
@@ -352,4 +352,4 @@ export function attachRoutePatchMiddleware(app) {
352
352
  next();
353
353
  });
354
354
  }
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==
355
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NlcnZlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7OztHQU9HO0FBRUgsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDekQsT0FBTyxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsR0FBRyxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDaEYsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUM1RCxPQUFPLEVBQ0wsc0JBQXNCLEVBQ3RCLG9CQUFvQixFQUNwQixjQUFjLEdBQ2YsTUFBTSw4QkFBOEIsQ0FBQztBQUN0QyxPQUFPLEVBQUUsWUFBWSxJQUFJLG1CQUFtQixFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDdEUsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBRzNDLE9BQU8sRUFDTCxnQkFBZ0IsRUFDaEIscUJBQXFCLEVBQ3JCLGlCQUFpQixFQUNqQixxQkFBcUIsRUFDckIsZUFBZSxFQUNmLG9CQUFvQixHQUdyQixNQUFNLGFBQWEsQ0FBQztBQUNyQixPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsYUFBYSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ2hFLE9BQU8sRUFBRSxzQkFBc0IsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUVyRCxPQUFPLEVBQ0wsb0JBQW9CLEVBQ3BCLHlCQUF5QixFQUN6QixvQkFBb0IsR0FDckIsTUFBTSxjQUFjLENBQUM7QUFDdEI7Ozs7O0dBS0c7QUFDSCxNQUFNLGdCQUFnQixHQUFHLEdBQUcsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLENBQUM7QUFpQnhDOzs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FrQkc7QUFDSCxNQUFNLENBQUMsS0FBSyxVQUFVLHVCQUF1QixDQUMzQyxjQUE4QixFQUM5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QixJQUFJLEVBQUUsQ0FBQztJQUNULENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogRXhwcmVzcy1sYXllciBwbHVtYmluZyBmb3IgdGhlIE1hc3RyYSBwbHVnaW46IGEgYE1hc3RyYVNlcnZlcmAgdGhhdFxuICogc3RhbXBzIHRoZSBwZXItcmVxdWVzdCBgUmVxdWVzdENvbnRleHRgLCBhbmQgYSByb3V0ZS1wYXRjaCBtaWRkbGV3YXJlXG4gKiB0aGF0IGxldHMgdGhlIHBsdWdpbidzIGN1c3RvbSBBUEkgcm91dGVzIChlLmcuIGBoaXN0b3J5Um91dGVgKSB3b3JrXG4gKiBiZWhpbmQgYW4gRXhwcmVzcyBtb3VudCBwb2ludC5cbiAqXG4gKiBAbW9kdWxlXG4gKi9cblxuaW1wb3J0IHsgZ2V0RXhlY3V0aW9uQ29udGV4dCB9IGZyb20gXCJAZGF0YWJyaWNrcy9hcHBraXRcIjtcbmltcG9ydCB7IGhhc2gsIGh0dHAsIGxvZywgb2JqZWN0LCBzdHJpbmcsIHRva2VuIH0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLWNvcmVcIjtcbmltcG9ydCB7IGZlZWRiYWNrLCB0aHJlYWQgfSBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtbWFzdHJhXCI7XG5pbXBvcnQge1xuICBNQVNUUkFfUkVTT1VSQ0VfSURfS0VZLFxuICBNQVNUUkFfVEhSRUFEX0lEX0tFWSxcbiAgUmVxdWVzdENvbnRleHQsXG59IGZyb20gXCJAbWFzdHJhL2NvcmUvcmVxdWVzdC1jb250ZXh0XCI7XG5pbXBvcnQgeyBNYXN0cmFTZXJ2ZXIgYXMgTWFzdHJhU2VydmVyRXhwcmVzcyB9IGZyb20gXCJAbWFzdHJhL2V4cHJlc3NcIjtcbmltcG9ydCB7IHRyYWNlIH0gZnJvbSBcIkBvcGVudGVsZW1ldHJ5L2FwaVwiO1xuaW1wb3J0IHR5cGUgZXhwcmVzcyBmcm9tIFwiZXhwcmVzc1wiO1xuXG5pbXBvcnQge1xuICBhdHRyaWJ1dGVkVXNlcklkLFxuICBNQVNUUkFfUkVRVUVTVF9JRF9LRVksXG4gIE1BU1RSQV9TQ09QRVNfS0VZLFxuICBNQVNUUkFfVVNFUl9FTUFJTF9LRVksXG4gIE1BU1RSQV9VU0VSX0tFWSxcbiAgTUFTVFJBX1VTRVJfTkFNRV9LRVksXG4gIHR5cGUgTWFzdHJhUGx1Z2luQ29uZmlnLFxuICB0eXBlIFVzZXIsXG59IGZyb20gXCIuL2NvbmZpZy50c1wiO1xuaW1wb3J0IHsgcmVxdWVzdFVzZXJFbWFpbCwgcmVxdWVzdFVzZXJJZCB9IGZyb20gXCIuL2lkZW50aXR5LnRzXCI7XG5pbXBvcnQgeyByZXNvbHZlRmVlZGJhY2tFbmFibGVkIH0gZnJvbSBcIi4vbWxmbG93LnRzXCI7XG5cbmltcG9ydCB7XG4gIGV4dHJhY3RNb2RlbE92ZXJyaWRlLFxuICBNQVNUUkFfTU9ERUxfT1ZFUlJJREVfS0VZLFxuICByZXNvbHZlU2VydmluZ0NvbmZpZyxcbn0gZnJvbSBcIi4vc2VydmluZy50c1wiO1xuLyoqXG4gKiBPcGVuVGVsZW1ldHJ5J3Mgc2VudGluZWwgZm9yIFwibm8gdmFsaWQgdHJhY2VcIiAtIDMyIHplcm8gaGV4IGNoYXJzLlxuICogYHRyYWNlLmdldEFjdGl2ZVNwYW4oKWAgcmV0dXJucyBhIG5vbi1yZWNvcmRpbmcgc3BhbiB3aXRoIHRoaXMgaWRcbiAqIHdoZW4gbm8gU0RLIGlzIHJlZ2lzdGVyZWQsIHdoaWNoIG11c3QgbmV2ZXIgYmUgc3VyZmFjZWQgYXMgYSB0cmFjZSB0b1xuICogYXR0YWNoIGZlZWRiYWNrIHRvLlxuICovXG5jb25zdCBJTlZBTElEX1RSQUNFX0lEID0gXCIwXCIucmVwZWF0KDMyKTtcblxuLyoqXG4gKiBXaG8gYSB0dXJuIGlzIEFUVFJJQlVURUQgdG8sIGluZGVwZW5kZW50IG9mIHdoaWNoIERhdGFicmlja3MgY3JlZGVudGlhbCBydW5zXG4gKiBpdHMgY2FsbHMuIFN1cHBsaWVkIGJ5IHRoZSBIVFRQIG1pZGRsZXdhcmUgZnJvbSB0aGUgZm9yd2FyZGVkIHVzZXIgaGVhZGVycyBzb1xuICogdGhhdCBpbiBgc2VydmljZS1wcmluY2lwYWxgIG1vZGUgLSB3aGVyZSBldmVyeSByZXF1ZXN0IHNoYXJlcyB0aGUgYXBwIFNQJ3NcbiAqIGNsaWVudCAtIHRoZSBtZW1vcnkgdGhyZWFkLCBwZXItdXNlciBjYWNoZSBuYW1lc3BhY2UsIGFuZCB0cmFjZSBtZXRhZGF0YVxuICogc3RpbGwga2V5IG9mZiB0aGUgcmVhbCBjYWxsZXIuIElnbm9yZWQgaW4gYW4gT0JPICh1c2VyKSBjb250ZXh0LCB3aG9zZSBvd25cbiAqIHVzZXIgaWQgLyBlbWFpbCBhcmUgYXV0aG9yaXRhdGl2ZS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBBdHRyaWJ1dGVkSWRlbnRpdHkge1xuICAvKiogRm9yd2FyZGVkIGB4LWZvcndhcmRlZC11c2VyYCBpZCwgdXNlZCB3aGVuIHRoZSBjbGllbnQgaXMgdGhlIHNlcnZpY2UgcHJpbmNpcGFsLiAqL1xuICB1c2VySWQ/OiBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gIC8qKiBGb3J3YXJkZWQgYHgtZm9yd2FyZGVkLWVtYWlsYCwgdXNlZCBmb3IgdHJhY2UgbWV0YWRhdGEgdW5kZXIgdGhlIHNlcnZpY2UgcHJpbmNpcGFsLiAqL1xuICBlbWFpbD86IHN0cmluZyB8IHVuZGVmaW5lZDtcbn1cblxuLyoqXG4gKiBTdGFtcCB0aGUgQXBwS2l0IHVzZXIgKHBsdXMgdGhlIHJlc291cmNlIGlkIGFuZCB0cmFjZSBtZXRhZGF0YSkgb250b1xuICogYHJlcXVlc3RDb250ZXh0YC5cbiAqXG4gKiBTcGxpdCBvdXQgb2Yge0BsaW5rIE1hc3RyYVNlcnZlcn0gYmVjYXVzZSB0aGUgSFRUUCBtaWRkbGV3YXJlIGlzIG5vdCB0aGUgb25seVxuICogY2FsbGVyIHRoYXQgbmVlZHMgaXQ6IGFuIG91dC1vZi1iYW5kIHR1cm4gKGEgVGVhbXMgYWN0aXZpdHkgYXJyaXZpbmcgb25cbiAqIGFub3RoZXIgcGx1Z2luJ3Mgcm91dGUsIGEgc2NoZWR1bGVkIGpvYikgZHJpdmVzIGBhZ2VudC5nZW5lcmF0ZWAgZGlyZWN0bHksIGFuZFxuICogd2l0aG91dCB0aGlzIHN0YW1wIGV2ZXJ5IHVzZXItc2NvcGVkIHRvb2wgLSBgYXNrX2dlbmllYCBhYm92ZSBhbGwgLSBmYWlscyB3aXRoXG4gKiBcImludm9rZSB0aGUgdG9vbCBmcm9tIGFuIGFnZW50IHR1cm4gc2VydmVkIGJ5IHRoZSBtYXN0cmEgcGx1Z2luXCIuIFRob3NlXG4gKiBjYWxsZXJzIGJ1aWxkIGEgY29udGV4dCB3aXRoIHtAbGluayBjcmVhdGVSZXF1ZXN0Q29udGV4dH0gaW5zdGVhZCBvZiBhXG4gKiByZXF1ZXN0LlxuICpcbiAqIFRoZSBEYXRhYnJpY2tzIGNyZWRlbnRpYWwgYWx3YXlzIGNvbWVzIGZyb20gdGhlIGFtYmllbnQgZXhlY3V0aW9uIGNvbnRleHQ7XG4gKiBgYXR0cmlidXRlZGAgb25seSBjaGFuZ2VzIFdITyB0aGUgdHVybiBpcyBhdHRyaWJ1dGVkIHRvIHdoZW4gdGhhdCBjb250ZXh0IGlzXG4gKiB0aGUgc2VydmljZSBwcmluY2lwYWwgKHNlZSB7QGxpbmsgQXR0cmlidXRlZElkZW50aXR5fSkuXG4gKlxuICogSWRlbXBvdGVudDogcmV0dXJucyBpbW1lZGlhdGVseSB3aGVuIHRoZSB1c2VyIGFuZCByZXNvdXJjZSBpZCBhcmUgYWxyZWFkeVxuICogcHJlc2VudCwgc28gdGhlIG1pZGRsZXdhcmUgY2FuIGNhbGwgaXQgb3ZlciBhIGNvbnRleHQgYW5vdGhlciBsYXllciBzdGFtcGVkLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc3RhbXBSZXF1ZXN0Q29udGV4dFVzZXIoXG4gIHJlcXVlc3RDb250ZXh0OiBSZXF1ZXN0Q29udGV4dCxcbiAgYXR0cmlidXRlZDogQXR0cmlidXRlZElkZW50aXR5ID0ge30sXG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgaWYgKFtNQVNUUkFfVVNFUl9LRVksIE1BU1RSQV9SRVNPVVJDRV9JRF9LRVldLmV2ZXJ5KChrZXkpID0+IHJlcXVlc3RDb250ZXh0LmdldChrZXkpKSkgcmV0dXJuO1xuICBjb25zdCBleGVjdXRpb25Db250ZXh0ID0gZ2V0RXhlY3V0aW9uQ29udGV4dCgpO1xuICBjb25zdCBpc1VzZXJDb250ZXh0ID0gXCJpc1VzZXJDb250ZXh0XCIgaW4gZXhlY3V0aW9uQ29udGV4dDtcbiAgLy8gVGhlIERhdGFicmlja3MgQ1JFREVOVElBTCBpcyBhbHdheXMgdGhlIGFtYmllbnQgZXhlY3V0aW9uIGNvbnRleHQncyBjbGllbnRcbiAgLy8gKE9CTyBpbiBhIHVzZXIgY29udGV4dCwgdGhlIHNlcnZpY2UgcHJpbmNpcGFsIG90aGVyd2lzZSkuIFdITyB0aGUgdHVybiBpc1xuICAvLyBhdHRyaWJ1dGVkIHRvIGNhbiBkaWZmZXI6IGluIGBzZXJ2aWNlLXByaW5jaXBhbGAgbW9kZSBldmVyeSByZXF1ZXN0IHNoYXJlc1xuICAvLyB0aGUgU1AgY2xpZW50LCBidXQgdGhlIGZvcndhcmRlZCB1c2VyIGlkIG11c3Qgc3RpbGwga2V5IHRoZSBtZW1vcnkgdGhyZWFkXG4gIC8vIGFuZCB0aGUgcGVyLXVzZXIgY2FjaGUgbmFtZXNwYWNlIHNvIHR3byBjYWxsZXJzIGRvbid0IHNoYXJlIGEgY29udmVyc2F0aW9uLlxuICBjb25zdCB1c2VyOiBVc2VyID0ge1xuICAgIGlkOiBhdHRyaWJ1dGVkVXNlcklkKGV4ZWN1dGlvbkNvbnRleHQsIGF0dHJpYnV0ZWQudXNlcklkKSxcbiAgICBleGVjdXRpb25Db250ZXh0LFxuICB9O1xuICByZXF1ZXN0Q29udGV4dC5zZXQoTUFTVFJBX1VTRVJfS0VZLCB1c2VyKTtcbiAgcmVxdWVzdENvbnRleHQuc2V0KE1BU1RSQV9SRVNPVVJDRV9JRF9LRVksIHVzZXIuaWQpO1xuICAvLyBBcHBLaXQncyBgVXNlckNvbnRleHRgIHN1cmZhY2VzIGRpc3BsYXkgbmFtZSAvIGVtYWlsIG9ubHkgb25cbiAgLy8gT0JPIHJlcXVlc3RzLiBTZXJ2aWNlLWNvbnRleHQgY2FsbHMgKGJhY2tncm91bmQgdGFza3MsIHNlcnZlclxuICAvLyBzdGFydC11cCkgbGVhdmUgdGhlc2UgdW5kZWZpbmVkIGFuZCB3ZSBza2lwIHRoZSBzdGFtcCBzb1xuICAvLyBkb3duc3RyZWFtIHRyYWNlIG1ldGFkYXRhIHN0YXlzIGFic2VudCByYXRoZXIgdGhhbiBlbXB0eS4gSW5cbiAgLy8gYHNlcnZpY2UtcHJpbmNpcGFsYCBtb2RlIHRoZSBmb3J3YXJkZWQgZW1haWwgc3RpbGwgaWRlbnRpZmllcyB0aGUgY2FsbGVyLFxuICAvLyBzbyBpdCBpcyB1c2VkIGZvciB0cmFjZSBtZXRhZGF0YSBldmVuIHRob3VnaCB0aGUgY2xpZW50IGlzIHRoZSBTUC5cbiAgbGV0IHVzZXJOYW1lOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gIGxldCBlbWFpbDogc3RyaW5nIHwgdW5kZWZpbmVkID0gYXR0cmlidXRlZC5lbWFpbDtcbiAgaWYgKGlzVXNlckNvbnRleHQpIHtcbiAgICB1c2VyTmFtZSA9IGV4ZWN1dGlvbkNvbnRleHQudXNlck5hbWU7XG4gICAgZW1haWwgPSBleGVjdXRpb25Db250ZXh0LnVzZXJFbWFpbCA/PyBlbWFpbDtcbiAgfSBlbHNlIGlmIChwcm9jZXNzLmVudi5OT0RFX0VOViA9PT0gXCJkZXZlbG9wbWVudFwiKSB7XG4gICAgY29uc3QgY3VycmVudFVzZXIgPSBhd2FpdCBleGVjdXRpb25Db250ZXh0LmNsaWVudC5jdXJyZW50VXNlci5tZSgpO1xuICAgIHVzZXJOYW1lID0gY3VycmVudFVzZXI/LnVzZXJOYW1lO1xuICAgIGVtYWlsID0gY3VycmVudFVzZXI/LmVtYWlscz8uZmlsdGVyKChlbWFpbCkgPT4gZW1haWwucHJpbWFyeSkuZmluZCgoZW1haWwpID0+IGVtYWlsLnZhbHVlKVxuICAgICAgPy52YWx1ZSBhcyBzdHJpbmc7XG4gIH1cbiAgaWYgKHVzZXJOYW1lKSB7XG4gICAgcmVxdWVzdENvbnRleHQuc2V0KE1BU1RSQV9VU0VSX05BTUVfS0VZLCB1c2VyTmFtZSk7XG4gIH1cbiAgaWYgKGVtYWlsKSB7XG4gICAgcmVxdWVzdENvbnRleHQuc2V0KE1BU1RSQV9VU0VSX0VNQUlMX0tFWSwgZW1haWwpO1xuICB9XG59XG5cbi8qKlxuICogQnVpbGQgdGhlIGBSZXF1ZXN0Q29udGV4dGAgYSBOT04tSFRUUCBhZ2VudCB0dXJuIG5lZWRzLlxuICpcbiAqIEV2ZXJ5dGhpbmcgTWFzdHJhJ3MgdG9vbHMgcmVhZCBvZmYgdGhlIGNvbnRleHQgaXMgc3RhbXBlZCB0aGUgc2FtZSB3YXkgdGhlXG4gKiByZXF1ZXN0IG1pZGRsZXdhcmUgc3RhbXBzIGl0IC0gdGhlIEFwcEtpdCB1c2VyIChzbyBgYXNrX2dlbmllYCBhbmQgdGhlIG1vZGVsXG4gKiByZXNvbHZlciBjYW4gbWludCB1c2VyLXNjb3BlZCB0b2tlbnMpLCB0aGUgbWVtb3J5IHRocmVhZCAvIHJlc291cmNlIHBhaXIsIGFuZFxuICogYSByZXF1ZXN0IGlkIHNvIHRoZSB0dXJuJ3Mgc3BhbnMgam9pbiB1cCBpbiB0cmFjZXMuIFRoZSByZXN1bHQgaXMgcGFzc2VkIGFzXG4gKiBgcmVxdWVzdENvbnRleHRgIHRvIGBhZ2VudC5nZW5lcmF0ZWAgLyBgYWdlbnQuc3RyZWFtYC5cbiAqXG4gKiBUaGlzIGlzIHdoYXQgbWFrZXMgYSBjYXJkIHR1cm4gYW5zd2VyIHdpdGggdGhlIFNBTUUgZGF0YSBhIGNoYXQgdHVybiBkb2VzOiB0aGVcbiAqIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgdHdvIGVuZHBvaW50cyBpcyBwcmVzZW50YXRpb24sIG5vdCBjYXBhYmlsaXR5LlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY3JlYXRlUmVxdWVzdENvbnRleHQoXG4gIG9wdGlvbnM6IHsgdGhyZWFkSWQ/OiBzdHJpbmc7IHJlc291cmNlSWQ/OiBzdHJpbmc7IHJlcXVlc3RJZD86IHN0cmluZyB9ID0ge30sXG4pOiBQcm9taXNlPFJlcXVlc3RDb250ZXh0PiB7XG4gIGNvbnN0IHJlcXVlc3RDb250ZXh0ID0gbmV3IFJlcXVlc3RDb250ZXh0KCk7XG4gIGF3YWl0IHN0YW1wUmVxdWVzdENvbnRleHRVc2VyKHJlcXVlc3RDb250ZXh0KTtcbiAgaWYgKG9wdGlvbnMudGhyZWFkSWQpIHJlcXVlc3RDb250ZXh0LnNldChNQVNUUkFfVEhSRUFEX0lEX0tFWSwgb3B0aW9ucy50aHJlYWRJZCk7XG4gIC8vIFN0YW1wZWQgQUZURVIgdGhlIHVzZXIgc28gYW4gZXhwbGljaXQgcmVzb3VyY2UgaWQgKGEgY2hhbm5lbCBtZW1iZXIsIHNheSlcbiAgLy8gd2lucyBvdmVyIHRoZSBhbWJpZW50IGlkZW50aXR5IGBzdGFtcFJlcXVlc3RDb250ZXh0VXNlcmAgZGVmYXVsdGVkIHRvLlxuICBpZiAob3B0aW9ucy5yZXNvdXJjZUlkKSByZXF1ZXN0Q29udGV4dC5zZXQoTUFTVFJBX1JFU09VUkNFX0lEX0tFWSwgb3B0aW9ucy5yZXNvdXJjZUlkKTtcbiAgcmVxdWVzdENvbnRleHQuc2V0KE1BU1RSQV9SRVFVRVNUX0lEX0tFWSwgb3B0aW9ucy5yZXF1ZXN0SWQgPz8gaGFzaC5pZCgpKTtcbiAgcmV0dXJuIHJlcXVlc3RDb250ZXh0O1xufVxuXG4vKipcbiAqIGBAbWFzdHJhL2V4cHJlc3NgIHN1YmNsYXNzIHRoYXQgc3RhbXBzIGBSZXF1ZXN0Q29udGV4dGAgd2l0aCB0aGVcbiAqIEFwcEtpdCB1c2VyLCByZXNvdXJjZSBpZCwgYW5kIGEgdGhyZWFkIGlkIGJhY2tlZCBieSBhbiBIVFRQLW9ubHlcbiAqIHNlc3Npb24gY29va2llIChgYXBwa2l0XzxwbHVnaW4tbmFtZT5fc2Vzc2lvbl9pZGApLlxuICovXG5leHBvcnQgY2xhc3MgTWFzdHJhU2VydmVyIGV4dGVuZHMgTWFzdHJhU2VydmVyRXhwcmVzcyB7XG4gIHByaXZhdGUgbG9nOiBsb2cuTG9nZ2VyO1xuICAvKipcbiAgICogV2hldGhlciB0byBzdGFtcCB0aGUgTUxmbG93IHRyYWNlLWlkIGhlYWRlciBvbiByZXNwb25zZXMuIFNoYXJlcyB0aGVcbiAgICogcGx1Z2luJ3MgZmVlZGJhY2sgZ2F0ZSB2aWEge0BsaW5rIHJlc29sdmVGZWVkYmFja0VuYWJsZWR9LlxuICAgKi9cbiAgcHJpdmF0ZSBmZWVkYmFja0VuYWJsZWQ6IGJvb2xlYW47XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSBjb25maWc6IE1hc3RyYVBsdWdpbkNvbmZpZyxcbiAgICAuLi5hcmdzOiBDb25zdHJ1Y3RvclBhcmFtZXRlcnM8dHlwZW9mIE1hc3RyYVNlcnZlckV4cHJlc3M+XG4gICkge1xuICAgIHN1cGVyKC4uLmFyZ3MpO1xuICAgIHRoaXMubG9nID0gbG9nLmxvZ2dlcihjb25maWcpO1xuICAgIHRoaXMuZmVlZGJhY2tFbmFibGVkID0gcmVzb2x2ZUZlZWRiYWNrRW5hYmxlZChjb25maWcuZmVlZGJhY2spO1xuICB9XG5cbiAgb3ZlcnJpZGUgcmVnaXN0ZXJBdXRoTWlkZGxld2FyZSgpOiB2b2lkIHtcbiAgICBzdXBlci5yZWdpc3RlckF1dGhNaWRkbGV3YXJlKCk7XG4gICAgdGhpcy5hcHAudXNlKGFzeW5jIChyZXEsIHJlcywgbmV4dCkgPT4ge1xuICAgICAgY29uc3QgcmVxdWVzdENvbnRleHQgPSByZXMubG9jYWxzLnJlcXVlc3RDb250ZXh0ISBhcyBSZXF1ZXN0Q29udGV4dDtcbiAgICAgIGF3YWl0IHRoaXMuY29uZmlndXJlUmVxdWVzdENvbnRleHRVc2VyKHJlcSwgcmVxdWVzdENvbnRleHQpO1xuICAgICAgdGhpcy5jb25maWd1cmVSZXF1ZXN0Q29udGV4dFRocmVhZElkKHJlcSwgcmVzLCByZXF1ZXN0Q29udGV4dCk7XG4gICAgICB0aGlzLmNvbmZpZ3VyZVJlcXVlc3RDb250ZXh0TW9kZWxPdmVycmlkZShyZXEsIHJlcXVlc3RDb250ZXh0KTtcbiAgICAgIHRoaXMuY29uZmlndXJlUmVxdWVzdENvbnRleHRSZXF1ZXN0SWQocmVxLCByZXMsIHJlcXVlc3RDb250ZXh0KTtcbiAgICAgIHRoaXMuY29uZmlndXJlUmVxdWVzdENvbnRleHRTY29wZXMocmVxLCByZXF1ZXN0Q29udGV4dCk7XG5cbiAgICAgIHRoaXMuY29uZmlndXJlTWxmbG93VHJhY2VJZChyZXMpO1xuICAgICAgdGhpcy5sb2cuZGVidWcoXCJhdXRoOm1pZGRsZXdhcmVcIiwge1xuICAgICAgICBtZXRob2Q6IHJlcS5tZXRob2QsXG4gICAgICAgIHBhdGg6IHJlcS5wYXRoLFxuICAgICAgICByZXF1ZXN0SWQ6IHJlcXVlc3RDb250ZXh0LmdldChNQVNUUkFfUkVRVUVTVF9JRF9LRVkpLFxuICAgICAgICB0aHJlYWRJZDogcmVxdWVzdENvbnRleHQuZ2V0KE1BU1RSQV9USFJFQURfSURfS0VZKSxcbiAgICAgICAgcmVzb3VyY2VJZDogcmVxdWVzdENvbnRleHQuZ2V0KE1BU1RSQV9SRVNPVVJDRV9JRF9LRVkpLFxuICAgICAgICB1c2VyTmFtZTogcmVxdWVzdENvbnRleHQuZ2V0KE1BU1RSQV9VU0VSX05BTUVfS0VZKSxcbiAgICAgICAgdXNlckVtYWlsOiByZXF1ZXN0Q29udGV4dC5nZXQoTUFTVFJBX1VTRVJfRU1BSUxfS0VZKSxcbiAgICAgICAgbW9kZWxPdmVycmlkZTogcmVxdWVzdENvbnRleHQuZ2V0KFxuICAgICAgICAgIC8vIGltcG9ydGVkIGJlbG93OyBsb2dnZWQgc28gYSBtaXNyb3V0ZWQgcmVxdWVzdCBzaG93c1xuICAgICAgICAgIC8vIHVwIGFsb25nc2lkZSBpdHMgbW9kZWwgc2VsZWN0aW9uIGluIGBMT0dfTEVWRUw9ZGVidWdgLlxuICAgICAgICAgIFwibWFzdHJhX19tb2RlbF9vdmVycmlkZVwiLFxuICAgICAgICApLFxuICAgICAgfSk7XG4gICAgICBuZXh0KCk7XG4gICAgfSk7XG4gIH1cblxuICBhc3luYyBjb25maWd1cmVSZXF1ZXN0Q29udGV4dFVzZXIocmVxOiBleHByZXNzLlJlcXVlc3QsIHJlcXVlc3RDb250ZXh0OiBSZXF1ZXN0Q29udGV4dCkge1xuICAgIC8vIFBhc3MgdGhlIGZvcndhcmRlZCBjYWxsZXIgaWRlbnRpdHkgc28gYHNlcnZpY2UtcHJpbmNpcGFsYCBtb2RlIHN0aWxsIGtleXNcbiAgICAvLyBtZW1vcnkgLyBjYWNoZSAvIHRyYWNlcyBwZXIgdXNlciBldmVuIHRob3VnaCB0aGUgY2xpZW50IGlzIHRoZSBhcHAgU1AuXG4gICAgLy8gSW4gYW4gT0JPIGNvbnRleHQgdGhlc2UgYXJlIGlnbm9yZWQgaW4gZmF2b3Igb2YgdGhlIGNvbnRleHQncyBvd24gdXNlci5cbiAgICBhd2FpdCBzdGFtcFJlcXVlc3RDb250ZXh0VXNlcihyZXF1ZXN0Q29udGV4dCwge1xuICAgICAgdXNlcklkOiByZXF1ZXN0VXNlcklkKHJlcSksXG4gICAgICBlbWFpbDogcmVxdWVzdFVzZXJFbWFpbChyZXEpLFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFN0YW1wIGEgcGVyLXJlcXVlc3QgaWQgYW5kIGVjaG8gaXQgb24gdGhlIHJlc3BvbnNlIHNvIGFuIHVwc3RyZWFtXG4gICAqIHByb3h5IC8gY3VybCBjbGllbnQgLyBicm93c2VyLXNpZGUgbG9nIGxpbmUgY2FuIHBhaXIgaXRzIHZpZXcgb2ZcbiAgICogdGhlIHJlcXVlc3Qgd2l0aCB0aGUgbWF0Y2hpbmcgdHJhY2Ugc3Bhbi4gUmV1c2VzIGBYLVJlcXVlc3QtSWRgXG4gICAqIHdoZW4gdGhlIHVwc3RyZWFtIGFscmVhZHkgc3VwcGxpZXMgb25lIHNvIG11bHRpLWhvcCB0cmFjZXMgc3RheVxuICAgKiBqb2luZWQ7IG90aGVyd2lzZSBtaW50cyBhIFVVSUR2NC5cbiAgICpcbiAgICogVGhlIGlkIGlzIHN1cmZhY2VkIGFzIGBtYXN0cmFfX3JlcXVlc3RJZGAgc3BhbiBtZXRhZGF0YSB2aWFcbiAgICoge0BsaW5rIFRSQUNFX1JFUVVFU1RfQ09OVEVYVF9LRVlTfSBhbmQgYXMgdGhlIGBYLVJlcXVlc3QtSWRgXG4gICAqIHJlc3BvbnNlIGhlYWRlciBzbyBkZXYgdG9vbHMgY2FuIGNvcHkgaXQgZnJvbSBlaXRoZXIgc2lkZS5cbiAgICovXG4gIGNvbmZpZ3VyZVJlcXVlc3RDb250ZXh0UmVxdWVzdElkKFxuICAgIHJlcTogZXhwcmVzcy5SZXF1ZXN0LFxuICAgIHJlczogZXhwcmVzcy5SZXNwb25zZSxcbiAgICByZXF1ZXN0Q29udGV4dDogUmVxdWVzdENvbnRleHQsXG4gICkge1xuICAgIGlmIChyZXF1ZXN0Q29udGV4dC5nZXQoTUFTVFJBX1JFUVVFU1RfSURfS0VZKSkgcmV0dXJuO1xuICAgIGNvbnN0IGhlYWRlclZhbHVlID0gcmVxLmhlYWRlcnNbXCJ4LXJlcXVlc3QtaWRcIl07XG4gICAgY29uc3QgdXBzdHJlYW0gPSBBcnJheS5pc0FycmF5KGhlYWRlclZhbHVlKSA/IGhlYWRlclZhbHVlWzBdIDogaGVhZGVyVmFsdWU7XG4gICAgY29uc3QgcmVxdWVzdElkID0gdXBzdHJlYW0/LnRyaW0oKSB8fCBoYXNoLmlkKCk7XG4gICAgcmVxdWVzdENvbnRleHQuc2V0KE1BU1RSQV9SRVFVRVNUX0lEX0tFWSwgcmVxdWVzdElkKTtcbiAgICByZXMuc2V0SGVhZGVyKFwiWC1SZXF1ZXN0LUlkXCIsIHJlcXVlc3RJZCk7XG4gIH1cblxuICAvKipcbiAgICogU3RhbXAgT0F1dGggc2NvcGVzIGZyb20gdGhlIGZvcndhcmRlZCBhY2Nlc3MgdG9rZW4gb25cbiAgICoge0BsaW5rIE1BU1RSQV9TQ09QRVNfS0VZfSBmb3Igd29ya3NwYWNlIG1vdW50IGdhdGluZy5cbiAgICovXG4gIGNvbmZpZ3VyZVJlcXVlc3RDb250ZXh0U2NvcGVzKHJlcTogZXhwcmVzcy5SZXF1ZXN0LCByZXF1ZXN0Q29udGV4dDogUmVxdWVzdENvbnRleHQpIHtcbiAgICBjb25zdCBzY29wZXMgPSBbXG4gICAgICAuLi5vYmplY3RcbiAgICAgICAgLnNlcXVlbmNlKHRva2VuLmdldEFjY2Vzc1Rva2VuU2NvcGVzKHJlcSksIHRva2VuLmdldEFjY2Vzc1Rva2VuU2NvcGVzKHJlcSwgXCJhdXRob3JpemF0aW9uXCIpKVxuICAgICAgICAuZGlzdGluY3QoKSxcbiAgICBdO1xuICAgIHJlcXVlc3RDb250ZXh0LnNldChNQVNUUkFfU0NPUEVTX0tFWSwgc2NvcGVzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTdGFtcCB0aGUgdHVybidzIE1MZmxvdyB0cmFjZSBpZCBvbiB0aGUgcmVzcG9uc2Ugc28gdGhlIGNoYXQgY2xpZW50XG4gICAqIGNhbiBhdHRhY2ggdGh1bWJzIC8gY29tbWVudCBmZWVkYmFjayB0byBpdCBsYXRlci4gTUxmbG93IGRlcml2ZXNcbiAgICogaXRzIHRyYWNlIGlkIGZyb20gdGhlIE9wZW5UZWxlbWV0cnkgdHJhY2UgaWQgKGB0ci08aGV4PmApLCBhbmQgZXZlcnlcbiAgICogTWFzdHJhIHNwYW4gZm9yIHRoaXMgcmVxdWVzdCBpbmhlcml0cyB0aGUgYW1iaWVudCBPVGVsIGNvbnRleHQgKHNlZVxuICAgKiBgb2JzZXJ2YWJpbGl0eS50c2ApLCBzbyB0aGUgYWN0aXZlIHNwYW4ncyB0cmFjZSBpZCBoZXJlIGlzIHRoZSBpZFxuICAgKiBNTGZsb3cgd2lsbCByZWNvcmQgZm9yIHRoZSB0dXJuLlxuICAgKlxuICAgKiBOby1vcCB1bmxlc3MgZmVlZGJhY2sgaXMgZW5hYmxlZCwgYW5kIHdoZW4gbm8gbGl2ZSBPVGVsIHNwYW4gaXNcbiAgICogYWN0aXZlIChlLmcuIHRoZSBPVExQIFNESyBpc24ndCByZWdpc3RlcmVkKTogaW4gdGhhdCBjYXNlIHRoZSBoZWFkZXJcbiAgICogaXMgc2ltcGx5IGFic2VudCBhbmQgdGhlIGNsaWVudCBoaWRlcyBmZWVkYmFjayBmb3IgdGhhdCBtZXNzYWdlLFxuICAgKiBkZWdyYWRpbmcgZ3JhY2VmdWxseSByYXRoZXIgdGhhbiBlbWl0dGluZyBhIGJvZ3VzIHRyYWNlIGlkLlxuICAgKi9cbiAgY29uZmlndXJlTWxmbG93VHJhY2VJZChyZXM6IGV4cHJlc3MuUmVzcG9uc2UpIHtcbiAgICBpZiAoIXRoaXMuZmVlZGJhY2tFbmFibGVkIHx8IHJlcy5oZWFkZXJzU2VudCkgcmV0dXJuO1xuICAgIGNvbnN0IHRyYWNlSWQgPSB0cmFjZS5nZXRBY3RpdmVTcGFuKCk/LnNwYW5Db250ZXh0KCkudHJhY2VJZDtcbiAgICBpZiAoIXRyYWNlSWQgfHwgdHJhY2VJZCA9PT0gSU5WQUxJRF9UUkFDRV9JRCkgcmV0dXJuO1xuICAgIHJlcy5zZXRIZWFkZXIoZmVlZGJhY2suTUxGTE9XX1RSQUNFX0lEX0hFQURFUiwgYHRyLSR7dHJhY2VJZH1gKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXNvbHZlIHRoZSB0aHJlYWQgaWQgdGhpcyByZXF1ZXN0IHRhcmdldHMgYW5kIHBpbiBpdCBvblxuICAgKiBgUmVxdWVzdENvbnRleHRgIChjb25zdW1lZCBieSB0aGUgYWdlbnQgc3RyZWFtIGZvciBwZXJzaXN0ZW5jZSBhbmRcbiAgICogYnkgdGhlIGhpc3RvcnkgLyB0aHJlYWRzIHJvdXRlcykuIFJlc29sdXRpb24gb3JkZXI6XG4gICAqXG4gICAqICAgMS4gQSBjbGllbnQtc3VwcGxpZWQgdGhyZWFkIGlkICh0aGUgdGhyZWFkLXNlbGVjdGlvbiBoZWFkZXIgL1xuICAgKiAgICAgIGA/dGhyZWFkSWQ9YCBxdWVyeSkuIFRoaXMgaXMgaG93IHRoZSBjaGF0IFVJIHJlZmVyZW5jZXMgYVxuICAgKiAgICAgIHNwZWNpZmljIGNvbnZlcnNhdGlvbiBhbW9uZyB0aGUgbWFueSBhIHVzZXIgb3ducyAtIGl0IHBpY2tzIGFcbiAgICogICAgICB0aHJlYWQgaWQgZnJvbSB0aGUgYC90aHJlYWRzYCBsaXN0aW5nIChvciBtaW50cyBvbmUgZm9yIGEgbmV3XG4gICAqICAgICAgY29udmVyc2F0aW9uKSBhbmQgc3RhbXBzIGl0IGhlcmUuIFRoZSBpZCBpcyBzY29wZWQgdG8gdGhlXG4gICAqICAgICAgY2FsbGVyJ3MgcmVzb3VyY2UgYnkgdGhlIHJlY2FsbCAvIGxpc3Qgcm91dGVzLCBzbyBhIGNsaWVudFxuICAgKiAgICAgIGNhbiBvbmx5IGV2ZXIgcmVhZCBvciB3cml0ZSBpdHMgb3duIHRocmVhZHMuXG4gICAqICAgMi4gVGhlIHBlci1zZXNzaW9uIGNvb2tpZSAoYGFwcGtpdF88cGx1Z2luLW5hbWU+X3Nlc3Npb25faWRgKSxcbiAgICogICAgICBtaW50ZWQgb24gZmlyc3QgY29udGFjdC4gVGhpcyBpcyB0aGUgZGVmYXVsdCBzaW5nbGUtdGhyZWFkXG4gICAqICAgICAgZmFsbGJhY2sgZm9yIGNsaWVudHMgdGhhdCBkb24ndCBtYW5hZ2UgdGhyZWFkcyBleHBsaWNpdGx5LCBzb1xuICAgKiAgICAgIGV4aXN0aW5nIGVtYmVkcyBrZWVwIG9uZSBzdGFibGUgY29udmVyc2F0aW9uIHBlciBzZXNzaW9uIHdpdGhcbiAgICogICAgICBubyBjbGllbnQgY2hhbmdlcy5cbiAgICovXG4gIGNvbmZpZ3VyZVJlcXVlc3RDb250ZXh0VGhyZWFkSWQoXG4gICAgcmVxOiBleHByZXNzLlJlcXVlc3QsXG4gICAgcmVzOiBleHByZXNzLlJlc3BvbnNlLFxuICAgIHJlcXVlc3RDb250ZXh0OiBSZXF1ZXN0Q29udGV4dCxcbiAgKSB7XG4gICAgaWYgKHJlcXVlc3RDb250ZXh0LmdldChNQVNUUkFfVEhSRUFEX0lEX0tFWSkpIHJldHVybjtcbiAgICBjb25zdCByZXF1ZXN0ZWQgPSB0aGlzLnJlYWRSZXF1ZXN0ZWRUaHJlYWRJZChyZXEpO1xuICAgIGlmIChyZXF1ZXN0ZWQpIHtcbiAgICAgIHJlcXVlc3RDb250ZXh0LnNldChNQVNUUkFfVEhSRUFEX0lEX0tFWSwgcmVxdWVzdGVkKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgY29va2llcyA9IGh0dHAucGFyc2VDb29raWVzKHJlcS5oZWFkZXJzLmNvb2tpZSk7XG4gICAgY29uc3QgY29va2llTmFtZSA9IHN0cmluZy50b0lkZW50aWZpZXJXaXRoT3B0aW9ucyhcbiAgICAgIHsgZGVsaW1pdGVyOiBcIl9cIiwgZGlzdGluY3Q6IHRydWUgfSxcbiAgICAgIFwiYXBwa2l0XCIsXG4gICAgICB0aGlzLmNvbmZpZy5uYW1lISxcbiAgICAgIFwic2Vzc2lvbklkXCIsXG4gICAgKTtcbiAgICBsZXQgc2Vzc2lvbklkID0gY29va2llc1tjb29raWVOYW1lXTtcbiAgICBpZiAoIXNlc3Npb25JZCkge1xuICAgICAgc2Vzc2lvbklkID0gaGFzaC5pZCgpO1xuICAgICAgcmVzLmNvb2tpZShjb29raWVOYW1lLCBzZXNzaW9uSWQsIHtcbiAgICAgICAgaHR0cE9ubHk6IHRydWUsXG4gICAgICAgIHNhbWVTaXRlOiBcImxheFwiLFxuICAgICAgICBzZWN1cmU6IHJlcS5zZWN1cmUsXG4gICAgICAgIHBhdGg6IFwiL1wiLFxuICAgICAgfSk7XG4gICAgfVxuICAgIHJlcXVlc3RDb250ZXh0LnNldChNQVNUUkFfVEhSRUFEX0lEX0tFWSwgc2Vzc2lvbklkKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZWFkIHRoZSBjbGllbnQtc2VsZWN0ZWQgdGhyZWFkIGlkIGZyb20gdGhlIHJlcXVlc3QsIHByZWZlcnJpbmdcbiAgICogdGhlIHRocmVhZC1zZWxlY3Rpb24gaGVhZGVyIG92ZXIgdGhlIGA/dGhyZWFkSWQ9YCBxdWVyeS4gUmV0dXJuc1xuICAgKiBgbnVsbGAgd2hlbiBuZWl0aGVyIGNhcnJpZXMgYSBub24tZW1wdHkgdmFsdWUgc28gdGhlIGNhbGxlciBmYWxsc1xuICAgKiBiYWNrIHRvIHRoZSBzZXNzaW9uIGNvb2tpZS5cbiAgICovXG4gIHByaXZhdGUgcmVhZFJlcXVlc3RlZFRocmVhZElkKHJlcTogZXhwcmVzcy5SZXF1ZXN0KTogc3RyaW5nIHwgbnVsbCB7XG4gICAgY29uc3QgaGVhZGVyVmFsdWUgPSByZXEuaGVhZGVyc1t0aHJlYWQuVEhSRUFEX0lEX0hFQURFUl07XG4gICAgY29uc3QgcXVlcnlWYWx1ZSA9IHJlcS5xdWVyeVt0aHJlYWQuVEhSRUFEX0lEX1FVRVJZXTtcbiAgICByZXR1cm4gKFxuICAgICAgc3RyaW5nLnRyaW1Ub051bGwoQXJyYXkuaXNBcnJheShoZWFkZXJWYWx1ZSkgPyBoZWFkZXJWYWx1ZVswXSA6IGhlYWRlclZhbHVlKSA/P1xuICAgICAgc3RyaW5nLnRyaW1Ub051bGwoQXJyYXkuaXNBcnJheShxdWVyeVZhbHVlKSA/IHF1ZXJ5VmFsdWVbMF0gOiBxdWVyeVZhbHVlKVxuICAgICk7XG4gIH1cblxuICBjb25maWd1cmVSZXF1ZXN0Q29udGV4dE1vZGVsT3ZlcnJpZGUocmVxOiBleHByZXNzLlJlcXVlc3QsIHJlcXVlc3RDb250ZXh0OiBSZXF1ZXN0Q29udGV4dCkge1xuICAgIC8vIFBlci1yZXF1ZXN0IG1vZGVsIG92ZXJyaWRlOiBvbmx5IGhvbm9yZWQgd2hlbiB0aGUgcGx1Z2luXG4gICAgLy8gb3B0cyBpbiAoZGVmYXVsdCkuIFNvdXJjZXMsIGluIHByaW9yaXR5IG9yZGVyLCBhcmVcbiAgICAvLyBgWC1NYXN0cmEtTW9kZWxgIGhlYWRlciwgYD9tb2RlbD1gIHF1ZXJ5LCBhbmQgYG1vZGVsYCAvXG4gICAgLy8gYG1vZGVsSWRgIGJvZHkgZmllbGQ7IHNlZSBgc2VydmluZy50c2AuXG4gICAgY29uc3Qgc2VydmluZyA9IHJlc29sdmVTZXJ2aW5nQ29uZmlnKHRoaXMuY29uZmlnKTtcbiAgICBpZiAoc2VydmluZy5hbGxvd092ZXJyaWRlKSB7XG4gICAgICBjb25zdCBvdmVycmlkZSA9IGV4dHJhY3RNb2RlbE92ZXJyaWRlKHtcbiAgICAgICAgaGVhZGVyczogcmVxLmhlYWRlcnMgYXMgUmVjb3JkPHN0cmluZywgc3RyaW5nIHwgc3RyaW5nW10gfCB1bmRlZmluZWQ+LFxuICAgICAgICBxdWVyeTogcmVxLnF1ZXJ5IGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+LFxuICAgICAgICBib2R5OiByZXEuYm9keSxcbiAgICAgIH0pO1xuICAgICAgaWYgKG92ZXJyaWRlKSByZXF1ZXN0Q29udGV4dC5zZXQoTUFTVFJBX01PREVMX09WRVJSSURFX0tFWSwgb3ZlcnJpZGUpO1xuICAgIH1cbiAgfVxufVxuXG4vKiogSW5wdXRzIGZvciB7QGxpbmsgaXNNYXN0cmFSZXF1ZXN0QWxsb3dlZH0uICovXG5leHBvcnQgaW50ZXJmYWNlIE1hc3RyYUFwaUdhdGVPcHRpb25zIHtcbiAgLyoqIGBjb25maWcuYXBpQWNjZXNzYDsgYFwiZnVsbFwiYCBzaG9ydC1jaXJjdWl0cyB0byBhbGxvdyBldmVyeXRoaW5nLiAqL1xuICBhY2Nlc3M6IFwic2NvcGVkXCIgfCBcImZ1bGxcIjtcbiAgLyoqIFdoZXRoZXIgdGhlIE1DUCB0cmFuc3BvcnQgaXMgbW91bnRlZCAoc28gYC9tY3AvKmAgaXMgbGVnaXRpbWF0ZSkuICovXG4gIG1jcEVuYWJsZWQ6IGJvb2xlYW47XG59XG5cbi8qKlxuICogTW91bnQtcmVsYXRpdmUgYWdlbnQgaW5mZXJlbmNlIHBhdGhzIChgL2FnZW50cy86aWQvPHZlcmI+Li4uYCkuIE1hdGNoZWRcbiAqIGJ5IHByZWZpeCBvbiB0aGUgdmVyYiBzbyBmdXR1cmUgdmFyaWFudHMgKGBzdHJlYW1WTmV4dGAsIGBzdHJlYW0vdm5leHRgLFxuICogYGdlbmVyYXRlVk5leHRgKSBzdGF5IGNvdmVyZWQgd2l0aG91dCBhIGNvZGUgY2hhbmdlLlxuICpcbiAqIENvdmVycyB0aGUgcGxhaW4gaW5mZXJlbmNlIHZlcmJzIChgc3RyZWFtYCAvIGBnZW5lcmF0ZWAgLyBgbmV0d29ya2ApIHBsdXNcbiAqIHRoZSBodW1hbi1pbi10aGUtbG9vcCByZXN1bWUgdmVyYnMgYSBwYXVzZWQgYHJlcXVpcmVBcHByb3ZhbGAgdG9vbCBuZWVkc1xuICogdG8gY29udGludWU6IGBhcHByb3ZlLXRvb2wtY2FsbGAgLyBgZGVjbGluZS10b29sLWNhbGxgIChzdHJlYW1pbmcsIGFuZCB2aWFcbiAqIHByZWZpeCB0aGVpciBgLWdlbmVyYXRlYCBub24tc3RyZWFtaW5nIHZhcmlhbnRzKSwgdGhlIGAtbmV0d29yay1gIHZhcmlhbnRzLFxuICogYW5kIGByZXN1bWUtc3RyZWFtYCAoY292ZXJzIGByZXN1bWUtc3RyZWFtLXVudGlsLWlkbGVgKS4gV2l0aG91dCB0aGVzZSBhblxuICogYXBwcm92YWwtZ2F0ZWQgdG9vbCAoZS5nLiBgc2VuZF9lbWFpbGApIGNhbiBiZSByZXF1ZXN0ZWQgYnV0IG5ldmVyIGFwcHJvdmVkXG4gKiBmcm9tIHRoZSBicm93c2VyIC0gdGhlIHJlc3VtZSBgUE9TVGAgNDAzcyB1bmRlciBzY29wZWQgbW9kZS4gVGhlc2UgYXJlIHRoZVxuICogb25seSAqd3JpdGVzKiB0aGUgYnJvd3NlciBjbGllbnQgaXMgYWxsb3dlZCB0byBtYWtlIGFnYWluc3Qgc3RvY2sgTWFzdHJhLlxuICovXG5jb25zdCBBR0VOVF9JTkZFUkVOQ0UgPVxuICAvXlxcL2FnZW50c1xcL1teL10rXFwvKHN0cmVhbXxnZW5lcmF0ZXxuZXR3b3JrfHJlc3VtZS1zdHJlYW18YXBwcm92ZS10b29sLWNhbGx8ZGVjbGluZS10b29sLWNhbGx8YXBwcm92ZS1uZXR3b3JrLXRvb2wtY2FsbHxkZWNsaW5lLW5ldHdvcmstdG9vbC1jYWxsKS9pO1xuXG4vKiogTW91bnQtcmVsYXRpdmUgcmVhZC1vbmx5IGFnZW50IG1ldGFkYXRhIChgL2FnZW50c2AsIGAvYWdlbnRzLzppZGApLiAqL1xuY29uc3QgQUdFTlRfTUVUQURBVEEgPSAvXlxcL2FnZW50cyhcXC9bXi9dKyk/JC87XG5cbi8qKlxuICogV2hldGhlciBhIHJlcXVlc3QgdG8gdGhlIHN0b2NrIGBAbWFzdHJhL2V4cHJlc3NgIHN1Yi1hcHAgc2hvdWxkIGJlXG4gKiBkaXNwYXRjaGVkLCBnaXZlbiB0aGUgY29uZmlndXJlZCB7QGxpbmsgTWFzdHJhQXBpR2F0ZU9wdGlvbnMuYWNjZXNzfS5cbiAqXG4gKiBgcGF0aGAgaXMgbW91bnQtcmVsYXRpdmUgKHdoYXQgdGhlIHBsdWdpbidzIGNhdGNoLWFsbCBzZWVzLCBlLmcuXG4gKiBgL2FnZW50cy94L3N0cmVhbWAsIGAvcm91dGUvaGlzdG9yeS94YCwgYC9tY3AvLi4uYCkuIEluIGBcInNjb3BlZFwiYFxuICogbW9kZSB0aGUgYWxsb3dsaXN0IGlzIGRlbGliZXJhdGVseSB0aWdodCAtIHRoZSBjaGF0IGNsaWVudCBvbmx5IGV2ZXJcbiAqIG5lZWRzIGFnZW50IGluZmVyZW5jZSwgcmVhZC1vbmx5IGFnZW50IG1ldGFkYXRhLCB0aGlzIHBsdWdpbidzIG93blxuICogT0JPL3Jlc291cmNlLXNjb3BlZCBgL3JvdXRlLypgIHJvdXRlcywgYW5kICh3aGVuIGVuYWJsZWQpIE1DUCAtIHNvIHRoZVxuICogd2hvbGUgYWRtaW4gLyBtdXRhdGluZyAvIGJ1bGstZXhwb3J0IHN1cmZhY2UgTWFzdHJhIGFsc28gZXhwb3NlcyBpc1xuICogZGVuaWVkIGJ5IGRlZmF1bHQgcmF0aGVyIHRoYW4gZW51bWVyYXRlZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzTWFzdHJhUmVxdWVzdEFsbG93ZWQoXG4gIG1ldGhvZDogc3RyaW5nLFxuICBwYXRoOiBzdHJpbmcsXG4gIG9wdHM6IE1hc3RyYUFwaUdhdGVPcHRpb25zLFxuKTogYm9vbGVhbiB7XG4gIGlmIChvcHRzLmFjY2VzcyA9PT0gXCJmdWxsXCIpIHJldHVybiB0cnVlO1xuICBjb25zdCBwID0gcGF0aC5zdGFydHNXaXRoKFwiL1wiKSA/IHBhdGggOiBgLyR7cGF0aH1gO1xuICAvLyBUaGlzIHBsdWdpbidzIG93biBjdXN0b20gcm91dGVzIGFyZSBpbmRpdmlkdWFsbHkgT0JPLSBhbmRcbiAgLy8gcmVzb3VyY2Utc2NvcGVkIChzZWUgaGlzdG9yeS50cyAvIHRocmVhZHMudHMpLCBzbyBldmVyeSBtZXRob2QgaXMgc2FmZS5cbiAgaWYgKHAgPT09IFwiL3JvdXRlXCIgfHwgcC5zdGFydHNXaXRoKFwiL3JvdXRlL1wiKSkgcmV0dXJuIHRydWU7XG4gIGlmIChvcHRzLm1jcEVuYWJsZWQgJiYgKHAgPT09IFwiL21jcFwiIHx8IHAuc3RhcnRzV2l0aChcIi9tY3AvXCIpKSkgcmV0dXJuIHRydWU7XG4gIGNvbnN0IG0gPSBtZXRob2QudG9VcHBlckNhc2UoKTtcbiAgaWYgKG0gPT09IFwiUE9TVFwiICYmIEFHRU5UX0lORkVSRU5DRS50ZXN0KHApKSByZXR1cm4gdHJ1ZTtcbiAgaWYgKG0gPT09IFwiR0VUXCIgJiYgQUdFTlRfTUVUQURBVEEudGVzdChwKSkgcmV0dXJuIHRydWU7XG4gIHJldHVybiBmYWxzZTtcbn1cblxuLyoqXG4gKiBQYXRjaGVzIGFyb3VuZCBgQG1hc3RyYS9leHByZXNzYCdzIGN1c3RvbS1yb3V0ZSBkaXNwYXRjaGVyIHNvIHRoZVxuICogcGx1Z2luJ3MgY3VzdG9tIEFQSSByb3V0ZXMgKGUuZy4gYGhpc3RvcnlSb3V0ZWApIHdvcmsgd2hlblxuICogYE1hc3RyYVNlcnZlcmAgaXMgaG9zdGVkIG9uIGFuIEV4cHJlc3Mgc3ViYXBwIG1vdW50ZWQgdW5kZXIgYSBwYXJlbnRcbiAqIHBhdGggKGUuZy4gYC9hcGkvbWFzdHJhYCkuXG4gKlxuICogVGhlIGFkYXB0ZXIncyBgcmVnaXN0ZXJDdXN0b21BcGlSb3V0ZXNgIG1hdGNoZXMgYWdhaW5zdCBgcmVxLnBhdGhgXG4gKiAobW91bnQtcmVsYXRpdmUsIGNvcnJlY3QpIGJ1dCBkaXNwYXRjaGVzIHRvIGl0cyBpbnRlcm5hbCBIb25vXG4gKiBtaW5pLWFwcCB1c2luZyBgcmVxLm9yaWdpbmFsVXJsYCwgd2hpY2ggc3RpbGwgY29udGFpbnMgdGhlIHBhcmVudFxuICogbW91bnQgcHJlZml4LiBUaGUgSG9ubyBhcHAgcmVnaXN0ZXJzIHRoZSBsaXRlcmFsIHJvdXRlIHBhdGhzXG4gKiAoZm9yIGV4YW1wbGUgYC9yb3V0ZS9oaXN0b3J5YCksIHNvIHRoZSBhYnNvbHV0ZSBVUkwgbmV2ZXIgbWF0Y2hlc1xuICogdW50aWwgd2Ugb3ZlcndyaXRlIGBvcmlnaW5hbFVybGAgZm9yIGAvcm91dGVgIGFuZCBgL3JvdXRlLypgIHRvIHRoZVxuICogbW91bnQtcmVsYXRpdmUgcGF0aC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGF0dGFjaFJvdXRlUGF0Y2hNaWRkbGV3YXJlKGFwcDogZXhwcmVzcy5FeHByZXNzKTogdm9pZCB7XG4gIGFwcC51c2UoKHJlcSwgX3JlcywgbmV4dCkgPT4ge1xuICAgIGNvbnN0IGlzQ3VzdG9tUm91dGUgPSByZXEucGF0aCA9PT0gXCIvcm91dGVcIiB8fCByZXEucGF0aC5zdGFydHNXaXRoKFwiL3JvdXRlL1wiKTtcbiAgICBpZiAoIWlzQ3VzdG9tUm91dGUpIHJldHVybiBuZXh0KCk7XG4gICAgcmVxLm9yaWdpbmFsVXJsID0gcmVxLnBhdGg7XG4gICAgbmV4dCgpO1xuICB9KTtcbn1cbiJdfQ==
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.6.3",
32
- "@dbx-tools/genie": "0.6.3",
33
- "@dbx-tools/core": "0.6.3",
34
- "@dbx-tools/shared-core": "0.6.3",
35
- "@dbx-tools/shared-mastra": "0.6.3",
36
- "@dbx-tools/model": "0.6.3",
37
- "@dbx-tools/shared-genie": "0.6.3",
38
- "@dbx-tools/shared-model": "0.6.3"
31
+ "@dbx-tools/appkit": "0.6.4",
32
+ "@dbx-tools/core": "0.6.4",
33
+ "@dbx-tools/genie": "0.6.4",
34
+ "@dbx-tools/model": "0.6.4",
35
+ "@dbx-tools/shared-genie": "0.6.4",
36
+ "@dbx-tools/shared-mastra": "0.6.4",
37
+ "@dbx-tools/shared-core": "0.6.4",
38
+ "@dbx-tools/shared-model": "0.6.4"
39
39
  },
40
40
  "main": "./lib/index.js",
41
41
  "license": "UNLICENSED",
42
42
  "publishConfig": {
43
43
  "access": "public"
44
44
  },
45
- "version": "0.6.3",
45
+ "version": "0.6.4",
46
46
  "types": "./lib/index.d.ts",
47
47
  "type": "module",
48
48
  "exports": {
package/src/config.ts CHANGED
@@ -100,14 +100,39 @@ export function executionContextUserId(context: appkit.ExecutionContextLike): st
100
100
  return "userId" in context ? context.userId : context.serviceUserId;
101
101
  }
102
102
 
103
+ /**
104
+ * Who a turn is ATTRIBUTED to, which is not always whose Databricks credential
105
+ * runs it. An OBO context's own user id is authoritative. Under the service
106
+ * principal, every caller shares one credential, so the forwarded user id is
107
+ * what keeps memory threads and per-user cache namespaces distinct; the service
108
+ * principal id is the floor when no user was forwarded.
109
+ *
110
+ * This rule has to be identical everywhere a cache key is built, so both the
111
+ * write side (the `RequestContext` user stamped by `stampRequestContextUser`)
112
+ * and the read side (the plugin's own AppKit routes, which have a request but
113
+ * no `RequestContext`) derive their key from this one function. When the two
114
+ * disagreed, a chart written under the forwarded user id was read back under
115
+ * the service principal id and the embed route answered 404, which the chat UI
116
+ * renders as an expired chart.
117
+ */
118
+ export function attributedUserId(
119
+ executionContext: appkit.ExecutionContextLike,
120
+ forwardedUserId?: string,
121
+ ): string {
122
+ if ("isUserContext" in executionContext) return executionContextUserId(executionContext);
123
+ return forwardedUserId ?? executionContextUserId(executionContext);
124
+ }
125
+
103
126
  /**
104
127
  * Identity every per-user cache entry is namespaced under, so an OBO result
105
128
  * cannot be read back by another caller.
106
129
  *
107
130
  * Prefers the {@link User} that {@link MastraServer} stamps on the request
108
- * context. The MCP transport routes do not thread that context into tool
109
- * execution, so those fall back to the ambient execution context (the active
110
- * OBO scope, or the service principal).
131
+ * context, whose id already follows {@link attributedUserId}. The MCP transport
132
+ * routes do not thread that context into tool execution, so those fall back to
133
+ * the ambient execution context (the active OBO scope, or the service
134
+ * principal). A caller holding an express request should build its key from
135
+ * {@link attributedUserId} instead, so the forwarded user is not lost.
111
136
  */
112
137
  export function resolveUserKey(requestContext?: RequestContext): string {
113
138
  const user = requestContext?.get(MASTRA_USER_KEY) as User | undefined;
package/src/genie.ts CHANGED
@@ -176,41 +176,44 @@ const CONVERSATION_TTL_SEC = 4 * 60 * 60;
176
176
  const CONVERSATION_CACHE_NAMESPACE = "mastra:genie:conversation";
177
177
 
178
178
  /**
179
- * Build the per-request {@link RequestContext} key the active
180
- * Genie `conversation_id` lives under for `spaceId`. Scoped by
181
- * space so an app calling two Genie spaces in one request keeps
182
- * each conversation distinct (Genie conversation ids are
183
- * space-scoped on the wire). The same `RequestContext` instance
184
- * flows from the central agent through to every `ask_genie`
185
- * invocation, so writes on one call are visible on the next
186
- * without an explicit shared ref.
179
+ * Per-request state for one Genie space. The reusable conversation is reserved
180
+ * by at most one invocation at a time. Additional concurrent invocations use
181
+ * isolated conversations so Mastra can execute parallel tool calls without
182
+ * appending multiple active messages to the same Genie conversation.
187
183
  */
184
+ interface ConversationState {
185
+ conversationId?: string;
186
+ reusableConversationInFlight: boolean;
187
+ }
188
+
189
+ /** Build the per-request {@link RequestContext} key for one Genie space. */
188
190
  const conversationContextKey = (spaceId: string): string =>
189
191
  `mastra__genie_conversation__${spaceId}`;
190
192
 
191
193
  /**
192
- * Read the active Genie `conversation_id` for `spaceId` off the
193
- * per-request {@link RequestContext}. Returns `undefined` when no
194
- * conversation has been started yet this request.
194
+ * Read or initialize the per-space conversation state. The string branch
195
+ * preserves compatibility with a context populated by an older package copy.
195
196
  */
196
- function readContextConversationId(
197
- requestContext: RequestContext,
198
- spaceId: string,
199
- ): string | undefined {
200
- return requestContext.get(conversationContextKey(spaceId)) as string | undefined;
197
+ function conversationState(requestContext: RequestContext, spaceId: string): ConversationState {
198
+ const key = conversationContextKey(spaceId);
199
+ const current = requestContext.get(key) as ConversationState | string | undefined;
200
+ if (current && typeof current === "object") return current;
201
+ const state: ConversationState = {
202
+ ...(typeof current === "string" ? { conversationId: current } : {}),
203
+ reusableConversationInFlight: false,
204
+ };
205
+ requestContext.set(key, state);
206
+ return state;
201
207
  }
202
208
 
203
209
  /**
204
- * Write the active Genie `conversation_id` for `spaceId` onto the
205
- * per-request {@link RequestContext}. Subsequent `ask_genie` calls
206
- * in this request will reuse it.
210
+ * Reserve the reusable conversation when it is idle. A caller that cannot
211
+ * reserve it gets an isolated conversation and may run in parallel.
207
212
  */
208
- function writeContextConversationId(
209
- requestContext: RequestContext,
210
- spaceId: string,
211
- conversationId: string | undefined,
212
- ): void {
213
- requestContext.set(conversationContextKey(spaceId), conversationId);
213
+ function reserveConversation(state: ConversationState): boolean {
214
+ if (state.reusableConversationInFlight) return false;
215
+ state.reusableConversationInFlight = true;
216
+ return true;
214
217
  }
215
218
 
216
219
  /**
@@ -296,13 +299,12 @@ async function evictCachedConversationId(cacheKey: string | undefined): Promise<
296
299
  * once per request per space.
297
300
  */
298
301
  async function ensureConversationSeeded(
299
- requestContext: RequestContext,
300
- spaceId: string,
302
+ state: ConversationState,
301
303
  cacheKey: string | undefined,
302
304
  ): Promise<void> {
303
- if (readContextConversationId(requestContext, spaceId)) return;
305
+ if (state.conversationId) return;
304
306
  const cached = await readCachedConversationId(cacheKey);
305
- if (cached) writeContextConversationId(requestContext, spaceId, cached);
307
+ if (cached) state.conversationId = cached;
306
308
  }
307
309
 
308
310
  /* ------------------------ prepare_chart input ------------------------ */
@@ -385,8 +387,11 @@ function buildAskGenieTool(opts: { spaceId: string; alias: string; hint?: string
385
387
  complete. Genie answers best when each call covers a
386
388
  single metric / dimension / time window, so expect to
387
389
  call this tool MULTIPLE TIMES per user turn (typically
388
- two to six) and let the results from earlier calls inform
389
- later ones - that's the normal pattern, not the exception.
390
+ two to six). Independent sub-questions may be called in
391
+ PARALLEL; calls that depend on an earlier answer should stay
392
+ sequential. Parallel calls use isolated Genie conversations,
393
+ while sequential calls retain the reusable conversation context.
394
+ This is the normal pattern, not the exception.
390
395
  Do NOT try to cram a multi-part question into a single
391
396
  call; decompose first, then ask each piece.
392
397
 
@@ -442,90 +447,87 @@ function buildAskGenieTool(opts: { spaceId: string; alias: string; hint?: string
442
447
  );
443
448
  }
444
449
 
445
- // Seed the active Genie `conversation_id` onto `RequestContext`
446
- // from the cross-request cache when a Mastra `threadId` is
447
- // present so multi-turn chats reuse the same Genie conversation
448
- // (and Genie's accumulated context) across separate user turns.
449
- // The same `RequestContext` is reused across every `ask_genie`
450
- // call within one user turn, so `ensureConversationSeeded`
451
- // hits the cache at most once per request per space.
452
- const cacheKey = await conversationCacheKey(
453
- spaceId,
454
- threadId,
455
- resolveUserKey(requestContext),
456
- );
457
- await ensureConversationSeeded(requestContext, spaceId, cacheKey);
458
-
459
- // Fire the lifecycle `started` event before any LLM /
460
- // network round-trip so the host UI can pop a "Thinking..."
461
- // pill the instant the model decides to delegate.
462
- const startedEvent: StartedEvent = {
463
- type: "started",
464
- spaceId,
465
- content: question,
466
- };
467
- await safeWrite(logger, writer, startedEvent);
468
-
469
- // Single turn of `genieEventChat`. Hoisted into a closure so
470
- // we can re-run it after evicting a stale `conversation_id`
471
- // without duplicating the event-loop body.
472
- const runTurn = async (): Promise<GenieMessage> => {
473
- const seedConversationId = readContextConversationId(requestContext, spaceId);
474
- let finalMessage: GenieMessage | undefined;
475
- for await (const event of chat.genieEventChat(spaceId, question, {
476
- workspaceClient: client,
477
- ...(seedConversationId ? { conversationId: seedConversationId } : {}),
478
- ...(signal ? { context: signal } : {}),
479
- })) {
480
- if (event.type !== "message") {
481
- await safeWrite(logger, writer, event);
482
- }
483
- const eventConversationId = event.conversation_id;
484
- if (eventConversationId) {
485
- writeContextConversationId(requestContext, spaceId, eventConversationId);
450
+ const state = conversationState(requestContext, spaceId);
451
+ const ownsReusableConversation = reserveConversation(state);
452
+ try {
453
+ // Only the reserved lane seeds and updates the thread's reusable
454
+ // conversation. Concurrent lanes deliberately start fresh conversations.
455
+ const cacheKey = ownsReusableConversation
456
+ ? await conversationCacheKey(spaceId, threadId, resolveUserKey(requestContext))
457
+ : undefined;
458
+ if (ownsReusableConversation) {
459
+ await ensureConversationSeeded(state, cacheKey);
460
+ }
461
+
462
+ // Each invocation keeps its conversation id locally. Only the reusable
463
+ // lane publishes updates to shared request and cross-request state.
464
+ let conversationId = ownsReusableConversation ? state.conversationId : undefined;
465
+
466
+ const startedEvent: StartedEvent = {
467
+ type: "started",
468
+ spaceId,
469
+ content: question,
470
+ };
471
+ await safeWrite(logger, writer, startedEvent);
472
+
473
+ const runTurn = async (): Promise<GenieMessage> => {
474
+ const seedConversationId = conversationId;
475
+ let finalMessage: GenieMessage | undefined;
476
+ for await (const event of chat.genieEventChat(spaceId, question, {
477
+ workspaceClient: client,
478
+ ...(seedConversationId ? { conversationId: seedConversationId } : {}),
479
+ ...(signal ? { context: signal } : {}),
480
+ })) {
481
+ if (event.type !== "message") {
482
+ await safeWrite(logger, writer, event);
483
+ }
484
+ const eventConversationId = event.conversation_id;
485
+ if (eventConversationId) {
486
+ conversationId = eventConversationId;
487
+ if (ownsReusableConversation) state.conversationId = eventConversationId;
488
+ }
489
+ if (event.type === "result") {
490
+ finalMessage = event.message;
491
+ }
486
492
  }
487
- if (event.type === "result") {
488
- finalMessage = event.message;
493
+ if (!finalMessage) {
494
+ throw ExecutionError.missingData("Genie result event");
489
495
  }
490
- }
491
- if (!finalMessage) {
492
- throw ExecutionError.missingData("Genie result event");
493
- }
494
- return finalMessage;
495
- };
496
+ return finalMessage;
497
+ };
496
498
 
497
- let finalMessage: GenieMessage;
498
- try {
499
- finalMessage = await runTurn();
500
- } catch (err) {
501
- // The seeded `conversation_id` was rejected by Genie - most
502
- // commonly because it was deleted upstream, expired past
503
- // Databricks' (undocumented) lifetime, or was minted in a
504
- // different space. Drop both the cached id AND the
505
- // per-request value so the retry calls `startConversation`,
506
- // and try once more. Only retry when we *had* a seeded id -
507
- // a fresh call that 404s shouldn't loop.
508
- const seeded = readContextConversationId(requestContext, spaceId);
509
- if (seeded && error.errorContext(err).notAccessible) {
510
- logger.warn("conversation-cache:stale, resetting", {
511
- spaceId,
512
- conversationId: seeded,
513
- error: error.errorMessage(err),
514
- });
515
- await evictCachedConversationId(cacheKey);
516
- writeContextConversationId(requestContext, spaceId, undefined);
499
+ let finalMessage: GenieMessage;
500
+ try {
517
501
  finalMessage = await runTurn();
518
- } else {
519
- throw err;
502
+ } catch (err) {
503
+ // A rejected conversation id is stale or inaccessible. Reset this
504
+ // lane and retry once with a fresh Genie conversation.
505
+ const rejectedConversationId = conversationId;
506
+ if (rejectedConversationId && error.errorContext(err).notAccessible) {
507
+ logger.warn("conversation-cache:stale, resetting", {
508
+ spaceId,
509
+ conversationId: rejectedConversationId,
510
+ error: error.errorMessage(err),
511
+ });
512
+ if (ownsReusableConversation) {
513
+ await evictCachedConversationId(cacheKey);
514
+ state.conversationId = undefined;
515
+ }
516
+ conversationId = undefined;
517
+ finalMessage = await runTurn();
518
+ } else {
519
+ throw err;
520
+ }
520
521
  }
521
- }
522
522
 
523
- // Refresh the cache entry on every successful turn. Re-setting
524
- // the same key both persists newly-minted ids (cache miss path)
525
- // and extends the TTL on active conversations (sliding window).
526
- await saveCachedConversationId(cacheKey, readContextConversationId(requestContext, spaceId));
523
+ if (ownsReusableConversation) {
524
+ await saveCachedConversationId(cacheKey, conversationId);
525
+ }
527
526
 
528
- return { message: stripSuggestedQuestions(finalMessage) };
527
+ return { message: stripSuggestedQuestions(finalMessage) };
528
+ } finally {
529
+ if (ownsReusableConversation) state.reusableConversationInFlight = false;
530
+ }
529
531
  },
530
532
  });
531
533
  }
@@ -791,10 +793,13 @@ export const GENIE_INSTRUCTIONS = string.toDescription([
791
793
  Decompose the user's question into focused sub-questions
792
794
  BEFORE asking Genie anything. One sub-question per distinct
793
795
  metric, dimension, or time window. Then call \`ask_genie\`
794
- once per sub-question - usually two to six calls per turn,
795
- and let earlier answers inform what you ask next. Cramming
796
- a multi-part question into one \`ask_genie\` call almost
797
- always produces a worse answer than asking the pieces
796
+ once per sub-question - usually two to six calls per turn.
797
+ Issue independent calls in parallel to reduce latency. Keep
798
+ dependent calls sequential when an earlier answer determines
799
+ the next question. Parallel calls use isolated Genie
800
+ conversations; sequential calls retain conversation context.
801
+ Cramming a multi-part question into one \`ask_genie\` call
802
+ almost always produces a worse answer than asking the pieces
798
803
  separately. Only collapse to a single call when the question
799
804
  is genuinely atomic ("what was Q3 revenue?").
800
805
 
@@ -803,8 +808,9 @@ export const GENIE_INSTRUCTIONS = string.toDescription([
803
808
  regions drove the gap?" Decomposes to: (a) \`ask_genie\`
804
809
  for SKU 1234's Q3 revenue, (b) \`ask_genie\` for the
805
810
  category-average Q3 revenue, (c) \`ask_genie\` for SKU
806
- 1234's Q3 revenue split by region. Three focused calls,
807
- each grounded in the prior results.
811
+ 1234's Q3 revenue split by region. The first two calls are
812
+ independent and can run in parallel; run the regional call
813
+ afterward only if its wording depends on those results.
808
814
  `,
809
815
  `
810
816
  Each \`ask_genie\` call returns the terminal \`GenieMessage\`.
package/src/plugin.ts CHANGED
@@ -76,7 +76,7 @@ import type { Pool } from "pg";
76
76
 
77
77
  import { buildAgents, FALLBACK_AGENT_ID, type BuiltAgents } from "./agents.ts";
78
78
  import { fetchChart } from "./chart.ts";
79
- import { MASTRA_CONFIG_SCHEMA, resolveUserKey, type MastraPluginConfig } from "./config.ts";
79
+ import { attributedUserId, MASTRA_CONFIG_SCHEMA, type MastraPluginConfig } from "./config.ts";
80
80
  import {
81
81
  chartFetchDefaults,
82
82
  feedbackWriteDefaults,
@@ -86,7 +86,12 @@ 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
+ import {
90
+ requestUserId,
91
+ resolveIdentityMode,
92
+ useServicePrincipal,
93
+ type MastraIdentityMode,
94
+ } from "./identity.ts";
90
95
  import { buildMcpServer, type ResolvedMcp } from "./mcp.ts";
91
96
  import { createMemoryBuilder, createServicePrincipalPool, needsLakebase } from "./memory.ts";
92
97
  import { logFeedback, resolveFeedbackEnabled } from "./mlflow.ts";
@@ -565,7 +570,7 @@ export class MastraPlugin extends Plugin<MastraPluginConfig> {
565
570
  const embedResolvers: Record<string, EmbedResolver> = {
566
571
  chart: (req, id, signal) => {
567
572
  const timeoutMs = parseTimeoutMs(req.query.timeoutMs);
568
- return this.scopedSelf(req).fetchChartEntry(id, {
573
+ return this.scopedSelf(req).fetchChartEntry(req, id, {
569
574
  ...(timeoutMs !== undefined ? { timeoutMs } : {}),
570
575
  signal,
571
576
  });
@@ -908,12 +913,21 @@ export class MastraPlugin extends Plugin<MastraPluginConfig> {
908
913
  * (`GET /embed/chart/:id`). Runs inside the AppKit user-context proxy so the
909
914
  * lookup is namespaced to the calling identity: a chart minted for another
910
915
  * user is indistinguishable from an unknown id, and the route answers 404.
916
+ *
917
+ * The key is built from {@link attributedUserId} - the same rule that named
918
+ * the identity the chart was written under - rather than from the ambient
919
+ * execution context alone. In `service-principal` mode the ambient context is
920
+ * the SP for every caller, so keying off it alone missed every chart the
921
+ * turn had written under the forwarded user and the UI showed each one as
922
+ * expired. `req` is read inside the method, not at the call site, so the
923
+ * execution context is the scoped one.
911
924
  */
912
925
  private async fetchChartEntry(
926
+ req: express.Request,
913
927
  chartId: string,
914
928
  options: { timeoutMs?: number; signal: AbortSignal },
915
929
  ): Promise<ExecutionResult<Chart | undefined>> {
916
- const userKey = resolveUserKey();
930
+ const userKey = attributedUserId(getExecutionContext(), requestUserId(req));
917
931
  return this.execute(
918
932
  (executeSignal) =>
919
933
  fetchChart(chartId, {