@cartanova/qgrid-cli 2.7.5 → 2.7.6

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.
Files changed (47) hide show
  1. package/bundle/dist/application/qgrid/qgrid.dispatcher.js +7 -3
  2. package/bundle/dist/application/qgrid/qgrid.frame.js +27 -11
  3. package/bundle/dist/application/qgrid/qgrid.types.js +2 -1
  4. package/bundle/dist/application/qgrid/token-subscriber.js +19 -1
  5. package/bundle/dist/application/qgrid/token-window-keepalive.js +153 -0
  6. package/bundle/dist/application/setting/setting.constant.js +11 -1
  7. package/bundle/dist/application/token/token.model.js +18 -1
  8. package/bundle/dist/migrations/20260819102011_alter_tokens_alter1.js +13 -0
  9. package/bundle/dist/sonamu.config.js +9 -1
  10. package/bundle/dist/utils/providers/anthropic/anthropic-dispatcher.js +7 -4
  11. package/bundle/dist/utils/providers/openai/openai-dispatcher.js +11 -3
  12. package/bundle/src/application/qgrid/qgrid.dispatcher.test.ts +51 -0
  13. package/bundle/src/application/qgrid/qgrid.dispatcher.ts +14 -4
  14. package/bundle/src/application/qgrid/qgrid.frame.test.ts +58 -0
  15. package/bundle/src/application/qgrid/qgrid.frame.ts +39 -12
  16. package/bundle/src/application/qgrid/qgrid.types.ts +2 -0
  17. package/bundle/src/application/qgrid/token-subscriber.test.ts +112 -0
  18. package/bundle/src/application/qgrid/token-subscriber.ts +35 -0
  19. package/bundle/src/application/qgrid/token-window-keepalive.test.ts +223 -0
  20. package/bundle/src/application/qgrid/token-window-keepalive.ts +227 -0
  21. package/bundle/src/application/setting/setting.constant.test.ts +10 -0
  22. package/bundle/src/application/setting/setting.constant.ts +11 -1
  23. package/bundle/src/application/sonamu.generated.http +2 -0
  24. package/bundle/src/application/token/token.entity.json +8 -1
  25. package/bundle/src/application/token/token.model.test.ts +37 -0
  26. package/bundle/src/application/token/token.model.ts +20 -0
  27. package/bundle/src/migrations/20260819102011_alter_tokens_alter1.ts +13 -0
  28. package/bundle/src/sonamu.config.ts +14 -0
  29. package/bundle/src/utils/providers/anthropic/anthropic-dispatcher.test.ts +46 -0
  30. package/bundle/src/utils/providers/anthropic/anthropic-dispatcher.ts +13 -4
  31. package/bundle/src/utils/providers/common/provider-dispatcher.ts +2 -0
  32. package/bundle/src/utils/providers/openai/openai-dispatcher.test.ts +30 -0
  33. package/bundle/src/utils/providers/openai/openai-dispatcher.ts +17 -1
  34. package/bundle/web-dist/client/assets/index-BbOyk01G.js +106 -0
  35. package/bundle/web-dist/client/assets/{logs-BrAu0koY.js → logs-B7Pc88bf.js} +1 -1
  36. package/bundle/web-dist/client/assets/{monit-D6JEk7n7.js → monit-CzMV4lZf.js} +1 -1
  37. package/bundle/web-dist/client/assets/{routes-Dvu63qre.js → routes-COWTRxZo.js} +1 -1
  38. package/bundle/web-dist/client/assets/settings-Dpaosy-o.js +1 -0
  39. package/bundle/web-dist/client/assets/{show-BFGjYsWb.js → show-YvdybkKd.js} +1 -1
  40. package/bundle/web-dist/client/assets/{tokens-D-P__jYk.js → tokens-DynVDx0c.js} +1 -1
  41. package/bundle/web-dist/client/assets/{use-oauth-login-flow-CJpoJD26.js → use-oauth-login-flow-OzmHElsE.js} +1 -1
  42. package/bundle/web-dist/client/index.html +1 -1
  43. package/bundle/web-dist/server/assets/{settings-nCv71sax.js → settings-CIYR7h3G.js} +1 -0
  44. package/bundle/web-dist/server/entry-server.generated.js +96 -51
  45. package/package.json +1 -1
  46. package/bundle/web-dist/client/assets/index-CwSSXuZv.js +0 -106
  47. package/bundle/web-dist/client/assets/settings-mwDGFwUi.js +0 -1
@@ -164,7 +164,7 @@ var OpenAIDispatcher = class OpenAIDispatcher {
164
164
  async run(req, onDelta) {
165
165
  const signal = activeSignal(req.abortSignal, req.timeoutMs);
166
166
  if (signal.aborted) throw abortError(signal);
167
- const selection = await this.selectToken(req.preferredTokenId, signal);
167
+ const selection = await this.selectToken(req.preferredTokenId, req.requirePreferredToken ?? false, signal);
168
168
  this.inFlightCount++;
169
169
  try {
170
170
  if (signal.aborted) throw abortError(signal);
@@ -300,13 +300,21 @@ var OpenAIDispatcher = class OpenAIDispatcher {
300
300
  * 비변경), 아니면 병렬 quota 판정 후 smooth weighted round-robin. 동시성 상한이
301
301
  * 없으므로 "빈 자리" 개념도 없다 — 선택 즉시 실행이다.
302
302
  */
303
- async selectToken(preferredTokenId, signal) {
303
+ async selectToken(preferredTokenId, requirePreferredToken, signal) {
304
304
  if (preferredTokenId !== void 0) {
305
305
  const preferred = this.tokenMetadata.get(preferredTokenId);
306
306
  if (preferred?.active && await this.isQuotaEligible(preferredTokenId, preferred, signal)) return {
307
307
  tokenId: preferredTokenId,
308
308
  metadata: preferred
309
309
  };
310
+ if (requirePreferredToken) {
311
+ if (!preferred?.active) throw new Error(`Preferred openai token ${preferredTokenId} is not available`);
312
+ const threshold = preferred.quotaThreshold;
313
+ if (threshold !== null && threshold !== void 0) throw new QuotaThresholdExceededError(quotaMessage([{
314
+ name: preferred.name,
315
+ threshold
316
+ }]));
317
+ }
310
318
  }
311
319
  const checks = await Promise.all([...this.tokenMetadata.entries()].filter(([, token]) => token.active).map(async ([id, token]) => ({
312
320
  id,
@@ -438,4 +446,4 @@ var OpenAIDispatcher = class OpenAIDispatcher {
438
446
  //#endregion
439
447
  export { ImageGenerationError, OpenAIDispatcher };
440
448
 
441
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3BlbmFpLWRpc3BhdGNoZXIuanMiLCJuYW1lcyI6W10sInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3V0aWxzL3Byb3ZpZGVycy9vcGVuYWkvb3BlbmFpLWRpc3BhdGNoZXIudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgZ2V0TG9nZ2VyIH0gZnJvbSBcIkBsb2d0YXBlL2xvZ3RhcGVcIjtcblxuaW1wb3J0IHsgUXVvdGFUaHJlc2hvbGRFeGNlZWRlZEVycm9yIH0gZnJvbSBcIi4uLy4uLy4uL2FwcGxpY2F0aW9uL3FncmlkL3FncmlkLnR5cGVzXCI7XG5pbXBvcnQgeyBUb2tlbk1vZGVsIH0gZnJvbSBcIi4uLy4uLy4uL2FwcGxpY2F0aW9uL3Rva2VuL3Rva2VuLm1vZGVsXCI7XG5pbXBvcnQgeyB0eXBlIE9wZW5BSUNyZWRlbnRpYWxzIH0gZnJvbSBcIi4uLy4uLy4uL2FwcGxpY2F0aW9uL3Rva2VuL3Rva2VuLnR5cGVzXCI7XG5pbXBvcnQge1xuICB0eXBlIEdlbmVyYXRlUmVxdWVzdCxcbiAgdHlwZSBHZW5lcmF0ZVJlc3VsdCxcbiAgdHlwZSBHZW5lcmF0ZVN0cmVhbUNhbGxiYWNrcyxcbiAgdHlwZSBHZW5lcmF0ZWRJbWFnZSxcbiAgdHlwZSBQcm92aWRlckRpc3BhdGNoZXIsXG59IGZyb20gXCIuLi9jb21tb24vcHJvdmlkZXItZGlzcGF0Y2hlclwiO1xuaW1wb3J0IHsgU21vb3RoV2VpZ2h0ZWRSb3VuZFJvYmluIH0gZnJvbSBcIi4uL2NvbW1vbi9zbW9vdGgtd2VpZ2h0ZWQtcm91bmQtcm9iaW5cIjtcbmltcG9ydCB7XG4gIHR5cGUgSnNvblZhbHVlLFxuICB0eXBlIE9wZW5BSVJlc3BvbnNlSXRlbSxcbiAgdHlwZSBPcGVuQUlSZXNwb25zZXNPcHRpb25zLFxufSBmcm9tIFwiLi9vcGVuYWktYmFja2VuZC1wcm90b2NvbFwiO1xuaW1wb3J0IHsgT3BlbkFJRGlyZWN0Q2xpZW50LCB0eXBlIE9wZW5BSURpcmVjdENsaWVudE9wdGlvbnMgfSBmcm9tIFwiLi9vcGVuYWktZGlyZWN0LWNsaWVudFwiO1xuaW1wb3J0IHsgcmVhZE9wZW5BSVF1b3RhVXNhZ2UsIHR5cGUgT3BlbkFJUmF0ZUxpbWl0c1dpdGhNZXRhIH0gZnJvbSBcIi4vb3BlbmFpLXF1b3RhXCI7XG5pbXBvcnQgeyBoYW5kbGVDaGF0Z3B0QXV0aFRva2Vuc1JlZnJlc2ggfSBmcm9tIFwiLi9vcGVuYWktcmVmcmVzaFwiO1xuaW1wb3J0IHsgdHlwZSBPcGVuQUlUcmFuc3BvcnRLaW5kLCByZXNvbHZlT3BlbkFJVHJhbnNwb3J0S2luZCB9IGZyb20gXCIuL29wZW5haS10cmFuc3BvcnQtY29uZmlnXCI7XG5cbmNvbnN0IGxvZ2dlciA9IGdldExvZ2dlcihbXCJxZ3JpZFwiLCBcIm9wZW5haS1kaXNwYXRjaGVyXCJdKTtcbi8vIOq1kOyytOuQnCBjb2RleCB3b3JrZXIg6rCAIOqwleygnO2VmOuNmCB3YXRjaGRvZy4g7Zi47Lac7J6Q6rCAIHRpbWVvdXRNcyDrpbwg7IOd65617ZW064+EIOyalOyyreydtFxuLy8g7JiB7JuQ7Z6IIOunpOuLrOumrOyngCDslYrrj4TroZ0gZGlyZWN0IHRyYW5zcG9ydCDrj4Qg7Jyg7ZWc7ZWcIOq4sOuzuCDsg4HtlZzsnYQg7Jyg7KeA7ZWc64ukLlxuY29uc3QgREVGQVVMVF9SRVFVRVNUX1RJTUVPVVRfTVMgPSA2MDBfMDAwO1xuXG5leHBvcnQgdHlwZSBJbWFnZUZhaWx1cmVLaW5kID0gXCJnYXRlXCIgfCBcIm5vdF9jYWxsZWRcIiB8IFwiaW5jb21wbGV0ZVwiO1xuXG5leHBvcnQgY2xhc3MgSW1hZ2VHZW5lcmF0aW9uRXJyb3IgZXh0ZW5kcyBFcnJvciB7XG4gIGNvbnN0cnVjdG9yKFxuICAgIHJlYWRvbmx5IGtpbmQ6IEltYWdlRmFpbHVyZUtpbmQsXG4gICAgbWVzc2FnZTogc3RyaW5nLFxuICApIHtcbiAgICBzdXBlcihtZXNzYWdlKTtcbiAgICB0aGlzLm5hbWUgPSBcIkltYWdlR2VuZXJhdGlvbkVycm9yXCI7XG4gIH1cbn1cblxudHlwZSBUb2tlbk1ldGFkYXRhID0ge1xuICBuYW1lOiBzdHJpbmc7XG4gIGNyZWRlbnRpYWxzOiBPcGVuQUlDcmVkZW50aWFscztcbiAgcXVvdGFUaHJlc2hvbGQ/OiBudW1iZXIgfCBudWxsO1xuICB3ZWlnaHQ6IG51bWJlcjtcbiAgYWN0aXZlOiBib29sZWFuO1xuICBnZW5lcmF0aW9uOiBudW1iZXI7XG59O1xuXG50eXBlIFRva2VuU2VsZWN0aW9uID0geyB0b2tlbklkOiBudW1iZXI7IG1ldGFkYXRhOiBUb2tlbk1ldGFkYXRhIH07XG5cbmV4cG9ydCB0eXBlIE9wZW5BSURpcmVjdENsaWVudEZhY3RvcnkgPSAoXG4gIG9wdGlvbnM6IE9wZW5BSURpcmVjdENsaWVudE9wdGlvbnMsXG4gIHRva2VuSWQ6IG51bWJlcixcbikgPT4gUGljazxPcGVuQUlEaXJlY3RDbGllbnQsIFwicmVzcG9uc2VzXCI+ICYgeyBjbG9zZT86ICgpID0+IHZvaWQgfTtcblxudHlwZSBDbGllbnRFbnRyeSA9IHtcbiAgZ2VuZXJhdGlvbjogbnVtYmVyO1xuICBjbGllbnQ6IFBpY2s8T3BlbkFJRGlyZWN0Q2xpZW50LCBcInJlc3BvbnNlc1wiPiAmIHsgY2xvc2U/OiAoKSA9PiB2b2lkIH07XG4gIGluRmxpZ2h0OiBudW1iZXI7XG4gIHJldGlyZWQ6IGJvb2xlYW47XG59O1xuXG5leHBvcnQgaW50ZXJmYWNlIE9wZW5BSURpc3BhdGNoZXJEZXBlbmRlbmNpZXMge1xuICBjbGllbnRGYWN0b3J5PzogT3BlbkFJRGlyZWN0Q2xpZW50RmFjdG9yeTtcbiAgZmV0Y2g/OiB0eXBlb2YgZmV0Y2g7XG59XG5cbmZ1bmN0aW9uIGFib3J0RXJyb3Ioc2lnbmFsOiBBYm9ydFNpZ25hbCk6IEVycm9yIHtcbiAgY29uc3QgcmVhc29uID0gc2lnbmFsLnJlYXNvbjtcbiAgcmV0dXJuIHJlYXNvbiBpbnN0YW5jZW9mIEVycm9yID8gcmVhc29uIDogbmV3IERPTUV4Y2VwdGlvbihcIkFib3J0ZWRcIiwgXCJBYm9ydEVycm9yXCIpO1xufVxuXG5mdW5jdGlvbiBhY3RpdmVTaWduYWwoc2lnbmFsPzogQWJvcnRTaWduYWwsIHRpbWVvdXRNcz86IG51bWJlcik6IEFib3J0U2lnbmFsIHtcbiAgY29uc3QgdGltZW91dCA9IEFib3J0U2lnbmFsLnRpbWVvdXQodGltZW91dE1zID8/IERFRkFVTFRfUkVRVUVTVF9USU1FT1VUX01TKTtcbiAgcmV0dXJuIHNpZ25hbCA/IEFib3J0U2lnbmFsLmFueShbc2lnbmFsLCB0aW1lb3V0XSkgOiB0aW1lb3V0O1xufVxuXG5mdW5jdGlvbiBxdW90YU1lc3NhZ2UoZW50cmllczogQXJyYXk8eyBuYW1lOiBzdHJpbmc7IHRocmVzaG9sZDogbnVtYmVyIH0+KTogc3RyaW5nIHtcbiAgY29uc3QgZGV0YWlsID0gZW50cmllcy5tYXAoKGUpID0+IGAke2UubmFtZX0gKHRocmVzaG9sZCAke2UudGhyZXNob2xkfSUpYCkuam9pbihcIiwgXCIpO1xuICByZXR1cm4gZGV0YWlsXG4gICAgPyBgQWxsIG9wZW5haSB0b2tlbnMgZXhjZWVkZWQgcXVvdGEgdGhyZXNob2xkOiAke2RldGFpbH1gXG4gICAgOiBcIkFsbCBvcGVuYWkgdG9rZW5zIGV4Y2VlZGVkIHF1b3RhIHRocmVzaG9sZFwiO1xufVxuXG5mdW5jdGlvbiBpbnB1dEl0ZW1zKHJlcTogR2VuZXJhdGVSZXF1ZXN0KTogT3BlbkFJUmVzcG9uc2VJdGVtW10ge1xuICBjb25zdCBoaXN0b3J5ID0gKHJlcS5jb2xkSGlzdG9yeSA/PyBbXSkgYXMgT3BlbkFJUmVzcG9uc2VJdGVtW107XG4gIGNvbnN0IGNvbnRlbnQ6IE9wZW5BSVJlc3BvbnNlSXRlbVtdID0gcmVxLmNvbGRJbnB1dC5tYXAoKGlucHV0KSA9PiB7XG4gICAgaWYgKGlucHV0LnR5cGUgPT09IFwidGV4dFwiKSByZXR1cm4geyB0eXBlOiBcImlucHV0X3RleHRcIiwgdGV4dDogaW5wdXQudGV4dCB9O1xuICAgIGlmIChpbnB1dC50eXBlID09PSBcImltYWdlXCIpIHJldHVybiB7IHR5cGU6IFwiaW5wdXRfaW1hZ2VcIiwgaW1hZ2VfdXJsOiBpbnB1dC51cmwgfTtcbiAgICBpZiAoaW5wdXQudHlwZSA9PT0gXCJsb2NhbEltYWdlXCIpIHJldHVybiB7IHR5cGU6IFwiaW5wdXRfaW1hZ2VcIiwgaW1hZ2VfdXJsOiBpbnB1dC5wYXRoIH07XG4gICAgcmV0dXJuIHsgdHlwZTogXCJpbnB1dF90ZXh0XCIsIHRleHQ6IGAke2lucHV0Lm5hbWV9OiAke2lucHV0LnBhdGh9YCB9O1xuICB9KTtcbiAgcmV0dXJuIFsuLi5oaXN0b3J5LCB7IHR5cGU6IFwibWVzc2FnZVwiLCByb2xlOiBcInVzZXJcIiwgY29udGVudCB9XTtcbn1cblxuZnVuY3Rpb24gYXNSZWFzb25pbmcocmVxOiBHZW5lcmF0ZVJlcXVlc3QpOiBPcGVuQUlSZXNwb25zZXNPcHRpb25zW1wicmVhc29uaW5nXCJdIHwgdW5kZWZpbmVkIHtcbiAgY29uc3Qgc3VtbWFyeSA9XG4gICAgcmVxLnJlYXNvbmluZ1N1bW1hcnkgJiYgcmVxLnJlYXNvbmluZ1N1bW1hcnkgIT09IFwibm9uZVwiID8gcmVxLnJlYXNvbmluZ1N1bW1hcnkgOiB1bmRlZmluZWQ7XG4gIGlmICghcmVxLmVmZm9ydCAmJiAhc3VtbWFyeSkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgcmV0dXJuIHtcbiAgICAuLi4ocmVxLmVmZm9ydFxuICAgICAgPyB7IGVmZm9ydDogcmVxLmVmZm9ydCBhcyBOb25OdWxsYWJsZTxPcGVuQUlSZXNwb25zZXNPcHRpb25zW1wicmVhc29uaW5nXCJdPltcImVmZm9ydFwiXSB9XG4gICAgICA6IHt9KSxcbiAgICAuLi4oc3VtbWFyeVxuICAgICAgPyB7XG4gICAgICAgICAgc3VtbWFyeTogc3VtbWFyeSBhcyBOb25OdWxsYWJsZTxPcGVuQUlSZXNwb25zZXNPcHRpb25zW1wicmVhc29uaW5nXCJdPltcInN1bW1hcnlcIl0sXG4gICAgICAgIH1cbiAgICAgIDoge30pLFxuICB9O1xufVxuXG5mdW5jdGlvbiByZXF1ZXN0T3B0aW9ucyhyZXE6IEdlbmVyYXRlUmVxdWVzdCk6IE9wZW5BSVJlc3BvbnNlc09wdGlvbnMge1xuICByZXR1cm4ge1xuICAgIG1vZGVsOiByZXEubW9kZWwgPz8gXCJcIixcbiAgICAuLi4ocmVxLnN5c3RlbVByb21wdCA/IHsgaW5zdHJ1Y3Rpb25zOiByZXEuc3lzdGVtUHJvbXB0IH0gOiB7fSksXG4gICAgaGlzdG9yeTogaW5wdXRJdGVtcyhyZXEpLFxuICAgIC4uLihhc1JlYXNvbmluZyhyZXEpID8geyByZWFzb25pbmc6IGFzUmVhc29uaW5nKHJlcSkgfSA6IHt9KSxcbiAgICAuLi4ocmVxLnZlcmJvc2l0eSA/IHsgdmVyYm9zaXR5OiByZXEudmVyYm9zaXR5IGFzIE9wZW5BSVJlc3BvbnNlc09wdGlvbnNbXCJ2ZXJib3NpdHlcIl0gfSA6IHt9KSxcbiAgICAuLi4ocmVxLnNlcnZpY2VUaWVyXG4gICAgICA/IHsgc2VydmljZVRpZXI6IHJlcS5zZXJ2aWNlVGllciA9PT0gXCJmYXN0XCIgPyBcInByaW9yaXR5XCIgOiByZXEuc2VydmljZVRpZXIgfVxuICAgICAgOiB7fSksXG4gICAgLi4uKHJlcS5wcm9tcHRDYWNoZUtleSA/IHsgcHJvbXB0Q2FjaGVLZXk6IHJlcS5wcm9tcHRDYWNoZUtleSB9IDoge30pLFxuICAgIC4uLihyZXEub3V0cHV0U2NoZW1hID8geyBvdXRwdXRTY2hlbWE6IHsgc2NoZW1hOiByZXEub3V0cHV0U2NoZW1hIGFzIEpzb25WYWx1ZSB9IH0gOiB7fSksXG4gICAgLi4uKHJlcS5pbWFnZUdlbmVyYXRpb25cbiAgICAgID8geyBpbWFnZUdlbmVyYXRpb246IHJlcS5pbWFnZUdlbmVyYXRpb25PcHRpb25zID8geyAuLi5yZXEuaW1hZ2VHZW5lcmF0aW9uT3B0aW9ucyB9IDogdHJ1ZSB9XG4gICAgICA6IHt9KSxcbiAgfTtcbn1cblxuLyoqXG4gKiBEaXJlY3QgT3BlbkFJIGRpc3BhdGNoZXIg4oCUIEFudGhyb3BpYyDqs7wg64+Z7J287ZWcIHN0YXRlbGVzcyDsi6Ttlokg66qo6424LlxuICpcbiAqIOyalOyyrSA9IO2GoO2BsCDshKDtg50ocXVvdGEgZ2F0ZSArIHdlaWdodGVkIHJvdW5kLXJvYmluICsgY2FjaGUgYWZmaW5pdHkg7ISg7Zi4KSDihpIgSFRUUFMvV1NcbiAqIOyghOyGoS4gcGVybWl0L+2BkCDqsJnsnYAg64+Z7Iuc7ISxIOyDge2VnOydgCDrkZDsp4Ag7JWK64qU64ukOiDsoITshqHsnYAgZmV0Y2gg7ZWcIOuyiOydtOudvCDroZzsu6wg7J6Q7JuQ7J20XG4gKiDtnazshoztlZjsp4Ag7JWK6rOgLCDsg4HrpZgg7KCc7ZWc7J2AIOuwseyXlOuTnOydmCDsnZHri7UoNDI5IOuTsSnsnbQg7KeE7Iuk7J2064ukLiB3b3JrZXIgcG9vbCDsi5zsoIjsnZhcbiAqIO2BkCDsnZjrr7jroaAoU0VSVkVSX0JVU1ksIO2BkCDtg4DsnoTslYTsm4Mp7J2AIOydtCDsoITtmZjsnLzroZwg7KCc6rGw65CQ64ukLlxuICovXG5leHBvcnQgY2xhc3MgT3BlbkFJRGlzcGF0Y2hlciBpbXBsZW1lbnRzIFByb3ZpZGVyRGlzcGF0Y2hlciB7XG4gIHJlYWRvbmx5IHRva2VuTWV0YWRhdGEgPSBuZXcgTWFwPG51bWJlciwgVG9rZW5NZXRhZGF0YT4oKTtcbiAgcmVhZG9ubHkgdHJhbnNwb3J0S2luZDogT3BlbkFJVHJhbnNwb3J0S2luZDtcbiAgcmVhZG9ubHkgcmF0ZUxpbWl0c0NhY2hlID0gbmV3IE1hcDxudW1iZXIsIE9wZW5BSVJhdGVMaW1pdHNXaXRoTWV0YSAmIHsgZ2VuZXJhdGlvbjogbnVtYmVyIH0+KCk7XG4gIHByaXZhdGUgcmVhZG9ubHkgcGVuZGluZ1JhdGVMaW1pdHMgPSBuZXcgTWFwPFxuICAgIG51bWJlcixcbiAgICBQcm9taXNlPE9wZW5BSVJhdGVMaW1pdHNXaXRoTWV0YSAmIHsgZ2VuZXJhdGlvbjogbnVtYmVyIH0+XG4gID4oKTtcbiAgcHJpdmF0ZSByZWFkb25seSBjbGllbnRzID0gbmV3IE1hcDxudW1iZXIsIENsaWVudEVudHJ5PigpO1xuICBwcml2YXRlIHJlYWRvbmx5IHJldGlyZWRDbGllbnRzID0gbmV3IFNldDxDbGllbnRFbnRyeT4oKTtcbiAgc3RhdGljIHJlYWRvbmx5IFJBVEVfTElNSVRTX0NBQ0hFX1RUTCA9IDYwXzAwMDtcblxuICBwcml2YXRlIHJlYWRvbmx5IHNlbGVjdG9yID0gbmV3IFNtb290aFdlaWdodGVkUm91bmRSb2JpbigpO1xuICBwcml2YXRlIHJlYWRvbmx5IGNsaWVudEZhY3Rvcnk6IE9wZW5BSURpcmVjdENsaWVudEZhY3Rvcnk7XG4gIHByaXZhdGUgcmVhZG9ubHkgZmV0Y2hJbXBsOiB0eXBlb2YgZmV0Y2g7XG4gIHByaXZhdGUgcmVhZG9ubHkgcXVvdGFCbG9ja2VkID0gbmV3IFNldDxudW1iZXI+KCk7XG4gIHByaXZhdGUgaW5GbGlnaHRDb3VudCA9IDA7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgdHJhbnNwb3J0S2luZDogT3BlbkFJVHJhbnNwb3J0S2luZCA9IHJlc29sdmVPcGVuQUlUcmFuc3BvcnRLaW5kKCksXG4gICAgZGVwZW5kZW5jaWVzOiBPcGVuQUlEaXNwYXRjaGVyRGVwZW5kZW5jaWVzID0ge30sXG4gICkge1xuICAgIHRoaXMudHJhbnNwb3J0S2luZCA9IHRyYW5zcG9ydEtpbmQ7XG4gICAgdGhpcy5jbGllbnRGYWN0b3J5ID1cbiAgICAgIGRlcGVuZGVuY2llcy5jbGllbnRGYWN0b3J5ID8/ICgob3B0aW9ucykgPT4gbmV3IE9wZW5BSURpcmVjdENsaWVudChvcHRpb25zKSk7XG4gICAgdGhpcy5mZXRjaEltcGwgPSBkZXBlbmRlbmNpZXMuZmV0Y2ggPz8gZmV0Y2g7XG4gIH1cblxuICBhc3luYyBzdGFydCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCB7IHJvd3MgfSA9IGF3YWl0IFRva2VuTW9kZWwuZmluZE1hbnkoXCJBXCIpO1xuICAgIGZvciAoY29uc3Qgcm93IG9mIHJvd3MpIHtcbiAgICAgIGlmIChyb3cucHJvdmlkZXIgIT09IFwib3BlbmFpXCIpIGNvbnRpbnVlO1xuICAgICAgdGhpcy5zZXRUb2tlbihcbiAgICAgICAgcm93LmlkLFxuICAgICAgICByb3cubmFtZSxcbiAgICAgICAgcm93LmNyZWRlbnRpYWxzIGFzIE9wZW5BSUNyZWRlbnRpYWxzLFxuICAgICAgICByb3cucXVvdGFfdGhyZXNob2xkLFxuICAgICAgICByb3cud2VpZ2h0LFxuICAgICAgICByb3cuYWN0aXZlLFxuICAgICAgKTtcbiAgICB9XG4gICAgbG9nZ2VyLmluZm8oYHN0YXJ0ZWQgZGlyZWN0IE9wZW5BSSBydW50aW1lIHdpdGggJHt0aGlzLnRva2VuTWV0YWRhdGEuc2l6ZX0gdG9rZW5zYCk7XG4gIH1cblxuICBhc3luYyBzdG9wKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGZvciAoY29uc3QgeyBjbGllbnQgfSBvZiB0aGlzLmNsaWVudHMudmFsdWVzKCkpIGNsaWVudC5jbG9zZT8uKCk7XG4gICAgdGhpcy5jbGllbnRzLmNsZWFyKCk7XG4gICAgZm9yIChjb25zdCBlbnRyeSBvZiB0aGlzLnJldGlyZWRDbGllbnRzKSBlbnRyeS5jbGllbnQuY2xvc2U/LigpO1xuICAgIHRoaXMucmV0aXJlZENsaWVudHMuY2xlYXIoKTtcbiAgICB0aGlzLnRva2VuTWV0YWRhdGEuY2xlYXIoKTtcbiAgICB0aGlzLnJhdGVMaW1pdHNDYWNoZS5jbGVhcigpO1xuICAgIHRoaXMucXVvdGFCbG9ja2VkLmNsZWFyKCk7XG4gICAgdGhpcy5zZWxlY3Rvci5yZXNldFNjb3JlcygpO1xuICB9XG5cbiAgYXN5bmMgb25Ub2tlbkFkZGVkKFxuICAgIGlkOiBudW1iZXIsXG4gICAgbmFtZTogc3RyaW5nLFxuICAgIGNyZWRlbnRpYWxzOiBPcGVuQUlDcmVkZW50aWFscyxcbiAgICBxdW90YVRocmVzaG9sZD86IG51bWJlciB8IG51bGwsXG4gICAgd2VpZ2h0ID0gMSxcbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdGhpcy5zZXRUb2tlbihpZCwgbmFtZSwgY3JlZGVudGlhbHMsIHF1b3RhVGhyZXNob2xkLCB3ZWlnaHQsIHRydWUpO1xuICB9XG5cbiAgYXN5bmMgb25Ub2tlblVwZGF0ZWQoXG4gICAgaWQ6IG51bWJlcixcbiAgICBuYW1lOiBzdHJpbmcsXG4gICAgY3JlZGVudGlhbHM6IE9wZW5BSUNyZWRlbnRpYWxzLFxuICAgIHF1b3RhVGhyZXNob2xkPzogbnVtYmVyIHwgbnVsbCxcbiAgICB3ZWlnaHQgPSAxLFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBvbGQgPSB0aGlzLnRva2VuTWV0YWRhdGEuZ2V0KGlkKTtcbiAgICB0aGlzLnNldFRva2VuKGlkLCBuYW1lLCBjcmVkZW50aWFscywgcXVvdGFUaHJlc2hvbGQsIHdlaWdodCwgb2xkPy5hY3RpdmUgPz8gdHJ1ZSk7XG4gIH1cblxuICBhc3luYyBvblRva2VuUmVtb3ZlZChpZDogbnVtYmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdGhpcy5yZXRpcmVDbGllbnQoaWQpO1xuICAgIHRoaXMudG9rZW5NZXRhZGF0YS5kZWxldGUoaWQpO1xuICAgIHRoaXMuc2VsZWN0b3IucmVtb3ZlVG9rZW4oaWQpO1xuICAgIHRoaXMuaW52YWxpZGF0ZVJhdGVMaW1pdHNDYWNoZShpZCk7XG4gICAgdGhpcy5xdW90YUJsb2NrZWQuZGVsZXRlKGlkKTtcbiAgfVxuXG4gIG9uVG9rZW5EZWFjdGl2YXRlZChpZDogbnVtYmVyKTogdm9pZCB7XG4gICAgY29uc3QgdG9rZW4gPSB0aGlzLnRva2VuTWV0YWRhdGEuZ2V0KGlkKTtcbiAgICBpZiAodG9rZW4pIHRva2VuLmFjdGl2ZSA9IGZhbHNlO1xuICAgIHRoaXMuc2VsZWN0b3IucmVzZXRTY29yZXMoKTtcbiAgfVxuXG4gIG9uVG9rZW5BY3RpdmF0ZWQoaWQ6IG51bWJlcik6IHZvaWQge1xuICAgIGNvbnN0IHRva2VuID0gdGhpcy50b2tlbk1ldGFkYXRhLmdldChpZCk7XG4gICAgaWYgKHRva2VuKSB0b2tlbi5hY3RpdmUgPSB0cnVlO1xuICAgIHRoaXMuc2VsZWN0b3IucmVzZXRTY29yZXMoKTtcbiAgfVxuXG4gIGFzeW5jIHJlcGxhY2VUb2tlbnMoXG4gICAgcm93czogQXJyYXk8e1xuICAgICAgaWQ6IG51bWJlcjtcbiAgICAgIG5hbWU6IHN0cmluZztcbiAgICAgIGNyZWRlbnRpYWxzOiBPcGVuQUlDcmVkZW50aWFscztcbiAgICAgIHF1b3RhVGhyZXNob2xkPzogbnVtYmVyIHwgbnVsbDtcbiAgICAgIHdlaWdodDogbnVtYmVyO1xuICAgIH0+LFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBpZHMgPSBuZXcgU2V0KHJvd3MubWFwKChyKSA9PiByLmlkKSk7XG4gICAgZm9yIChjb25zdCBpZCBvZiB0aGlzLnRva2VuTWV0YWRhdGEua2V5cygpKSBpZiAoIWlkcy5oYXMoaWQpKSBhd2FpdCB0aGlzLm9uVG9rZW5SZW1vdmVkKGlkKTtcbiAgICBmb3IgKGNvbnN0IHJvdyBvZiByb3dzKVxuICAgICAgYXdhaXQgdGhpcy5vblRva2VuVXBkYXRlZChyb3cuaWQsIHJvdy5uYW1lLCByb3cuY3JlZGVudGlhbHMsIHJvdy5xdW90YVRocmVzaG9sZCwgcm93LndlaWdodCk7XG4gIH1cblxuICBhc3luYyBnZW5lcmF0ZShyZXE6IEdlbmVyYXRlUmVxdWVzdCk6IFByb21pc2U8R2VuZXJhdGVSZXN1bHQ+IHtcbiAgICByZXR1cm4gdGhpcy5ydW4ocmVxKTtcbiAgfVxuXG4gIGFzeW5jIGdlbmVyYXRlU3RyZWFtKHJlcTogR2VuZXJhdGVSZXF1ZXN0LCBjYjogR2VuZXJhdGVTdHJlYW1DYWxsYmFja3MpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAocmVxLmltYWdlR2VuZXJhdGlvbilcbiAgICAgIHRocm93IG5ldyBJbWFnZUdlbmVyYXRpb25FcnJvcihcbiAgICAgICAgXCJnYXRlXCIsXG4gICAgICAgIFwiaW1hZ2UgZ2VuZXJhdGlvbiBpcyBub3Qgc3VwcG9ydGVkIG9uIHRoZSBzdHJlYW1pbmcgcGF0aFwiLFxuICAgICAgKTtcbiAgICB0cnkge1xuICAgICAgY2Iub25Db21wbGV0ZShhd2FpdCB0aGlzLnJ1bihyZXEsIGNiLm9uRGVsdGEpKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgY2Iub25FcnJvcihlcnJvciBhcyBFcnJvcik7XG4gICAgICB0aHJvdyBlcnJvcjtcbiAgICB9XG4gIH1cblxuICAvLyBnZW5lcmF0ZS9nZW5lcmF0ZVN0cmVhbSDqs7XthrUg7Iuk7ZaJIOKAlCDthqDtgbAg7ISg7YOd6rO8IGluLWZsaWdodCDsp5Hqs4Trpbwg7ZWcIOqzs+yXkCDrkZTri6QuXG4gIHByaXZhdGUgYXN5bmMgcnVuKFxuICAgIHJlcTogR2VuZXJhdGVSZXF1ZXN0LFxuICAgIG9uRGVsdGE/OiAodGV4dDogc3RyaW5nKSA9PiB2b2lkLFxuICApOiBQcm9taXNlPEdlbmVyYXRlUmVzdWx0PiB7XG4gICAgY29uc3Qgc2lnbmFsID0gYWN0aXZlU2lnbmFsKHJlcS5hYm9ydFNpZ25hbCwgcmVxLnRpbWVvdXRNcyk7XG4gICAgaWYgKHNpZ25hbC5hYm9ydGVkKSB0aHJvdyBhYm9ydEVycm9yKHNpZ25hbCk7XG4gICAgY29uc3Qgc2VsZWN0aW9uID0gYXdhaXQgdGhpcy5zZWxlY3RUb2tlbihyZXEucHJlZmVycmVkVG9rZW5JZCwgc2lnbmFsKTtcbiAgICB0aGlzLmluRmxpZ2h0Q291bnQrKztcbiAgICB0cnkge1xuICAgICAgaWYgKHNpZ25hbC5hYm9ydGVkKSB0aHJvdyBhYm9ydEVycm9yKHNpZ25hbCk7XG4gICAgICByZXR1cm4gYXdhaXQgdGhpcy5ydW5EaXJlY3Qoc2VsZWN0aW9uLCB7IC4uLnJlcSwgYWJvcnRTaWduYWw6IHNpZ25hbCB9LCBvbkRlbHRhKTtcbiAgICB9IGZpbmFsbHkge1xuICAgICAgdGhpcy5pbkZsaWdodENvdW50LS07XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBydW5EaXJlY3QoXG4gICAgc2VsZWN0aW9uOiBUb2tlblNlbGVjdGlvbixcbiAgICByZXE6IEdlbmVyYXRlUmVxdWVzdCxcbiAgICBvbkRlbHRhPzogKHRleHQ6IHN0cmluZykgPT4gdm9pZCxcbiAgKTogUHJvbWlzZTxHZW5lcmF0ZVJlc3VsdD4ge1xuICAgIGNvbnN0IHN0YXJ0ZWRBdCA9IERhdGUubm93KCk7XG4gICAgbGV0IGZpcnN0RGVsdGFBdDogbnVtYmVyIHwgdW5kZWZpbmVkO1xuICAgIGxldCB0ZXh0ID0gXCJcIjtcbiAgICBsZXQgdXNhZ2UgPSB7XG4gICAgICB0b3RhbFRva2VuczogMCxcbiAgICAgIGlucHV0VG9rZW5zOiAwLFxuICAgICAgb3V0cHV0VG9rZW5zOiAwLFxuICAgICAgY2FjaGVkSW5wdXRUb2tlbnM6IDAsXG4gICAgICByZWFzb25pbmdPdXRwdXRUb2tlbnM6IDAsXG4gICAgfTtcbiAgICBjb25zdCBpbWFnZXM6IEdlbmVyYXRlZEltYWdlW10gPSBbXTtcbiAgICBsZXQgaW1hZ2VBdHRlbXB0ZWQgPSBmYWxzZTtcbiAgICBsZXQgc2VydmluZ01vZGVsID0gcmVxLm1vZGVsID8/IFwiXCI7XG4gICAgY29uc3QgbWV0YWRhdGEgPSBzZWxlY3Rpb24ubWV0YWRhdGE7XG4gICAgY29uc3QgY2xpZW50RW50cnkgPSB0aGlzLmFjcXVpcmVDbGllbnQoc2VsZWN0aW9uKTtcbiAgICB0cnkge1xuICAgICAgZm9yIGF3YWl0IChjb25zdCBldmVudCBvZiBjbGllbnRFbnRyeS5jbGllbnQucmVzcG9uc2VzKFxuICAgICAgICByZXF1ZXN0T3B0aW9ucyhyZXEpLFxuICAgICAgICByZXEuYWJvcnRTaWduYWwsXG4gICAgICApKSB7XG4gICAgICAgIGlmIChldmVudC50eXBlID09PSBcInRleHQtZGVsdGFcIikge1xuICAgICAgICAgIGZpcnN0RGVsdGFBdCA/Pz0gRGF0ZS5ub3coKTtcbiAgICAgICAgICB0ZXh0ICs9IGV2ZW50LnRleHQ7XG4gICAgICAgICAgb25EZWx0YT8uKGV2ZW50LnRleHQpO1xuICAgICAgICB9IGVsc2UgaWYgKGV2ZW50LnR5cGUgPT09IFwiaW1hZ2VcIikge1xuICAgICAgICAgIGltYWdlQXR0ZW1wdGVkID0gdHJ1ZTtcbiAgICAgICAgICBpbWFnZXMucHVzaCh7IGRhdGE6IGV2ZW50LmJhc2U2NCwgcmV2aXNlZFByb21wdDogZXZlbnQucmV2aXNlZFByb21wdCA/PyBudWxsIH0pO1xuICAgICAgICB9IGVsc2UgaWYgKGV2ZW50LnR5cGUgPT09IFwib3V0cHV0LWl0ZW1cIiAmJiBldmVudC5pdGVtLnR5cGUgPT09IFwiaW1hZ2VfZ2VuZXJhdGlvbl9jYWxsXCIpIHtcbiAgICAgICAgICBpbWFnZUF0dGVtcHRlZCA9IHRydWU7XG4gICAgICAgIH0gZWxzZSBpZiAoZXZlbnQudHlwZSA9PT0gXCJjb21wbGV0ZWRcIiAmJiBldmVudC51c2FnZSkge1xuICAgICAgICAgIHNlcnZpbmdNb2RlbCA9IGV2ZW50Lm1vZGVsID8/IHNlcnZpbmdNb2RlbDtcbiAgICAgICAgICB1c2FnZSA9IHtcbiAgICAgICAgICAgIHRvdGFsVG9rZW5zOiBldmVudC51c2FnZS50b3RhbFRva2VucyxcbiAgICAgICAgICAgIGlucHV0VG9rZW5zOiBldmVudC51c2FnZS5pbnB1dFRva2VucyxcbiAgICAgICAgICAgIG91dHB1dFRva2VuczogZXZlbnQudXNhZ2Uub3V0cHV0VG9rZW5zLFxuICAgICAgICAgICAgY2FjaGVkSW5wdXRUb2tlbnM6IGV2ZW50LnVzYWdlLmNhY2hlZElucHV0VG9rZW5zLFxuICAgICAgICAgICAgcmVhc29uaW5nT3V0cHV0VG9rZW5zOiBldmVudC51c2FnZS5yZWFzb25pbmdUb2tlbnMsXG4gICAgICAgICAgfTtcbiAgICAgICAgfSBlbHNlIGlmIChldmVudC50eXBlID09PSBcImNvbXBsZXRlZFwiKSB7XG4gICAgICAgICAgc2VydmluZ01vZGVsID0gZXZlbnQubW9kZWwgPz8gc2VydmluZ01vZGVsO1xuICAgICAgICB9IGVsc2UgaWYgKGV2ZW50LnR5cGUgPT09IFwiZXJyb3JcIikge1xuICAgICAgICAgIGlmIChyZXEuaW1hZ2VHZW5lcmF0aW9uKVxuICAgICAgICAgICAgdGhyb3cgbmV3IEltYWdlR2VuZXJhdGlvbkVycm9yKFwiaW5jb21wbGV0ZVwiLCBldmVudC5lcnJvci5tZXNzYWdlKTtcbiAgICAgICAgICB0aHJvdyBldmVudC5lcnJvcjtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0gZmluYWxseSB7XG4gICAgICB0aGlzLnJlbGVhc2VDbGllbnQoY2xpZW50RW50cnkpO1xuICAgIH1cbiAgICBpZiAocmVxLmltYWdlR2VuZXJhdGlvbiAmJiBpbWFnZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICB0aHJvdyBuZXcgSW1hZ2VHZW5lcmF0aW9uRXJyb3IoXG4gICAgICAgIGltYWdlQXR0ZW1wdGVkID8gXCJpbmNvbXBsZXRlXCIgOiBcIm5vdF9jYWxsZWRcIixcbiAgICAgICAgaW1hZ2VBdHRlbXB0ZWRcbiAgICAgICAgICA/IFwiaW1hZ2UgZ2VuZXJhdGlvbiBkaWQgbm90IGNvbXBsZXRlXCJcbiAgICAgICAgICA6IFwibW9kZWwgZGlkIG5vdCBjYWxsIGltYWdlIGdlbmVyYXRpb25cIixcbiAgICAgICk7XG4gICAgfVxuICAgIHJldHVybiB7XG4gICAgICB0ZXh0LFxuICAgICAgdG9rZW5OYW1lOiBtZXRhZGF0YS5uYW1lLFxuICAgICAgdXNhZ2UsXG4gICAgICBkdXJhdGlvbk1zOiBEYXRlLm5vdygpIC0gc3RhcnRlZEF0LFxuICAgICAgdHRmdE1zOiBmaXJzdERlbHRhQXQgPT09IHVuZGVmaW5lZCA/IG51bGwgOiBmaXJzdERlbHRhQXQgLSBzdGFydGVkQXQsXG4gICAgICBtb2RlbDogc2VydmluZ01vZGVsLFxuICAgICAgdGhyZWFkQ29vcmQ6IHsgd29ya2VySWQ6IHNlbGVjdGlvbi50b2tlbklkLCB0aHJlYWRJZDogcmVxLnByb21wdENhY2hlS2V5ID8/IFwiXCIsIGVwb2NoOiAtMSB9LFxuICAgICAgLi4uKGltYWdlcy5sZW5ndGggPyB7IGltYWdlcyB9IDoge30pLFxuICAgIH07XG4gIH1cblxuICAvKiog7IS464yA6rCAIOuwlOuAkCBjbGllbnQg64qUIOyCrOyaqSDspJHsnbgg7JqU7LKt7J20IOuBneuCnCDrkqTsl5Ag64ur64qU64ukLiAqL1xuICBwcml2YXRlIGFjcXVpcmVDbGllbnQoc2VsZWN0aW9uOiBUb2tlblNlbGVjdGlvbik6IENsaWVudEVudHJ5IHtcbiAgICBjb25zdCBtZXRhZGF0YSA9IHNlbGVjdGlvbi5tZXRhZGF0YTtcbiAgICBsZXQgZW50cnkgPSB0aGlzLmNsaWVudHMuZ2V0KHNlbGVjdGlvbi50b2tlbklkKTtcbiAgICBpZiAoZW50cnkgJiYgZW50cnkuZ2VuZXJhdGlvbiAhPT0gbWV0YWRhdGEuZ2VuZXJhdGlvbikge1xuICAgICAgdGhpcy5yZXRpcmVDbGllbnQoc2VsZWN0aW9uLnRva2VuSWQpO1xuICAgICAgZW50cnkgPSB1bmRlZmluZWQ7XG4gICAgfVxuICAgIGlmICghZW50cnkpIHtcbiAgICAgIGNvbnN0IGNsaWVudCA9IHRoaXMuY2xpZW50RmFjdG9yeShcbiAgICAgICAge1xuICAgICAgICAgIGNyZWRlbnRpYWxzOiB7XG4gICAgICAgICAgICBhY2Nlc3NUb2tlbjogbWV0YWRhdGEuY3JlZGVudGlhbHMuYWNjZXNzVG9rZW4sXG4gICAgICAgICAgICBhY2NvdW50SWQ6IG1ldGFkYXRhLmNyZWRlbnRpYWxzLmFjY291bnRJZCxcbiAgICAgICAgICB9LFxuICAgICAgICAgIHRyYW5zcG9ydEtpbmQ6IHRoaXMudHJhbnNwb3J0S2luZCxcbiAgICAgICAgICBmZXRjaDogdGhpcy5mZXRjaEltcGwsXG4gICAgICAgICAgcmVmcmVzaENyZWRlbnRpYWxzOiBhc3luYyAoKSA9PiB7XG4gICAgICAgICAgICBjb25zdCByZWZyZXNoZWQgPSBhd2FpdCBoYW5kbGVDaGF0Z3B0QXV0aFRva2Vuc1JlZnJlc2goc2VsZWN0aW9uLnRva2VuSWQpO1xuICAgICAgICAgICAgY29uc3QgY3VycmVudCA9IHRoaXMudG9rZW5NZXRhZGF0YS5nZXQoc2VsZWN0aW9uLnRva2VuSWQpO1xuICAgICAgICAgICAgaWYgKGN1cnJlbnQpXG4gICAgICAgICAgICAgIGN1cnJlbnQuY3JlZGVudGlhbHMgPSB7XG4gICAgICAgICAgICAgICAgLi4uY3VycmVudC5jcmVkZW50aWFscyxcbiAgICAgICAgICAgICAgICBhY2Nlc3NUb2tlbjogcmVmcmVzaGVkLmFjY2Vzc1Rva2VuLFxuICAgICAgICAgICAgICAgIGFjY291bnRJZDogcmVmcmVzaGVkLmNoYXRncHRBY2NvdW50SWQsXG4gICAgICAgICAgICAgIH07XG4gICAgICAgICAgICByZXR1cm4geyBhY2Nlc3NUb2tlbjogcmVmcmVzaGVkLmFjY2Vzc1Rva2VuLCBhY2NvdW50SWQ6IHJlZnJlc2hlZC5jaGF0Z3B0QWNjb3VudElkIH07XG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgICAgc2VsZWN0aW9uLnRva2VuSWQsXG4gICAgICApO1xuICAgICAgZW50cnkgPSB7IGdlbmVyYXRpb246IG1ldGFkYXRhLmdlbmVyYXRpb24sIGNsaWVudCwgaW5GbGlnaHQ6IDAsIHJldGlyZWQ6IGZhbHNlIH07XG4gICAgICB0aGlzLmNsaWVudHMuc2V0KHNlbGVjdGlvbi50b2tlbklkLCBlbnRyeSk7XG4gICAgfVxuICAgIGVudHJ5LmluRmxpZ2h0Kys7XG4gICAgcmV0dXJuIGVudHJ5O1xuICB9XG5cbiAgcHJpdmF0ZSByZWxlYXNlQ2xpZW50KGVudHJ5OiBDbGllbnRFbnRyeSk6IHZvaWQge1xuICAgIGVudHJ5LmluRmxpZ2h0ID0gTWF0aC5tYXgoMCwgZW50cnkuaW5GbGlnaHQgLSAxKTtcbiAgICBpZiAoZW50cnkucmV0aXJlZCAmJiBlbnRyeS5pbkZsaWdodCA9PT0gMCkge1xuICAgICAgdGhpcy5yZXRpcmVkQ2xpZW50cy5kZWxldGUoZW50cnkpO1xuICAgICAgZW50cnkuY2xpZW50LmNsb3NlPy4oKTtcbiAgICB9XG4gIH1cblxuICAvKiogbWFwIOyXkOyEnCDrlrzslrTrgrTqs6AsIOynhO2WiSDspJHsnbgg7JqU7LKt7J20IOyXhuydhCDrlYzrp4wg7KaJ7IucIOuLq+uKlOuLpC4gKi9cbiAgcHJpdmF0ZSByZXRpcmVDbGllbnQodG9rZW5JZDogbnVtYmVyKTogdm9pZCB7XG4gICAgY29uc3QgZW50cnkgPSB0aGlzLmNsaWVudHMuZ2V0KHRva2VuSWQpO1xuICAgIGlmICghZW50cnkpIHJldHVybjtcbiAgICB0aGlzLmNsaWVudHMuZGVsZXRlKHRva2VuSWQpO1xuICAgIGVudHJ5LnJldGlyZWQgPSB0cnVlO1xuICAgIGlmIChlbnRyeS5pbkZsaWdodCA9PT0gMCkgZW50cnkuY2xpZW50LmNsb3NlPy4oKTtcbiAgICBlbHNlIHRoaXMucmV0aXJlZENsaWVudHMuYWRkKGVudHJ5KTtcbiAgfVxuXG4gIC8qKlxuICAgKiDthqDtgbAg7ISg7YOdIOKAlCBxdW90YSBnYXRlIOulvCDthrXqs7ztlZwgYWN0aXZlIO2GoO2BsCDspJHsl5DshJwg6rOg66W464ukLiBjYWNoZSBhZmZpbml0eSDshKDtmLhcbiAgICog7Yag7YGw7J20IGVsaWdpYmxlIO2VmOuptCDqt7gg7YyQ7KCV66eM7Jy866GcIOymieyLnCDqsrDsoJXtlZjqs6Ao7KCE7LK0IHN3ZWVwIOyDneuetSwgd2VpZ2h0ZWQg7IOB7YOcXG4gICAqIOu5hOuzgOqyvSksIOyVhOuLiOuptCDrs5HroKwgcXVvdGEg7YyQ7KCVIO2bhCBzbW9vdGggd2VpZ2h0ZWQgcm91bmQtcm9iaW4uIOuPmeyLnOyEsSDsg4HtlZzsnbRcbiAgICog7JeG7Jy866+A66GcIFwi67mIIOyekOumrFwiIOqwnOuFkOuPhCDsl4bri6Qg4oCUIOyEoO2DnSDsponsi5wg7Iuk7ZaJ7J2064ukLlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBzZWxlY3RUb2tlbihcbiAgICBwcmVmZXJyZWRUb2tlbklkOiBudW1iZXIgfCB1bmRlZmluZWQsXG4gICAgc2lnbmFsOiBBYm9ydFNpZ25hbCxcbiAgKTogUHJvbWlzZTxUb2tlblNlbGVjdGlvbj4ge1xuICAgIGlmIChwcmVmZXJyZWRUb2tlbklkICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGNvbnN0IHByZWZlcnJlZCA9IHRoaXMudG9rZW5NZXRhZGF0YS5nZXQocHJlZmVycmVkVG9rZW5JZCk7XG4gICAgICBpZiAocHJlZmVycmVkPy5hY3RpdmUgJiYgKGF3YWl0IHRoaXMuaXNRdW90YUVsaWdpYmxlKHByZWZlcnJlZFRva2VuSWQsIHByZWZlcnJlZCwgc2lnbmFsKSkpIHtcbiAgICAgICAgcmV0dXJuIHsgdG9rZW5JZDogcHJlZmVycmVkVG9rZW5JZCwgbWV0YWRhdGE6IHByZWZlcnJlZCB9O1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIO2GoO2BsOuzhCBxdW90YSDtjJDsoJXsnYAg7ISc66GcIOuPheumveydtOudvCDrs5HroKzroZwg4oCUIOyngeugrCDrjIDquLDripQg7L2c65OcIOy6kOyLnOyXkOyEnFxuICAgIC8vIO2GoO2BsCDsiJggw5cg7KGw7ZqMIOyngOyXsOunjO2BvCDsmpTssq0g7Iuc7J6R7J2EIOuKpuy2mOuLpC5cbiAgICBjb25zdCBjaGVja3MgPSBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgIFsuLi50aGlzLnRva2VuTWV0YWRhdGEuZW50cmllcygpXVxuICAgICAgICAuZmlsdGVyKChbLCB0b2tlbl0pID0+IHRva2VuLmFjdGl2ZSlcbiAgICAgICAgLm1hcChhc3luYyAoW2lkLCB0b2tlbl0pID0+ICh7XG4gICAgICAgICAgaWQsXG4gICAgICAgICAgdG9rZW4sXG4gICAgICAgICAgZWxpZ2libGU6IGF3YWl0IHRoaXMuaXNRdW90YUVsaWdpYmxlKGlkLCB0b2tlbiwgc2lnbmFsKSxcbiAgICAgICAgfSkpLFxuICAgICk7XG4gICAgY29uc3QgZWxpZ2libGUgPSBuZXcgU2V0KGNoZWNrcy5maWx0ZXIoKGMpID0+IGMuZWxpZ2libGUpLm1hcCgoYykgPT4gYy5pZCkpO1xuICAgIGlmIChlbGlnaWJsZS5zaXplID09PSAwKSB7XG4gICAgICBjb25zdCBvdmVyID0gY2hlY2tzXG4gICAgICAgIC5maWx0ZXIoXG4gICAgICAgICAgKGMpID0+XG4gICAgICAgICAgICAhYy5lbGlnaWJsZSAmJiBjLnRva2VuLnF1b3RhVGhyZXNob2xkICE9PSBudWxsICYmIGMudG9rZW4ucXVvdGFUaHJlc2hvbGQgIT09IHVuZGVmaW5lZCxcbiAgICAgICAgKVxuICAgICAgICAubWFwKChjKSA9PiAoeyBuYW1lOiBjLnRva2VuLm5hbWUsIHRocmVzaG9sZDogYy50b2tlbi5xdW90YVRocmVzaG9sZCBhcyBudW1iZXIgfSkpO1xuICAgICAgaWYgKG92ZXIubGVuZ3RoKSB7XG4gICAgICAgIGxvZ2dlci53YXJuKFwicXVvdGFfdGhyZXNob2xkIGdhdGU6IGFsbF9leGNlZWRlZFwiLCB7XG4gICAgICAgICAgcHJvdmlkZXI6IFwib3BlbmFpXCIsXG4gICAgICAgICAgb3ZlclRocmVzaG9sZFRva2Vuczogb3ZlcixcbiAgICAgICAgfSk7XG4gICAgICAgIHRocm93IG5ldyBRdW90YVRocmVzaG9sZEV4Y2VlZGVkRXJyb3IocXVvdGFNZXNzYWdlKG92ZXIpKTtcbiAgICAgIH1cbiAgICAgIHRocm93IG5ldyBFcnJvcihcIk5PX09QRU5BSV9XT1JLRVJTXCIpO1xuICAgIH1cbiAgICBjb25zdCBzZWxlY3RlZCA9IHRoaXMuc2VsZWN0b3Iuc2VsZWN0KGVsaWdpYmxlKTtcbiAgICBjb25zdCBtZXRhZGF0YSA9IHNlbGVjdGVkICE9PSBudWxsID8gdGhpcy50b2tlbk1ldGFkYXRhLmdldChzZWxlY3RlZCkgOiB1bmRlZmluZWQ7XG4gICAgaWYgKHNlbGVjdGVkID09PSBudWxsIHx8ICFtZXRhZGF0YSkgdGhyb3cgbmV3IEVycm9yKFwiTk9fT1BFTkFJX1dPUktFUlNcIik7XG4gICAgcmV0dXJuIHsgdG9rZW5JZDogc2VsZWN0ZWQsIG1ldGFkYXRhIH07XG4gIH1cblxuICBwcml2YXRlIHNldFRva2VuKFxuICAgIGlkOiBudW1iZXIsXG4gICAgbmFtZTogc3RyaW5nLFxuICAgIGNyZWRlbnRpYWxzOiBPcGVuQUlDcmVkZW50aWFscyxcbiAgICBxdW90YVRocmVzaG9sZDogbnVtYmVyIHwgbnVsbCB8IHVuZGVmaW5lZCxcbiAgICB3ZWlnaHQ6IG51bWJlcixcbiAgICBhY3RpdmU6IGJvb2xlYW4sXG4gICk6IHZvaWQge1xuICAgIGNvbnN0IG9sZCA9IHRoaXMudG9rZW5NZXRhZGF0YS5nZXQoaWQpO1xuICAgIGlmIChvbGQpIHtcbiAgICAgIE9iamVjdC5hc3NpZ24ob2xkLCB7XG4gICAgICAgIG5hbWUsXG4gICAgICAgIGNyZWRlbnRpYWxzLFxuICAgICAgICBxdW90YVRocmVzaG9sZCxcbiAgICAgICAgd2VpZ2h0LFxuICAgICAgICBhY3RpdmUsXG4gICAgICAgIGdlbmVyYXRpb246IG9sZC5nZW5lcmF0aW9uICsgMSxcbiAgICAgIH0pO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLnRva2VuTWV0YWRhdGEuc2V0KGlkLCB7XG4gICAgICAgIG5hbWUsXG4gICAgICAgIGNyZWRlbnRpYWxzLFxuICAgICAgICBxdW90YVRocmVzaG9sZCxcbiAgICAgICAgd2VpZ2h0LFxuICAgICAgICBhY3RpdmUsXG4gICAgICAgIGdlbmVyYXRpb246IDEsXG4gICAgICB9KTtcbiAgICB9XG4gICAgdGhpcy5zZWxlY3Rvci5zZXRUb2tlbihpZCwgd2VpZ2h0KTtcbiAgICB0aGlzLmludmFsaWRhdGVSYXRlTGltaXRzQ2FjaGUoaWQpO1xuICAgIHRoaXMucXVvdGFCbG9ja2VkLmRlbGV0ZShpZCk7XG4gIH1cblxuICBhc3luYyBnZXRSYXRlTGltaXRzQnlUb2tlbklkKFxuICAgIHRva2VuSWQ6IG51bWJlcixcbiAgICBzaWduYWw/OiBBYm9ydFNpZ25hbCxcbiAgKTogUHJvbWlzZTxPcGVuQUlSYXRlTGltaXRzV2l0aE1ldGE+IHtcbiAgICBjb25zdCB0b2tlbiA9IHRoaXMudG9rZW5NZXRhZGF0YS5nZXQodG9rZW5JZCk7XG4gICAgaWYgKCF0b2tlbikgdGhyb3cgbmV3IEVycm9yKGBvcGVuYWkgdG9rZW4gJHt0b2tlbklkfSBub3QgZm91bmRgKTtcbiAgICBjb25zdCBjYWNoZWQgPSB0aGlzLnJhdGVMaW1pdHNDYWNoZS5nZXQodG9rZW5JZCk7XG4gICAgaWYgKFxuICAgICAgY2FjaGVkICYmXG4gICAgICBjYWNoZWQuZ2VuZXJhdGlvbiA9PT0gdG9rZW4uZ2VuZXJhdGlvbiAmJlxuICAgICAgRGF0ZS5ub3coKSAtIGNhY2hlZC5jYWNoZWRBdCA8IE9wZW5BSURpc3BhdGNoZXIuUkFURV9MSU1JVFNfQ0FDSEVfVFRMXG4gICAgKVxuICAgICAgcmV0dXJuIGNhY2hlZDtcblxuICAgIC8vIHNpbmdsZS1mbGlnaHQ6IOuPmeyLnOyEsSDsg4HtlZzsnbQg7JeG7Ja07KeEIOuSpOuhnCBUVEwg66eM66OMIOyInOqwhCDrj5nsi5wg7JqU7LKtIOyImOunjO2BvCDqsJnsnYBcbiAgICAvLyDsobDtmozqsIAg66qw66a0IOyImCDsnojri6Qg4oCUIOynhO2WiSDspJHsnbggZmV0Y2gg66W8IOqzteycoO2VnOuLpC4g7LWc7LSIIO2YuOy2nOyekOydmCBhYm9ydCDroZxcbiAgICAvLyDqs7XsnKAg7KGw7ZqM6rCAIOyLpO2MqO2VtOuPhCDshozruYTsspgoaXNRdW90YUVsaWdpYmxlKeqwgCBmYWlsLW9wZW4g7Jy866GcIOyymOumrO2VnOuLpC5cbiAgICBjb25zdCBwZW5kaW5nID0gdGhpcy5wZW5kaW5nUmF0ZUxpbWl0cy5nZXQodG9rZW5JZCk7XG4gICAgaWYgKHBlbmRpbmcpIHJldHVybiBwZW5kaW5nO1xuICAgIGNvbnN0IGZldGNoUHJvbWlzZSA9IChhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCByZWFkT3BlbkFJUXVvdGFVc2FnZSh7XG4gICAgICAgIGNyZWRlbnRpYWxzOiB0b2tlbi5jcmVkZW50aWFscyxcbiAgICAgICAgZmV0Y2g6IHRoaXMuZmV0Y2hJbXBsLFxuICAgICAgICAuLi4oc2lnbmFsID8geyBzaWduYWwgfSA6IHt9KSxcbiAgICAgIH0pO1xuICAgICAgaWYgKHJlc3VsdC5raW5kID09PSBcImxvb2t1cF9mYWlsZWRcIikgdGhyb3cgbmV3IEVycm9yKHJlc3VsdC5yZWFzb24pO1xuICAgICAgaWYgKCFyZXN1bHQucmF3KSB0aHJvdyBuZXcgRXJyb3IoXCJPcGVuQUkgcXVvdGEgcmVzcG9uc2UgbWlzc2luZyByYXcgcmF0ZSBsaW1pdHNcIik7XG4gICAgICBjb25zdCBlbnRyeSA9IHsgZGF0YTogcmVzdWx0LnJhdywgY2FjaGVkQXQ6IERhdGUubm93KCksIGdlbmVyYXRpb246IHRva2VuLmdlbmVyYXRpb24gfTtcbiAgICAgIGlmICh0aGlzLnRva2VuTWV0YWRhdGEuZ2V0KHRva2VuSWQpID09PSB0b2tlbikgdGhpcy5yYXRlTGltaXRzQ2FjaGUuc2V0KHRva2VuSWQsIGVudHJ5KTtcbiAgICAgIHJldHVybiBlbnRyeTtcbiAgICB9KSgpLmZpbmFsbHkoKCkgPT4gdGhpcy5wZW5kaW5nUmF0ZUxpbWl0cy5kZWxldGUodG9rZW5JZCkpO1xuICAgIHRoaXMucGVuZGluZ1JhdGVMaW1pdHMuc2V0KHRva2VuSWQsIGZldGNoUHJvbWlzZSk7XG4gICAgcmV0dXJuIGZldGNoUHJvbWlzZTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgaXNRdW90YUVsaWdpYmxlKFxuICAgIGlkOiBudW1iZXIsXG4gICAgdG9rZW46IFRva2VuTWV0YWRhdGEsXG4gICAgc2lnbmFsPzogQWJvcnRTaWduYWwsXG4gICk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGlmICh0b2tlbi5xdW90YVRocmVzaG9sZCA9PT0gbnVsbCB8fCB0b2tlbi5xdW90YVRocmVzaG9sZCA9PT0gdW5kZWZpbmVkKSByZXR1cm4gdHJ1ZTtcbiAgICBjb25zdCBnZW5lcmF0aW9uID0gdG9rZW4uZ2VuZXJhdGlvbjtcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCByZWFkT3BlbkFJUXVvdGFVc2FnZShhc3luYyAoKSA9PiB0aGlzLmdldFJhdGVMaW1pdHNCeVRva2VuSWQoaWQsIHNpZ25hbCkpO1xuICAgIGlmICh0aGlzLnRva2VuTWV0YWRhdGEuZ2V0KGlkKSAhPT0gdG9rZW4gfHwgdG9rZW4uZ2VuZXJhdGlvbiAhPT0gZ2VuZXJhdGlvbikgcmV0dXJuIGZhbHNlO1xuICAgIGlmIChyZXN1bHQua2luZCA9PT0gXCJsb29rdXBfZmFpbGVkXCIpIHtcbiAgICAgIHRoaXMucXVvdGFCbG9ja2VkLmRlbGV0ZShpZCk7XG4gICAgICBsb2dnZXIud2FybihcInF1b3RhX3RocmVzaG9sZCBnYXRlOiBsb29rdXBfZmFpbF9vcGVuXCIsIHtcbiAgICAgICAgdG9rZW5JZDogaWQsXG4gICAgICAgIHRva2VuTmFtZTogdG9rZW4ubmFtZSxcbiAgICAgICAgbG9va3VwUmVhc29uOiByZXN1bHQucmVhc29uLFxuICAgICAgfSk7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gICAgaWYgKHJlc3VsdC51dGlsaXphdGlvblBjdCA+PSB0b2tlbi5xdW90YVRocmVzaG9sZCkge1xuICAgICAgaWYgKCF0aGlzLnF1b3RhQmxvY2tlZC5oYXMoaWQpKVxuICAgICAgICBsb2dnZXIuaW5mbyhcbiAgICAgICAgICBgcXVvdGFfdGhyZXNob2xkIGdhdGU6IG92ZXJfdGhyZXNob2xkICR7dG9rZW4ubmFtZX1bJHtpZH1dICgke3Jlc3VsdC51dGlsaXphdGlvblBjdH0lID49ICR7dG9rZW4ucXVvdGFUaHJlc2hvbGR9JSlgLFxuICAgICAgICApO1xuICAgICAgdGhpcy5xdW90YUJsb2NrZWQuYWRkKGlkKTtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgaWYgKHRoaXMucXVvdGFCbG9ja2VkLmRlbGV0ZShpZCkpXG4gICAgICBsb2dnZXIuaW5mbyhcbiAgICAgICAgYHF1b3RhX3RocmVzaG9sZCBnYXRlOiByZWNvdmVyZWQgJHt0b2tlbi5uYW1lfVske2lkfV0gKCR7cmVzdWx0LnV0aWxpemF0aW9uUGN0fSUgPCAke3Rva2VuLnF1b3RhVGhyZXNob2xkfSUpYCxcbiAgICAgICk7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICBwcml2YXRlIGludmFsaWRhdGVSYXRlTGltaXRzQ2FjaGUoaWQ6IG51bWJlcik6IHZvaWQge1xuICAgIHRoaXMucmF0ZUxpbWl0c0NhY2hlLmRlbGV0ZShpZCk7XG4gIH1cblxuICBnZXQgdG9rZW5Db3VudCgpOiBudW1iZXIge1xuICAgIHJldHVybiBbLi4udGhpcy50b2tlbk1ldGFkYXRhLnZhbHVlcygpXS5maWx0ZXIoKHQpID0+IHQuYWN0aXZlKS5sZW5ndGg7XG4gIH1cbiAgZ2V0IGluRmxpZ2h0KCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMuaW5GbGlnaHRDb3VudDtcbiAgfVxuXG4gIC8qKlxuICAgKiDthqDtgbDrs4Qg7L+87YSwIOyKpOuDheyDtyDigJQg7Iug7ISg7ZWcKHJhdGUgbGltaXRzIFRUTCDrgrQpIOy6kOyLnOunjCDsnb3qs6Ag7KCI64yAIGZldGNoIO2VmOyngCDslYrripTri6QuXG4gICAqIG1vbml0IHZpdGFscyDripQg66Gc6re4IO2PtOungeyXkCDtjrjsirntlZjripQg6rCS7J206528IOyXrOq4sOyEnCDrhKTtirjsm4ztgazrpbwg7YOA66m0IOyViCDrkJzri6QuXG4gICAqIHRocmVzaG9sZCDrr7jshKTsoJUg7Yag7YGw7J2AIOy/vO2EsCDtjJDsoJXsnYQg64+M7KeAIOyViuyVhCB1c2VkUGVyY2VudCDqsIAgbnVsbCDroZwg64Ko7J2EIOyImCDsnojri6QuXG4gICAqL1xuICBnZXQgcXVvdGFCeVRva2VuKCk6IEFycmF5PHtcbiAgICBuYW1lOiBzdHJpbmc7XG4gICAgdXNlZFBlcmNlbnQ6IG51bWJlciB8IG51bGw7XG4gICAgdGhyZXNob2xkOiBudW1iZXIgfCBudWxsO1xuICAgIGJsb2NrZWQ6IGJvb2xlYW47XG4gICAgcmVzZXRzQXQ6IG51bWJlciB8IG51bGw7XG4gIH0+IHtcbiAgICBjb25zdCBub3cgPSBEYXRlLm5vdygpO1xuICAgIHJldHVybiBbLi4udGhpcy50b2tlbk1ldGFkYXRhLmVudHJpZXMoKV1cbiAgICAgIC5tYXAoKFtpZCwgdF0pID0+IHtcbiAgICAgICAgY29uc3QgY2FjaGVkID0gdGhpcy5yYXRlTGltaXRzQ2FjaGUuZ2V0KGlkKTtcbiAgICAgICAgY29uc3QgZnJlc2ggPVxuICAgICAgICAgIGNhY2hlZCAhPT0gdW5kZWZpbmVkICYmXG4gICAgICAgICAgY2FjaGVkLmdlbmVyYXRpb24gPT09IHQuZ2VuZXJhdGlvbiAmJlxuICAgICAgICAgIG5vdyAtIGNhY2hlZC5jYWNoZWRBdCA8IE9wZW5BSURpc3BhdGNoZXIuUkFURV9MSU1JVFNfQ0FDSEVfVFRMO1xuICAgICAgICBjb25zdCBwcmltYXJ5ID0gZnJlc2ggPyBjYWNoZWQuZGF0YS5yYXRlTGltaXRzPy5wcmltYXJ5IDogdW5kZWZpbmVkO1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIG5hbWU6IHQubmFtZSxcbiAgICAgICAgICB1c2VkUGVyY2VudDogcHJpbWFyeT8udXNlZFBlcmNlbnQgPz8gbnVsbCxcbiAgICAgICAgICB0aHJlc2hvbGQ6IHQucXVvdGFUaHJlc2hvbGQgPz8gbnVsbCxcbiAgICAgICAgICBibG9ja2VkOiB0aGlzLnF1b3RhQmxvY2tlZC5oYXMoaWQpLFxuICAgICAgICAgIC8vIHdoYW0g7J2YIHJlc2V0c0F0IOydgCB1bml4IOy0iCDri6jsnITri6QocWdyaWQuZnJhbWUgdW5peFNlY29uZHNUb0lzbyDsmYAg64+Z7J28IOq3nOyVvSkuXG4gICAgICAgICAgLy8g7IaM67mE7LKY6rCAIOuLqOychOulvCDstpTsuKHtlZjsp4Ag7JWK64+E66GdIOyXrOq4sOyEnCBtcyBlcG9jaCDsnLzroZwg7KCV6rec7ZmU7ZWc64ukLlxuICAgICAgICAgIHJlc2V0c0F0OlxuICAgICAgICAgICAgcHJpbWFyeT8ucmVzZXRzQXQgIT09IG51bGwgJiYgcHJpbWFyeT8ucmVzZXRzQXQgIT09IHVuZGVmaW5lZFxuICAgICAgICAgICAgICA/IHByaW1hcnkucmVzZXRzQXQgKiAxMDAwXG4gICAgICAgICAgICAgIDogbnVsbCxcbiAgICAgICAgfTtcbiAgICAgIH0pXG4gICAgICAudG9Tb3J0ZWQoKGEsIGIpID0+IGEubmFtZS5sb2NhbGVDb21wYXJlKGIubmFtZSkpO1xuICB9XG59XG4iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7OztBQXVCQSxNQUFNLFNBQVMsVUFBVSxDQUFDLFNBQVMsbUJBQW1CLENBQUM7QUFHdkQsTUFBTSw2QkFBNkI7QUFJ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
449
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3BlbmFpLWRpc3BhdGNoZXIuanMiLCJuYW1lcyI6W10sInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3V0aWxzL3Byb3ZpZGVycy9vcGVuYWkvb3BlbmFpLWRpc3BhdGNoZXIudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgZ2V0TG9nZ2VyIH0gZnJvbSBcIkBsb2d0YXBlL2xvZ3RhcGVcIjtcblxuaW1wb3J0IHsgUXVvdGFUaHJlc2hvbGRFeGNlZWRlZEVycm9yIH0gZnJvbSBcIi4uLy4uLy4uL2FwcGxpY2F0aW9uL3FncmlkL3FncmlkLnR5cGVzXCI7XG5pbXBvcnQgeyBUb2tlbk1vZGVsIH0gZnJvbSBcIi4uLy4uLy4uL2FwcGxpY2F0aW9uL3Rva2VuL3Rva2VuLm1vZGVsXCI7XG5pbXBvcnQgeyB0eXBlIE9wZW5BSUNyZWRlbnRpYWxzIH0gZnJvbSBcIi4uLy4uLy4uL2FwcGxpY2F0aW9uL3Rva2VuL3Rva2VuLnR5cGVzXCI7XG5pbXBvcnQge1xuICB0eXBlIEdlbmVyYXRlUmVxdWVzdCxcbiAgdHlwZSBHZW5lcmF0ZVJlc3VsdCxcbiAgdHlwZSBHZW5lcmF0ZVN0cmVhbUNhbGxiYWNrcyxcbiAgdHlwZSBHZW5lcmF0ZWRJbWFnZSxcbiAgdHlwZSBQcm92aWRlckRpc3BhdGNoZXIsXG59IGZyb20gXCIuLi9jb21tb24vcHJvdmlkZXItZGlzcGF0Y2hlclwiO1xuaW1wb3J0IHsgU21vb3RoV2VpZ2h0ZWRSb3VuZFJvYmluIH0gZnJvbSBcIi4uL2NvbW1vbi9zbW9vdGgtd2VpZ2h0ZWQtcm91bmQtcm9iaW5cIjtcbmltcG9ydCB7XG4gIHR5cGUgSnNvblZhbHVlLFxuICB0eXBlIE9wZW5BSVJlc3BvbnNlSXRlbSxcbiAgdHlwZSBPcGVuQUlSZXNwb25zZXNPcHRpb25zLFxufSBmcm9tIFwiLi9vcGVuYWktYmFja2VuZC1wcm90b2NvbFwiO1xuaW1wb3J0IHsgT3BlbkFJRGlyZWN0Q2xpZW50LCB0eXBlIE9wZW5BSURpcmVjdENsaWVudE9wdGlvbnMgfSBmcm9tIFwiLi9vcGVuYWktZGlyZWN0LWNsaWVudFwiO1xuaW1wb3J0IHsgcmVhZE9wZW5BSVF1b3RhVXNhZ2UsIHR5cGUgT3BlbkFJUmF0ZUxpbWl0c1dpdGhNZXRhIH0gZnJvbSBcIi4vb3BlbmFpLXF1b3RhXCI7XG5pbXBvcnQgeyBoYW5kbGVDaGF0Z3B0QXV0aFRva2Vuc1JlZnJlc2ggfSBmcm9tIFwiLi9vcGVuYWktcmVmcmVzaFwiO1xuaW1wb3J0IHsgdHlwZSBPcGVuQUlUcmFuc3BvcnRLaW5kLCByZXNvbHZlT3BlbkFJVHJhbnNwb3J0S2luZCB9IGZyb20gXCIuL29wZW5haS10cmFuc3BvcnQtY29uZmlnXCI7XG5cbmNvbnN0IGxvZ2dlciA9IGdldExvZ2dlcihbXCJxZ3JpZFwiLCBcIm9wZW5haS1kaXNwYXRjaGVyXCJdKTtcbi8vIOq1kOyytOuQnCBjb2RleCB3b3JrZXIg6rCAIOqwleygnO2VmOuNmCB3YXRjaGRvZy4g7Zi47Lac7J6Q6rCAIHRpbWVvdXRNcyDrpbwg7IOd65617ZW064+EIOyalOyyreydtFxuLy8g7JiB7JuQ7Z6IIOunpOuLrOumrOyngCDslYrrj4TroZ0gZGlyZWN0IHRyYW5zcG9ydCDrj4Qg7Jyg7ZWc7ZWcIOq4sOuzuCDsg4HtlZzsnYQg7Jyg7KeA7ZWc64ukLlxuY29uc3QgREVGQVVMVF9SRVFVRVNUX1RJTUVPVVRfTVMgPSA2MDBfMDAwO1xuXG5leHBvcnQgdHlwZSBJbWFnZUZhaWx1cmVLaW5kID0gXCJnYXRlXCIgfCBcIm5vdF9jYWxsZWRcIiB8IFwiaW5jb21wbGV0ZVwiO1xuXG5leHBvcnQgY2xhc3MgSW1hZ2VHZW5lcmF0aW9uRXJyb3IgZXh0ZW5kcyBFcnJvciB7XG4gIGNvbnN0cnVjdG9yKFxuICAgIHJlYWRvbmx5IGtpbmQ6IEltYWdlRmFpbHVyZUtpbmQsXG4gICAgbWVzc2FnZTogc3RyaW5nLFxuICApIHtcbiAgICBzdXBlcihtZXNzYWdlKTtcbiAgICB0aGlzLm5hbWUgPSBcIkltYWdlR2VuZXJhdGlvbkVycm9yXCI7XG4gIH1cbn1cblxudHlwZSBUb2tlbk1ldGFkYXRhID0ge1xuICBuYW1lOiBzdHJpbmc7XG4gIGNyZWRlbnRpYWxzOiBPcGVuQUlDcmVkZW50aWFscztcbiAgcXVvdGFUaHJlc2hvbGQ/OiBudW1iZXIgfCBudWxsO1xuICB3ZWlnaHQ6IG51bWJlcjtcbiAgYWN0aXZlOiBib29sZWFuO1xuICBnZW5lcmF0aW9uOiBudW1iZXI7XG59O1xuXG50eXBlIFRva2VuU2VsZWN0aW9uID0geyB0b2tlbklkOiBudW1iZXI7IG1ldGFkYXRhOiBUb2tlbk1ldGFkYXRhIH07XG5cbmV4cG9ydCB0eXBlIE9wZW5BSURpcmVjdENsaWVudEZhY3RvcnkgPSAoXG4gIG9wdGlvbnM6IE9wZW5BSURpcmVjdENsaWVudE9wdGlvbnMsXG4gIHRva2VuSWQ6IG51bWJlcixcbikgPT4gUGljazxPcGVuQUlEaXJlY3RDbGllbnQsIFwicmVzcG9uc2VzXCI+ICYgeyBjbG9zZT86ICgpID0+IHZvaWQgfTtcblxudHlwZSBDbGllbnRFbnRyeSA9IHtcbiAgZ2VuZXJhdGlvbjogbnVtYmVyO1xuICBjbGllbnQ6IFBpY2s8T3BlbkFJRGlyZWN0Q2xpZW50LCBcInJlc3BvbnNlc1wiPiAmIHsgY2xvc2U/OiAoKSA9PiB2b2lkIH07XG4gIGluRmxpZ2h0OiBudW1iZXI7XG4gIHJldGlyZWQ6IGJvb2xlYW47XG59O1xuXG5leHBvcnQgaW50ZXJmYWNlIE9wZW5BSURpc3BhdGNoZXJEZXBlbmRlbmNpZXMge1xuICBjbGllbnRGYWN0b3J5PzogT3BlbkFJRGlyZWN0Q2xpZW50RmFjdG9yeTtcbiAgZmV0Y2g/OiB0eXBlb2YgZmV0Y2g7XG59XG5cbmZ1bmN0aW9uIGFib3J0RXJyb3Ioc2lnbmFsOiBBYm9ydFNpZ25hbCk6IEVycm9yIHtcbiAgY29uc3QgcmVhc29uID0gc2lnbmFsLnJlYXNvbjtcbiAgcmV0dXJuIHJlYXNvbiBpbnN0YW5jZW9mIEVycm9yID8gcmVhc29uIDogbmV3IERPTUV4Y2VwdGlvbihcIkFib3J0ZWRcIiwgXCJBYm9ydEVycm9yXCIpO1xufVxuXG5mdW5jdGlvbiBhY3RpdmVTaWduYWwoc2lnbmFsPzogQWJvcnRTaWduYWwsIHRpbWVvdXRNcz86IG51bWJlcik6IEFib3J0U2lnbmFsIHtcbiAgY29uc3QgdGltZW91dCA9IEFib3J0U2lnbmFsLnRpbWVvdXQodGltZW91dE1zID8/IERFRkFVTFRfUkVRVUVTVF9USU1FT1VUX01TKTtcbiAgcmV0dXJuIHNpZ25hbCA/IEFib3J0U2lnbmFsLmFueShbc2lnbmFsLCB0aW1lb3V0XSkgOiB0aW1lb3V0O1xufVxuXG5mdW5jdGlvbiBxdW90YU1lc3NhZ2UoZW50cmllczogQXJyYXk8eyBuYW1lOiBzdHJpbmc7IHRocmVzaG9sZDogbnVtYmVyIH0+KTogc3RyaW5nIHtcbiAgY29uc3QgZGV0YWlsID0gZW50cmllcy5tYXAoKGUpID0+IGAke2UubmFtZX0gKHRocmVzaG9sZCAke2UudGhyZXNob2xkfSUpYCkuam9pbihcIiwgXCIpO1xuICByZXR1cm4gZGV0YWlsXG4gICAgPyBgQWxsIG9wZW5haSB0b2tlbnMgZXhjZWVkZWQgcXVvdGEgdGhyZXNob2xkOiAke2RldGFpbH1gXG4gICAgOiBcIkFsbCBvcGVuYWkgdG9rZW5zIGV4Y2VlZGVkIHF1b3RhIHRocmVzaG9sZFwiO1xufVxuXG5mdW5jdGlvbiBpbnB1dEl0ZW1zKHJlcTogR2VuZXJhdGVSZXF1ZXN0KTogT3BlbkFJUmVzcG9uc2VJdGVtW10ge1xuICBjb25zdCBoaXN0b3J5ID0gKHJlcS5jb2xkSGlzdG9yeSA/PyBbXSkgYXMgT3BlbkFJUmVzcG9uc2VJdGVtW107XG4gIGNvbnN0IGNvbnRlbnQ6IE9wZW5BSVJlc3BvbnNlSXRlbVtdID0gcmVxLmNvbGRJbnB1dC5tYXAoKGlucHV0KSA9PiB7XG4gICAgaWYgKGlucHV0LnR5cGUgPT09IFwidGV4dFwiKSByZXR1cm4geyB0eXBlOiBcImlucHV0X3RleHRcIiwgdGV4dDogaW5wdXQudGV4dCB9O1xuICAgIGlmIChpbnB1dC50eXBlID09PSBcImltYWdlXCIpIHJldHVybiB7IHR5cGU6IFwiaW5wdXRfaW1hZ2VcIiwgaW1hZ2VfdXJsOiBpbnB1dC51cmwgfTtcbiAgICBpZiAoaW5wdXQudHlwZSA9PT0gXCJsb2NhbEltYWdlXCIpIHJldHVybiB7IHR5cGU6IFwiaW5wdXRfaW1hZ2VcIiwgaW1hZ2VfdXJsOiBpbnB1dC5wYXRoIH07XG4gICAgcmV0dXJuIHsgdHlwZTogXCJpbnB1dF90ZXh0XCIsIHRleHQ6IGAke2lucHV0Lm5hbWV9OiAke2lucHV0LnBhdGh9YCB9O1xuICB9KTtcbiAgcmV0dXJuIFsuLi5oaXN0b3J5LCB7IHR5cGU6IFwibWVzc2FnZVwiLCByb2xlOiBcInVzZXJcIiwgY29udGVudCB9XTtcbn1cblxuZnVuY3Rpb24gYXNSZWFzb25pbmcocmVxOiBHZW5lcmF0ZVJlcXVlc3QpOiBPcGVuQUlSZXNwb25zZXNPcHRpb25zW1wicmVhc29uaW5nXCJdIHwgdW5kZWZpbmVkIHtcbiAgY29uc3Qgc3VtbWFyeSA9XG4gICAgcmVxLnJlYXNvbmluZ1N1bW1hcnkgJiYgcmVxLnJlYXNvbmluZ1N1bW1hcnkgIT09IFwibm9uZVwiID8gcmVxLnJlYXNvbmluZ1N1bW1hcnkgOiB1bmRlZmluZWQ7XG4gIGlmICghcmVxLmVmZm9ydCAmJiAhc3VtbWFyeSkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgcmV0dXJuIHtcbiAgICAuLi4ocmVxLmVmZm9ydFxuICAgICAgPyB7IGVmZm9ydDogcmVxLmVmZm9ydCBhcyBOb25OdWxsYWJsZTxPcGVuQUlSZXNwb25zZXNPcHRpb25zW1wicmVhc29uaW5nXCJdPltcImVmZm9ydFwiXSB9XG4gICAgICA6IHt9KSxcbiAgICAuLi4oc3VtbWFyeVxuICAgICAgPyB7XG4gICAgICAgICAgc3VtbWFyeTogc3VtbWFyeSBhcyBOb25OdWxsYWJsZTxPcGVuQUlSZXNwb25zZXNPcHRpb25zW1wicmVhc29uaW5nXCJdPltcInN1bW1hcnlcIl0sXG4gICAgICAgIH1cbiAgICAgIDoge30pLFxuICB9O1xufVxuXG5mdW5jdGlvbiByZXF1ZXN0T3B0aW9ucyhyZXE6IEdlbmVyYXRlUmVxdWVzdCk6IE9wZW5BSVJlc3BvbnNlc09wdGlvbnMge1xuICByZXR1cm4ge1xuICAgIG1vZGVsOiByZXEubW9kZWwgPz8gXCJcIixcbiAgICAuLi4ocmVxLnN5c3RlbVByb21wdCA/IHsgaW5zdHJ1Y3Rpb25zOiByZXEuc3lzdGVtUHJvbXB0IH0gOiB7fSksXG4gICAgaGlzdG9yeTogaW5wdXRJdGVtcyhyZXEpLFxuICAgIC4uLihhc1JlYXNvbmluZyhyZXEpID8geyByZWFzb25pbmc6IGFzUmVhc29uaW5nKHJlcSkgfSA6IHt9KSxcbiAgICAuLi4ocmVxLnZlcmJvc2l0eSA/IHsgdmVyYm9zaXR5OiByZXEudmVyYm9zaXR5IGFzIE9wZW5BSVJlc3BvbnNlc09wdGlvbnNbXCJ2ZXJib3NpdHlcIl0gfSA6IHt9KSxcbiAgICAuLi4ocmVxLnNlcnZpY2VUaWVyXG4gICAgICA/IHsgc2VydmljZVRpZXI6IHJlcS5zZXJ2aWNlVGllciA9PT0gXCJmYXN0XCIgPyBcInByaW9yaXR5XCIgOiByZXEuc2VydmljZVRpZXIgfVxuICAgICAgOiB7fSksXG4gICAgLi4uKHJlcS5wcm9tcHRDYWNoZUtleSA/IHsgcHJvbXB0Q2FjaGVLZXk6IHJlcS5wcm9tcHRDYWNoZUtleSB9IDoge30pLFxuICAgIC4uLihyZXEub3V0cHV0U2NoZW1hID8geyBvdXRwdXRTY2hlbWE6IHsgc2NoZW1hOiByZXEub3V0cHV0U2NoZW1hIGFzIEpzb25WYWx1ZSB9IH0gOiB7fSksXG4gICAgLi4uKHJlcS5pbWFnZUdlbmVyYXRpb25cbiAgICAgID8geyBpbWFnZUdlbmVyYXRpb246IHJlcS5pbWFnZUdlbmVyYXRpb25PcHRpb25zID8geyAuLi5yZXEuaW1hZ2VHZW5lcmF0aW9uT3B0aW9ucyB9IDogdHJ1ZSB9XG4gICAgICA6IHt9KSxcbiAgfTtcbn1cblxuLyoqXG4gKiBEaXJlY3QgT3BlbkFJIGRpc3BhdGNoZXIg4oCUIEFudGhyb3BpYyDqs7wg64+Z7J287ZWcIHN0YXRlbGVzcyDsi6Ttlokg66qo6424LlxuICpcbiAqIOyalOyyrSA9IO2GoO2BsCDshKDtg50ocXVvdGEgZ2F0ZSArIHdlaWdodGVkIHJvdW5kLXJvYmluICsgY2FjaGUgYWZmaW5pdHkg7ISg7Zi4KSDihpIgSFRUUFMvV1NcbiAqIOyghOyGoS4gcGVybWl0L+2BkCDqsJnsnYAg64+Z7Iuc7ISxIOyDge2VnOydgCDrkZDsp4Ag7JWK64qU64ukOiDsoITshqHsnYAgZmV0Y2gg7ZWcIOuyiOydtOudvCDroZzsu6wg7J6Q7JuQ7J20XG4gKiDtnazshoztlZjsp4Ag7JWK6rOgLCDsg4HrpZgg7KCc7ZWc7J2AIOuwseyXlOuTnOydmCDsnZHri7UoNDI5IOuTsSnsnbQg7KeE7Iuk7J2064ukLiB3b3JrZXIgcG9vbCDsi5zsoIjsnZhcbiAqIO2BkCDsnZjrr7jroaAoU0VSVkVSX0JVU1ksIO2BkCDtg4DsnoTslYTsm4Mp7J2AIOydtCDsoITtmZjsnLzroZwg7KCc6rGw65CQ64ukLlxuICovXG5leHBvcnQgY2xhc3MgT3BlbkFJRGlzcGF0Y2hlciBpbXBsZW1lbnRzIFByb3ZpZGVyRGlzcGF0Y2hlciB7XG4gIHJlYWRvbmx5IHRva2VuTWV0YWRhdGEgPSBuZXcgTWFwPG51bWJlciwgVG9rZW5NZXRhZGF0YT4oKTtcbiAgcmVhZG9ubHkgdHJhbnNwb3J0S2luZDogT3BlbkFJVHJhbnNwb3J0S2luZDtcbiAgcmVhZG9ubHkgcmF0ZUxpbWl0c0NhY2hlID0gbmV3IE1hcDxudW1iZXIsIE9wZW5BSVJhdGVMaW1pdHNXaXRoTWV0YSAmIHsgZ2VuZXJhdGlvbjogbnVtYmVyIH0+KCk7XG4gIHByaXZhdGUgcmVhZG9ubHkgcGVuZGluZ1JhdGVMaW1pdHMgPSBuZXcgTWFwPFxuICAgIG51bWJlcixcbiAgICBQcm9taXNlPE9wZW5BSVJhdGVMaW1pdHNXaXRoTWV0YSAmIHsgZ2VuZXJhdGlvbjogbnVtYmVyIH0+XG4gID4oKTtcbiAgcHJpdmF0ZSByZWFkb25seSBjbGllbnRzID0gbmV3IE1hcDxudW1iZXIsIENsaWVudEVudHJ5PigpO1xuICBwcml2YXRlIHJlYWRvbmx5IHJldGlyZWRDbGllbnRzID0gbmV3IFNldDxDbGllbnRFbnRyeT4oKTtcbiAgc3RhdGljIHJlYWRvbmx5IFJBVEVfTElNSVRTX0NBQ0hFX1RUTCA9IDYwXzAwMDtcblxuICBwcml2YXRlIHJlYWRvbmx5IHNlbGVjdG9yID0gbmV3IFNtb290aFdlaWdodGVkUm91bmRSb2JpbigpO1xuICBwcml2YXRlIHJlYWRvbmx5IGNsaWVudEZhY3Rvcnk6IE9wZW5BSURpcmVjdENsaWVudEZhY3Rvcnk7XG4gIHByaXZhdGUgcmVhZG9ubHkgZmV0Y2hJbXBsOiB0eXBlb2YgZmV0Y2g7XG4gIHByaXZhdGUgcmVhZG9ubHkgcXVvdGFCbG9ja2VkID0gbmV3IFNldDxudW1iZXI+KCk7XG4gIHByaXZhdGUgaW5GbGlnaHRDb3VudCA9IDA7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgdHJhbnNwb3J0S2luZDogT3BlbkFJVHJhbnNwb3J0S2luZCA9IHJlc29sdmVPcGVuQUlUcmFuc3BvcnRLaW5kKCksXG4gICAgZGVwZW5kZW5jaWVzOiBPcGVuQUlEaXNwYXRjaGVyRGVwZW5kZW5jaWVzID0ge30sXG4gICkge1xuICAgIHRoaXMudHJhbnNwb3J0S2luZCA9IHRyYW5zcG9ydEtpbmQ7XG4gICAgdGhpcy5jbGllbnRGYWN0b3J5ID1cbiAgICAgIGRlcGVuZGVuY2llcy5jbGllbnRGYWN0b3J5ID8/ICgob3B0aW9ucykgPT4gbmV3IE9wZW5BSURpcmVjdENsaWVudChvcHRpb25zKSk7XG4gICAgdGhpcy5mZXRjaEltcGwgPSBkZXBlbmRlbmNpZXMuZmV0Y2ggPz8gZmV0Y2g7XG4gIH1cblxuICBhc3luYyBzdGFydCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCB7IHJvd3MgfSA9IGF3YWl0IFRva2VuTW9kZWwuZmluZE1hbnkoXCJBXCIpO1xuICAgIGZvciAoY29uc3Qgcm93IG9mIHJvd3MpIHtcbiAgICAgIGlmIChyb3cucHJvdmlkZXIgIT09IFwib3BlbmFpXCIpIGNvbnRpbnVlO1xuICAgICAgdGhpcy5zZXRUb2tlbihcbiAgICAgICAgcm93LmlkLFxuICAgICAgICByb3cubmFtZSxcbiAgICAgICAgcm93LmNyZWRlbnRpYWxzIGFzIE9wZW5BSUNyZWRlbnRpYWxzLFxuICAgICAgICByb3cucXVvdGFfdGhyZXNob2xkLFxuICAgICAgICByb3cud2VpZ2h0LFxuICAgICAgICByb3cuYWN0aXZlLFxuICAgICAgKTtcbiAgICB9XG4gICAgbG9nZ2VyLmluZm8oYHN0YXJ0ZWQgZGlyZWN0IE9wZW5BSSBydW50aW1lIHdpdGggJHt0aGlzLnRva2VuTWV0YWRhdGEuc2l6ZX0gdG9rZW5zYCk7XG4gIH1cblxuICBhc3luYyBzdG9wKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGZvciAoY29uc3QgeyBjbGllbnQgfSBvZiB0aGlzLmNsaWVudHMudmFsdWVzKCkpIGNsaWVudC5jbG9zZT8uKCk7XG4gICAgdGhpcy5jbGllbnRzLmNsZWFyKCk7XG4gICAgZm9yIChjb25zdCBlbnRyeSBvZiB0aGlzLnJldGlyZWRDbGllbnRzKSBlbnRyeS5jbGllbnQuY2xvc2U/LigpO1xuICAgIHRoaXMucmV0aXJlZENsaWVudHMuY2xlYXIoKTtcbiAgICB0aGlzLnRva2VuTWV0YWRhdGEuY2xlYXIoKTtcbiAgICB0aGlzLnJhdGVMaW1pdHNDYWNoZS5jbGVhcigpO1xuICAgIHRoaXMucXVvdGFCbG9ja2VkLmNsZWFyKCk7XG4gICAgdGhpcy5zZWxlY3Rvci5yZXNldFNjb3JlcygpO1xuICB9XG5cbiAgYXN5bmMgb25Ub2tlbkFkZGVkKFxuICAgIGlkOiBudW1iZXIsXG4gICAgbmFtZTogc3RyaW5nLFxuICAgIGNyZWRlbnRpYWxzOiBPcGVuQUlDcmVkZW50aWFscyxcbiAgICBxdW90YVRocmVzaG9sZD86IG51bWJlciB8IG51bGwsXG4gICAgd2VpZ2h0ID0gMSxcbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdGhpcy5zZXRUb2tlbihpZCwgbmFtZSwgY3JlZGVudGlhbHMsIHF1b3RhVGhyZXNob2xkLCB3ZWlnaHQsIHRydWUpO1xuICB9XG5cbiAgYXN5bmMgb25Ub2tlblVwZGF0ZWQoXG4gICAgaWQ6IG51bWJlcixcbiAgICBuYW1lOiBzdHJpbmcsXG4gICAgY3JlZGVudGlhbHM6IE9wZW5BSUNyZWRlbnRpYWxzLFxuICAgIHF1b3RhVGhyZXNob2xkPzogbnVtYmVyIHwgbnVsbCxcbiAgICB3ZWlnaHQgPSAxLFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBvbGQgPSB0aGlzLnRva2VuTWV0YWRhdGEuZ2V0KGlkKTtcbiAgICB0aGlzLnNldFRva2VuKGlkLCBuYW1lLCBjcmVkZW50aWFscywgcXVvdGFUaHJlc2hvbGQsIHdlaWdodCwgb2xkPy5hY3RpdmUgPz8gdHJ1ZSk7XG4gIH1cblxuICBhc3luYyBvblRva2VuUmVtb3ZlZChpZDogbnVtYmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdGhpcy5yZXRpcmVDbGllbnQoaWQpO1xuICAgIHRoaXMudG9rZW5NZXRhZGF0YS5kZWxldGUoaWQpO1xuICAgIHRoaXMuc2VsZWN0b3IucmVtb3ZlVG9rZW4oaWQpO1xuICAgIHRoaXMuaW52YWxpZGF0ZVJhdGVMaW1pdHNDYWNoZShpZCk7XG4gICAgdGhpcy5xdW90YUJsb2NrZWQuZGVsZXRlKGlkKTtcbiAgfVxuXG4gIG9uVG9rZW5EZWFjdGl2YXRlZChpZDogbnVtYmVyKTogdm9pZCB7XG4gICAgY29uc3QgdG9rZW4gPSB0aGlzLnRva2VuTWV0YWRhdGEuZ2V0KGlkKTtcbiAgICBpZiAodG9rZW4pIHRva2VuLmFjdGl2ZSA9IGZhbHNlO1xuICAgIHRoaXMuc2VsZWN0b3IucmVzZXRTY29yZXMoKTtcbiAgfVxuXG4gIG9uVG9rZW5BY3RpdmF0ZWQoaWQ6IG51bWJlcik6IHZvaWQge1xuICAgIGNvbnN0IHRva2VuID0gdGhpcy50b2tlbk1ldGFkYXRhLmdldChpZCk7XG4gICAgaWYgKHRva2VuKSB0b2tlbi5hY3RpdmUgPSB0cnVlO1xuICAgIHRoaXMuc2VsZWN0b3IucmVzZXRTY29yZXMoKTtcbiAgfVxuXG4gIGFzeW5jIHJlcGxhY2VUb2tlbnMoXG4gICAgcm93czogQXJyYXk8e1xuICAgICAgaWQ6IG51bWJlcjtcbiAgICAgIG5hbWU6IHN0cmluZztcbiAgICAgIGNyZWRlbnRpYWxzOiBPcGVuQUlDcmVkZW50aWFscztcbiAgICAgIHF1b3RhVGhyZXNob2xkPzogbnVtYmVyIHwgbnVsbDtcbiAgICAgIHdlaWdodDogbnVtYmVyO1xuICAgIH0+LFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBpZHMgPSBuZXcgU2V0KHJvd3MubWFwKChyKSA9PiByLmlkKSk7XG4gICAgZm9yIChjb25zdCBpZCBvZiB0aGlzLnRva2VuTWV0YWRhdGEua2V5cygpKSBpZiAoIWlkcy5oYXMoaWQpKSBhd2FpdCB0aGlzLm9uVG9rZW5SZW1vdmVkKGlkKTtcbiAgICBmb3IgKGNvbnN0IHJvdyBvZiByb3dzKVxuICAgICAgYXdhaXQgdGhpcy5vblRva2VuVXBkYXRlZChyb3cuaWQsIHJvdy5uYW1lLCByb3cuY3JlZGVudGlhbHMsIHJvdy5xdW90YVRocmVzaG9sZCwgcm93LndlaWdodCk7XG4gIH1cblxuICBhc3luYyBnZW5lcmF0ZShyZXE6IEdlbmVyYXRlUmVxdWVzdCk6IFByb21pc2U8R2VuZXJhdGVSZXN1bHQ+IHtcbiAgICByZXR1cm4gdGhpcy5ydW4ocmVxKTtcbiAgfVxuXG4gIGFzeW5jIGdlbmVyYXRlU3RyZWFtKHJlcTogR2VuZXJhdGVSZXF1ZXN0LCBjYjogR2VuZXJhdGVTdHJlYW1DYWxsYmFja3MpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAocmVxLmltYWdlR2VuZXJhdGlvbilcbiAgICAgIHRocm93IG5ldyBJbWFnZUdlbmVyYXRpb25FcnJvcihcbiAgICAgICAgXCJnYXRlXCIsXG4gICAgICAgIFwiaW1hZ2UgZ2VuZXJhdGlvbiBpcyBub3Qgc3VwcG9ydGVkIG9uIHRoZSBzdHJlYW1pbmcgcGF0aFwiLFxuICAgICAgKTtcbiAgICB0cnkge1xuICAgICAgY2Iub25Db21wbGV0ZShhd2FpdCB0aGlzLnJ1bihyZXEsIGNiLm9uRGVsdGEpKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgY2Iub25FcnJvcihlcnJvciBhcyBFcnJvcik7XG4gICAgICB0aHJvdyBlcnJvcjtcbiAgICB9XG4gIH1cblxuICAvLyBnZW5lcmF0ZS9nZW5lcmF0ZVN0cmVhbSDqs7XthrUg7Iuk7ZaJIOKAlCDthqDtgbAg7ISg7YOd6rO8IGluLWZsaWdodCDsp5Hqs4Trpbwg7ZWcIOqzs+yXkCDrkZTri6QuXG4gIHByaXZhdGUgYXN5bmMgcnVuKFxuICAgIHJlcTogR2VuZXJhdGVSZXF1ZXN0LFxuICAgIG9uRGVsdGE/OiAodGV4dDogc3RyaW5nKSA9PiB2b2lkLFxuICApOiBQcm9taXNlPEdlbmVyYXRlUmVzdWx0PiB7XG4gICAgY29uc3Qgc2lnbmFsID0gYWN0aXZlU2lnbmFsKHJlcS5hYm9ydFNpZ25hbCwgcmVxLnRpbWVvdXRNcyk7XG4gICAgaWYgKHNpZ25hbC5hYm9ydGVkKSB0aHJvdyBhYm9ydEVycm9yKHNpZ25hbCk7XG4gICAgY29uc3Qgc2VsZWN0aW9uID0gYXdhaXQgdGhpcy5zZWxlY3RUb2tlbihcbiAgICAgIHJlcS5wcmVmZXJyZWRUb2tlbklkLFxuICAgICAgcmVxLnJlcXVpcmVQcmVmZXJyZWRUb2tlbiA/PyBmYWxzZSxcbiAgICAgIHNpZ25hbCxcbiAgICApO1xuICAgIHRoaXMuaW5GbGlnaHRDb3VudCsrO1xuICAgIHRyeSB7XG4gICAgICBpZiAoc2lnbmFsLmFib3J0ZWQpIHRocm93IGFib3J0RXJyb3Ioc2lnbmFsKTtcbiAgICAgIHJldHVybiBhd2FpdCB0aGlzLnJ1bkRpcmVjdChzZWxlY3Rpb24sIHsgLi4ucmVxLCBhYm9ydFNpZ25hbDogc2lnbmFsIH0sIG9uRGVsdGEpO1xuICAgIH0gZmluYWxseSB7XG4gICAgICB0aGlzLmluRmxpZ2h0Q291bnQtLTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHJ1bkRpcmVjdChcbiAgICBzZWxlY3Rpb246IFRva2VuU2VsZWN0aW9uLFxuICAgIHJlcTogR2VuZXJhdGVSZXF1ZXN0LFxuICAgIG9uRGVsdGE/OiAodGV4dDogc3RyaW5nKSA9PiB2b2lkLFxuICApOiBQcm9taXNlPEdlbmVyYXRlUmVzdWx0PiB7XG4gICAgY29uc3Qgc3RhcnRlZEF0ID0gRGF0ZS5ub3coKTtcbiAgICBsZXQgZmlyc3REZWx0YUF0OiBudW1iZXIgfCB1bmRlZmluZWQ7XG4gICAgbGV0IHRleHQgPSBcIlwiO1xuICAgIGxldCB1c2FnZSA9IHtcbiAgICAgIHRvdGFsVG9rZW5zOiAwLFxuICAgICAgaW5wdXRUb2tlbnM6IDAsXG4gICAgICBvdXRwdXRUb2tlbnM6IDAsXG4gICAgICBjYWNoZWRJbnB1dFRva2VuczogMCxcbiAgICAgIHJlYXNvbmluZ091dHB1dFRva2VuczogMCxcbiAgICB9O1xuICAgIGNvbnN0IGltYWdlczogR2VuZXJhdGVkSW1hZ2VbXSA9IFtdO1xuICAgIGxldCBpbWFnZUF0dGVtcHRlZCA9IGZhbHNlO1xuICAgIGxldCBzZXJ2aW5nTW9kZWwgPSByZXEubW9kZWwgPz8gXCJcIjtcbiAgICBjb25zdCBtZXRhZGF0YSA9IHNlbGVjdGlvbi5tZXRhZGF0YTtcbiAgICBjb25zdCBjbGllbnRFbnRyeSA9IHRoaXMuYWNxdWlyZUNsaWVudChzZWxlY3Rpb24pO1xuICAgIHRyeSB7XG4gICAgICBmb3IgYXdhaXQgKGNvbnN0IGV2ZW50IG9mIGNsaWVudEVudHJ5LmNsaWVudC5yZXNwb25zZXMoXG4gICAgICAgIHJlcXVlc3RPcHRpb25zKHJlcSksXG4gICAgICAgIHJlcS5hYm9ydFNpZ25hbCxcbiAgICAgICkpIHtcbiAgICAgICAgaWYgKGV2ZW50LnR5cGUgPT09IFwidGV4dC1kZWx0YVwiKSB7XG4gICAgICAgICAgZmlyc3REZWx0YUF0ID8/PSBEYXRlLm5vdygpO1xuICAgICAgICAgIHRleHQgKz0gZXZlbnQudGV4dDtcbiAgICAgICAgICBvbkRlbHRhPy4oZXZlbnQudGV4dCk7XG4gICAgICAgIH0gZWxzZSBpZiAoZXZlbnQudHlwZSA9PT0gXCJpbWFnZVwiKSB7XG4gICAgICAgICAgaW1hZ2VBdHRlbXB0ZWQgPSB0cnVlO1xuICAgICAgICAgIGltYWdlcy5wdXNoKHsgZGF0YTogZXZlbnQuYmFzZTY0LCByZXZpc2VkUHJvbXB0OiBldmVudC5yZXZpc2VkUHJvbXB0ID8/IG51bGwgfSk7XG4gICAgICAgIH0gZWxzZSBpZiAoZXZlbnQudHlwZSA9PT0gXCJvdXRwdXQtaXRlbVwiICYmIGV2ZW50Lml0ZW0udHlwZSA9PT0gXCJpbWFnZV9nZW5lcmF0aW9uX2NhbGxcIikge1xuICAgICAgICAgIGltYWdlQXR0ZW1wdGVkID0gdHJ1ZTtcbiAgICAgICAgfSBlbHNlIGlmIChldmVudC50eXBlID09PSBcImNvbXBsZXRlZFwiICYmIGV2ZW50LnVzYWdlKSB7XG4gICAgICAgICAgc2VydmluZ01vZGVsID0gZXZlbnQubW9kZWwgPz8gc2VydmluZ01vZGVsO1xuICAgICAgICAgIHVzYWdlID0ge1xuICAgICAgICAgICAgdG90YWxUb2tlbnM6IGV2ZW50LnVzYWdlLnRvdGFsVG9rZW5zLFxuICAgICAgICAgICAgaW5wdXRUb2tlbnM6IGV2ZW50LnVzYWdlLmlucHV0VG9rZW5zLFxuICAgICAgICAgICAgb3V0cHV0VG9rZW5zOiBldmVudC51c2FnZS5vdXRwdXRUb2tlbnMsXG4gICAgICAgICAgICBjYWNoZWRJbnB1dFRva2VuczogZXZlbnQudXNhZ2UuY2FjaGVkSW5wdXRUb2tlbnMsXG4gICAgICAgICAgICByZWFzb25pbmdPdXRwdXRUb2tlbnM6IGV2ZW50LnVzYWdlLnJlYXNvbmluZ1Rva2VucyxcbiAgICAgICAgICB9O1xuICAgICAgICB9IGVsc2UgaWYgKGV2ZW50LnR5cGUgPT09IFwiY29tcGxldGVkXCIpIHtcbiAgICAgICAgICBzZXJ2aW5nTW9kZWwgPSBldmVudC5tb2RlbCA/PyBzZXJ2aW5nTW9kZWw7XG4gICAgICAgIH0gZWxzZSBpZiAoZXZlbnQudHlwZSA9PT0gXCJlcnJvclwiKSB7XG4gICAgICAgICAgaWYgKHJlcS5pbWFnZUdlbmVyYXRpb24pXG4gICAgICAgICAgICB0aHJvdyBuZXcgSW1hZ2VHZW5lcmF0aW9uRXJyb3IoXCJpbmNvbXBsZXRlXCIsIGV2ZW50LmVycm9yLm1lc3NhZ2UpO1xuICAgICAgICAgIHRocm93IGV2ZW50LmVycm9yO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIHRoaXMucmVsZWFzZUNsaWVudChjbGllbnRFbnRyeSk7XG4gICAgfVxuICAgIGlmIChyZXEuaW1hZ2VHZW5lcmF0aW9uICYmIGltYWdlcy5sZW5ndGggPT09IDApIHtcbiAgICAgIHRocm93IG5ldyBJbWFnZUdlbmVyYXRpb25FcnJvcihcbiAgICAgICAgaW1hZ2VBdHRlbXB0ZWQgPyBcImluY29tcGxldGVcIiA6IFwibm90X2NhbGxlZFwiLFxuICAgICAgICBpbWFnZUF0dGVtcHRlZFxuICAgICAgICAgID8gXCJpbWFnZSBnZW5lcmF0aW9uIGRpZCBub3QgY29tcGxldGVcIlxuICAgICAgICAgIDogXCJtb2RlbCBkaWQgbm90IGNhbGwgaW1hZ2UgZ2VuZXJhdGlvblwiLFxuICAgICAgKTtcbiAgICB9XG4gICAgcmV0dXJuIHtcbiAgICAgIHRleHQsXG4gICAgICB0b2tlbk5hbWU6IG1ldGFkYXRhLm5hbWUsXG4gICAgICB1c2FnZSxcbiAgICAgIGR1cmF0aW9uTXM6IERhdGUubm93KCkgLSBzdGFydGVkQXQsXG4gICAgICB0dGZ0TXM6IGZpcnN0RGVsdGFBdCA9PT0gdW5kZWZpbmVkID8gbnVsbCA6IGZpcnN0RGVsdGFBdCAtIHN0YXJ0ZWRBdCxcbiAgICAgIG1vZGVsOiBzZXJ2aW5nTW9kZWwsXG4gICAgICB0aHJlYWRDb29yZDogeyB3b3JrZXJJZDogc2VsZWN0aW9uLnRva2VuSWQsIHRocmVhZElkOiByZXEucHJvbXB0Q2FjaGVLZXkgPz8gXCJcIiwgZXBvY2g6IC0xIH0sXG4gICAgICAuLi4oaW1hZ2VzLmxlbmd0aCA/IHsgaW1hZ2VzIH0gOiB7fSksXG4gICAgfTtcbiAgfVxuXG4gIC8qKiDshLjrjIDqsIAg67CU64CQIGNsaWVudCDripQg7IKs7JqpIOykkeyduCDsmpTssq3snbQg64Gd64KcIOuSpOyXkCDri6vripTri6QuICovXG4gIHByaXZhdGUgYWNxdWlyZUNsaWVudChzZWxlY3Rpb246IFRva2VuU2VsZWN0aW9uKTogQ2xpZW50RW50cnkge1xuICAgIGNvbnN0IG1ldGFkYXRhID0gc2VsZWN0aW9uLm1ldGFkYXRhO1xuICAgIGxldCBlbnRyeSA9IHRoaXMuY2xpZW50cy5nZXQoc2VsZWN0aW9uLnRva2VuSWQpO1xuICAgIGlmIChlbnRyeSAmJiBlbnRyeS5nZW5lcmF0aW9uICE9PSBtZXRhZGF0YS5nZW5lcmF0aW9uKSB7XG4gICAgICB0aGlzLnJldGlyZUNsaWVudChzZWxlY3Rpb24udG9rZW5JZCk7XG4gICAgICBlbnRyeSA9IHVuZGVmaW5lZDtcbiAgICB9XG4gICAgaWYgKCFlbnRyeSkge1xuICAgICAgY29uc3QgY2xpZW50ID0gdGhpcy5jbGllbnRGYWN0b3J5KFxuICAgICAgICB7XG4gICAgICAgICAgY3JlZGVudGlhbHM6IHtcbiAgICAgICAgICAgIGFjY2Vzc1Rva2VuOiBtZXRhZGF0YS5jcmVkZW50aWFscy5hY2Nlc3NUb2tlbixcbiAgICAgICAgICAgIGFjY291bnRJZDogbWV0YWRhdGEuY3JlZGVudGlhbHMuYWNjb3VudElkLFxuICAgICAgICAgIH0sXG4gICAgICAgICAgdHJhbnNwb3J0S2luZDogdGhpcy50cmFuc3BvcnRLaW5kLFxuICAgICAgICAgIGZldGNoOiB0aGlzLmZldGNoSW1wbCxcbiAgICAgICAgICByZWZyZXNoQ3JlZGVudGlhbHM6IGFzeW5jICgpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IHJlZnJlc2hlZCA9IGF3YWl0IGhhbmRsZUNoYXRncHRBdXRoVG9rZW5zUmVmcmVzaChzZWxlY3Rpb24udG9rZW5JZCk7XG4gICAgICAgICAgICBjb25zdCBjdXJyZW50ID0gdGhpcy50b2tlbk1ldGFkYXRhLmdldChzZWxlY3Rpb24udG9rZW5JZCk7XG4gICAgICAgICAgICBpZiAoY3VycmVudClcbiAgICAgICAgICAgICAgY3VycmVudC5jcmVkZW50aWFscyA9IHtcbiAgICAgICAgICAgICAgICAuLi5jdXJyZW50LmNyZWRlbnRpYWxzLFxuICAgICAgICAgICAgICAgIGFjY2Vzc1Rva2VuOiByZWZyZXNoZWQuYWNjZXNzVG9rZW4sXG4gICAgICAgICAgICAgICAgYWNjb3VudElkOiByZWZyZXNoZWQuY2hhdGdwdEFjY291bnRJZCxcbiAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIHJldHVybiB7IGFjY2Vzc1Rva2VuOiByZWZyZXNoZWQuYWNjZXNzVG9rZW4sIGFjY291bnRJZDogcmVmcmVzaGVkLmNoYXRncHRBY2NvdW50SWQgfTtcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgICBzZWxlY3Rpb24udG9rZW5JZCxcbiAgICAgICk7XG4gICAgICBlbnRyeSA9IHsgZ2VuZXJhdGlvbjogbWV0YWRhdGEuZ2VuZXJhdGlvbiwgY2xpZW50LCBpbkZsaWdodDogMCwgcmV0aXJlZDogZmFsc2UgfTtcbiAgICAgIHRoaXMuY2xpZW50cy5zZXQoc2VsZWN0aW9uLnRva2VuSWQsIGVudHJ5KTtcbiAgICB9XG4gICAgZW50cnkuaW5GbGlnaHQrKztcbiAgICByZXR1cm4gZW50cnk7XG4gIH1cblxuICBwcml2YXRlIHJlbGVhc2VDbGllbnQoZW50cnk6IENsaWVudEVudHJ5KTogdm9pZCB7XG4gICAgZW50cnkuaW5GbGlnaHQgPSBNYXRoLm1heCgwLCBlbnRyeS5pbkZsaWdodCAtIDEpO1xuICAgIGlmIChlbnRyeS5yZXRpcmVkICYmIGVudHJ5LmluRmxpZ2h0ID09PSAwKSB7XG4gICAgICB0aGlzLnJldGlyZWRDbGllbnRzLmRlbGV0ZShlbnRyeSk7XG4gICAgICBlbnRyeS5jbGllbnQuY2xvc2U/LigpO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBtYXAg7JeQ7IScIOuWvOyWtOuCtOqzoCwg7KeE7ZaJIOykkeyduCDsmpTssq3snbQg7JeG7J2EIOuVjOunjCDsponsi5wg64ur64qU64ukLiAqL1xuICBwcml2YXRlIHJldGlyZUNsaWVudCh0b2tlbklkOiBudW1iZXIpOiB2b2lkIHtcbiAgICBjb25zdCBlbnRyeSA9IHRoaXMuY2xpZW50cy5nZXQodG9rZW5JZCk7XG4gICAgaWYgKCFlbnRyeSkgcmV0dXJuO1xuICAgIHRoaXMuY2xpZW50cy5kZWxldGUodG9rZW5JZCk7XG4gICAgZW50cnkucmV0aXJlZCA9IHRydWU7XG4gICAgaWYgKGVudHJ5LmluRmxpZ2h0ID09PSAwKSBlbnRyeS5jbGllbnQuY2xvc2U/LigpO1xuICAgIGVsc2UgdGhpcy5yZXRpcmVkQ2xpZW50cy5hZGQoZW50cnkpO1xuICB9XG5cbiAgLyoqXG4gICAqIO2GoO2BsCDshKDtg50g4oCUIHF1b3RhIGdhdGUg66W8IO2GteqzvO2VnCBhY3RpdmUg7Yag7YGwIOykkeyXkOyEnCDqs6Drpbjri6QuIGNhY2hlIGFmZmluaXR5IOyEoO2YuFxuICAgKiDthqDtgbDsnbQgZWxpZ2libGUg7ZWY66m0IOq3uCDtjJDsoJXrp4zsnLzroZwg7KaJ7IucIOqysOygle2VmOqzoCjsoITssrQgc3dlZXAg7IOd6561LCB3ZWlnaHRlZCDsg4Htg5xcbiAgICog67mE67OA6rK9KSwg7JWE64uI66m0IOuzkeugrCBxdW90YSDtjJDsoJUg7ZuEIHNtb290aCB3ZWlnaHRlZCByb3VuZC1yb2Jpbi4g64+Z7Iuc7ISxIOyDge2VnOydtFxuICAgKiDsl4bsnLzrr4DroZwgXCLruYgg7J6Q66asXCIg6rCc64WQ64+EIOyXhuuLpCDigJQg7ISg7YOdIOymieyLnCDsi6TtlonsnbTri6QuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHNlbGVjdFRva2VuKFxuICAgIHByZWZlcnJlZFRva2VuSWQ6IG51bWJlciB8IHVuZGVmaW5lZCxcbiAgICByZXF1aXJlUHJlZmVycmVkVG9rZW46IGJvb2xlYW4sXG4gICAgc2lnbmFsOiBBYm9ydFNpZ25hbCxcbiAgKTogUHJvbWlzZTxUb2tlblNlbGVjdGlvbj4ge1xuICAgIGlmIChwcmVmZXJyZWRUb2tlbklkICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGNvbnN0IHByZWZlcnJlZCA9IHRoaXMudG9rZW5NZXRhZGF0YS5nZXQocHJlZmVycmVkVG9rZW5JZCk7XG4gICAgICBpZiAocHJlZmVycmVkPy5hY3RpdmUgJiYgKGF3YWl0IHRoaXMuaXNRdW90YUVsaWdpYmxlKHByZWZlcnJlZFRva2VuSWQsIHByZWZlcnJlZCwgc2lnbmFsKSkpIHtcbiAgICAgICAgcmV0dXJuIHsgdG9rZW5JZDogcHJlZmVycmVkVG9rZW5JZCwgbWV0YWRhdGE6IHByZWZlcnJlZCB9O1xuICAgICAgfVxuICAgICAgaWYgKHJlcXVpcmVQcmVmZXJyZWRUb2tlbikge1xuICAgICAgICBpZiAoIXByZWZlcnJlZD8uYWN0aXZlKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBQcmVmZXJyZWQgb3BlbmFpIHRva2VuICR7cHJlZmVycmVkVG9rZW5JZH0gaXMgbm90IGF2YWlsYWJsZWApO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHRocmVzaG9sZCA9IHByZWZlcnJlZC5xdW90YVRocmVzaG9sZDtcbiAgICAgICAgaWYgKHRocmVzaG9sZCAhPT0gbnVsbCAmJiB0aHJlc2hvbGQgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgIHRocm93IG5ldyBRdW90YVRocmVzaG9sZEV4Y2VlZGVkRXJyb3IoXG4gICAgICAgICAgICBxdW90YU1lc3NhZ2UoW3sgbmFtZTogcHJlZmVycmVkLm5hbWUsIHRocmVzaG9sZCB9XSksXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIC8vIO2GoO2BsOuzhCBxdW90YSDtjJDsoJXsnYAg7ISc66GcIOuPheumveydtOudvCDrs5HroKzroZwg4oCUIOyngeugrCDrjIDquLDripQg7L2c65OcIOy6kOyLnOyXkOyEnFxuICAgIC8vIO2GoO2BsCDsiJggw5cg7KGw7ZqMIOyngOyXsOunjO2BvCDsmpTssq0g7Iuc7J6R7J2EIOuKpuy2mOuLpC5cbiAgICBjb25zdCBjaGVja3MgPSBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgIFsuLi50aGlzLnRva2VuTWV0YWRhdGEuZW50cmllcygpXVxuICAgICAgICAuZmlsdGVyKChbLCB0b2tlbl0pID0+IHRva2VuLmFjdGl2ZSlcbiAgICAgICAgLm1hcChhc3luYyAoW2lkLCB0b2tlbl0pID0+ICh7XG4gICAgICAgICAgaWQsXG4gICAgICAgICAgdG9rZW4sXG4gICAgICAgICAgZWxpZ2libGU6IGF3YWl0IHRoaXMuaXNRdW90YUVsaWdpYmxlKGlkLCB0b2tlbiwgc2lnbmFsKSxcbiAgICAgICAgfSkpLFxuICAgICk7XG4gICAgY29uc3QgZWxpZ2libGUgPSBuZXcgU2V0KGNoZWNrcy5maWx0ZXIoKGMpID0+IGMuZWxpZ2libGUpLm1hcCgoYykgPT4gYy5pZCkpO1xuICAgIGlmIChlbGlnaWJsZS5zaXplID09PSAwKSB7XG4gICAgICBjb25zdCBvdmVyID0gY2hlY2tzXG4gICAgICAgIC5maWx0ZXIoXG4gICAgICAgICAgKGMpID0+XG4gICAgICAgICAgICAhYy5lbGlnaWJsZSAmJiBjLnRva2VuLnF1b3RhVGhyZXNob2xkICE9PSBudWxsICYmIGMudG9rZW4ucXVvdGFUaHJlc2hvbGQgIT09IHVuZGVmaW5lZCxcbiAgICAgICAgKVxuICAgICAgICAubWFwKChjKSA9PiAoeyBuYW1lOiBjLnRva2VuLm5hbWUsIHRocmVzaG9sZDogYy50b2tlbi5xdW90YVRocmVzaG9sZCBhcyBudW1iZXIgfSkpO1xuICAgICAgaWYgKG92ZXIubGVuZ3RoKSB7XG4gICAgICAgIGxvZ2dlci53YXJuKFwicXVvdGFfdGhyZXNob2xkIGdhdGU6IGFsbF9leGNlZWRlZFwiLCB7XG4gICAgICAgICAgcHJvdmlkZXI6IFwib3BlbmFpXCIsXG4gICAgICAgICAgb3ZlclRocmVzaG9sZFRva2Vuczogb3ZlcixcbiAgICAgICAgfSk7XG4gICAgICAgIHRocm93IG5ldyBRdW90YVRocmVzaG9sZEV4Y2VlZGVkRXJyb3IocXVvdGFNZXNzYWdlKG92ZXIpKTtcbiAgICAgIH1cbiAgICAgIHRocm93IG5ldyBFcnJvcihcIk5PX09QRU5BSV9XT1JLRVJTXCIpO1xuICAgIH1cbiAgICBjb25zdCBzZWxlY3RlZCA9IHRoaXMuc2VsZWN0b3Iuc2VsZWN0KGVsaWdpYmxlKTtcbiAgICBjb25zdCBtZXRhZGF0YSA9IHNlbGVjdGVkICE9PSBudWxsID8gdGhpcy50b2tlbk1ldGFkYXRhLmdldChzZWxlY3RlZCkgOiB1bmRlZmluZWQ7XG4gICAgaWYgKHNlbGVjdGVkID09PSBudWxsIHx8ICFtZXRhZGF0YSkgdGhyb3cgbmV3IEVycm9yKFwiTk9fT1BFTkFJX1dPUktFUlNcIik7XG4gICAgcmV0dXJuIHsgdG9rZW5JZDogc2VsZWN0ZWQsIG1ldGFkYXRhIH07XG4gIH1cblxuICBwcml2YXRlIHNldFRva2VuKFxuICAgIGlkOiBudW1iZXIsXG4gICAgbmFtZTogc3RyaW5nLFxuICAgIGNyZWRlbnRpYWxzOiBPcGVuQUlDcmVkZW50aWFscyxcbiAgICBxdW90YVRocmVzaG9sZDogbnVtYmVyIHwgbnVsbCB8IHVuZGVmaW5lZCxcbiAgICB3ZWlnaHQ6IG51bWJlcixcbiAgICBhY3RpdmU6IGJvb2xlYW4sXG4gICk6IHZvaWQge1xuICAgIGNvbnN0IG9sZCA9IHRoaXMudG9rZW5NZXRhZGF0YS5nZXQoaWQpO1xuICAgIGlmIChvbGQpIHtcbiAgICAgIE9iamVjdC5hc3NpZ24ob2xkLCB7XG4gICAgICAgIG5hbWUsXG4gICAgICAgIGNyZWRlbnRpYWxzLFxuICAgICAgICBxdW90YVRocmVzaG9sZCxcbiAgICAgICAgd2VpZ2h0LFxuICAgICAgICBhY3RpdmUsXG4gICAgICAgIGdlbmVyYXRpb246IG9sZC5nZW5lcmF0aW9uICsgMSxcbiAgICAgIH0pO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLnRva2VuTWV0YWRhdGEuc2V0KGlkLCB7XG4gICAgICAgIG5hbWUsXG4gICAgICAgIGNyZWRlbnRpYWxzLFxuICAgICAgICBxdW90YVRocmVzaG9sZCxcbiAgICAgICAgd2VpZ2h0LFxuICAgICAgICBhY3RpdmUsXG4gICAgICAgIGdlbmVyYXRpb246IDEsXG4gICAgICB9KTtcbiAgICB9XG4gICAgdGhpcy5zZWxlY3Rvci5zZXRUb2tlbihpZCwgd2VpZ2h0KTtcbiAgICB0aGlzLmludmFsaWRhdGVSYXRlTGltaXRzQ2FjaGUoaWQpO1xuICAgIHRoaXMucXVvdGFCbG9ja2VkLmRlbGV0ZShpZCk7XG4gIH1cblxuICBhc3luYyBnZXRSYXRlTGltaXRzQnlUb2tlbklkKFxuICAgIHRva2VuSWQ6IG51bWJlcixcbiAgICBzaWduYWw/OiBBYm9ydFNpZ25hbCxcbiAgKTogUHJvbWlzZTxPcGVuQUlSYXRlTGltaXRzV2l0aE1ldGE+IHtcbiAgICBjb25zdCB0b2tlbiA9IHRoaXMudG9rZW5NZXRhZGF0YS5nZXQodG9rZW5JZCk7XG4gICAgaWYgKCF0b2tlbikgdGhyb3cgbmV3IEVycm9yKGBvcGVuYWkgdG9rZW4gJHt0b2tlbklkfSBub3QgZm91bmRgKTtcbiAgICBjb25zdCBjYWNoZWQgPSB0aGlzLnJhdGVMaW1pdHNDYWNoZS5nZXQodG9rZW5JZCk7XG4gICAgaWYgKFxuICAgICAgY2FjaGVkICYmXG4gICAgICBjYWNoZWQuZ2VuZXJhdGlvbiA9PT0gdG9rZW4uZ2VuZXJhdGlvbiAmJlxuICAgICAgRGF0ZS5ub3coKSAtIGNhY2hlZC5jYWNoZWRBdCA8IE9wZW5BSURpc3BhdGNoZXIuUkFURV9MSU1JVFNfQ0FDSEVfVFRMXG4gICAgKVxuICAgICAgcmV0dXJuIGNhY2hlZDtcblxuICAgIC8vIHNpbmdsZS1mbGlnaHQ6IOuPmeyLnOyEsSDsg4HtlZzsnbQg7JeG7Ja07KeEIOuSpOuhnCBUVEwg66eM66OMIOyInOqwhCDrj5nsi5wg7JqU7LKtIOyImOunjO2BvCDqsJnsnYBcbiAgICAvLyDsobDtmozqsIAg66qw66a0IOyImCDsnojri6Qg4oCUIOynhO2WiSDspJHsnbggZmV0Y2gg66W8IOqzteycoO2VnOuLpC4g7LWc7LSIIO2YuOy2nOyekOydmCBhYm9ydCDroZxcbiAgICAvLyDqs7XsnKAg7KGw7ZqM6rCAIOyLpO2MqO2VtOuPhCDshozruYTsspgoaXNRdW90YUVsaWdpYmxlKeqwgCBmYWlsLW9wZW4g7Jy866GcIOyymOumrO2VnOuLpC5cbiAgICBjb25zdCBwZW5kaW5nID0gdGhpcy5wZW5kaW5nUmF0ZUxpbWl0cy5nZXQodG9rZW5JZCk7XG4gICAgaWYgKHBlbmRpbmcpIHJldHVybiBwZW5kaW5nO1xuICAgIGNvbnN0IGZldGNoUHJvbWlzZSA9IChhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCByZWFkT3BlbkFJUXVvdGFVc2FnZSh7XG4gICAgICAgIGNyZWRlbnRpYWxzOiB0b2tlbi5jcmVkZW50aWFscyxcbiAgICAgICAgZmV0Y2g6IHRoaXMuZmV0Y2hJbXBsLFxuICAgICAgICAuLi4oc2lnbmFsID8geyBzaWduYWwgfSA6IHt9KSxcbiAgICAgIH0pO1xuICAgICAgaWYgKHJlc3VsdC5raW5kID09PSBcImxvb2t1cF9mYWlsZWRcIikgdGhyb3cgbmV3IEVycm9yKHJlc3VsdC5yZWFzb24pO1xuICAgICAgaWYgKCFyZXN1bHQucmF3KSB0aHJvdyBuZXcgRXJyb3IoXCJPcGVuQUkgcXVvdGEgcmVzcG9uc2UgbWlzc2luZyByYXcgcmF0ZSBsaW1pdHNcIik7XG4gICAgICBjb25zdCBlbnRyeSA9IHsgZGF0YTogcmVzdWx0LnJhdywgY2FjaGVkQXQ6IERhdGUubm93KCksIGdlbmVyYXRpb246IHRva2VuLmdlbmVyYXRpb24gfTtcbiAgICAgIGlmICh0aGlzLnRva2VuTWV0YWRhdGEuZ2V0KHRva2VuSWQpID09PSB0b2tlbikgdGhpcy5yYXRlTGltaXRzQ2FjaGUuc2V0KHRva2VuSWQsIGVudHJ5KTtcbiAgICAgIHJldHVybiBlbnRyeTtcbiAgICB9KSgpLmZpbmFsbHkoKCkgPT4gdGhpcy5wZW5kaW5nUmF0ZUxpbWl0cy5kZWxldGUodG9rZW5JZCkpO1xuICAgIHRoaXMucGVuZGluZ1JhdGVMaW1pdHMuc2V0KHRva2VuSWQsIGZldGNoUHJvbWlzZSk7XG4gICAgcmV0dXJuIGZldGNoUHJvbWlzZTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgaXNRdW90YUVsaWdpYmxlKFxuICAgIGlkOiBudW1iZXIsXG4gICAgdG9rZW46IFRva2VuTWV0YWRhdGEsXG4gICAgc2lnbmFsPzogQWJvcnRTaWduYWwsXG4gICk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGlmICh0b2tlbi5xdW90YVRocmVzaG9sZCA9PT0gbnVsbCB8fCB0b2tlbi5xdW90YVRocmVzaG9sZCA9PT0gdW5kZWZpbmVkKSByZXR1cm4gdHJ1ZTtcbiAgICBjb25zdCBnZW5lcmF0aW9uID0gdG9rZW4uZ2VuZXJhdGlvbjtcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCByZWFkT3BlbkFJUXVvdGFVc2FnZShhc3luYyAoKSA9PiB0aGlzLmdldFJhdGVMaW1pdHNCeVRva2VuSWQoaWQsIHNpZ25hbCkpO1xuICAgIGlmICh0aGlzLnRva2VuTWV0YWRhdGEuZ2V0KGlkKSAhPT0gdG9rZW4gfHwgdG9rZW4uZ2VuZXJhdGlvbiAhPT0gZ2VuZXJhdGlvbikgcmV0dXJuIGZhbHNlO1xuICAgIGlmIChyZXN1bHQua2luZCA9PT0gXCJsb29rdXBfZmFpbGVkXCIpIHtcbiAgICAgIHRoaXMucXVvdGFCbG9ja2VkLmRlbGV0ZShpZCk7XG4gICAgICBsb2dnZXIud2FybihcInF1b3RhX3RocmVzaG9sZCBnYXRlOiBsb29rdXBfZmFpbF9vcGVuXCIsIHtcbiAgICAgICAgdG9rZW5JZDogaWQsXG4gICAgICAgIHRva2VuTmFtZTogdG9rZW4ubmFtZSxcbiAgICAgICAgbG9va3VwUmVhc29uOiByZXN1bHQucmVhc29uLFxuICAgICAgfSk7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gICAgaWYgKHJlc3VsdC51dGlsaXphdGlvblBjdCA+PSB0b2tlbi5xdW90YVRocmVzaG9sZCkge1xuICAgICAgaWYgKCF0aGlzLnF1b3RhQmxvY2tlZC5oYXMoaWQpKVxuICAgICAgICBsb2dnZXIuaW5mbyhcbiAgICAgICAgICBgcXVvdGFfdGhyZXNob2xkIGdhdGU6IG92ZXJfdGhyZXNob2xkICR7dG9rZW4ubmFtZX1bJHtpZH1dICgke3Jlc3VsdC51dGlsaXphdGlvblBjdH0lID49ICR7dG9rZW4ucXVvdGFUaHJlc2hvbGR9JSlgLFxuICAgICAgICApO1xuICAgICAgdGhpcy5xdW90YUJsb2NrZWQuYWRkKGlkKTtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgaWYgKHRoaXMucXVvdGFCbG9ja2VkLmRlbGV0ZShpZCkpXG4gICAgICBsb2dnZXIuaW5mbyhcbiAgICAgICAgYHF1b3RhX3RocmVzaG9sZCBnYXRlOiByZWNvdmVyZWQgJHt0b2tlbi5uYW1lfVske2lkfV0gKCR7cmVzdWx0LnV0aWxpemF0aW9uUGN0fSUgPCAke3Rva2VuLnF1b3RhVGhyZXNob2xkfSUpYCxcbiAgICAgICk7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICBwcml2YXRlIGludmFsaWRhdGVSYXRlTGltaXRzQ2FjaGUoaWQ6IG51bWJlcik6IHZvaWQge1xuICAgIHRoaXMucmF0ZUxpbWl0c0NhY2hlLmRlbGV0ZShpZCk7XG4gIH1cblxuICBnZXQgdG9rZW5Db3VudCgpOiBudW1iZXIge1xuICAgIHJldHVybiBbLi4udGhpcy50b2tlbk1ldGFkYXRhLnZhbHVlcygpXS5maWx0ZXIoKHQpID0+IHQuYWN0aXZlKS5sZW5ndGg7XG4gIH1cbiAgZ2V0IGluRmxpZ2h0KCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMuaW5GbGlnaHRDb3VudDtcbiAgfVxuXG4gIC8qKlxuICAgKiDthqDtgbDrs4Qg7L+87YSwIOyKpOuDheyDtyDigJQg7Iug7ISg7ZWcKHJhdGUgbGltaXRzIFRUTCDrgrQpIOy6kOyLnOunjCDsnb3qs6Ag7KCI64yAIGZldGNoIO2VmOyngCDslYrripTri6QuXG4gICAqIG1vbml0IHZpdGFscyDripQg66Gc6re4IO2PtOungeyXkCDtjrjsirntlZjripQg6rCS7J206528IOyXrOq4sOyEnCDrhKTtirjsm4ztgazrpbwg7YOA66m0IOyViCDrkJzri6QuXG4gICAqIHRocmVzaG9sZCDrr7jshKTsoJUg7Yag7YGw7J2AIOy/vO2EsCDtjJDsoJXsnYQg64+M7KeAIOyViuyVhCB1c2VkUGVyY2VudCDqsIAgbnVsbCDroZwg64Ko7J2EIOyImCDsnojri6QuXG4gICAqL1xuICBnZXQgcXVvdGFCeVRva2VuKCk6IEFycmF5PHtcbiAgICBuYW1lOiBzdHJpbmc7XG4gICAgdXNlZFBlcmNlbnQ6IG51bWJlciB8IG51bGw7XG4gICAgdGhyZXNob2xkOiBudW1iZXIgfCBudWxsO1xuICAgIGJsb2NrZWQ6IGJvb2xlYW47XG4gICAgcmVzZXRzQXQ6IG51bWJlciB8IG51bGw7XG4gIH0+IHtcbiAgICBjb25zdCBub3cgPSBEYXRlLm5vdygpO1xuICAgIHJldHVybiBbLi4udGhpcy50b2tlbk1ldGFkYXRhLmVudHJpZXMoKV1cbiAgICAgIC5tYXAoKFtpZCwgdF0pID0+IHtcbiAgICAgICAgY29uc3QgY2FjaGVkID0gdGhpcy5yYXRlTGltaXRzQ2FjaGUuZ2V0KGlkKTtcbiAgICAgICAgY29uc3QgZnJlc2ggPVxuICAgICAgICAgIGNhY2hlZCAhPT0gdW5kZWZpbmVkICYmXG4gICAgICAgICAgY2FjaGVkLmdlbmVyYXRpb24gPT09IHQuZ2VuZXJhdGlvbiAmJlxuICAgICAgICAgIG5vdyAtIGNhY2hlZC5jYWNoZWRBdCA8IE9wZW5BSURpc3BhdGNoZXIuUkFURV9MSU1JVFNfQ0FDSEVfVFRMO1xuICAgICAgICBjb25zdCBwcmltYXJ5ID0gZnJlc2ggPyBjYWNoZWQuZGF0YS5yYXRlTGltaXRzPy5wcmltYXJ5IDogdW5kZWZpbmVkO1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIG5hbWU6IHQubmFtZSxcbiAgICAgICAgICB1c2VkUGVyY2VudDogcHJpbWFyeT8udXNlZFBlcmNlbnQgPz8gbnVsbCxcbiAgICAgICAgICB0aHJlc2hvbGQ6IHQucXVvdGFUaHJlc2hvbGQgPz8gbnVsbCxcbiAgICAgICAgICBibG9ja2VkOiB0aGlzLnF1b3RhQmxvY2tlZC5oYXMoaWQpLFxuICAgICAgICAgIC8vIHdoYW0g7J2YIHJlc2V0c0F0IOydgCB1bml4IOy0iCDri6jsnITri6QocWdyaWQuZnJhbWUgdW5peFNlY29uZHNUb0lzbyDsmYAg64+Z7J28IOq3nOyVvSkuXG4gICAgICAgICAgLy8g7IaM67mE7LKY6rCAIOuLqOychOulvCDstpTsuKHtlZjsp4Ag7JWK64+E66GdIOyXrOq4sOyEnCBtcyBlcG9jaCDsnLzroZwg7KCV6rec7ZmU7ZWc64ukLlxuICAgICAgICAgIHJlc2V0c0F0OlxuICAgICAgICAgICAgcHJpbWFyeT8ucmVzZXRzQXQgIT09IG51bGwgJiYgcHJpbWFyeT8ucmVzZXRzQXQgIT09IHVuZGVmaW5lZFxuICAgICAgICAgICAgICA/IHByaW1hcnkucmVzZXRzQXQgKiAxMDAwXG4gICAgICAgICAgICAgIDogbnVsbCxcbiAgICAgICAgfTtcbiAgICAgIH0pXG4gICAgICAudG9Tb3J0ZWQoKGEsIGIpID0+IGEubmFtZS5sb2NhbGVDb21wYXJlKGIubmFtZSkpO1xuICB9XG59XG4iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7OztBQXVCQSxNQUFNLFNBQVMsVUFBVSxDQUFDLFNBQVMsbUJBQW1CLENBQUM7QUFHdkQsTUFBTSw2QkFBNkI7QUFJbkMsSUFBYSx1QkFBYixjQUEwQyxNQUFNO0NBRW5DO0NBRFgsWUFDRSxNQUNBLFNBQ0E7RUFDQSxNQUFNLE9BQU87RUFISixLQUFBLE9BQUE7RUFJVCxLQUFLLE9BQU87Q0FDZDtBQUNGO0FBOEJBLFNBQVMsV0FBVyxRQUE0QjtDQUM5QyxNQUFNLFNBQVMsT0FBTztDQUN0QixPQUFPLGtCQUFrQixRQUFRLFNBQVMsSUFBSSxhQUFhLFdBQVcsWUFBWTtBQUNwRjtBQUVBLFNBQVMsYUFBYSxRQUFzQixXQUFpQztDQUMzRSxNQUFNLFVBQVUsWUFBWSxRQUFRLGFBQWEsMEJBQTBCO0NBQzNFLE9BQU8sU0FBUyxZQUFZLElBQUksQ0FBQyxRQUFRLE9BQU8sQ0FBQyxJQUFJO0FBQ3ZEO0FBRUEsU0FBUyxhQUFhLFNBQTZEO0NBQ2pGLE1BQU0sU0FBUyxRQUFRLEtBQUssTUFBTSxHQUFHLEVBQUUsS0FBSyxjQUFjLEVBQUUsVUFBVSxHQUFHLENBQUMsQ0FBQyxLQUFLLElBQUk7Q0FDcEYsT0FBTyxTQUNILCtDQUErQyxXQUMvQztBQUNOO0FBRUEsU0FBUyxXQUFXLEtBQTRDO0NBQzlELE1BQU0sVUFBVyxJQUFJLGVBQWUsQ0FBQztDQUNyQyxNQUFNLFVBQWdDLElBQUksVUFBVSxLQUFLLFVBQVU7RUFDakUsSUFBSSxNQUFNLFNBQVMsUUFBUSxPQUFPO0dBQUUsTUFBTTtHQUFjLE1BQU0sTUFBTTtFQUFLO0VBQ3pFLElBQUksTUFBTSxTQUFTLFNBQVMsT0FBTztHQUFFLE1BQU07R0FBZSxXQUFXLE1BQU07RUFBSTtFQUMvRSxJQUFJLE1BQU0sU0FBUyxjQUFjLE9BQU87R0FBRSxNQUFNO0dBQWUsV0FBVyxNQUFNO0VBQUs7RUFDckYsT0FBTztHQUFFLE1BQU07R0FBYyxNQUFNLEdBQUcsTUFBTSxLQUFLLElBQUksTUFBTTtFQUFPO0NBQ3BFLENBQUM7Q0FDRCxPQUFPLENBQUMsR0FBRyxTQUFTO0VBQUUsTUFBTTtFQUFXLE1BQU07RUFBUTtDQUFRLENBQUM7QUFDaEU7QUFFQSxTQUFTLFlBQVksS0FBdUU7Q0FDMUYsTUFBTSxVQUNKLElBQUksb0JBQW9CLElBQUkscUJBQXFCLFNBQVMsSUFBSSxtQkFBbUI7Q0FDbkYsSUFBSSxDQUFDLElBQUksVUFBVSxDQUFDLFNBQVMsT0FBTztDQUNwQyxPQUFPO0VBQ0wsR0FBSSxJQUFJLFNBQ0osRUFBRSxRQUFRLElBQUksT0FBcUUsSUFDbkYsQ0FBQztFQUNMLEdBQUksVUFDQSxFQUNXLFFBQ1gsSUFDQSxDQUFDO0NBQ1A7QUFDRjtBQUVBLFNBQVMsZUFBZSxLQUE4QztDQUNwRSxPQUFPO0VBQ0wsT0FBTyxJQUFJLFNBQVM7RUFDcEIsR0FBSSxJQUFJLGVBQWUsRUFBRSxjQUFjLElBQUksYUFBYSxJQUFJLENBQUM7RUFDN0QsU0FBUyxXQUFXLEdBQUc7RUFDdkIsR0FBSSxZQUFZLEdBQUcsSUFBSSxFQUFFLFdBQVcsWUFBWSxHQUFHLEVBQUUsSUFBSSxDQUFDO0VBQzFELEdBQUksSUFBSSxZQUFZLEVBQUUsV0FBVyxJQUFJLFVBQWlELElBQUksQ0FBQztFQUMzRixHQUFJLElBQUksY0FDSixFQUFFLGFBQWEsSUFBSSxnQkFBZ0IsU0FBUyxhQUFhLElBQUksWUFBWSxJQUN6RSxDQUFDO0VBQ0wsR0FBSSxJQUFJLGlCQUFpQixFQUFFLGdCQUFnQixJQUFJLGVBQWUsSUFBSSxDQUFDO0VBQ25FLEdBQUksSUFBSSxlQUFlLEVBQUUsY0FBYyxFQUFFLFFBQVEsSUFBSSxhQUEwQixFQUFFLElBQUksQ0FBQztFQUN0RixHQUFJLElBQUksa0JBQ0osRUFBRSxpQkFBaUIsSUFBSSx5QkFBeUIsRUFBRSxHQUFHLElBQUksdUJBQXVCLElBQUksS0FBSyxJQUN6RixDQUFDO0NBQ1A7QUFDRjs7Ozs7Ozs7O0FBVUEsSUFBYSxtQkFBYixNQUFhLGlCQUErQztDQUMxRCxnQ0FBeUIsSUFBSSxJQUEyQjtDQUN4RDtDQUNBLGtDQUEyQixJQUFJLElBQStEO0NBQzlGLG9DQUFxQyxJQUFJLElBR3ZDO0NBQ0YsMEJBQTJCLElBQUksSUFBeUI7Q0FDeEQsaUNBQWtDLElBQUksSUFBaUI7Q0FDdkQsT0FBZ0Isd0JBQXdCO0NBRXhDLFdBQTRCLElBQUkseUJBQXlCO0NBQ3pEO0NBQ0E7Q0FDQSwrQkFBZ0MsSUFBSSxJQUFZO0NBQ2hELGdCQUF3QjtDQUV4QixZQUNFLGdCQUFxQywyQkFBMkIsR0FDaEUsZUFBNkMsQ0FBQyxHQUM5QztFQUNBLEtBQUssZ0JBQWdCO0VBQ3JCLEtBQUssZ0JBQ0gsYUFBYSxtQkFBbUIsWUFBWSxJQUFJLG1CQUFtQixPQUFPO0VBQzVFLEtBQUssWUFBWSxhQUFhLFNBQVM7Q0FDekM7Q0FFQSxNQUFNLFFBQXVCO0VBQzNCLE1BQU0sRUFBRSxTQUFTLE1BQU0sV0FBVyxTQUFTLEdBQUc7RUFDOUMsS0FBSyxNQUFNLE9BQU8sTUFBTTtHQUN0QixJQUFJLElBQUksYUFBYSxVQUFVO0dBQy9CLEtBQUssU0FDSCxJQUFJLElBQ0osSUFBSSxNQUNKLElBQUksYUFDSixJQUFJLGlCQUNKLElBQUksUUFDSixJQUFJLE1BQ047RUFDRjtFQUNBLE9BQU8sS0FBSyxzQ0FBc0MsS0FBSyxjQUFjLEtBQUssUUFBUTtDQUNwRjtDQUVBLE1BQU0sT0FBc0I7RUFDMUIsS0FBSyxNQUFNLEVBQUUsWUFBWSxLQUFLLFFBQVEsT0FBTyxHQUFHLE9BQU8sUUFBUTtFQUMvRCxLQUFLLFFBQVEsTUFBTTtFQUNuQixLQUFLLE1BQU0sU0FBUyxLQUFLLGdCQUFnQixNQUFNLE9BQU8sUUFBUTtFQUM5RCxLQUFLLGVBQWUsTUFBTTtFQUMxQixLQUFLLGNBQWMsTUFBTTtFQUN6QixLQUFLLGdCQUFnQixNQUFNO0VBQzNCLEtBQUssYUFBYSxNQUFNO0VBQ3hCLEtBQUssU0FBUyxZQUFZO0NBQzVCO0NBRUEsTUFBTSxhQUNKLElBQ0EsTUFDQSxhQUNBLGdCQUNBLFNBQVMsR0FDTTtFQUNmLEtBQUssU0FBUyxJQUFJLE1BQU0sYUFBYSxnQkFBZ0IsUUFBUSxJQUFJO0NBQ25FO0NBRUEsTUFBTSxlQUNKLElBQ0EsTUFDQSxhQUNBLGdCQUNBLFNBQVMsR0FDTTtFQUNmLE1BQU0sTUFBTSxLQUFLLGNBQWMsSUFBSSxFQUFFO0VBQ3JDLEtBQUssU0FBUyxJQUFJLE1BQU0sYUFBYSxnQkFBZ0IsUUFBUSxLQUFLLFVBQVUsSUFBSTtDQUNsRjtDQUVBLE1BQU0sZUFBZSxJQUEyQjtFQUM5QyxLQUFLLGFBQWEsRUFBRTtFQUNwQixLQUFLLGNBQWMsT0FBTyxFQUFFO0VBQzVCLEtBQUssU0FBUyxZQUFZLEVBQUU7RUFDNUIsS0FBSywwQkFBMEIsRUFBRTtFQUNqQyxLQUFLLGFBQWEsT0FBTyxFQUFFO0NBQzdCO0NBRUEsbUJBQW1CLElBQWtCO0VBQ25DLE1BQU0sUUFBUSxLQUFLLGNBQWMsSUFBSSxFQUFFO0VBQ3ZDLElBQUksT0FBTyxNQUFNLFNBQVM7RUFDMUIsS0FBSyxTQUFTLFlBQVk7Q0FDNUI7Q0FFQSxpQkFBaUIsSUFBa0I7RUFDakMsTUFBTSxRQUFRLEtBQUssY0FBYyxJQUFJLEVBQUU7RUFDdkMsSUFBSSxPQUFPLE1BQU0sU0FBUztFQUMxQixLQUFLLFNBQVMsWUFBWTtDQUM1QjtDQUVBLE1BQU0sY0FDSixNQU9lO0VBQ2YsTUFBTSxNQUFNLElBQUksSUFBSSxLQUFLLEtBQUssTUFBTSxFQUFFLEVBQUUsQ0FBQztFQUN6QyxLQUFLLE1BQU0sTUFBTSxLQUFLLGNBQWMsS0FBSyxHQUFHLElBQUksQ0FBQyxJQUFJLElBQUksRUFBRSxHQUFHLE1BQU0sS0FBSyxlQUFlLEVBQUU7RUFDMUYsS0FBSyxNQUFNLE9BQU8sTUFDaEIsTUFBTSxLQUFLLGVBQWUsSUFBSSxJQUFJLElBQUksTUFBTSxJQUFJLGFBQWEsSUFBSSxnQkFBZ0IsSUFBSSxNQUFNO0NBQy9GO0NBRUEsTUFBTSxTQUFTLEtBQStDO0VBQzVELE9BQU8sS0FBSyxJQUFJLEdBQUc7Q0FDckI7Q0FFQSxNQUFNLGVBQWUsS0FBc0IsSUFBNEM7RUFDckYsSUFBSSxJQUFJLGlCQUNOLE1BQU0sSUFBSSxxQkFDUixRQUNBLHlEQUNGO0VBQ0YsSUFBSTtHQUNGLEdBQUcsV0FBVyxNQUFNLEtBQUssSUFBSSxLQUFLLEdBQUcsT0FBTyxDQUFDO0VBQy9DLFNBQVMsT0FBTztHQUNkLEdBQUcsUUFBUSxLQUFjO0dBQ3pCLE1BQU07RUFDUjtDQUNGO0NBR0EsTUFBYyxJQUNaLEtBQ0EsU0FDeUI7RUFDekIsTUFBTSxTQUFTLGFBQWEsSUFBSSxhQUFhLElBQUksU0FBUztFQUMxRCxJQUFJLE9BQU8sU0FBUyxNQUFNLFdBQVcsTUFBTTtFQUMzQyxNQUFNLFlBQVksTUFBTSxLQUFLLFlBQzNCLElBQUksa0JBQ0osSUFBSSx5QkFBeUIsT0FDN0IsTUFDRjtFQUNBLEtBQUs7RUFDTCxJQUFJO0dBQ0YsSUFBSSxPQUFPLFNBQVMsTUFBTSxXQUFXLE1BQU07R0FDM0MsT0FBTyxNQUFNLEtBQUssVUFBVSxXQUFXO0lBQUUsR0FBRztJQUFLLGFBQWE7R0FBTyxHQUFHLE9BQU87RUFDakYsVUFBVTtHQUNSLEtBQUs7RUFDUDtDQUNGO0NBRUEsTUFBYyxVQUNaLFdBQ0EsS0FDQSxTQUN5QjtFQUN6QixNQUFNLFlBQVksS0FBSyxJQUFJO0VBQzNCLElBQUk7RUFDSixJQUFJLE9BQU87RUFDWCxJQUFJLFFBQVE7R0FDVixhQUFhO0dBQ2IsYUFBYTtHQUNiLGNBQWM7R0FDZCxtQkFBbUI7R0FDbkIsdUJBQXVCO0VBQ3pCO0VBQ0EsTUFBTSxTQUEyQixDQUFDO0VBQ2xDLElBQUksaUJBQWlCO0VBQ3JCLElBQUksZUFBZSxJQUFJLFNBQVM7RUFDaEMsTUFBTSxXQUFXLFVBQVU7RUFDM0IsTUFBTSxjQUFjLEtBQUssY0FBYyxTQUFTO0VBQ2hELElBQUk7R0FDRixXQUFXLE1BQU0sU0FBUyxZQUFZLE9BQU8sVUFDM0MsZUFBZSxHQUFHLEdBQ2xCLElBQUksV0FDTixHQUNFLElBQUksTUFBTSxTQUFTLGNBQWM7SUFDL0IsaUJBQWlCLEtBQUssSUFBSTtJQUMxQixRQUFRLE1BQU07SUFDZCxVQUFVLE1BQU0sSUFBSTtHQUN0QixPQUFPLElBQUksTUFBTSxTQUFTLFNBQVM7SUFDakMsaUJBQWlCO0lBQ2pCLE9BQU8sS0FBSztLQUFFLE1BQU0sTUFBTTtLQUFRLGVBQWUsTUFBTSxpQkFBaUI7SUFBSyxDQUFDO0dBQ2hGLE9BQU8sSUFBSSxNQUFNLFNBQVMsaUJBQWlCLE1BQU0sS0FBSyxTQUFTLHlCQUM3RCxpQkFBaUI7UUFDWixJQUFJLE1BQU0sU0FBUyxlQUFlLE1BQU0sT0FBTztJQUNwRCxlQUFlLE1BQU0sU0FBUztJQUM5QixRQUFRO0tBQ04sYUFBYSxNQUFNLE1BQU07S0FDekIsYUFBYSxNQUFNLE1BQU07S0FDekIsY0FBYyxNQUFNLE1BQU07S0FDMUIsbUJBQW1CLE1BQU0sTUFBTTtLQUMvQix1QkFBdUIsTUFBTSxNQUFNO0lBQ3JDO0dBQ0YsT0FBTyxJQUFJLE1BQU0sU0FBUyxhQUN4QixlQUFlLE1BQU0sU0FBUztRQUN6QixJQUFJLE1BQU0sU0FBUyxTQUFTO0lBQ2pDLElBQUksSUFBSSxpQkFDTixNQUFNLElBQUkscUJBQXFCLGNBQWMsTUFBTSxNQUFNLE9BQU87SUFDbEUsTUFBTSxNQUFNO0dBQ2Q7RUFFSixVQUFVO0dBQ1IsS0FBSyxjQUFjLFdBQVc7RUFDaEM7RUFDQSxJQUFJLElBQUksbUJBQW1CLE9BQU8sV0FBVyxHQUMzQyxNQUFNLElBQUkscUJBQ1IsaUJBQWlCLGVBQWUsY0FDaEMsaUJBQ0ksc0NBQ0EscUNBQ047RUFFRixPQUFPO0dBQ0w7R0FDQSxXQUFXLFNBQVM7R0FDcEI7R0FDQSxZQUFZLEtBQUssSUFBSSxJQUFJO0dBQ3pCLFFBQVEsaUJBQWlCLFNBQVksT0FBTyxlQUFlO0dBQzNELE9BQU87R0FDUCxhQUFhO0lBQUUsVUFBVSxVQUFVO0lBQVMsVUFBVSxJQUFJLGtCQUFrQjtJQUFJLE9BQU87R0FBRztHQUMxRixHQUFJLE9BQU8sU0FBUyxFQUFFLE9BQU8sSUFBSSxDQUFDO0VBQ3BDO0NBQ0Y7O0NBR0EsY0FBc0IsV0FBd0M7RUFDNUQsTUFBTSxXQUFXLFVBQVU7RUFDM0IsSUFBSSxRQUFRLEtBQUssUUFBUSxJQUFJLFVBQVUsT0FBTztFQUM5QyxJQUFJLFNBQVMsTUFBTSxlQUFlLFNBQVMsWUFBWTtHQUNyRCxLQUFLLGFBQWEsVUFBVSxPQUFPO0dBQ25DLFFBQVE7RUFDVjtFQUNBLElBQUksQ0FBQyxPQUFPO0dBQ1YsTUFBTSxTQUFTLEtBQUssY0FDbEI7SUFDRSxhQUFhO0tBQ1gsYUFBYSxTQUFTLFlBQVk7S0FDbEMsV0FBVyxTQUFTLFlBQVk7SUFDbEM7SUFDQSxlQUFlLEtBQUs7SUFDcEIsT0FBTyxLQUFLO0lBQ1osb0JBQW9CLFlBQVk7S0FDOUIsTUFBTSxZQUFZLE1BQU0sK0JBQStCLFVBQVUsT0FBTztLQUN4RSxNQUFNLFVBQVUsS0FBSyxjQUFjLElBQUksVUFBVSxPQUFPO0tBQ3hELElBQUksU0FDRixRQUFRLGNBQWM7TUFDcEIsR0FBRyxRQUFRO01BQ1gsYUFBYSxVQUFVO01BQ3ZCLFdBQVcsVUFBVTtLQUN2QjtLQUNGLE9BQU87TUFBRSxhQUFhLFVBQVU7TUFBYSxXQUFXLFVBQVU7S0FBaUI7SUFDckY7R0FDRixHQUNBLFVBQVUsT0FDWjtHQUNBLFFBQVE7SUFBRSxZQUFZLFNBQVM7SUFBWTtJQUFRLFVBQVU7SUFBRyxTQUFTO0dBQU07R0FDL0UsS0FBSyxRQUFRLElBQUksVUFBVSxTQUFTLEtBQUs7RUFDM0M7RUFDQSxNQUFNO0VBQ04sT0FBTztDQUNUO0NBRUEsY0FBc0IsT0FBMEI7RUFDOUMsTUFBTSxXQUFXLEtBQUssSUFBSSxHQUFHLE1BQU0sV0FBVyxDQUFDO0VBQy9DLElBQUksTUFBTSxXQUFXLE1BQU0sYUFBYSxHQUFHO0dBQ3pDLEtBQUssZUFBZSxPQUFPLEtBQUs7R0FDaEMsTUFBTSxPQUFPLFFBQVE7RUFDdkI7Q0FDRjs7Q0FHQSxhQUFxQixTQUF1QjtFQUMxQyxNQUFNLFFBQVEsS0FBSyxRQUFRLElBQUksT0FBTztFQUN0QyxJQUFJLENBQUMsT0FBTztFQUNaLEtBQUssUUFBUSxPQUFPLE9BQU87RUFDM0IsTUFBTSxVQUFVO0VBQ2hCLElBQUksTUFBTSxhQUFhLEdBQUcsTUFBTSxPQUFPLFFBQVE7T0FDMUMsS0FBSyxlQUFlLElBQUksS0FBSztDQUNwQzs7Ozs7OztDQVFBLE1BQWMsWUFDWixrQkFDQSx1QkFDQSxRQUN5QjtFQUN6QixJQUFJLHFCQUFxQixRQUFXO0dBQ2xDLE1BQU0sWUFBWSxLQUFLLGNBQWMsSUFBSSxnQkFBZ0I7R0FDekQsSUFBSSxXQUFXLFVBQVcsTUFBTSxLQUFLLGdCQUFnQixrQkFBa0IsV0FBVyxNQUFNLEdBQ3RGLE9BQU87SUFBRSxTQUFTO0lBQWtCLFVBQVU7R0FBVTtHQUUxRCxJQUFJLHVCQUF1QjtJQUN6QixJQUFJLENBQUMsV0FBVyxRQUNkLE1BQU0sSUFBSSxNQUFNLDBCQUEwQixpQkFBaUIsa0JBQWtCO0lBRS9FLE1BQU0sWUFBWSxVQUFVO0lBQzVCLElBQUksY0FBYyxRQUFRLGNBQWMsUUFDdEMsTUFBTSxJQUFJLDRCQUNSLGFBQWEsQ0FBQztLQUFFLE1BQU0sVUFBVTtLQUFNO0lBQVUsQ0FBQyxDQUFDLENBQ3BEO0dBRUo7RUFDRjtFQUlBLE1BQU0sU0FBUyxNQUFNLFFBQVEsSUFDM0IsQ0FBQyxHQUFHLEtBQUssY0FBYyxRQUFRLENBQUMsQ0FBQyxDQUM5QixRQUFRLEdBQUcsV0FBVyxNQUFNLE1BQU0sQ0FBQyxDQUNuQyxJQUFJLE9BQU8sQ0FBQyxJQUFJLFlBQVk7R0FDM0I7R0FDQTtHQUNBLFVBQVUsTUFBTSxLQUFLLGdCQUFnQixJQUFJLE9BQU8sTUFBTTtFQUN4RCxFQUFFLENBQ047RUFDQSxNQUFNLFdBQVcsSUFBSSxJQUFJLE9BQU8sUUFBUSxNQUFNLEVBQUUsUUFBUSxDQUFDLENBQUMsS0FBSyxNQUFNLEVBQUUsRUFBRSxDQUFDO0VBQzFFLElBQUksU0FBUyxTQUFTLEdBQUc7R0FDdkIsTUFBTSxPQUFPLE9BQ1YsUUFDRSxNQUNDLENBQUMsRUFBRSxZQUFZLEVBQUUsTUFBTSxtQkFBbUIsUUFBUSxFQUFFLE1BQU0sbUJBQW1CLE1BQ2pGLENBQUMsQ0FDQSxLQUFLLE9BQU87SUFBRSxNQUFNLEVBQUUsTUFBTTtJQUFNLFdBQVcsRUFBRSxNQUFNO0dBQXlCLEVBQUU7R0FDbkYsSUFBSSxLQUFLLFFBQVE7SUFDZixPQUFPLEtBQUssc0NBQXNDO0tBQ2hELFVBQVU7S0FDVixxQkFBcUI7SUFDdkIsQ0FBQztJQUNELE1BQU0sSUFBSSw0QkFBNEIsYUFBYSxJQUFJLENBQUM7R0FDMUQ7R0FDQSxNQUFNLElBQUksTUFBTSxtQkFBbUI7RUFDckM7RUFDQSxNQUFNLFdBQVcsS0FBSyxTQUFTLE9BQU8sUUFBUTtFQUM5QyxNQUFNLFdBQVcsYUFBYSxPQUFPLEtBQUssY0FBYyxJQUFJLFFBQVEsSUFBSTtFQUN4RSxJQUFJLGFBQWEsUUFBUSxDQUFDLFVBQVUsTUFBTSxJQUFJLE1BQU0sbUJBQW1CO0VBQ3ZFLE9BQU87R0FBRSxTQUFTO0dBQVU7RUFBUztDQUN2QztDQUVBLFNBQ0UsSUFDQSxNQUNBLGFBQ0EsZ0JBQ0EsUUFDQSxRQUNNO0VBQ04sTUFBTSxNQUFNLEtBQUssY0FBYyxJQUFJLEVBQUU7RUFDckMsSUFBSSxLQUNGLE9BQU8sT0FBTyxLQUFLO0dBQ2pCO0dBQ0E7R0FDQTtHQUNBO0dBQ0E7R0FDQSxZQUFZLElBQUksYUFBYTtFQUMvQixDQUFDO09BRUQsS0FBSyxjQUFjLElBQUksSUFBSTtHQUN6QjtHQUNBO0dBQ0E7R0FDQTtHQUNBO0dBQ0EsWUFBWTtFQUNkLENBQUM7RUFFSCxLQUFLLFNBQVMsU0FBUyxJQUFJLE1BQU07RUFDakMsS0FBSywwQkFBMEIsRUFBRTtFQUNqQyxLQUFLLGFBQWEsT0FBTyxFQUFFO0NBQzdCO0NBRUEsTUFBTSx1QkFDSixTQUNBLFFBQ21DO0VBQ25DLE1BQU0sUUFBUSxLQUFLLGNBQWMsSUFBSSxPQUFPO0VBQzVDLElBQUksQ0FBQyxPQUFPLE1BQU0sSUFBSSxNQUFNLGdCQUFnQixRQUFRLFdBQVc7RUFDL0QsTUFBTSxTQUFTLEtBQUssZ0JBQWdCLElBQUksT0FBTztFQUMvQyxJQUNFLFVBQ0EsT0FBTyxlQUFlLE1BQU0sY0FDNUIsS0FBSyxJQUFJLElBQUksT0FBTyxXQUFXLGlCQUFpQix1QkFFaEQsT0FBTztFQUtULE1BQU0sVUFBVSxLQUFLLGtCQUFrQixJQUFJLE9BQU87RUFDbEQsSUFBSSxTQUFTLE9BQU87RUFDcEIsTUFBTSxnQkFBZ0IsWUFBWTtHQUNoQyxNQUFNLFNBQVMsTUFBTSxxQkFBcUI7SUFDeEMsYUFBYSxNQUFNO0lBQ25CLE9BQU8sS0FBSztJQUNaLEdBQUksU0FBUyxFQUFFLE9BQU8sSUFBSSxDQUFDO0dBQzdCLENBQUM7R0FDRCxJQUFJLE9BQU8sU0FBUyxpQkFBaUIsTUFBTSxJQUFJLE1BQU0sT0FBTyxNQUFNO0dBQ2xFLElBQUksQ0FBQyxPQUFPLEtBQUssTUFBTSxJQUFJLE1BQU0sK0NBQStDO0dBQ2hGLE1BQU0sUUFBUTtJQUFFLE1BQU0sT0FBTztJQUFLLFVBQVUsS0FBSyxJQUFJO0lBQUcsWUFBWSxNQUFNO0dBQVc7R0FDckYsSUFBSSxLQUFLLGNBQWMsSUFBSSxPQUFPLE1BQU0sT0FBTyxLQUFLLGdCQUFnQixJQUFJLFNBQVMsS0FBSztHQUN0RixPQUFPO0VBQ1QsRUFBQSxDQUFHLENBQUMsQ0FBQyxjQUFjLEtBQUssa0JBQWtCLE9BQU8sT0FBTyxDQUFDO0VBQ3pELEtBQUssa0JBQWtCLElBQUksU0FBUyxZQUFZO0VBQ2hELE9BQU87Q0FDVDtDQUVBLE1BQWMsZ0JBQ1osSUFDQSxPQUNBLFFBQ2tCO0VBQ2xCLElBQUksTUFBTSxtQkFBbUIsUUFBUSxNQUFNLG1CQUFtQixRQUFXLE9BQU87RUFDaEYsTUFBTSxhQUFhLE1BQU07RUFDekIsTUFBTSxTQUFTLE1BQU0scUJBQXFCLFlBQVksS0FBSyx1QkFBdUIsSUFBSSxNQUFNLENBQUM7RUFDN0YsSUFBSSxLQUFLLGNBQWMsSUFBSSxFQUFFLE1BQU0sU0FBUyxNQUFNLGVBQWUsWUFBWSxPQUFPO0VBQ3BGLElBQUksT0FBTyxTQUFTLGlCQUFpQjtHQUNuQyxLQUFLLGFBQWEsT0FBTyxFQUFFO0dBQzNCLE9BQU8sS0FBSywwQ0FBMEM7SUFDcEQsU0FBUztJQUNULFdBQVcsTUFBTTtJQUNqQixjQUFjLE9BQU87R0FDdkIsQ0FBQztHQUNELE9BQU87RUFDVDtFQUNBLElBQUksT0FBTyxrQkFBa0IsTUFBTSxnQkFBZ0I7R0FDakQsSUFBSSxDQUFDLEtBQUssYUFBYSxJQUFJLEVBQUUsR0FDM0IsT0FBTyxLQUNMLHdDQUF3QyxNQUFNLEtBQUssR0FBRyxHQUFHLEtBQUssT0FBTyxlQUFlLE9BQU8sTUFBTSxlQUFlLEdBQ2xIO0dBQ0YsS0FBSyxhQUFhLElBQUksRUFBRTtHQUN4QixPQUFPO0VBQ1Q7RUFDQSxJQUFJLEtBQUssYUFBYSxPQUFPLEVBQUUsR0FDN0IsT0FBTyxLQUNMLG1DQUFtQyxNQUFNLEtBQUssR0FBRyxHQUFHLEtBQUssT0FBTyxlQUFlLE1BQU0sTUFBTSxlQUFlLEdBQzVHO0VBQ0YsT0FBTztDQUNUO0NBRUEsMEJBQWtDLElBQWtCO0VBQ2xELEtBQUssZ0JBQWdCLE9BQU8sRUFBRTtDQUNoQztDQUVBLElBQUksYUFBcUI7RUFDdkIsT0FBTyxDQUFDLEdBQUcsS0FBSyxjQUFjLE9BQU8sQ0FBQyxDQUFDLENBQUMsUUFBUSxNQUFNLEVBQUUsTUFBTSxDQUFDLENBQUM7Q0FDbEU7Q0FDQSxJQUFJLFdBQW1CO0VBQ3JCLE9BQU8sS0FBSztDQUNkOzs7Ozs7Q0FPQSxJQUFJLGVBTUQ7RUFDRCxNQUFNLE1BQU0sS0FBSyxJQUFJO0VBQ3JCLE9BQU8sQ0FBQyxHQUFHLEtBQUssY0FBYyxRQUFRLENBQUMsQ0FBQyxDQUNyQyxLQUFLLENBQUMsSUFBSSxPQUFPO0dBQ2hCLE1BQU0sU0FBUyxLQUFLLGdCQUFnQixJQUFJLEVBQUU7R0FLMUMsTUFBTSxVQUhKLFdBQVcsVUFDWCxPQUFPLGVBQWUsRUFBRSxjQUN4QixNQUFNLE9BQU8sV0FBVyxpQkFBaUIsd0JBQ25CLE9BQU8sS0FBSyxZQUFZLFVBQVU7R0FDMUQsT0FBTztJQUNMLE1BQU0sRUFBRTtJQUNSLGFBQWEsU0FBUyxlQUFlO0lBQ3JDLFdBQVcsRUFBRSxrQkFBa0I7SUFDL0IsU0FBUyxLQUFLLGFBQWEsSUFBSSxFQUFFO0lBR2pDLFVBQ0UsU0FBUyxhQUFhLFFBQVEsU0FBUyxhQUFhLFNBQ2hELFFBQVEsV0FBVyxNQUNuQjtHQUNSO0VBQ0YsQ0FBQyxDQUFDLENBQ0QsVUFBVSxHQUFHLE1BQU0sRUFBRSxLQUFLLGNBQWMsRUFBRSxJQUFJLENBQUM7Q0FDcEQ7QUFDRiJ9
@@ -207,6 +207,22 @@ describe("QgridDispatcherClass", () => {
207
207
  expect(req.preferredTokenId).toBe(1);
208
208
  });
209
209
 
210
+ it("OpenAI query 는 이름 해석으로 받은 내부 preferredTokenId 를 우선한다", async () => {
211
+ const dispatcher = new QgridDispatcherClass();
212
+ const generate = vi.fn(async (_req: GenerateRequest) => providerResult({ model: "gpt-5.5" }));
213
+ dispatcher.openaiDispatcher = { generate } as never;
214
+
215
+ await dispatcher.query({
216
+ prompt: "targeted",
217
+ model: "openai/gpt-5.5",
218
+ preferredTokenId: 7,
219
+ requirePreferredToken: true,
220
+ });
221
+
222
+ expect(generate.mock.calls[0]![0].preferredTokenId).toBe(7);
223
+ expect(generate.mock.calls[0]![0].requirePreferredToken).toBe(true);
224
+ });
225
+
210
226
  it("OpenAI response issues a four-field epoch=-1 affinity coord", async () => {
211
227
  const dispatcher = new QgridDispatcherClass();
212
228
  dispatcher.openaiDispatcher = {
@@ -257,6 +273,22 @@ describe("QgridDispatcherClass", () => {
257
273
  expect(req.coldInput).toEqual([{ type: "text", text: "next", text_elements: [] }]);
258
274
  });
259
275
 
276
+ it("Anthropic query 는 내부 preferredTokenId 를 provider 로 전달한다", async () => {
277
+ const dispatcher = new QgridDispatcherClass();
278
+ const generate = vi.fn(async (_req: GenerateRequest) =>
279
+ providerResult({ model: "claude-sonnet-4-6" }),
280
+ );
281
+ dispatcher.anthropicDispatcher = { generate } as never;
282
+
283
+ await dispatcher.query({
284
+ prompt: "keepalive",
285
+ model: "anthropic/claude-haiku-4-5",
286
+ preferredTokenId: 7,
287
+ });
288
+
289
+ expect(generate.mock.calls[0]![0].preferredTokenId).toBe(7);
290
+ });
291
+
260
292
  it("Anthropic query 에도 imageGeneration 플래그를 전달해 provider 가 명시적으로 거부하게 한다", async () => {
261
293
  const dispatcher = new QgridDispatcherClass();
262
294
  const generate = vi.fn(async (_req: GenerateRequest) =>
@@ -315,6 +347,25 @@ describe("QgridDispatcherClass", () => {
315
347
  );
316
348
  });
317
349
 
350
+ it("Anthropic queryStream 은 내부 preferredTokenId 를 provider 로 전달한다", async () => {
351
+ const dispatcher = new QgridDispatcherClass();
352
+ const generateStream = vi.fn(async (_req, cb) => {
353
+ cb.onComplete(providerResult({ model: "claude-sonnet-4-6" }));
354
+ });
355
+ dispatcher.anthropicDispatcher = { generateStream } as never;
356
+
357
+ await dispatcher.queryStream(
358
+ {
359
+ prompt: "keepalive",
360
+ model: "anthropic/claude-haiku-4-5",
361
+ preferredTokenId: 7,
362
+ },
363
+ { onDelta: vi.fn(), onComplete: vi.fn(), onError: vi.fn() },
364
+ );
365
+
366
+ expect(generateStream.mock.calls[0]![0].preferredTokenId).toBe(7);
367
+ });
368
+
318
369
  it("Anthropic queryStream 에도 imageGeneration 플래그를 전달해 provider 가 명시적으로 거부하게 한다", async () => {
319
370
  const dispatcher = new QgridDispatcherClass();
320
371
  const generateStream = vi.fn(async (_req, _cb) => {});
@@ -40,6 +40,11 @@ import { type TokenSubscriber } from "./token-subscriber";
40
40
  import { applyToolCallEmulation } from "./tool-emulation";
41
41
  import { buildToolCallSchema } from "./tool-emulation-schema";
42
42
 
43
+ export type InternalQueryInput = QueryInput & {
44
+ preferredTokenId?: number;
45
+ requirePreferredToken?: boolean;
46
+ };
47
+
43
48
  export class QgridDispatcherClass {
44
49
  tokens = new Map<number, TokenSubsetA>();
45
50
 
@@ -105,7 +110,7 @@ export class QgridDispatcherClass {
105
110
  }));
106
111
  }
107
112
 
108
- async query(input: QueryInput, abortSignal?: AbortSignal): Promise<QueryOutput> {
113
+ async query(input: InternalQueryInput, abortSignal?: AbortSignal): Promise<QueryOutput> {
109
114
  const route = parseProviderRoute(input.model);
110
115
  const outputSchema = buildAndValidateStrictOutputSchema(input, route.provider);
111
116
  // answer 인코딩 판정: jsonSchema 있으면 사용자 스키마 JSON, 없으면 평문 string. 4개 방출 지점이 공유.
@@ -131,7 +136,9 @@ export class QgridDispatcherClass {
131
136
  coldInput: decision.coldInput,
132
137
  coldHistory: decision.coldHistory,
133
138
  promptCacheKey: input.imageGeneration ? undefined : decision.promptCacheKey,
134
- preferredTokenId: input.imageGeneration ? undefined : decision.preferredTokenId,
139
+ preferredTokenId:
140
+ input.preferredTokenId ?? (input.imageGeneration ? undefined : decision.preferredTokenId),
141
+ requirePreferredToken: input.requirePreferredToken,
135
142
  abortSignal,
136
143
  imageGeneration: input.imageGeneration,
137
144
  imageGenerationOptions: input.imageGenerationOptions,
@@ -164,6 +171,7 @@ export class QgridDispatcherClass {
164
171
  abortSignal,
165
172
  coldInput: decision.coldInput,
166
173
  coldHistory: decision.coldHistory,
174
+ preferredTokenId: input.preferredTokenId,
167
175
  imageGeneration: input.imageGeneration,
168
176
  imageGenerationOptions: input.imageGenerationOptions,
169
177
  });
@@ -178,7 +186,7 @@ export class QgridDispatcherClass {
178
186
  }
179
187
 
180
188
  async queryStream(
181
- input: QueryInput,
189
+ input: InternalQueryInput,
182
190
  cb: StreamCallbacks<QueryOutput>,
183
191
  abortSignal?: AbortSignal,
184
192
  ): Promise<void> {
@@ -207,7 +215,8 @@ export class QgridDispatcherClass {
207
215
  coldInput: decision.coldInput,
208
216
  coldHistory: decision.coldHistory,
209
217
  promptCacheKey: decision.promptCacheKey,
210
- preferredTokenId: decision.preferredTokenId,
218
+ preferredTokenId: input.preferredTokenId ?? decision.preferredTokenId,
219
+ requirePreferredToken: input.requirePreferredToken,
211
220
  abortSignal,
212
221
  // 이미지 플래그를 전달해야 generateStream 의 non-stream 전용 거부(R2)가 발동한다.
213
222
  imageGeneration: input.imageGeneration,
@@ -257,6 +266,7 @@ export class QgridDispatcherClass {
257
266
  effort: input.effort,
258
267
  coldInput: decision.coldInput,
259
268
  coldHistory: decision.coldHistory,
269
+ preferredTokenId: input.preferredTokenId,
260
270
  timeoutMs: input.timeout,
261
271
  abortSignal,
262
272
  imageGeneration: input.imageGeneration,
@@ -9,6 +9,7 @@ import { QueryInput } from "./qgrid.types";
9
9
  const {
10
10
  findOneMock,
11
11
  findManyMock,
12
+ findActiveByProviderAndNameMock,
12
13
  saveMock,
13
14
  updateFieldsMock,
14
15
  requestLogSaveMock,
@@ -30,6 +31,7 @@ const {
30
31
  return {
31
32
  findOneMock: vi.fn(),
32
33
  findManyMock: vi.fn(),
34
+ findActiveByProviderAndNameMock: vi.fn(),
33
35
  saveMock: vi.fn(),
34
36
  updateFieldsMock: vi.fn(),
35
37
  requestLogSaveMock: vi.fn(),
@@ -59,6 +61,7 @@ vi.mock("../token/token.model", () => ({
59
61
  TokenModel: {
60
62
  findOne: findOneMock,
61
63
  findMany: findManyMock,
64
+ findActiveByProviderAndName: findActiveByProviderAndNameMock,
62
65
  save: saveMock,
63
66
  updateFields: updateFieldsMock,
64
67
  },
@@ -125,6 +128,7 @@ describe("QgridFrame.updateToken", () => {
125
128
  appendStepMock.mockReset();
126
129
  appendStepMock.mockResolvedValue(1);
127
130
  dispatcherQueryMock.mockReset();
131
+ findActiveByProviderAndNameMock.mockReset();
128
132
  });
129
133
 
130
134
  it("rejects quota thresholds outside bounds before updating", async () => {
@@ -180,6 +184,7 @@ describe("QgridFrame.query request logging", () => {
180
184
  assertNativeRunAdmissionMock.mockReset();
181
185
  finishRunWithErrorMock.mockReset();
182
186
  dispatcherQueryMock.mockReset();
187
+ findActiveByProviderAndNameMock.mockReset();
183
188
  });
184
189
 
185
190
  function queryOutput() {
@@ -234,6 +239,59 @@ describe("QgridFrame.query request logging", () => {
234
239
  expect(result.runContext).toEqual(queryOutput().runContext);
235
240
  });
236
241
 
242
+ it("tokenName 을 활성 토큰 id 로 해석해 지정 요청으로 전달한다", async () => {
243
+ findActiveByProviderAndNameMock.mockResolvedValueOnce({
244
+ ...tokenEntry,
245
+ id: 17,
246
+ name: "anthropic/tok-A",
247
+ });
248
+ dispatcherQueryMock.mockResolvedValueOnce(queryOutput());
249
+
250
+ await QgridFrame.query({
251
+ prompt: "hi",
252
+ model: "anthropic/claude-sonnet-4-6",
253
+ tokenName: "anthropic/tok-A",
254
+ });
255
+
256
+ expect(findActiveByProviderAndNameMock).toHaveBeenCalledWith(
257
+ "A",
258
+ "anthropic",
259
+ "anthropic/tok-A",
260
+ );
261
+ expect(dispatcherQueryMock).toHaveBeenCalledWith(
262
+ expect.objectContaining({ preferredTokenId: 17, requirePreferredToken: true }),
263
+ expect.any(AbortSignal),
264
+ );
265
+ });
266
+
267
+ it("tokenName 에 해당하는 활성 토큰이 없으면 대체 없이 실패한다", async () => {
268
+ findActiveByProviderAndNameMock.mockResolvedValueOnce(undefined);
269
+
270
+ await expect(
271
+ QgridFrame.query({
272
+ prompt: "hi",
273
+ model: "anthropic/claude-sonnet-4-6",
274
+ tokenName: "anthropic/missing",
275
+ }),
276
+ ).rejects.toThrow("Active token not found: anthropic/missing");
277
+
278
+ expect(dispatcherQueryMock).not.toHaveBeenCalled();
279
+ expect(beforeQueryMock).not.toHaveBeenCalled();
280
+ });
281
+
282
+ it("tokenName provider 와 model provider 가 다르면 조회 전에 실패한다", async () => {
283
+ await expect(
284
+ QgridFrame.query({
285
+ prompt: "hi",
286
+ model: "anthropic/claude-sonnet-4-6",
287
+ tokenName: "openai/tok-A",
288
+ }),
289
+ ).rejects.toThrow("Token provider does not match model provider");
290
+
291
+ expect(findActiveByProviderAndNameMock).not.toHaveBeenCalled();
292
+ expect(dispatcherQueryMock).not.toHaveBeenCalled();
293
+ });
294
+
237
295
  it("persists an immediate tools+schema structured answer as final JSON text", async () => {
238
296
  const output = {
239
297
  ...queryOutput(),
@@ -39,7 +39,11 @@ import {
39
39
  finishRunAborted,
40
40
  finishRunWithError,
41
41
  } from "./qgrid-run-lifecycle";
42
- import { buildAndValidateStrictOutputSchema, QgridDispatcher } from "./qgrid.dispatcher";
42
+ import {
43
+ buildAndValidateStrictOutputSchema,
44
+ type InternalQueryInput,
45
+ QgridDispatcher,
46
+ } from "./qgrid.dispatcher";
43
47
  import {
44
48
  type QueryInput,
45
49
  type AppendStepInput,
@@ -147,6 +151,27 @@ function rejectInvalidCallerSchemas(args: QueryInput): void {
147
151
  }
148
152
  }
149
153
 
154
+ async function resolveTokenName(args: QueryInput): Promise<InternalQueryInput> {
155
+ if (!args.tokenName) return args;
156
+
157
+ const tokenProvider = args.tokenName.split("/", 1)[0];
158
+ const modelProvider = args.model?.split("/", 1)[0];
159
+ if (tokenProvider !== "anthropic" && tokenProvider !== "openai") {
160
+ throw new BadRequestException(`Invalid token name: ${args.tokenName}` as LocalizedString);
161
+ }
162
+ if (modelProvider !== tokenProvider) {
163
+ throw new BadRequestException(
164
+ "Token provider does not match model provider" as LocalizedString,
165
+ );
166
+ }
167
+
168
+ const token = await TokenModel.findActiveByProviderAndName("A", tokenProvider, args.tokenName);
169
+ if (!token) {
170
+ throw new BadRequestException(`Active token not found: ${args.tokenName}` as LocalizedString);
171
+ }
172
+ return { ...args, preferredTokenId: token.id, requirePreferredToken: true };
173
+ }
174
+
150
175
  function createHttpDisconnectHandle(): {
151
176
  signal: AbortSignal;
152
177
  dispose: () => void;
@@ -199,29 +224,30 @@ class QgridFrameClass extends BaseFrameClass {
199
224
  async query(args: QueryInput): Promise<QueryOutput> {
200
225
  assertNativeRunAdmission();
201
226
  rejectInvalidCallerSchemas(args);
227
+ const resolvedArgs = await resolveTokenName(args);
202
228
  const disconnect = createHttpDisconnectHandle();
203
229
  try {
204
- if (args.logger === false) {
205
- return await QgridDispatcher.query(args, disconnect.signal);
230
+ if (resolvedArgs.logger === false) {
231
+ return await QgridDispatcher.query(resolvedArgs, disconnect.signal);
206
232
  }
207
233
 
208
- const { requestLogId, stepIndex } = await beforeQuery(args);
234
+ const { requestLogId, stepIndex } = await beforeQuery(resolvedArgs);
209
235
  let result: QueryOutput;
210
236
  try {
211
- result = await QgridDispatcher.query(args, disconnect.signal);
237
+ result = await QgridDispatcher.query(resolvedArgs, disconnect.signal);
212
238
  } catch (e) {
213
239
  if (disconnect.signal.aborted) {
214
- await finishRunAborted(requestLogId, args);
240
+ await finishRunAborted(requestLogId, resolvedArgs);
215
241
  } else {
216
- await finishRunWithError(requestLogId, (e as Error).message, args);
242
+ await finishRunWithError(requestLogId, (e as Error).message, resolvedArgs);
217
243
  }
218
244
  throw e;
219
245
  }
220
246
 
221
247
  try {
222
- const lifecycle = await afterQuery(requestLogId, stepIndex, args, result);
248
+ const lifecycle = await afterQuery(requestLogId, stepIndex, resolvedArgs, result);
223
249
  if (disconnect.signal.aborted) {
224
- await finishRunAborted(requestLogId, args);
250
+ await finishRunAborted(requestLogId, resolvedArgs);
225
251
  }
226
252
  // tool-call requestLogId와 provider threadCoord는 서로 독립적으로 유지한다.
227
253
  const threadCoord = result.runContext?.threadCoord;
@@ -233,9 +259,9 @@ class QgridFrameClass extends BaseFrameClass {
233
259
  } catch (e) {
234
260
  logger.error(`query afterQuery failed: ${(e as Error).message}`);
235
261
  if (disconnect.signal.aborted) {
236
- await finishRunAborted(requestLogId, args);
262
+ await finishRunAborted(requestLogId, resolvedArgs);
237
263
  } else {
238
- await finishRunWithError(requestLogId, (e as Error).message, args);
264
+ await finishRunWithError(requestLogId, (e as Error).message, resolvedArgs);
239
265
  }
240
266
  // provider 응답은 성공했으므로 로깅 장애가 생성 결과를 덮어쓰지 않는다.
241
267
  return result;
@@ -250,8 +276,9 @@ class QgridFrameClass extends BaseFrameClass {
250
276
  assertNativeRunAdmission();
251
277
  rejectImageGenerationStream(args);
252
278
  rejectInvalidCallerSchemas(args);
279
+ const resolvedArgs = await resolveTokenName(args);
253
280
  const streamId = crypto.randomUUID();
254
- pendingStreams.set(streamId, args);
281
+ pendingStreams.set(streamId, resolvedArgs);
255
282
  const expiry = setTimeout(() => pendingStreams.delete(streamId), 30_000);
256
283
  expiry.unref?.();
257
284
  return { streamId };
@@ -114,6 +114,8 @@ export const QueryInput = z.looseObject({
114
114
  serviceTier: ServiceTier.optional(),
115
115
  history: z.string().optional(),
116
116
  projectName: z.string().optional(),
117
+ // 내부·대시보드 호출용 지정 주소. 공개 AI SDK provider options 에는 노출하지 않는다.
118
+ tokenName: z.string().optional(),
117
119
  // SDK-derived opaque affinity. It is intentionally distinct from the caller's sessionKey.
118
120
  cacheAffinityKey: z
119
121
  .string()