@cartanova/qgrid-cli 2.10.6 → 2.10.8

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 (63) hide show
  1. package/bundle/dist/application/qgrid/qgrid-run-lifecycle.js +3 -1
  2. package/bundle/dist/application/qgrid/qgrid.dispatcher.js +7 -7
  3. package/bundle/dist/application/qgrid/qgrid.frame.js +2 -2
  4. package/bundle/dist/application/request-log/request-log.model.js +3 -1
  5. package/bundle/dist/application/sonamu.generated.js +4 -1
  6. package/bundle/dist/application/sonamu.generated.sso.js +3 -1
  7. package/bundle/dist/i18n/sd.generated.js +2 -1
  8. package/bundle/dist/migrations/20261016155350_alter_request_logs_add1_alter1.js +15 -0
  9. package/bundle/dist/utils/providers/common/model-cost.js +14 -3
  10. package/bundle/dist/utils/providers/openai/openai-direct-client.js +1 -2
  11. package/bundle/src/application/qgrid/qgrid-run-lifecycle.test.ts +18 -0
  12. package/bundle/src/application/qgrid/qgrid-run-lifecycle.ts +2 -0
  13. package/bundle/src/application/qgrid/qgrid.dispatcher.test.ts +24 -0
  14. package/bundle/src/application/qgrid/qgrid.dispatcher.ts +31 -19
  15. package/bundle/src/application/qgrid/qgrid.frame.test.ts +2 -1
  16. package/bundle/src/application/qgrid/qgrid.frame.ts +1 -1
  17. package/bundle/src/application/request-log/request-log.entity.json +9 -0
  18. package/bundle/src/application/request-log/request-log.model.ts +4 -0
  19. package/bundle/src/application/sonamu.generated.sso.ts +2 -0
  20. package/bundle/src/application/sonamu.generated.ts +4 -0
  21. package/bundle/src/i18n/sd.generated.ts +1 -0
  22. package/bundle/src/migrations/20261016155350_alter_request_logs_add1_alter1.ts +15 -0
  23. package/bundle/src/utils/providers/common/model-cost.test.ts +28 -0
  24. package/bundle/src/utils/providers/common/model-cost.ts +19 -2
  25. package/bundle/src/utils/providers/openai/openai-direct-client.test.ts +47 -6
  26. package/bundle/src/utils/providers/openai/openai-direct-client.ts +2 -1
  27. package/bundle/web-dist/client/assets/index-Bw2s88Ot.css +1 -0
  28. package/bundle/web-dist/client/assets/{index-D9ryIyL-.js → index-DmCLKefs.js} +4 -4
  29. package/bundle/web-dist/client/assets/logs-BedgCqdB.js +1 -0
  30. package/bundle/web-dist/client/assets/{monit-DojxOLj6.js → monit-76gLIcaG.js} +1 -1
  31. package/bundle/web-dist/client/assets/request-model-CojtinqK.js +1 -0
  32. package/bundle/web-dist/client/assets/{routes-DXJhNvbI.js → routes-BcU0zD8h.js} +1 -1
  33. package/bundle/web-dist/client/assets/{services.generated-DqFYgWsY.js → services.generated-BsieU37H.js} +1 -1
  34. package/bundle/web-dist/client/assets/{settings-bopyz9pa.js → settings-DNVHSTQH.js} +1 -1
  35. package/bundle/web-dist/client/assets/show-dZPDC-qz.js +2 -0
  36. package/bundle/web-dist/client/assets/{tokens-2-AIi9sZ.js → tokens-BaQQcYUT.js} +1 -1
  37. package/bundle/web-dist/client/assets/{use-oauth-login-flow-CnqTWs_H.js → use-oauth-login-flow-D1jlq9ha.js} +1 -1
  38. package/bundle/web-dist/client/assets/{use-update-token-mutation-Cxb9K0fM.js → use-update-token-mutation-DAq0F8p-.js} +1 -1
  39. package/bundle/web-dist/client/index.html +3 -3
  40. package/bundle/web-dist/server/assets/{lazyRouteComponent-Bi0fYGLs.js → lazyRouteComponent-Dtd0NR4r.js} +2 -2
  41. package/bundle/web-dist/server/assets/{logs-CIVFxfoi.js → logs-l91avYif.js} +26 -15
  42. package/bundle/web-dist/server/assets/{monit-DBXezg7R.js → monit-DvzribSE.js} +3 -3
  43. package/bundle/web-dist/server/assets/{plus-BH-t4cm_.js → plus-KZrECewT.js} +1 -1
  44. package/bundle/web-dist/server/assets/{react-dom-CZ2eynd8.js → react-dom-B4a6-uuR.js} +1 -1
  45. package/bundle/web-dist/server/assets/{refresh-cw-CosAdcz0.js → refresh-cw-BND93JrF.js} +1 -1
  46. package/bundle/web-dist/server/assets/{request-model-CnCeaNLE.js → request-model-CbqfnQOJ.js} +19 -1
  47. package/bundle/web-dist/server/assets/{routes-COWYIvA-.js → routes-BAPWTizT.js} +4 -4
  48. package/bundle/web-dist/server/assets/{services.generated-607iwhMI.js → services.generated-CEbGjsI0.js} +1 -0
  49. package/bundle/web-dist/server/assets/{settings-C_6dpK5p.js → settings-BZR5HSAL.js} +3 -3
  50. package/bundle/web-dist/server/assets/{show-DY396-LD.js → show-CxVZTAdv.js} +11 -3
  51. package/bundle/web-dist/server/assets/{tokens-COvV7qUP.js → tokens-D1hb4eKk.js} +4 -4
  52. package/bundle/web-dist/server/assets/{use-oauth-login-flow-VYCYf3uv.js → use-oauth-login-flow-Cvdy0zF8.js} +1 -1
  53. package/bundle/web-dist/server/assets/{use-update-token-mutation-D8XYV5of.js → use-update-token-mutation-CfYmk_4_.js} +1 -1
  54. package/bundle/web-dist/server/entry-server.generated.js +13 -10
  55. package/package.json +1 -1
  56. package/skills/qgrid/references/ai-sdk-provider-contract.md +2 -1
  57. package/skills/qgrid/references/openai-codex-runtime.md +1 -1
  58. package/skills/qgrid/references/prompt-cache-and-usage.md +3 -0
  59. package/skills/qgrid/references/request-log-run-lifecycle.md +10 -0
  60. package/bundle/web-dist/client/assets/index-CvG4UB9v.css +0 -1
  61. package/bundle/web-dist/client/assets/logs-CLf2VNfk.js +0 -1
  62. package/bundle/web-dist/client/assets/request-model-D4CZPmnG.js +0 -1
  63. package/bundle/web-dist/client/assets/show-DbLD3MzB.js +0 -2
@@ -82,7 +82,6 @@ function socketEvents(socket, signal) {
82
82
  socket.off("open", onOpen);
83
83
  socket.off("message", onMessage);
84
84
  socket.off("close", onClose);
85
- socket.off("error", onError);
86
85
  socket.off("unexpected-response", onUnexpectedResponse);
87
86
  records.length = 0;
88
87
  const closed = {
@@ -353,4 +352,4 @@ var OpenAIDirectClient = class {
353
352
  //#endregion
354
353
  export { OpenAIDirectClient, OpenAIHttpsTransport, OpenAIWebSocketTransport };
355
354
 
356
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3BlbmFpLWRpcmVjdC1jbGllbnQuanMiLCJuYW1lcyI6W10sInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3V0aWxzL3Byb3ZpZGVycy9vcGVuYWkvb3BlbmFpLWRpcmVjdC1jbGllbnQudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGNyeXB0byBmcm9tIFwibm9kZTpjcnlwdG9cIjtcblxuaW1wb3J0IFdzQ2xpZW50LCB7IHR5cGUgQ2xpZW50T3B0aW9ucywgdHlwZSBSYXdEYXRhIH0gZnJvbSBcIndzXCI7XG5cbmltcG9ydCB7XG4gIGJ1aWxkQ29kZXhJZGVudGl0eUhlYWRlcnMsXG4gIGJ1aWxkT3BlbkFJUmVzcG9uc2VzUmVxdWVzdCxcbiAgQ0hBVEdQVF9DT0RFWF9SRVNQT05TRVNfVVJMLFxuICBub3JtYWxpemVPcGVuQUlFdmVudCxcbiAgT3BlbkFJUHJvdG9jb2xFcnJvcixcbiAgdHlwZSBPcGVuQUlOb3JtYWxpemVkRXZlbnQsXG4gIHR5cGUgT3BlbkFJUmVzcG9uc2VzT3B0aW9ucyxcbiAgdHlwZSBPcGVuQUlSZXNwb25zZXNSZXF1ZXN0LFxufSBmcm9tIFwiLi9vcGVuYWktYmFja2VuZC1wcm90b2NvbFwiO1xuaW1wb3J0IHtcbiAgYnVpbGRTdGFuZGFsb25lSW1hZ2VSZXF1ZXN0LFxuICByZWFkU3RhbmRhbG9uZUltYWdlUmVzcG9uc2UsXG59IGZyb20gXCIuL29wZW5haS1pbWFnZS1nZW5lcmF0aW9uXCI7XG5pbXBvcnQgeyBub3JtYWxpemVPcGVuQUlTU0UsIHR5cGUgT3BlbkFJRXZlbnRTdHJlYW0gfSBmcm9tIFwiLi9vcGVuYWktc3NlXCI7XG5cbmV4cG9ydCBpbnRlcmZhY2UgT3BlbkFJRGlyZWN0Q3JlZGVudGlhbHMge1xuICBhY2Nlc3NUb2tlbjogc3RyaW5nO1xuICBhY2NvdW50SWQ6IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBPcGVuQUlUcmFuc3BvcnRSZXF1ZXN0IHtcbiAgYm9keTogT3BlbkFJUmVzcG9uc2VzUmVxdWVzdDtcbiAgc2lnbmFsPzogQWJvcnRTaWduYWw7XG4gIHNlc3Npb25JZDogc3RyaW5nO1xuICB0aHJlYWRJZDogc3RyaW5nO1xuICBjbGllbnRSZXF1ZXN0SWQ6IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBPcGVuQUlSZXNwb25zZXNUcmFuc3BvcnQge1xuICBzdHJlYW0ocmVxdWVzdDogT3BlbkFJVHJhbnNwb3J0UmVxdWVzdCk6IE9wZW5BSUV2ZW50U3RyZWFtO1xuICBjbG9zZT8oKTogdm9pZDtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBPcGVuQUlIdHRwc1RyYW5zcG9ydE9wdGlvbnMge1xuICBjcmVkZW50aWFsczogT3BlbkFJRGlyZWN0Q3JlZGVudGlhbHM7XG4gIGZldGNoPzogdHlwZW9mIGZldGNoO1xuICByZWZyZXNoQ3JlZGVudGlhbHM/OiAoKSA9PiBQcm9taXNlPE9wZW5BSURpcmVjdENyZWRlbnRpYWxzPjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBPcGVuQUlXZWJTb2NrZXRMaWtlIHtcbiAgb24oZXZlbnQ6IFwib3BlblwiLCBsaXN0ZW5lcjogKCkgPT4gdm9pZCk6IHRoaXM7XG4gIG9uKGV2ZW50OiBcIm1lc3NhZ2VcIiwgbGlzdGVuZXI6IChkYXRhOiBSYXdEYXRhLCBpc0JpbmFyeTogYm9vbGVhbikgPT4gdm9pZCk6IHRoaXM7XG4gIG9uKGV2ZW50OiBcImNsb3NlXCIsIGxpc3RlbmVyOiAoY29kZTogbnVtYmVyLCByZWFzb246IEJ1ZmZlcikgPT4gdm9pZCk6IHRoaXM7XG4gIG9uKGV2ZW50OiBcImVycm9yXCIsIGxpc3RlbmVyOiAoZXJyb3I6IEVycm9yKSA9PiB2b2lkKTogdGhpcztcbiAgb24oXG4gICAgZXZlbnQ6IFwidW5leHBlY3RlZC1yZXNwb25zZVwiLFxuICAgIGxpc3RlbmVyOiAocmVxdWVzdDogdW5rbm93biwgcmVzcG9uc2U6IHsgc3RhdHVzQ29kZT86IG51bWJlciB9KSA9PiB2b2lkLFxuICApOiB0aGlzO1xuICBvZmYoZXZlbnQ6IHN0cmluZywgbGlzdGVuZXI6ICguLi5hcmdzOiBuZXZlcltdKSA9PiB2b2lkKTogdGhpcztcbiAgc2VuZChkYXRhOiBzdHJpbmcsIGNhbGxiYWNrPzogKGVycm9yPzogRXJyb3IpID0+IHZvaWQpOiB2b2lkO1xuICBjbG9zZShjb2RlPzogbnVtYmVyLCByZWFzb24/OiBzdHJpbmcpOiB2b2lkO1xuICB0ZXJtaW5hdGUoKTogdm9pZDtcbn1cblxuZXhwb3J0IHR5cGUgT3BlbkFJV2ViU29ja2V0RmFjdG9yeSA9ICh1cmw6IHN0cmluZywgb3B0aW9uczogQ2xpZW50T3B0aW9ucykgPT4gT3BlbkFJV2ViU29ja2V0TGlrZTtcblxuZXhwb3J0IGludGVyZmFjZSBPcGVuQUlXZWJTb2NrZXRUcmFuc3BvcnRPcHRpb25zIGV4dGVuZHMgT3BlbkFJSHR0cHNUcmFuc3BvcnRPcHRpb25zIHtcbiAgd2ViU29ja2V0RmFjdG9yeT86IE9wZW5BSVdlYlNvY2tldEZhY3Rvcnk7XG59XG5cbnR5cGUgU29ja2V0UmVjb3JkID1cbiAgfCB7IGtpbmQ6IFwib3BlblwiIH1cbiAgfCB7IGtpbmQ6IFwibWVzc2FnZVwiOyBkYXRhOiBSYXdEYXRhOyBpc0JpbmFyeTogYm9vbGVhbiB9XG4gIHwgeyBraW5kOiBcImNsb3NlXCI7IGNvZGU6IG51bWJlcjsgcmVhc29uOiBzdHJpbmcgfVxuICB8IHsga2luZDogXCJlcnJvclwiOyBlcnJvcjogRXJyb3IgfVxuICB8IHsga2luZDogXCJyZWplY3RlZFwiOyBzdGF0dXM/OiBudW1iZXIgfTtcblxuY29uc3QgTUFYX0JVRkZFUkVEX1NPQ0tFVF9SRUNPUkRTID0gMTYwMDtcblxuZnVuY3Rpb24gd2Vic29ja2V0VXJsKHVybDogc3RyaW5nKTogc3RyaW5nIHtcbiAgbGV0IHBhcnNlZDogVVJMO1xuICB0cnkge1xuICAgIHBhcnNlZCA9IG5ldyBVUkwodXJsKTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICB0aHJvdyBuZXcgT3BlbkFJUHJvdG9jb2xFcnJvcihgSW52YWxpZCBPcGVuQUkgUmVzcG9uc2VzIFVSTDogJHtTdHJpbmcoZXJyb3IpfWApO1xuICB9XG4gIHBhcnNlZC5wcm90b2NvbCA9IHBhcnNlZC5wcm90b2NvbCA9PT0gXCJodHRwczpcIiA/IFwid3NzOlwiIDogXCJ3czpcIjtcbiAgcmV0dXJuIHBhcnNlZC50b1N0cmluZygpO1xufVxuXG5mdW5jdGlvbiByYXdEYXRhVGV4dChkYXRhOiBSYXdEYXRhKTogc3RyaW5nIHtcbiAgaWYgKEFycmF5LmlzQXJyYXkoZGF0YSkpIHJldHVybiBCdWZmZXIuY29uY2F0KGRhdGEpLnRvU3RyaW5nKCk7XG4gIGlmIChkYXRhIGluc3RhbmNlb2YgQXJyYXlCdWZmZXIpIHJldHVybiBCdWZmZXIuZnJvbShuZXcgVWludDhBcnJheShkYXRhKSkudG9TdHJpbmcoKTtcbiAgcmV0dXJuIEJ1ZmZlci5mcm9tKGRhdGEpLnRvU3RyaW5nKCk7XG59XG5cbmZ1bmN0aW9uIHNvY2tldEV2ZW50cyhzb2NrZXQ6IE9wZW5BSVdlYlNvY2tldExpa2UsIHNpZ25hbD86IEFib3J0U2lnbmFsKSB7XG4gIGNvbnN0IHJlY29yZHM6IFNvY2tldFJlY29yZFtdID0gW107XG4gIGNvbnN0IHdhaXRlcnM6IEFycmF5PChyZWNvcmQ6IFNvY2tldFJlY29yZCkgPT4gdm9pZD4gPSBbXTtcbiAgbGV0IGFjdGl2ZSA9IHRydWU7XG4gIGNvbnN0IHB1c2ggPSAocmVjb3JkOiBTb2NrZXRSZWNvcmQpID0+IHtcbiAgICBpZiAoIWFjdGl2ZSkgcmV0dXJuO1xuICAgIGNvbnN0IHdhaXRlciA9IHdhaXRlcnMuc2hpZnQoKTtcbiAgICBpZiAod2FpdGVyKSB3YWl0ZXIocmVjb3JkKTtcbiAgICBlbHNlIGlmIChyZWNvcmRzLmxlbmd0aCA8IE1BWF9CVUZGRVJFRF9TT0NLRVRfUkVDT1JEUykgcmVjb3Jkcy5wdXNoKHJlY29yZCk7XG4gICAgZWxzZSB7XG4gICAgICBhY3RpdmUgPSBmYWxzZTtcbiAgICAgIHJlY29yZHMubGVuZ3RoID0gMDtcbiAgICAgIHNvY2tldC50ZXJtaW5hdGUoKTtcbiAgICAgIGNvbnN0IG92ZXJmbG93ID0ge1xuICAgICAgICBraW5kOiBcImVycm9yXCIgYXMgY29uc3QsXG4gICAgICAgIGVycm9yOiBuZXcgT3BlbkFJUHJvdG9jb2xFcnJvcihcbiAgICAgICAgICBgT3BlbkFJIFdlYlNvY2tldCBleGNlZWRlZCB0aGUgJHtNQVhfQlVGRkVSRURfU09DS0VUX1JFQ09SRFN9LXJlY29yZCByZWNlaXZlIGJ1ZmZlcmAsXG4gICAgICAgICAgXCJ3ZWJzb2NrZXRfYmFja3ByZXNzdXJlXCIsXG4gICAgICAgICksXG4gICAgICB9O1xuICAgICAgY29uc3Qgb3ZlcmZsb3dXYWl0ZXIgPSB3YWl0ZXJzLnNoaWZ0KCk7XG4gICAgICBpZiAob3ZlcmZsb3dXYWl0ZXIpIG92ZXJmbG93V2FpdGVyKG92ZXJmbG93KTtcbiAgICAgIGVsc2UgcmVjb3Jkcy5wdXNoKG92ZXJmbG93KTtcbiAgICB9XG4gIH07XG4gIGNvbnN0IG9uT3BlbiA9ICgpID0+IHB1c2goeyBraW5kOiBcIm9wZW5cIiB9KTtcbiAgY29uc3Qgb25NZXNzYWdlID0gKGRhdGE6IFJhd0RhdGEsIGlzQmluYXJ5OiBib29sZWFuKSA9PiBwdXNoKHsga2luZDogXCJtZXNzYWdlXCIsIGRhdGEsIGlzQmluYXJ5IH0pO1xuICBjb25zdCBvbkNsb3NlID0gKGNvZGU6IG51bWJlciwgcmVhc29uOiBCdWZmZXIpID0+XG4gICAgcHVzaCh7IGtpbmQ6IFwiY2xvc2VcIiwgY29kZSwgcmVhc29uOiByZWFzb24udG9TdHJpbmcoKSB9KTtcbiAgY29uc3Qgb25FcnJvciA9IChlcnJvcjogRXJyb3IpID0+IHB1c2goeyBraW5kOiBcImVycm9yXCIsIGVycm9yIH0pO1xuICBjb25zdCBvblVuZXhwZWN0ZWRSZXNwb25zZSA9IChfcmVxdWVzdDogdW5rbm93biwgcmVzcG9uc2U6IHsgc3RhdHVzQ29kZT86IG51bWJlciB9KSA9PlxuICAgIHB1c2goeyBraW5kOiBcInJlamVjdGVkXCIsIHN0YXR1czogcmVzcG9uc2Uuc3RhdHVzQ29kZSB9KTtcbiAgc29ja2V0Lm9uKFwib3BlblwiLCBvbk9wZW4pO1xuICBzb2NrZXQub24oXCJtZXNzYWdlXCIsIG9uTWVzc2FnZSk7XG4gIHNvY2tldC5vbihcImNsb3NlXCIsIG9uQ2xvc2UpO1xuICBzb2NrZXQub24oXCJlcnJvclwiLCBvbkVycm9yKTtcbiAgc29ja2V0Lm9uKFwidW5leHBlY3RlZC1yZXNwb25zZVwiLCBvblVuZXhwZWN0ZWRSZXNwb25zZSk7XG4gIGNvbnN0IG9uQWJvcnQgPSAoKSA9PiB7XG4gICAgc29ja2V0LnRlcm1pbmF0ZSgpO1xuICAgIHB1c2goeyBraW5kOiBcImVycm9yXCIsIGVycm9yOiBhYm9ydEVycm9yKHNpZ25hbCkgfSk7XG4gIH07XG4gIHNpZ25hbD8uYWRkRXZlbnRMaXN0ZW5lcihcImFib3J0XCIsIG9uQWJvcnQsIHsgb25jZTogdHJ1ZSB9KTtcbiAgcmV0dXJuIHtcbiAgICBuZXh0OiAoKSA9PlxuICAgICAgcmVjb3Jkcy5sZW5ndGhcbiAgICAgICAgPyBQcm9taXNlLnJlc29sdmUocmVjb3Jkcy5zaGlmdCgpISlcbiAgICAgICAgOiBuZXcgUHJvbWlzZTxTb2NrZXRSZWNvcmQ+KChyZXNvbHZlKSA9PiB3YWl0ZXJzLnB1c2gocmVzb2x2ZSkpLFxuICAgIGNsZWFudXA6ICgpID0+IHtcbiAgICAgIGFjdGl2ZSA9IGZhbHNlO1xuICAgICAgc2lnbmFsPy5yZW1vdmVFdmVudExpc3RlbmVyKFwiYWJvcnRcIiwgb25BYm9ydCk7XG4gICAgICBzb2NrZXQub2ZmKFwib3BlblwiLCBvbk9wZW4pO1xuICAgICAgc29ja2V0Lm9mZihcIm1lc3NhZ2VcIiwgb25NZXNzYWdlKTtcbiAgICAgIHNvY2tldC5vZmYoXCJjbG9zZVwiLCBvbkNsb3NlKTtcbiAgICAgIHNvY2tldC5vZmYoXCJlcnJvclwiLCBvbkVycm9yKTtcbiAgICAgIHNvY2tldC5vZmYoXCJ1bmV4cGVjdGVkLXJlc3BvbnNlXCIsIG9uVW5leHBlY3RlZFJlc3BvbnNlKTtcbiAgICAgIHJlY29yZHMubGVuZ3RoID0gMDtcbiAgICAgIGNvbnN0IGNsb3NlZCA9IHtcbiAgICAgICAga2luZDogXCJlcnJvclwiIGFzIGNvbnN0LFxuICAgICAgICBlcnJvcjogbmV3IE9wZW5BSVByb3RvY29sRXJyb3IoXCJPcGVuQUkgV2ViU29ja2V0IGV2ZW50IHN0cmVhbSB3YXMgY2xvc2VkXCIpLFxuICAgICAgfTtcbiAgICAgIHdhaXRlcnMuc3BsaWNlKDApLmZvckVhY2goKHdhaXRlcikgPT4gd2FpdGVyKGNsb3NlZCkpO1xuICAgIH0sXG4gICAgZGV0YWNoQWJvcnQ6ICgpID0+IHNpZ25hbD8ucmVtb3ZlRXZlbnRMaXN0ZW5lcihcImFib3J0XCIsIG9uQWJvcnQpLFxuICB9O1xufVxuXG5mdW5jdGlvbiBhYm9ydEVycm9yKHNpZ25hbD86IEFib3J0U2lnbmFsKTogRXJyb3Ige1xuICByZXR1cm4gc2lnbmFsPy5yZWFzb24gaW5zdGFuY2VvZiBFcnJvclxuICAgID8gc2lnbmFsLnJlYXNvblxuICAgIDogbmV3IERPTUV4Y2VwdGlvbihcIkFib3J0ZWRcIiwgXCJBYm9ydEVycm9yXCIpO1xufVxuXG5hc3luYyBmdW5jdGlvbiBuZXh0UG9vbGVkUmVjb3JkKFxuICBldmVudHM6IFJldHVyblR5cGU8dHlwZW9mIHNvY2tldEV2ZW50cz4sXG4gIHNvY2tldDogT3BlbkFJV2ViU29ja2V0TGlrZSxcbiAgc2lnbmFsPzogQWJvcnRTaWduYWwsXG4pOiBQcm9taXNlPFNvY2tldFJlY29yZD4ge1xuICBpZiAoIXNpZ25hbCkgcmV0dXJuIGV2ZW50cy5uZXh0KCk7XG4gIGlmIChzaWduYWwuYWJvcnRlZCkgdGhyb3cgYWJvcnRFcnJvcihzaWduYWwpO1xuICByZXR1cm4gbmV3IFByb21pc2U8U29ja2V0UmVjb3JkPigocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgY29uc3Qgb25BYm9ydCA9ICgpID0+IHtcbiAgICAgIHNvY2tldC50ZXJtaW5hdGUoKTtcbiAgICAgIHJlamVjdChhYm9ydEVycm9yKHNpZ25hbCkpO1xuICAgIH07XG4gICAgc2lnbmFsLmFkZEV2ZW50TGlzdGVuZXIoXCJhYm9ydFwiLCBvbkFib3J0LCB7IG9uY2U6IHRydWUgfSk7XG4gICAgdm9pZCBldmVudHNcbiAgICAgIC5uZXh0KClcbiAgICAgIC50aGVuKHJlc29sdmUsIHJlamVjdClcbiAgICAgIC5maW5hbGx5KCgpID0+IHtcbiAgICAgICAgc2lnbmFsLnJlbW92ZUV2ZW50TGlzdGVuZXIoXCJhYm9ydFwiLCBvbkFib3J0KTtcbiAgICAgIH0pO1xuICB9KTtcbn1cblxuZnVuY3Rpb24gY2FjaGVBZmZpbml0eVV1aWQoa2V5OiBzdHJpbmcpOiBzdHJpbmcge1xuICBjb25zdCBoZXggPSBjcnlwdG8uY3JlYXRlSGFzaChcInNoYTI1NlwiKS51cGRhdGUoa2V5KS5kaWdlc3QoXCJoZXhcIikuc2xpY2UoMCwgMzIpLnNwbGl0KFwiXCIpO1xuICBoZXhbMTJdID0gXCI0XCI7XG4gIGhleFsxNl0gPSAoKE51bWJlci5wYXJzZUludChoZXhbMTZdISwgMTYpICYgMHgzKSB8IDB4OCkudG9TdHJpbmcoMTYpO1xuICByZXR1cm4gYCR7aGV4LnNsaWNlKDAsIDgpLmpvaW4oXCJcIil9LSR7aGV4LnNsaWNlKDgsIDEyKS5qb2luKFwiXCIpfS0ke2hleC5zbGljZSgxMiwgMTYpLmpvaW4oXCJcIil9LSR7aGV4LnNsaWNlKDE2LCAyMCkuam9pbihcIlwiKX0tJHtoZXguc2xpY2UoMjApLmpvaW4oXCJcIil9YDtcbn1cblxudHlwZSBBZmZpbml0eUNvbm5lY3Rpb24gPSB7XG4gIHNvY2tldDogT3BlbkFJV2ViU29ja2V0TGlrZTtcbiAgZXZlbnRzOiBSZXR1cm5UeXBlPHR5cGVvZiBzb2NrZXRFdmVudHM+O1xuICBjbG9zZWQ/OiBib29sZWFuO1xufTtcblxuZXhwb3J0IGNsYXNzIE9wZW5BSVdlYlNvY2tldFRyYW5zcG9ydCBpbXBsZW1lbnRzIE9wZW5BSVJlc3BvbnNlc1RyYW5zcG9ydCB7XG4gIHN0YXRpYyByZWFkb25seSBNQVhfQUZGSU5JVFlfQ09OTkVDVElPTlMgPSAxNjtcbiAgY3JlZGVudGlhbHM6IE9wZW5BSURpcmVjdENyZWRlbnRpYWxzO1xuICByZWFkb25seSByZWZyZXNoQ3JlZGVudGlhbHM/OiAoKSA9PiBQcm9taXNlPE9wZW5BSURpcmVjdENyZWRlbnRpYWxzPjtcbiAgcmVhZG9ubHkgd2ViU29ja2V0RmFjdG9yeTogT3BlbkFJV2ViU29ja2V0RmFjdG9yeTtcbiAgcmVhZG9ubHkgYWZmaW5pdHlDb25uZWN0aW9ucyA9IG5ldyBNYXA8c3RyaW5nLCBBZmZpbml0eUNvbm5lY3Rpb24+KCk7XG4gIHJlYWRvbmx5IGJ1c3lBZmZpbml0aWVzID0gbmV3IFNldDxzdHJpbmc+KCk7XG5cbiAgY29uc3RydWN0b3Iob3B0aW9uczogT3BlbkFJV2ViU29ja2V0VHJhbnNwb3J0T3B0aW9ucykge1xuICAgIHRoaXMuY3JlZGVudGlhbHMgPSBvcHRpb25zLmNyZWRlbnRpYWxzO1xuICAgIHRoaXMucmVmcmVzaENyZWRlbnRpYWxzID0gb3B0aW9ucy5yZWZyZXNoQ3JlZGVudGlhbHM7XG4gICAgdGhpcy53ZWJTb2NrZXRGYWN0b3J5ID1cbiAgICAgIG9wdGlvbnMud2ViU29ja2V0RmFjdG9yeSA/PyAoKHVybCwgd3NPcHRpb25zKSA9PiBuZXcgV3NDbGllbnQodXJsLCB3c09wdGlvbnMpKTtcbiAgfVxuXG4gIGNsb3NlKCk6IHZvaWQge1xuICAgIHRoaXMuYWZmaW5pdHlDb25uZWN0aW9ucy5mb3JFYWNoKCh7IHNvY2tldCwgZXZlbnRzIH0pID0+IHtcbiAgICAgIGV2ZW50cy5jbGVhbnVwKCk7XG4gICAgICBzb2NrZXQuY2xvc2UoMTAwMCwgXCJ0cmFuc3BvcnQgY2xvc2VkXCIpO1xuICAgIH0pO1xuICAgIHRoaXMuYWZmaW5pdHlDb25uZWN0aW9ucy5jbGVhcigpO1xuICAgIHRoaXMuYnVzeUFmZmluaXRpZXMuY2xlYXIoKTtcbiAgfVxuXG4gIC8vIOycoO2ctCDsl7DqsrDrp4wg7LaV7Lac7ZWc64ukLiDsoITrtoAg7IKs7JqpIOykkeydtOuptCBmYWxzZeulvCDrsJjtmZjtlbQg7J287ZqM7ISxIOyGjOy8k+ycvOuhnCDsspjrpqztlZzri6QuXG4gIHJlbWVtYmVyQWZmaW5pdHlDb25uZWN0aW9uKHRocmVhZElkOiBzdHJpbmcsIGNvbm5lY3Rpb246IEFmZmluaXR5Q29ubmVjdGlvbik6IGJvb2xlYW4ge1xuICAgIGlmIChcbiAgICAgICF0aGlzLmFmZmluaXR5Q29ubmVjdGlvbnMuaGFzKHRocmVhZElkKSAmJlxuICAgICAgdGhpcy5hZmZpbml0eUNvbm5lY3Rpb25zLnNpemUgPj0gT3BlbkFJV2ViU29ja2V0VHJhbnNwb3J0Lk1BWF9BRkZJTklUWV9DT05ORUNUSU9OU1xuICAgICkge1xuICAgICAgY29uc3QgaWRsZUtleSA9IFsuLi50aGlzLmFmZmluaXR5Q29ubmVjdGlvbnMua2V5cygpXS5maW5kKFxuICAgICAgICAoa2V5KSA9PiAhdGhpcy5idXN5QWZmaW5pdGllcy5oYXMoa2V5KSxcbiAgICAgICk7XG4gICAgICBpZiAoaWRsZUtleSA9PT0gdW5kZWZpbmVkKSByZXR1cm4gZmFsc2U7XG4gICAgICBjb25zdCBpZGxlID0gdGhpcy5hZmZpbml0eUNvbm5lY3Rpb25zLmdldChpZGxlS2V5KSE7XG4gICAgICBpZGxlLmV2ZW50cy5jbGVhbnVwKCk7XG4gICAgICBpZGxlLnNvY2tldC5jbG9zZSgxMDAwLCBcImFmZmluaXR5IGNhY2hlIGV2aWN0ZWRcIik7XG4gICAgICB0aGlzLmFmZmluaXR5Q29ubmVjdGlvbnMuZGVsZXRlKGlkbGVLZXkpO1xuICAgIH1cbiAgICB0aGlzLmFmZmluaXR5Q29ubmVjdGlvbnMuc2V0KHRocmVhZElkLCBjb25uZWN0aW9uKTtcbiAgICAvLyDsnKDtnLQg7IOB7YOc7JeQ7IScIGJhY2tlbmQg6rCAIOuBiuydgCDshozsvJPsnYQg64uk7J2MIOyalOyyreydtCDsp5HslrTrk6Tsp4Ag7JWK64+E66GdIOy6kOyLnOyXkOyEnCDsoJzqsbDtlZzri6QuXG4gICAgY29uc3QgZHJvcCA9ICgpID0+IHtcbiAgICAgIGNvbm5lY3Rpb24uY2xvc2VkID0gdHJ1ZTtcbiAgICAgIGlmICh0aGlzLmJ1c3lBZmZpbml0aWVzLmhhcyh0aHJlYWRJZCkpIHJldHVybjtcbiAgICAgIGlmICh0aGlzLmFmZmluaXR5Q29ubmVjdGlvbnMuZ2V0KHRocmVhZElkKSAhPT0gY29ubmVjdGlvbikgcmV0dXJuO1xuICAgICAgdGhpcy5hZmZpbml0eUNvbm5lY3Rpb25zLmRlbGV0ZSh0aHJlYWRJZCk7XG4gICAgICBjb25uZWN0aW9uLmV2ZW50cy5jbGVhbnVwKCk7XG4gICAgfTtcbiAgICBjb25uZWN0aW9uLnNvY2tldC5vbihcImNsb3NlXCIsIGRyb3ApO1xuICAgIGNvbm5lY3Rpb24uc29ja2V0Lm9uKFwiZXJyb3JcIiwgZHJvcCk7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICBhc3luYyAqc3RyZWFtKHJlcXVlc3Q6IE9wZW5BSVRyYW5zcG9ydFJlcXVlc3QpOiBBc3luY0dlbmVyYXRvcjxPcGVuQUlOb3JtYWxpemVkRXZlbnQ+IHtcbiAgICBsZXQgcmVmcmVzaGVkID0gZmFsc2U7XG4gICAgd2hpbGUgKHRydWUpIHtcbiAgICAgIGlmIChyZXF1ZXN0LnNpZ25hbD8uYWJvcnRlZCkgdGhyb3cgYWJvcnRFcnJvcihyZXF1ZXN0LnNpZ25hbCk7XG4gICAgICBjb25zdCBoYXNBZmZpbml0eSA9IHJlcXVlc3QuYm9keS5wcm9tcHRfY2FjaGVfa2V5ICE9PSB1bmRlZmluZWQ7XG4gICAgICBjb25zdCByZXRhaW5Db25uZWN0aW9uID0gaGFzQWZmaW5pdHkgJiYgIXRoaXMuYnVzeUFmZmluaXRpZXMuaGFzKHJlcXVlc3QudGhyZWFkSWQpO1xuICAgICAgaWYgKHJldGFpbkNvbm5lY3Rpb24pIHRoaXMuYnVzeUFmZmluaXRpZXMuYWRkKHJlcXVlc3QudGhyZWFkSWQpO1xuICAgICAgY29uc3QgZW50cnkgPSByZXRhaW5Db25uZWN0aW9uID8gdGhpcy5hZmZpbml0eUNvbm5lY3Rpb25zLmdldChyZXF1ZXN0LnRocmVhZElkKSA6IHVuZGVmaW5lZDtcbiAgICAgIGlmIChlbnRyeT8uY2xvc2VkKSB7XG4gICAgICAgIHRoaXMuYWZmaW5pdHlDb25uZWN0aW9ucy5kZWxldGUocmVxdWVzdC50aHJlYWRJZCk7XG4gICAgICAgIGVudHJ5LmV2ZW50cy5jbGVhbnVwKCk7XG4gICAgICB9XG4gICAgICBjb25zdCBjYWNoZWQgPSBlbnRyeT8uY2xvc2VkID8gdW5kZWZpbmVkIDogZW50cnk7XG4gICAgICBsZXQgcmV0YWluZWQgPSByZXRhaW5Db25uZWN0aW9uO1xuICAgICAgY29uc3Qgc29ja2V0ID1cbiAgICAgICAgY2FjaGVkPy5zb2NrZXQgPz9cbiAgICAgICAgdGhpcy53ZWJTb2NrZXRGYWN0b3J5KHdlYnNvY2tldFVybChDSEFUR1BUX0NPREVYX1JFU1BPTlNFU19VUkwpLCB7XG4gICAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgICAgLi4uYnVpbGRDb2RleElkZW50aXR5SGVhZGVycyh0aGlzLmNyZWRlbnRpYWxzLmFjY2Vzc1Rva2VuLCB0aGlzLmNyZWRlbnRpYWxzLmFjY291bnRJZCwge1xuICAgICAgICAgICAgICBzZXNzaW9uSWQ6IHJlcXVlc3Quc2Vzc2lvbklkLFxuICAgICAgICAgICAgICB0aHJlYWRJZDogcmVxdWVzdC50aHJlYWRJZCxcbiAgICAgICAgICAgICAgY2xpZW50UmVxdWVzdElkOiByZXF1ZXN0LmNsaWVudFJlcXVlc3RJZCxcbiAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgXCJPcGVuQUktQmV0YVwiOiBcInJlc3BvbnNlc193ZWJzb2NrZXRzPTIwMjYtMDItMDZcIixcbiAgICAgICAgICB9LFxuICAgICAgICB9KTtcbiAgICAgIGNvbnN0IGV2ZW50cyA9IGNhY2hlZD8uZXZlbnRzID8/IHNvY2tldEV2ZW50cyhzb2NrZXQsIHJlcXVlc3Quc2lnbmFsKTtcbiAgICAgIGxldCBjb21wbGV0ZWQgPSBmYWxzZTtcbiAgICAgIHRyeSB7XG4gICAgICAgIGlmICghY2FjaGVkKSB7XG4gICAgICAgICAgY29uc3QgaGFuZHNoYWtlID0gYXdhaXQgZXZlbnRzLm5leHQoKTtcbiAgICAgICAgICBpZiAoXG4gICAgICAgICAgICBoYW5kc2hha2Uua2luZCA9PT0gXCJyZWplY3RlZFwiICYmXG4gICAgICAgICAgICBoYW5kc2hha2Uuc3RhdHVzID09PSA0MDEgJiZcbiAgICAgICAgICAgICFyZWZyZXNoZWQgJiZcbiAgICAgICAgICAgIHRoaXMucmVmcmVzaENyZWRlbnRpYWxzXG4gICAgICAgICAgKSB7XG4gICAgICAgICAgICBzb2NrZXQudGVybWluYXRlKCk7XG4gICAgICAgICAgICB0aGlzLmNyZWRlbnRpYWxzID0gYXdhaXQgdGhpcy5yZWZyZXNoQ3JlZGVudGlhbHMoKTtcbiAgICAgICAgICAgIHJlZnJlc2hlZCA9IHRydWU7XG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICB9XG4gICAgICAgICAgaWYgKGhhbmRzaGFrZS5raW5kID09PSBcInJlamVjdGVkXCIpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBPcGVuQUlQcm90b2NvbEVycm9yKFxuICAgICAgICAgICAgICBgT3BlbkFJIFdlYlNvY2tldCBoYW5kc2hha2UgcmVqZWN0ZWQke2hhbmRzaGFrZS5zdGF0dXMgPyBgIHdpdGggSFRUUCAke2hhbmRzaGFrZS5zdGF0dXN9YCA6IFwiXCJ9YCxcbiAgICAgICAgICAgICAgdW5kZWZpbmVkLFxuICAgICAgICAgICAgICBoYW5kc2hha2Uuc3RhdHVzLFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgaWYgKGhhbmRzaGFrZS5raW5kID09PSBcImVycm9yXCIpIHRocm93IGhhbmRzaGFrZS5lcnJvcjtcbiAgICAgICAgICBpZiAoaGFuZHNoYWtlLmtpbmQgIT09IFwib3BlblwiKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgT3BlbkFJUHJvdG9jb2xFcnJvcihcIk9wZW5BSSBXZWJTb2NrZXQgY2xvc2VkIGJlZm9yZSB0aGUgaGFuZHNoYWtlIGNvbXBsZXRlZFwiKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgaWYgKHJldGFpbkNvbm5lY3Rpb24pIHtcbiAgICAgICAgICAgIHJldGFpbmVkID0gdGhpcy5yZW1lbWJlckFmZmluaXR5Q29ubmVjdGlvbihyZXF1ZXN0LnRocmVhZElkLCB7IHNvY2tldCwgZXZlbnRzIH0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGF3YWl0IG5ldyBQcm9taXNlPHZvaWQ+KChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgICBzb2NrZXQuc2VuZChKU09OLnN0cmluZ2lmeSh7IHR5cGU6IFwicmVzcG9uc2UuY3JlYXRlXCIsIC4uLnJlcXVlc3QuYm9keSB9KSwgKGVycm9yKSA9PlxuICAgICAgICAgICAgZXJyb3IgPyByZWplY3QoZXJyb3IpIDogcmVzb2x2ZSgpLFxuICAgICAgICAgICk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHdoaWxlICh0cnVlKSB7XG4gICAgICAgICAgY29uc3QgcmVjb3JkID0gY2FjaGVkXG4gICAgICAgICAgICA/IGF3YWl0IG5leHRQb29sZWRSZWNvcmQoZXZlbnRzLCBzb2NrZXQsIHJlcXVlc3Quc2lnbmFsKVxuICAgICAgICAgICAgOiBhd2FpdCBldmVudHMubmV4dCgpO1xuICAgICAgICAgIGlmIChyZWNvcmQua2luZCA9PT0gXCJtZXNzYWdlXCIpIHtcbiAgICAgICAgICAgIGlmIChyZWNvcmQuaXNCaW5hcnkpIHtcbiAgICAgICAgICAgICAgdGhyb3cgbmV3IE9wZW5BSVByb3RvY29sRXJyb3IoXCJPcGVuQUkgV2ViU29ja2V0IHNlbnQgYW4gdW5leHBlY3RlZCBiaW5hcnkgbWVzc2FnZVwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGxldCByYXc6IHVua25vd247XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICByYXcgPSBKU09OLnBhcnNlKHJhd0RhdGFUZXh0KHJlY29yZC5kYXRhKSk7XG4gICAgICAgICAgICB9IGNhdGNoIHtcbiAgICAgICAgICAgICAgdGhyb3cgbmV3IE9wZW5BSVByb3RvY29sRXJyb3IoXCJPcGVuQUkgV2ViU29ja2V0IHNlbnQgaW52YWxpZCBKU09OXCIpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY29uc3QgZXZlbnQgPSBub3JtYWxpemVPcGVuQUlFdmVudChyYXcpO1xuICAgICAgICAgICAgaWYgKCFldmVudCkgY29udGludWU7XG4gICAgICAgICAgICBpZiAoZXZlbnQudHlwZSA9PT0gXCJjb21wbGV0ZWRcIikge1xuICAgICAgICAgICAgICBjb21wbGV0ZWQgPSB0cnVlO1xuICAgICAgICAgICAgICBpZiAocmV0YWluZWQpIGV2ZW50cy5kZXRhY2hBYm9ydCgpO1xuICAgICAgICAgICAgICBlbHNlIHNvY2tldC5jbG9zZSgxMDAwLCBcInJlc3BvbnNlIGNvbXBsZXRlZFwiKTtcbiAgICAgICAgICAgICAgeWllbGQgZXZlbnQ7XG4gICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHlpZWxkIGV2ZW50O1xuICAgICAgICAgICAgaWYgKGV2ZW50LnR5cGUgPT09IFwiZXJyb3JcIikgdGhyb3cgZXZlbnQuZXJyb3I7XG4gICAgICAgICAgfSBlbHNlIGlmIChyZWNvcmQua2luZCA9PT0gXCJlcnJvclwiKSB7XG4gICAgICAgICAgICB0aHJvdyByZWNvcmQuZXJyb3I7XG4gICAgICAgICAgfSBlbHNlIGlmIChyZWNvcmQua2luZCA9PT0gXCJjbG9zZVwiKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgT3BlbkFJUHJvdG9jb2xFcnJvcihcbiAgICAgICAgICAgICAgYE9wZW5BSSBXZWJTb2NrZXQgY2xvc2VkIGJlZm9yZSBhIHRlcm1pbmFsIHJlc3BvbnNlIGV2ZW50ICgke3JlY29yZC5jb2RlfSR7cmVjb3JkLnJlYXNvbiA/IGA6ICR7cmVjb3JkLnJlYXNvbn1gIDogXCJcIn0pYCxcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBPcGVuQUlQcm90b2NvbEVycm9yKFwiT3BlbkFJIFdlYlNvY2tldCBlbWl0dGVkIGFuIHVuZXhwZWN0ZWQgaGFuZHNoYWtlIGV2ZW50XCIpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgaWYgKCFjb21wbGV0ZWQgfHwgIXJldGFpbmVkKSB7XG4gICAgICAgICAgaWYgKHJldGFpbmVkKSB0aGlzLmFmZmluaXR5Q29ubmVjdGlvbnMuZGVsZXRlKHJlcXVlc3QudGhyZWFkSWQpO1xuICAgICAgICAgIGV2ZW50cy5jbGVhbnVwKCk7XG4gICAgICAgICAgaWYgKCFjb21wbGV0ZWQpIHNvY2tldC50ZXJtaW5hdGUoKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAocmV0YWluQ29ubmVjdGlvbikgdGhpcy5idXN5QWZmaW5pdGllcy5kZWxldGUocmVxdWVzdC50aHJlYWRJZCk7XG4gICAgICB9XG4gICAgfVxuICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHJlc3BvbnNlRXJyb3IocmVzcG9uc2U6IFJlc3BvbnNlKTogUHJvbWlzZTxPcGVuQUlQcm90b2NvbEVycm9yPiB7XG4gIGNvbnN0IHRleHQgPSBhd2FpdCByZXNwb25zZS50ZXh0KCkuY2F0Y2goKCkgPT4gXCJcIik7XG4gIGxldCBtZXNzYWdlID0gdGV4dCB8fCByZXNwb25zZS5zdGF0dXNUZXh0IHx8IGBIVFRQICR7cmVzcG9uc2Uuc3RhdHVzfWA7XG4gIGxldCBjb2RlOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gIHRyeSB7XG4gICAgY29uc3QgcGFyc2VkID0gSlNPTi5wYXJzZSh0ZXh0KSBhcyB7XG4gICAgICBlcnJvcj86IHsgbWVzc2FnZT86IHN0cmluZzsgY29kZT86IHN0cmluZyB9IHwgc3RyaW5nO1xuICAgICAgbWVzc2FnZT86IHN0cmluZztcbiAgICAgIGNvZGU/OiBzdHJpbmc7XG4gICAgfTtcbiAgICBjb25zdCBlcnJvciA9IHBhcnNlZC5lcnJvcjtcbiAgICBtZXNzYWdlID1cbiAgICAgICh0eXBlb2YgZXJyb3IgPT09IFwib2JqZWN0XCIgPyBlcnJvci5tZXNzYWdlIDogdW5kZWZpbmVkKSA/P1xuICAgICAgcGFyc2VkLm1lc3NhZ2UgPz9cbiAgICAgICh0eXBlb2YgZXJyb3IgPT09IFwic3RyaW5nXCIgPyBlcnJvciA6IG1lc3NhZ2UpO1xuICAgIGNvZGUgPSAodHlwZW9mIGVycm9yID09PSBcIm9iamVjdFwiID8gZXJyb3IuY29kZSA6IHVuZGVmaW5lZCkgPz8gcGFyc2VkLmNvZGU7XG4gIH0gY2F0Y2gge1xuICAgIGNvZGUgPSB1bmRlZmluZWQ7XG4gIH1cbiAgcmV0dXJuIG5ldyBPcGVuQUlQcm90b2NvbEVycm9yKG1lc3NhZ2UsIGNvZGUsIHJlc3BvbnNlLnN0YXR1cyk7XG59XG5cbmV4cG9ydCBjbGFzcyBPcGVuQUlIdHRwc1RyYW5zcG9ydCBpbXBsZW1lbnRzIE9wZW5BSVJlc3BvbnNlc1RyYW5zcG9ydCB7XG4gIGNyZWRlbnRpYWxzOiBPcGVuQUlEaXJlY3RDcmVkZW50aWFscztcbiAgcmVhZG9ubHkgZmV0Y2hJbXBsOiB0eXBlb2YgZmV0Y2g7XG4gIHJlYWRvbmx5IHJlZnJlc2hDcmVkZW50aWFscz86ICgpID0+IFByb21pc2U8T3BlbkFJRGlyZWN0Q3JlZGVudGlhbHM+O1xuXG4gIGNvbnN0cnVjdG9yKG9wdGlvbnM6IE9wZW5BSUh0dHBzVHJhbnNwb3J0T3B0aW9ucykge1xuICAgIHRoaXMuY3JlZGVudGlhbHMgPSBvcHRpb25zLmNyZWRlbnRpYWxzO1xuICAgIHRoaXMuZmV0Y2hJbXBsID0gb3B0aW9ucy5mZXRjaCA/PyBmZXRjaDtcbiAgICB0aGlzLnJlZnJlc2hDcmVkZW50aWFscyA9IG9wdGlvbnMucmVmcmVzaENyZWRlbnRpYWxzO1xuICB9XG5cbiAgYXN5bmMgKnN0cmVhbShyZXF1ZXN0OiBPcGVuQUlUcmFuc3BvcnRSZXF1ZXN0KTogQXN5bmNHZW5lcmF0b3I8T3BlbkFJTm9ybWFsaXplZEV2ZW50PiB7XG4gICAgbGV0IHJlZnJlc2hlZCA9IGZhbHNlO1xuXG4gICAgd2hpbGUgKHRydWUpIHtcbiAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgdGhpcy5mZXRjaEltcGwoQ0hBVEdQVF9DT0RFWF9SRVNQT05TRVNfVVJMLCB7XG4gICAgICAgIG1ldGhvZDogXCJQT1NUXCIsXG4gICAgICAgIGhlYWRlcnM6IGJ1aWxkQ29kZXhJZGVudGl0eUhlYWRlcnMoXG4gICAgICAgICAgdGhpcy5jcmVkZW50aWFscy5hY2Nlc3NUb2tlbixcbiAgICAgICAgICB0aGlzLmNyZWRlbnRpYWxzLmFjY291bnRJZCxcbiAgICAgICAgICB7XG4gICAgICAgICAgICBzZXNzaW9uSWQ6IHJlcXVlc3Quc2Vzc2lvbklkLFxuICAgICAgICAgICAgdGhyZWFkSWQ6IHJlcXVlc3QudGhyZWFkSWQsXG4gICAgICAgICAgICBjbGllbnRSZXF1ZXN0SWQ6IHJlcXVlc3QuY2xpZW50UmVxdWVzdElkLFxuICAgICAgICAgIH0sXG4gICAgICAgICksXG4gICAgICAgIGJvZHk6IEpTT04uc3RyaW5naWZ5KHJlcXVlc3QuYm9keSksXG4gICAgICAgIHNpZ25hbDogcmVxdWVzdC5zaWduYWwsXG4gICAgICB9KTtcblxuICAgICAgaWYgKHJlc3BvbnNlLnN0YXR1cyA9PT0gNDAxICYmICFyZWZyZXNoZWQgJiYgdGhpcy5yZWZyZXNoQ3JlZGVudGlhbHMpIHtcbiAgICAgICAgYXdhaXQgcmVzcG9uc2UuYm9keT8uY2FuY2VsKCk7XG4gICAgICAgIHRoaXMuY3JlZGVudGlhbHMgPSBhd2FpdCB0aGlzLnJlZnJlc2hDcmVkZW50aWFscygpO1xuICAgICAgICByZWZyZXNoZWQgPSB0cnVlO1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cbiAgICAgIGlmICghcmVzcG9uc2Uub2spIHRocm93IGF3YWl0IHJlc3BvbnNlRXJyb3IocmVzcG9uc2UpO1xuICAgICAgaWYgKCFyZXNwb25zZS5ib2R5KSB0aHJvdyBuZXcgT3BlbkFJUHJvdG9jb2xFcnJvcihcIk9wZW5BSSByZXNwb25zZSBoYWQgbm8gYm9keVwiKTtcblxuICAgICAgZm9yIGF3YWl0IChjb25zdCBldmVudCBvZiBub3JtYWxpemVPcGVuQUlTU0UocmVzcG9uc2UuYm9keSkpIHtcbiAgICAgICAgeWllbGQgZXZlbnQ7XG4gICAgICB9XG4gICAgICByZXR1cm47XG4gICAgfVxuICB9XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgT3BlbkFJRGlyZWN0Q2xpZW50T3B0aW9ucyBleHRlbmRzIE9wZW5BSUh0dHBzVHJhbnNwb3J0T3B0aW9ucyB7XG4gIHRyYW5zcG9ydD86IE9wZW5BSVJlc3BvbnNlc1RyYW5zcG9ydDtcbiAgdHJhbnNwb3J0S2luZD86IFwiaHR0cHNcIiB8IFwid2Vic29ja2V0XCI7XG4gIHdlYlNvY2tldEZhY3Rvcnk/OiBPcGVuQUlXZWJTb2NrZXRGYWN0b3J5O1xufVxuXG5leHBvcnQgY2xhc3MgT3BlbkFJRGlyZWN0Q2xpZW50IHtcbiAgcmVhZG9ubHkgdHJhbnNwb3J0OiBPcGVuQUlSZXNwb25zZXNUcmFuc3BvcnQ7XG4gIGltYWdlQ3JlZGVudGlhbHM6IE9wZW5BSURpcmVjdENyZWRlbnRpYWxzO1xuXG4gIGNvbnN0cnVjdG9yKHJlYWRvbmx5IG9wdGlvbnM6IE9wZW5BSURpcmVjdENsaWVudE9wdGlvbnMpIHtcbiAgICB0aGlzLmltYWdlQ3JlZGVudGlhbHMgPSBvcHRpb25zLmNyZWRlbnRpYWxzO1xuICAgIHRoaXMudHJhbnNwb3J0ID1cbiAgICAgIG9wdGlvbnMudHJhbnNwb3J0ID8/XG4gICAgICAob3B0aW9ucy50cmFuc3BvcnRLaW5kID09PSBcIndlYnNvY2tldFwiXG4gICAgICAgID8gbmV3IE9wZW5BSVdlYlNvY2tldFRyYW5zcG9ydChvcHRpb25zKVxuICAgICAgICA6IG5ldyBPcGVuQUlIdHRwc1RyYW5zcG9ydChvcHRpb25zKSk7XG4gIH1cblxuICByZXNwb25zZXMob3B0aW9uczogT3BlbkFJUmVzcG9uc2VzT3B0aW9ucywgc2lnbmFsPzogQWJvcnRTaWduYWwpOiBPcGVuQUlFdmVudFN0cmVhbSB7XG4gICAgaWYgKFxuICAgICAgb3B0aW9ucy5tb2RlbCA9PT0gXCJncHQtaW1hZ2UtMlwiIHx8XG4gICAgICAodHlwZW9mIG9wdGlvbnMuaW1hZ2VHZW5lcmF0aW9uID09PSBcIm9iamVjdFwiICYmXG4gICAgICAgIG9wdGlvbnMuaW1hZ2VHZW5lcmF0aW9uLmJhY2tncm91bmQgPT09IFwidHJhbnNwYXJlbnRcIilcbiAgICApIHtcbiAgICAgIHJldHVybiB0aGlzLnN0YW5kYWxvbmVJbWFnZXMob3B0aW9ucywgc2lnbmFsKTtcbiAgICB9XG4gICAgY29uc3QgY2xpZW50UmVxdWVzdElkID0gY3J5cHRvLnJhbmRvbVVVSUQoKTtcbiAgICBjb25zdCBhZmZpbml0eUlkID0gb3B0aW9ucy5wcm9tcHRDYWNoZUtleVxuICAgICAgPyBjYWNoZUFmZmluaXR5VXVpZChvcHRpb25zLnByb21wdENhY2hlS2V5KVxuICAgICAgOiBjbGllbnRSZXF1ZXN0SWQ7XG4gICAgcmV0dXJuIHRoaXMudHJhbnNwb3J0LnN0cmVhbSh7XG4gICAgICBib2R5OiBidWlsZE9wZW5BSVJlc3BvbnNlc1JlcXVlc3QoXG4gICAgICAgIG9wdGlvbnMucHJvbXB0Q2FjaGVLZXkgPyB7IC4uLm9wdGlvbnMsIHByb21wdENhY2hlS2V5OiBhZmZpbml0eUlkIH0gOiBvcHRpb25zLFxuICAgICAgKSxcbiAgICAgIHNpZ25hbCxcbiAgICAgIHNlc3Npb25JZDogYWZmaW5pdHlJZCxcbiAgICAgIC8vIHByb21wdENhY2hlS2V5IGlzIGFscmVhZHkgYSBvbmUtd2F5IFNESyBhZmZpbml0eSB2YWx1ZSwgbmV2ZXIgYSByYXcgc2Vzc2lvbktleS5cbiAgICAgIHRocmVhZElkOiBhZmZpbml0eUlkLFxuICAgICAgY2xpZW50UmVxdWVzdElkLFxuICAgIH0pO1xuICB9XG5cbiAgYXN5bmMgKnN0YW5kYWxvbmVJbWFnZXMoXG4gICAgb3B0aW9uczogT3BlbkFJUmVzcG9uc2VzT3B0aW9ucyxcbiAgICBzaWduYWw/OiBBYm9ydFNpZ25hbCxcbiAgKTogT3BlbkFJRXZlbnRTdHJlYW0ge1xuICAgIGNvbnN0IHJlcXVlc3QgPSBidWlsZFN0YW5kYWxvbmVJbWFnZVJlcXVlc3Qob3B0aW9ucyk7XG4gICAgY29uc3QgcmVxdWVzdElkID0gY3J5cHRvLnJhbmRvbVVVSUQoKTtcbiAgICBmb3IgKGxldCBhdHRlbXB0ID0gMDsgYXR0ZW1wdCA8IDI7IGF0dGVtcHQrKykge1xuICAgICAgc2lnbmFsPy50aHJvd0lmQWJvcnRlZCgpO1xuICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCAodGhpcy5vcHRpb25zLmZldGNoID8/IGZldGNoKShyZXF1ZXN0LnVybCwge1xuICAgICAgICBtZXRob2Q6IFwiUE9TVFwiLFxuICAgICAgICBoZWFkZXJzOiB7XG4gICAgICAgICAgLi4uYnVpbGRDb2RleElkZW50aXR5SGVhZGVycyhcbiAgICAgICAgICAgIHRoaXMuaW1hZ2VDcmVkZW50aWFscy5hY2Nlc3NUb2tlbixcbiAgICAgICAgICAgIHRoaXMuaW1hZ2VDcmVkZW50aWFscy5hY2NvdW50SWQsXG4gICAgICAgICAgKSxcbiAgICAgICAgICBBY2NlcHQ6IFwiYXBwbGljYXRpb24vanNvblwiLFxuICAgICAgICAgIFwieC1jb2RleC1pbWFnZS10dXJuLWlkXCI6IHJlcXVlc3RJZCxcbiAgICAgICAgfSxcbiAgICAgICAgYm9keTogSlNPTi5zdHJpbmdpZnkocmVxdWVzdC5ib2R5KSxcbiAgICAgICAgc2lnbmFsLFxuICAgICAgfSk7XG4gICAgICBpZiAocmVzcG9uc2Uuc3RhdHVzID09PSA0MDEgJiYgYXR0ZW1wdCA9PT0gMCAmJiB0aGlzLm9wdGlvbnMucmVmcmVzaENyZWRlbnRpYWxzKSB7XG4gICAgICAgIGF3YWl0IHJlc3BvbnNlLmJvZHk/LmNhbmNlbCgpO1xuICAgICAgICB0aGlzLmltYWdlQ3JlZGVudGlhbHMgPSBhd2FpdCB0aGlzLm9wdGlvbnMucmVmcmVzaENyZWRlbnRpYWxzKCk7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgaWYgKCFyZXNwb25zZS5vaykgdGhyb3cgYXdhaXQgcmVzcG9uc2VFcnJvcihyZXNwb25zZSk7XG4gICAgICBjb25zdCBpbWFnZXMgPSBhd2FpdCByZWFkU3RhbmRhbG9uZUltYWdlUmVzcG9uc2UoXG4gICAgICAgIHJlc3BvbnNlLFxuICAgICAgICB0eXBlb2Ygb3B0aW9ucy5pbWFnZUdlbmVyYXRpb24gPT09IFwib2JqZWN0XCIgJiZcbiAgICAgICAgICBvcHRpb25zLmltYWdlR2VuZXJhdGlvbi5iYWNrZ3JvdW5kID09PSBcInRyYW5zcGFyZW50XCIsXG4gICAgICApO1xuICAgICAgc2lnbmFsPy50aHJvd0lmQWJvcnRlZCgpO1xuICAgICAgeWllbGQqIGltYWdlcztcbiAgICAgIGNvbnN0IGZpcnN0SW1hZ2UgPSBpbWFnZXNbMF07XG4gICAgICB5aWVsZCB7XG4gICAgICAgIHR5cGU6IFwiY29tcGxldGVkXCIsXG4gICAgICAgIHJlc3BvbnNlSWQ6IHJlcXVlc3RJZCxcbiAgICAgICAgbW9kZWw6IGZpcnN0SW1hZ2U/LnR5cGUgPT09IFwiaW1hZ2VcIiA/IGZpcnN0SW1hZ2UuZ2VuZXJhdGlvbj8ubW9kZWwgOiBcImdwdC1pbWFnZS0yXCIsXG4gICAgICB9O1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgfVxuXG4gIGNsb3NlKCk6IHZvaWQge1xuICAgIHRoaXMudHJhbnNwb3J0LmNsb3NlPy4oKTtcbiAgfVxufVxuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7QUF3RUEsTUFBTSw4QkFBOEI7QUFFcEMsU0FBUyxhQUFhLEtBQXFCO0NBQ3pDLElBQUk7Q0FDSixJQUFJO0VBQ0YsU0FBUyxJQUFJLElBQUksR0FBRztDQUN0QixTQUFTLE9BQU87RUFDZCxNQUFNLElBQUksb0JBQW9CLGlDQUFpQyxPQUFPLEtBQUssR0FBRztDQUNoRjtDQUNBLE9BQU8sV0FBVyxPQUFPLGFBQWEsV0FBVyxTQUFTO0NBQzFELE9BQU8sT0FBTyxTQUFTO0FBQ3pCO0FBRUEsU0FBUyxZQUFZLE1BQXVCO0NBQzFDLElBQUksTUFBTSxRQUFRLElBQUks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
355
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3BlbmFpLWRpcmVjdC1jbGllbnQuanMiLCJuYW1lcyI6W10sInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3V0aWxzL3Byb3ZpZGVycy9vcGVuYWkvb3BlbmFpLWRpcmVjdC1jbGllbnQudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGNyeXB0byBmcm9tIFwibm9kZTpjcnlwdG9cIjtcblxuaW1wb3J0IFdzQ2xpZW50LCB7IHR5cGUgQ2xpZW50T3B0aW9ucywgdHlwZSBSYXdEYXRhIH0gZnJvbSBcIndzXCI7XG5cbmltcG9ydCB7XG4gIGJ1aWxkQ29kZXhJZGVudGl0eUhlYWRlcnMsXG4gIGJ1aWxkT3BlbkFJUmVzcG9uc2VzUmVxdWVzdCxcbiAgQ0hBVEdQVF9DT0RFWF9SRVNQT05TRVNfVVJMLFxuICBub3JtYWxpemVPcGVuQUlFdmVudCxcbiAgT3BlbkFJUHJvdG9jb2xFcnJvcixcbiAgdHlwZSBPcGVuQUlOb3JtYWxpemVkRXZlbnQsXG4gIHR5cGUgT3BlbkFJUmVzcG9uc2VzT3B0aW9ucyxcbiAgdHlwZSBPcGVuQUlSZXNwb25zZXNSZXF1ZXN0LFxufSBmcm9tIFwiLi9vcGVuYWktYmFja2VuZC1wcm90b2NvbFwiO1xuaW1wb3J0IHtcbiAgYnVpbGRTdGFuZGFsb25lSW1hZ2VSZXF1ZXN0LFxuICByZWFkU3RhbmRhbG9uZUltYWdlUmVzcG9uc2UsXG59IGZyb20gXCIuL29wZW5haS1pbWFnZS1nZW5lcmF0aW9uXCI7XG5pbXBvcnQgeyBub3JtYWxpemVPcGVuQUlTU0UsIHR5cGUgT3BlbkFJRXZlbnRTdHJlYW0gfSBmcm9tIFwiLi9vcGVuYWktc3NlXCI7XG5cbmV4cG9ydCBpbnRlcmZhY2UgT3BlbkFJRGlyZWN0Q3JlZGVudGlhbHMge1xuICBhY2Nlc3NUb2tlbjogc3RyaW5nO1xuICBhY2NvdW50SWQ6IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBPcGVuQUlUcmFuc3BvcnRSZXF1ZXN0IHtcbiAgYm9keTogT3BlbkFJUmVzcG9uc2VzUmVxdWVzdDtcbiAgc2lnbmFsPzogQWJvcnRTaWduYWw7XG4gIHNlc3Npb25JZDogc3RyaW5nO1xuICB0aHJlYWRJZDogc3RyaW5nO1xuICBjbGllbnRSZXF1ZXN0SWQ6IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBPcGVuQUlSZXNwb25zZXNUcmFuc3BvcnQge1xuICBzdHJlYW0ocmVxdWVzdDogT3BlbkFJVHJhbnNwb3J0UmVxdWVzdCk6IE9wZW5BSUV2ZW50U3RyZWFtO1xuICBjbG9zZT8oKTogdm9pZDtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBPcGVuQUlIdHRwc1RyYW5zcG9ydE9wdGlvbnMge1xuICBjcmVkZW50aWFsczogT3BlbkFJRGlyZWN0Q3JlZGVudGlhbHM7XG4gIGZldGNoPzogdHlwZW9mIGZldGNoO1xuICByZWZyZXNoQ3JlZGVudGlhbHM/OiAoKSA9PiBQcm9taXNlPE9wZW5BSURpcmVjdENyZWRlbnRpYWxzPjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBPcGVuQUlXZWJTb2NrZXRMaWtlIHtcbiAgb24oZXZlbnQ6IFwib3BlblwiLCBsaXN0ZW5lcjogKCkgPT4gdm9pZCk6IHRoaXM7XG4gIG9uKGV2ZW50OiBcIm1lc3NhZ2VcIiwgbGlzdGVuZXI6IChkYXRhOiBSYXdEYXRhLCBpc0JpbmFyeTogYm9vbGVhbikgPT4gdm9pZCk6IHRoaXM7XG4gIG9uKGV2ZW50OiBcImNsb3NlXCIsIGxpc3RlbmVyOiAoY29kZTogbnVtYmVyLCByZWFzb246IEJ1ZmZlcikgPT4gdm9pZCk6IHRoaXM7XG4gIG9uKGV2ZW50OiBcImVycm9yXCIsIGxpc3RlbmVyOiAoZXJyb3I6IEVycm9yKSA9PiB2b2lkKTogdGhpcztcbiAgb24oXG4gICAgZXZlbnQ6IFwidW5leHBlY3RlZC1yZXNwb25zZVwiLFxuICAgIGxpc3RlbmVyOiAocmVxdWVzdDogdW5rbm93biwgcmVzcG9uc2U6IHsgc3RhdHVzQ29kZT86IG51bWJlciB9KSA9PiB2b2lkLFxuICApOiB0aGlzO1xuICBvZmYoZXZlbnQ6IHN0cmluZywgbGlzdGVuZXI6ICguLi5hcmdzOiBuZXZlcltdKSA9PiB2b2lkKTogdGhpcztcbiAgc2VuZChkYXRhOiBzdHJpbmcsIGNhbGxiYWNrPzogKGVycm9yPzogRXJyb3IpID0+IHZvaWQpOiB2b2lkO1xuICBjbG9zZShjb2RlPzogbnVtYmVyLCByZWFzb24/OiBzdHJpbmcpOiB2b2lkO1xuICB0ZXJtaW5hdGUoKTogdm9pZDtcbn1cblxuZXhwb3J0IHR5cGUgT3BlbkFJV2ViU29ja2V0RmFjdG9yeSA9ICh1cmw6IHN0cmluZywgb3B0aW9uczogQ2xpZW50T3B0aW9ucykgPT4gT3BlbkFJV2ViU29ja2V0TGlrZTtcblxuZXhwb3J0IGludGVyZmFjZSBPcGVuQUlXZWJTb2NrZXRUcmFuc3BvcnRPcHRpb25zIGV4dGVuZHMgT3BlbkFJSHR0cHNUcmFuc3BvcnRPcHRpb25zIHtcbiAgd2ViU29ja2V0RmFjdG9yeT86IE9wZW5BSVdlYlNvY2tldEZhY3Rvcnk7XG59XG5cbnR5cGUgU29ja2V0UmVjb3JkID1cbiAgfCB7IGtpbmQ6IFwib3BlblwiIH1cbiAgfCB7IGtpbmQ6IFwibWVzc2FnZVwiOyBkYXRhOiBSYXdEYXRhOyBpc0JpbmFyeTogYm9vbGVhbiB9XG4gIHwgeyBraW5kOiBcImNsb3NlXCI7IGNvZGU6IG51bWJlcjsgcmVhc29uOiBzdHJpbmcgfVxuICB8IHsga2luZDogXCJlcnJvclwiOyBlcnJvcjogRXJyb3IgfVxuICB8IHsga2luZDogXCJyZWplY3RlZFwiOyBzdGF0dXM/OiBudW1iZXIgfTtcblxuY29uc3QgTUFYX0JVRkZFUkVEX1NPQ0tFVF9SRUNPUkRTID0gMTYwMDtcblxuZnVuY3Rpb24gd2Vic29ja2V0VXJsKHVybDogc3RyaW5nKTogc3RyaW5nIHtcbiAgbGV0IHBhcnNlZDogVVJMO1xuICB0cnkge1xuICAgIHBhcnNlZCA9IG5ldyBVUkwodXJsKTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICB0aHJvdyBuZXcgT3BlbkFJUHJvdG9jb2xFcnJvcihgSW52YWxpZCBPcGVuQUkgUmVzcG9uc2VzIFVSTDogJHtTdHJpbmcoZXJyb3IpfWApO1xuICB9XG4gIHBhcnNlZC5wcm90b2NvbCA9IHBhcnNlZC5wcm90b2NvbCA9PT0gXCJodHRwczpcIiA/IFwid3NzOlwiIDogXCJ3czpcIjtcbiAgcmV0dXJuIHBhcnNlZC50b1N0cmluZygpO1xufVxuXG5mdW5jdGlvbiByYXdEYXRhVGV4dChkYXRhOiBSYXdEYXRhKTogc3RyaW5nIHtcbiAgaWYgKEFycmF5LmlzQXJyYXkoZGF0YSkpIHJldHVybiBCdWZmZXIuY29uY2F0KGRhdGEpLnRvU3RyaW5nKCk7XG4gIGlmIChkYXRhIGluc3RhbmNlb2YgQXJyYXlCdWZmZXIpIHJldHVybiBCdWZmZXIuZnJvbShuZXcgVWludDhBcnJheShkYXRhKSkudG9TdHJpbmcoKTtcbiAgcmV0dXJuIEJ1ZmZlci5mcm9tKGRhdGEpLnRvU3RyaW5nKCk7XG59XG5cbmZ1bmN0aW9uIHNvY2tldEV2ZW50cyhzb2NrZXQ6IE9wZW5BSVdlYlNvY2tldExpa2UsIHNpZ25hbD86IEFib3J0U2lnbmFsKSB7XG4gIGNvbnN0IHJlY29yZHM6IFNvY2tldFJlY29yZFtdID0gW107XG4gIGNvbnN0IHdhaXRlcnM6IEFycmF5PChyZWNvcmQ6IFNvY2tldFJlY29yZCkgPT4gdm9pZD4gPSBbXTtcbiAgbGV0IGFjdGl2ZSA9IHRydWU7XG4gIGNvbnN0IHB1c2ggPSAocmVjb3JkOiBTb2NrZXRSZWNvcmQpID0+IHtcbiAgICBpZiAoIWFjdGl2ZSkgcmV0dXJuO1xuICAgIGNvbnN0IHdhaXRlciA9IHdhaXRlcnMuc2hpZnQoKTtcbiAgICBpZiAod2FpdGVyKSB3YWl0ZXIocmVjb3JkKTtcbiAgICBlbHNlIGlmIChyZWNvcmRzLmxlbmd0aCA8IE1BWF9CVUZGRVJFRF9TT0NLRVRfUkVDT1JEUykgcmVjb3Jkcy5wdXNoKHJlY29yZCk7XG4gICAgZWxzZSB7XG4gICAgICBhY3RpdmUgPSBmYWxzZTtcbiAgICAgIHJlY29yZHMubGVuZ3RoID0gMDtcbiAgICAgIHNvY2tldC50ZXJtaW5hdGUoKTtcbiAgICAgIGNvbnN0IG92ZXJmbG93ID0ge1xuICAgICAgICBraW5kOiBcImVycm9yXCIgYXMgY29uc3QsXG4gICAgICAgIGVycm9yOiBuZXcgT3BlbkFJUHJvdG9jb2xFcnJvcihcbiAgICAgICAgICBgT3BlbkFJIFdlYlNvY2tldCBleGNlZWRlZCB0aGUgJHtNQVhfQlVGRkVSRURfU09DS0VUX1JFQ09SRFN9LXJlY29yZCByZWNlaXZlIGJ1ZmZlcmAsXG4gICAgICAgICAgXCJ3ZWJzb2NrZXRfYmFja3ByZXNzdXJlXCIsXG4gICAgICAgICksXG4gICAgICB9O1xuICAgICAgY29uc3Qgb3ZlcmZsb3dXYWl0ZXIgPSB3YWl0ZXJzLnNoaWZ0KCk7XG4gICAgICBpZiAob3ZlcmZsb3dXYWl0ZXIpIG92ZXJmbG93V2FpdGVyKG92ZXJmbG93KTtcbiAgICAgIGVsc2UgcmVjb3Jkcy5wdXNoKG92ZXJmbG93KTtcbiAgICB9XG4gIH07XG4gIGNvbnN0IG9uT3BlbiA9ICgpID0+IHB1c2goeyBraW5kOiBcIm9wZW5cIiB9KTtcbiAgY29uc3Qgb25NZXNzYWdlID0gKGRhdGE6IFJhd0RhdGEsIGlzQmluYXJ5OiBib29sZWFuKSA9PiBwdXNoKHsga2luZDogXCJtZXNzYWdlXCIsIGRhdGEsIGlzQmluYXJ5IH0pO1xuICBjb25zdCBvbkNsb3NlID0gKGNvZGU6IG51bWJlciwgcmVhc29uOiBCdWZmZXIpID0+XG4gICAgcHVzaCh7IGtpbmQ6IFwiY2xvc2VcIiwgY29kZSwgcmVhc29uOiByZWFzb24udG9TdHJpbmcoKSB9KTtcbiAgY29uc3Qgb25FcnJvciA9IChlcnJvcjogRXJyb3IpID0+IHB1c2goeyBraW5kOiBcImVycm9yXCIsIGVycm9yIH0pO1xuICBjb25zdCBvblVuZXhwZWN0ZWRSZXNwb25zZSA9IChfcmVxdWVzdDogdW5rbm93biwgcmVzcG9uc2U6IHsgc3RhdHVzQ29kZT86IG51bWJlciB9KSA9PlxuICAgIHB1c2goeyBraW5kOiBcInJlamVjdGVkXCIsIHN0YXR1czogcmVzcG9uc2Uuc3RhdHVzQ29kZSB9KTtcbiAgc29ja2V0Lm9uKFwib3BlblwiLCBvbk9wZW4pO1xuICBzb2NrZXQub24oXCJtZXNzYWdlXCIsIG9uTWVzc2FnZSk7XG4gIHNvY2tldC5vbihcImNsb3NlXCIsIG9uQ2xvc2UpO1xuICBzb2NrZXQub24oXCJlcnJvclwiLCBvbkVycm9yKTtcbiAgc29ja2V0Lm9uKFwidW5leHBlY3RlZC1yZXNwb25zZVwiLCBvblVuZXhwZWN0ZWRSZXNwb25zZSk7XG4gIGNvbnN0IG9uQWJvcnQgPSAoKSA9PiB7XG4gICAgc29ja2V0LnRlcm1pbmF0ZSgpO1xuICAgIHB1c2goeyBraW5kOiBcImVycm9yXCIsIGVycm9yOiBhYm9ydEVycm9yKHNpZ25hbCkgfSk7XG4gIH07XG4gIHNpZ25hbD8uYWRkRXZlbnRMaXN0ZW5lcihcImFib3J0XCIsIG9uQWJvcnQsIHsgb25jZTogdHJ1ZSB9KTtcbiAgcmV0dXJuIHtcbiAgICBuZXh0OiAoKSA9PlxuICAgICAgcmVjb3Jkcy5sZW5ndGhcbiAgICAgICAgPyBQcm9taXNlLnJlc29sdmUocmVjb3Jkcy5zaGlmdCgpISlcbiAgICAgICAgOiBuZXcgUHJvbWlzZTxTb2NrZXRSZWNvcmQ+KChyZXNvbHZlKSA9PiB3YWl0ZXJzLnB1c2gocmVzb2x2ZSkpLFxuICAgIGNsZWFudXA6ICgpID0+IHtcbiAgICAgIGFjdGl2ZSA9IGZhbHNlO1xuICAgICAgc2lnbmFsPy5yZW1vdmVFdmVudExpc3RlbmVyKFwiYWJvcnRcIiwgb25BYm9ydCk7XG4gICAgICBzb2NrZXQub2ZmKFwib3BlblwiLCBvbk9wZW4pO1xuICAgICAgc29ja2V0Lm9mZihcIm1lc3NhZ2VcIiwgb25NZXNzYWdlKTtcbiAgICAgIHNvY2tldC5vZmYoXCJjbG9zZVwiLCBvbkNsb3NlKTtcbiAgICAgIC8vIGVycm9yIOumrOyKpOuEiOuKlCDrgqjquLTri6QoYWN0aXZlPWZhbHNl6528IHB1c2jripQgbm8tb3ApLiBDT05ORUNUSU5HIOyGjOy8k+ydmCB0ZXJtaW5hdGUoKeuKlFxuICAgICAgLy8g64uk7J2MIHRpY2vsl5AgZXJyb3LrpbwgZW1pdO2VmOuvgOuhnCwg65a87Ja0IOuRkOuptCBVbmhhbmRsZWQgJ2Vycm9yJ+uhnCDtlITroZzshLjsiqTqsIAg7KO964qU64ukLlxuICAgICAgc29ja2V0Lm9mZihcInVuZXhwZWN0ZWQtcmVzcG9uc2VcIiwgb25VbmV4cGVjdGVkUmVzcG9uc2UpO1xuICAgICAgcmVjb3Jkcy5sZW5ndGggPSAwO1xuICAgICAgY29uc3QgY2xvc2VkID0ge1xuICAgICAgICBraW5kOiBcImVycm9yXCIgYXMgY29uc3QsXG4gICAgICAgIGVycm9yOiBuZXcgT3BlbkFJUHJvdG9jb2xFcnJvcihcIk9wZW5BSSBXZWJTb2NrZXQgZXZlbnQgc3RyZWFtIHdhcyBjbG9zZWRcIiksXG4gICAgICB9O1xuICAgICAgd2FpdGVycy5zcGxpY2UoMCkuZm9yRWFjaCgod2FpdGVyKSA9PiB3YWl0ZXIoY2xvc2VkKSk7XG4gICAgfSxcbiAgICBkZXRhY2hBYm9ydDogKCkgPT4gc2lnbmFsPy5yZW1vdmVFdmVudExpc3RlbmVyKFwiYWJvcnRcIiwgb25BYm9ydCksXG4gIH07XG59XG5cbmZ1bmN0aW9uIGFib3J0RXJyb3Ioc2lnbmFsPzogQWJvcnRTaWduYWwpOiBFcnJvciB7XG4gIHJldHVybiBzaWduYWw/LnJlYXNvbiBpbnN0YW5jZW9mIEVycm9yXG4gICAgPyBzaWduYWwucmVhc29uXG4gICAgOiBuZXcgRE9NRXhjZXB0aW9uKFwiQWJvcnRlZFwiLCBcIkFib3J0RXJyb3JcIik7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIG5leHRQb29sZWRSZWNvcmQoXG4gIGV2ZW50czogUmV0dXJuVHlwZTx0eXBlb2Ygc29ja2V0RXZlbnRzPixcbiAgc29ja2V0OiBPcGVuQUlXZWJTb2NrZXRMaWtlLFxuICBzaWduYWw/OiBBYm9ydFNpZ25hbCxcbik6IFByb21pc2U8U29ja2V0UmVjb3JkPiB7XG4gIGlmICghc2lnbmFsKSByZXR1cm4gZXZlbnRzLm5leHQoKTtcbiAgaWYgKHNpZ25hbC5hYm9ydGVkKSB0aHJvdyBhYm9ydEVycm9yKHNpZ25hbCk7XG4gIHJldHVybiBuZXcgUHJvbWlzZTxTb2NrZXRSZWNvcmQ+KChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICBjb25zdCBvbkFib3J0ID0gKCkgPT4ge1xuICAgICAgc29ja2V0LnRlcm1pbmF0ZSgpO1xuICAgICAgcmVqZWN0KGFib3J0RXJyb3Ioc2lnbmFsKSk7XG4gICAgfTtcbiAgICBzaWduYWwuYWRkRXZlbnRMaXN0ZW5lcihcImFib3J0XCIsIG9uQWJvcnQsIHsgb25jZTogdHJ1ZSB9KTtcbiAgICB2b2lkIGV2ZW50c1xuICAgICAgLm5leHQoKVxuICAgICAgLnRoZW4ocmVzb2x2ZSwgcmVqZWN0KVxuICAgICAgLmZpbmFsbHkoKCkgPT4ge1xuICAgICAgICBzaWduYWwucmVtb3ZlRXZlbnRMaXN0ZW5lcihcImFib3J0XCIsIG9uQWJvcnQpO1xuICAgICAgfSk7XG4gIH0pO1xufVxuXG5mdW5jdGlvbiBjYWNoZUFmZmluaXR5VXVpZChrZXk6IHN0cmluZyk6IHN0cmluZyB7XG4gIGNvbnN0IGhleCA9IGNyeXB0by5jcmVhdGVIYXNoKFwic2hhMjU2XCIpLnVwZGF0ZShrZXkpLmRpZ2VzdChcImhleFwiKS5zbGljZSgwLCAzMikuc3BsaXQoXCJcIik7XG4gIGhleFsxMl0gPSBcIjRcIjtcbiAgaGV4WzE2XSA9ICgoTnVtYmVyLnBhcnNlSW50KGhleFsxNl0hLCAxNikgJiAweDMpIHwgMHg4KS50b1N0cmluZygxNik7XG4gIHJldHVybiBgJHtoZXguc2xpY2UoMCwgOCkuam9pbihcIlwiKX0tJHtoZXguc2xpY2UoOCwgMTIpLmpvaW4oXCJcIil9LSR7aGV4LnNsaWNlKDEyLCAxNikuam9pbihcIlwiKX0tJHtoZXguc2xpY2UoMTYsIDIwKS5qb2luKFwiXCIpfS0ke2hleC5zbGljZSgyMCkuam9pbihcIlwiKX1gO1xufVxuXG50eXBlIEFmZmluaXR5Q29ubmVjdGlvbiA9IHtcbiAgc29ja2V0OiBPcGVuQUlXZWJTb2NrZXRMaWtlO1xuICBldmVudHM6IFJldHVyblR5cGU8dHlwZW9mIHNvY2tldEV2ZW50cz47XG4gIGNsb3NlZD86IGJvb2xlYW47XG59O1xuXG5leHBvcnQgY2xhc3MgT3BlbkFJV2ViU29ja2V0VHJhbnNwb3J0IGltcGxlbWVudHMgT3BlbkFJUmVzcG9uc2VzVHJhbnNwb3J0IHtcbiAgc3RhdGljIHJlYWRvbmx5IE1BWF9BRkZJTklUWV9DT05ORUNUSU9OUyA9IDE2O1xuICBjcmVkZW50aWFsczogT3BlbkFJRGlyZWN0Q3JlZGVudGlhbHM7XG4gIHJlYWRvbmx5IHJlZnJlc2hDcmVkZW50aWFscz86ICgpID0+IFByb21pc2U8T3BlbkFJRGlyZWN0Q3JlZGVudGlhbHM+O1xuICByZWFkb25seSB3ZWJTb2NrZXRGYWN0b3J5OiBPcGVuQUlXZWJTb2NrZXRGYWN0b3J5O1xuICByZWFkb25seSBhZmZpbml0eUNvbm5lY3Rpb25zID0gbmV3IE1hcDxzdHJpbmcsIEFmZmluaXR5Q29ubmVjdGlvbj4oKTtcbiAgcmVhZG9ubHkgYnVzeUFmZmluaXRpZXMgPSBuZXcgU2V0PHN0cmluZz4oKTtcblxuICBjb25zdHJ1Y3RvcihvcHRpb25zOiBPcGVuQUlXZWJTb2NrZXRUcmFuc3BvcnRPcHRpb25zKSB7XG4gICAgdGhpcy5jcmVkZW50aWFscyA9IG9wdGlvbnMuY3JlZGVudGlhbHM7XG4gICAgdGhpcy5yZWZyZXNoQ3JlZGVudGlhbHMgPSBvcHRpb25zLnJlZnJlc2hDcmVkZW50aWFscztcbiAgICB0aGlzLndlYlNvY2tldEZhY3RvcnkgPVxuICAgICAgb3B0aW9ucy53ZWJTb2NrZXRGYWN0b3J5ID8/ICgodXJsLCB3c09wdGlvbnMpID0+IG5ldyBXc0NsaWVudCh1cmwsIHdzT3B0aW9ucykpO1xuICB9XG5cbiAgY2xvc2UoKTogdm9pZCB7XG4gICAgdGhpcy5hZmZpbml0eUNvbm5lY3Rpb25zLmZvckVhY2goKHsgc29ja2V0LCBldmVudHMgfSkgPT4ge1xuICAgICAgZXZlbnRzLmNsZWFudXAoKTtcbiAgICAgIHNvY2tldC5jbG9zZSgxMDAwLCBcInRyYW5zcG9ydCBjbG9zZWRcIik7XG4gICAgfSk7XG4gICAgdGhpcy5hZmZpbml0eUNvbm5lY3Rpb25zLmNsZWFyKCk7XG4gICAgdGhpcy5idXN5QWZmaW5pdGllcy5jbGVhcigpO1xuICB9XG5cbiAgLy8g7Jyg7Zy0IOyXsOqysOunjCDstpXstpztlZzri6QuIOyghOu2gCDsgqzsmqkg7KSR7J2066m0IGZhbHNl66W8IOuwmO2ZmO2VtCDsnbztmozshLEg7IaM7LyT7Jy866GcIOyymOumrO2VnOuLpC5cbiAgcmVtZW1iZXJBZmZpbml0eUNvbm5lY3Rpb24odGhyZWFkSWQ6IHN0cmluZywgY29ubmVjdGlvbjogQWZmaW5pdHlDb25uZWN0aW9uKTogYm9vbGVhbiB7XG4gICAgaWYgKFxuICAgICAgIXRoaXMuYWZmaW5pdHlDb25uZWN0aW9ucy5oYXModGhyZWFkSWQpICYmXG4gICAgICB0aGlzLmFmZmluaXR5Q29ubmVjdGlvbnMuc2l6ZSA+PSBPcGVuQUlXZWJTb2NrZXRUcmFuc3BvcnQuTUFYX0FGRklOSVRZX0NPTk5FQ1RJT05TXG4gICAgKSB7XG4gICAgICBjb25zdCBpZGxlS2V5ID0gWy4uLnRoaXMuYWZmaW5pdHlDb25uZWN0aW9ucy5rZXlzKCldLmZpbmQoXG4gICAgICAgIChrZXkpID0+ICF0aGlzLmJ1c3lBZmZpbml0aWVzLmhhcyhrZXkpLFxuICAgICAgKTtcbiAgICAgIGlmIChpZGxlS2V5ID09PSB1bmRlZmluZWQpIHJldHVybiBmYWxzZTtcbiAgICAgIGNvbnN0IGlkbGUgPSB0aGlzLmFmZmluaXR5Q29ubmVjdGlvbnMuZ2V0KGlkbGVLZXkpITtcbiAgICAgIGlkbGUuZXZlbnRzLmNsZWFudXAoKTtcbiAgICAgIGlkbGUuc29ja2V0LmNsb3NlKDEwMDAsIFwiYWZmaW5pdHkgY2FjaGUgZXZpY3RlZFwiKTtcbiAgICAgIHRoaXMuYWZmaW5pdHlDb25uZWN0aW9ucy5kZWxldGUoaWRsZUtleSk7XG4gICAgfVxuICAgIHRoaXMuYWZmaW5pdHlDb25uZWN0aW9ucy5zZXQodGhyZWFkSWQsIGNvbm5lY3Rpb24pO1xuICAgIC8vIOycoO2ctCDsg4Htg5zsl5DshJwgYmFja2VuZCDqsIAg64GK7J2AIOyGjOy8k+ydhCDri6TsnYwg7JqU7LKt7J20IOynkeyWtOuTpOyngCDslYrrj4TroZ0g7LqQ7Iuc7JeQ7IScIOygnOqxsO2VnOuLpC5cbiAgICBjb25zdCBkcm9wID0gKCkgPT4ge1xuICAgICAgY29ubmVjdGlvbi5jbG9zZWQgPSB0cnVlO1xuICAgICAgaWYgKHRoaXMuYnVzeUFmZmluaXRpZXMuaGFzKHRocmVhZElkKSkgcmV0dXJuO1xuICAgICAgaWYgKHRoaXMuYWZmaW5pdHlDb25uZWN0aW9ucy5nZXQodGhyZWFkSWQpICE9PSBjb25uZWN0aW9uKSByZXR1cm47XG4gICAgICB0aGlzLmFmZmluaXR5Q29ubmVjdGlvbnMuZGVsZXRlKHRocmVhZElkKTtcbiAgICAgIGNvbm5lY3Rpb24uZXZlbnRzLmNsZWFudXAoKTtcbiAgICB9O1xuICAgIGNvbm5lY3Rpb24uc29ja2V0Lm9uKFwiY2xvc2VcIiwgZHJvcCk7XG4gICAgY29ubmVjdGlvbi5zb2NrZXQub24oXCJlcnJvclwiLCBkcm9wKTtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIGFzeW5jICpzdHJlYW0ocmVxdWVzdDogT3BlbkFJVHJhbnNwb3J0UmVxdWVzdCk6IEFzeW5jR2VuZXJhdG9yPE9wZW5BSU5vcm1hbGl6ZWRFdmVudD4ge1xuICAgIGxldCByZWZyZXNoZWQgPSBmYWxzZTtcbiAgICB3aGlsZSAodHJ1ZSkge1xuICAgICAgaWYgKHJlcXVlc3Quc2lnbmFsPy5hYm9ydGVkKSB0aHJvdyBhYm9ydEVycm9yKHJlcXVlc3Quc2lnbmFsKTtcbiAgICAgIGNvbnN0IGhhc0FmZmluaXR5ID0gcmVxdWVzdC5ib2R5LnByb21wdF9jYWNoZV9rZXkgIT09IHVuZGVmaW5lZDtcbiAgICAgIGNvbnN0IHJldGFpbkNvbm5lY3Rpb24gPSBoYXNBZmZpbml0eSAmJiAhdGhpcy5idXN5QWZmaW5pdGllcy5oYXMocmVxdWVzdC50aHJlYWRJZCk7XG4gICAgICBpZiAocmV0YWluQ29ubmVjdGlvbikgdGhpcy5idXN5QWZmaW5pdGllcy5hZGQocmVxdWVzdC50aHJlYWRJZCk7XG4gICAgICBjb25zdCBlbnRyeSA9IHJldGFpbkNvbm5lY3Rpb24gPyB0aGlzLmFmZmluaXR5Q29ubmVjdGlvbnMuZ2V0KHJlcXVlc3QudGhyZWFkSWQpIDogdW5kZWZpbmVkO1xuICAgICAgaWYgKGVudHJ5Py5jbG9zZWQpIHtcbiAgICAgICAgdGhpcy5hZmZpbml0eUNvbm5lY3Rpb25zLmRlbGV0ZShyZXF1ZXN0LnRocmVhZElkKTtcbiAgICAgICAgZW50cnkuZXZlbnRzLmNsZWFudXAoKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IGNhY2hlZCA9IGVudHJ5Py5jbG9zZWQgPyB1bmRlZmluZWQgOiBlbnRyeTtcbiAgICAgIGxldCByZXRhaW5lZCA9IHJldGFpbkNvbm5lY3Rpb247XG4gICAgICBjb25zdCBzb2NrZXQgPVxuICAgICAgICBjYWNoZWQ/LnNvY2tldCA/P1xuICAgICAgICB0aGlzLndlYlNvY2tldEZhY3Rvcnkod2Vic29ja2V0VXJsKENIQVRHUFRfQ09ERVhfUkVTUE9OU0VTX1VSTCksIHtcbiAgICAgICAgICBoZWFkZXJzOiB7XG4gICAgICAgICAgICAuLi5idWlsZENvZGV4SWRlbnRpdHlIZWFkZXJzKHRoaXMuY3JlZGVudGlhbHMuYWNjZXNzVG9rZW4sIHRoaXMuY3JlZGVudGlhbHMuYWNjb3VudElkLCB7XG4gICAgICAgICAgICAgIHNlc3Npb25JZDogcmVxdWVzdC5zZXNzaW9uSWQsXG4gICAgICAgICAgICAgIHRocmVhZElkOiByZXF1ZXN0LnRocmVhZElkLFxuICAgICAgICAgICAgICBjbGllbnRSZXF1ZXN0SWQ6IHJlcXVlc3QuY2xpZW50UmVxdWVzdElkLFxuICAgICAgICAgICAgfSksXG4gICAgICAgICAgICBcIk9wZW5BSS1CZXRhXCI6IFwicmVzcG9uc2VzX3dlYnNvY2tldHM9MjAyNi0wMi0wNlwiLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0pO1xuICAgICAgY29uc3QgZXZlbnRzID0gY2FjaGVkPy5ldmVudHMgPz8gc29ja2V0RXZlbnRzKHNvY2tldCwgcmVxdWVzdC5zaWduYWwpO1xuICAgICAgbGV0IGNvbXBsZXRlZCA9IGZhbHNlO1xuICAgICAgdHJ5IHtcbiAgICAgICAgaWYgKCFjYWNoZWQpIHtcbiAgICAgICAgICBjb25zdCBoYW5kc2hha2UgPSBhd2FpdCBldmVudHMubmV4dCgpO1xuICAgICAgICAgIGlmIChcbiAgICAgICAgICAgIGhhbmRzaGFrZS5raW5kID09PSBcInJlamVjdGVkXCIgJiZcbiAgICAgICAgICAgIGhhbmRzaGFrZS5zdGF0dXMgPT09IDQwMSAmJlxuICAgICAgICAgICAgIXJlZnJlc2hlZCAmJlxuICAgICAgICAgICAgdGhpcy5yZWZyZXNoQ3JlZGVudGlhbHNcbiAgICAgICAgICApIHtcbiAgICAgICAgICAgIHNvY2tldC50ZXJtaW5hdGUoKTtcbiAgICAgICAgICAgIHRoaXMuY3JlZGVudGlhbHMgPSBhd2FpdCB0aGlzLnJlZnJlc2hDcmVkZW50aWFscygpO1xuICAgICAgICAgICAgcmVmcmVzaGVkID0gdHJ1ZTtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAoaGFuZHNoYWtlLmtpbmQgPT09IFwicmVqZWN0ZWRcIikge1xuICAgICAgICAgICAgdGhyb3cgbmV3IE9wZW5BSVByb3RvY29sRXJyb3IoXG4gICAgICAgICAgICAgIGBPcGVuQUkgV2ViU29ja2V0IGhhbmRzaGFrZSByZWplY3RlZCR7aGFuZHNoYWtlLnN0YXR1cyA/IGAgd2l0aCBIVFRQICR7aGFuZHNoYWtlLnN0YXR1c31gIDogXCJcIn1gLFxuICAgICAgICAgICAgICB1bmRlZmluZWQsXG4gICAgICAgICAgICAgIGhhbmRzaGFrZS5zdGF0dXMsXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAoaGFuZHNoYWtlLmtpbmQgPT09IFwiZXJyb3JcIikgdGhyb3cgaGFuZHNoYWtlLmVycm9yO1xuICAgICAgICAgIGlmIChoYW5kc2hha2Uua2luZCAhPT0gXCJvcGVuXCIpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBPcGVuQUlQcm90b2NvbEVycm9yKFwiT3BlbkFJIFdlYlNvY2tldCBjbG9zZWQgYmVmb3JlIHRoZSBoYW5kc2hha2UgY29tcGxldGVkXCIpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAocmV0YWluQ29ubmVjdGlvbikge1xuICAgICAgICAgICAgcmV0YWluZWQgPSB0aGlzLnJlbWVtYmVyQWZmaW5pdHlDb25uZWN0aW9uKHJlcXVlc3QudGhyZWFkSWQsIHsgc29ja2V0LCBldmVudHMgfSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgYXdhaXQgbmV3IFByb21pc2U8dm9pZD4oKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICAgIHNvY2tldC5zZW5kKEpTT04uc3RyaW5naWZ5KHsgdHlwZTogXCJyZXNwb25zZS5jcmVhdGVcIiwgLi4ucmVxdWVzdC5ib2R5IH0pLCAoZXJyb3IpID0+XG4gICAgICAgICAgICBlcnJvciA/IHJlamVjdChlcnJvcikgOiByZXNvbHZlKCksXG4gICAgICAgICAgKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgd2hpbGUgKHRydWUpIHtcbiAgICAgICAgICBjb25zdCByZWNvcmQgPSBjYWNoZWRcbiAgICAgICAgICAgID8gYXdhaXQgbmV4dFBvb2xlZFJlY29yZChldmVudHMsIHNvY2tldCwgcmVxdWVzdC5zaWduYWwpXG4gICAgICAgICAgICA6IGF3YWl0IGV2ZW50cy5uZXh0KCk7XG4gICAgICAgICAgaWYgKHJlY29yZC5raW5kID09PSBcIm1lc3NhZ2VcIikge1xuICAgICAgICAgICAgaWYgKHJlY29yZC5pc0JpbmFyeSkge1xuICAgICAgICAgICAgICB0aHJvdyBuZXcgT3BlbkFJUHJvdG9jb2xFcnJvcihcIk9wZW5BSSBXZWJTb2NrZXQgc2VudCBhbiB1bmV4cGVjdGVkIGJpbmFyeSBtZXNzYWdlXCIpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgbGV0IHJhdzogdW5rbm93bjtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgIHJhdyA9IEpTT04ucGFyc2UocmF3RGF0YVRleHQocmVjb3JkLmRhdGEpKTtcbiAgICAgICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgICAgICB0aHJvdyBuZXcgT3BlbkFJUHJvdG9jb2xFcnJvcihcIk9wZW5BSSBXZWJTb2NrZXQgc2VudCBpbnZhbGlkIEpTT05cIik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zdCBldmVudCA9IG5vcm1hbGl6ZU9wZW5BSUV2ZW50KHJhdyk7XG4gICAgICAgICAgICBpZiAoIWV2ZW50KSBjb250aW51ZTtcbiAgICAgICAgICAgIGlmIChldmVudC50eXBlID09PSBcImNvbXBsZXRlZFwiKSB7XG4gICAgICAgICAgICAgIGNvbXBsZXRlZCA9IHRydWU7XG4gICAgICAgICAgICAgIGlmIChyZXRhaW5lZCkgZXZlbnRzLmRldGFjaEFib3J0KCk7XG4gICAgICAgICAgICAgIGVsc2Ugc29ja2V0LmNsb3NlKDEwMDAsIFwicmVzcG9uc2UgY29tcGxldGVkXCIpO1xuICAgICAgICAgICAgICB5aWVsZCBldmVudDtcbiAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgeWllbGQgZXZlbnQ7XG4gICAgICAgICAgICBpZiAoZXZlbnQudHlwZSA9PT0gXCJlcnJvclwiKSB0aHJvdyBldmVudC5lcnJvcjtcbiAgICAgICAgICB9IGVsc2UgaWYgKHJlY29yZC5raW5kID09PSBcImVycm9yXCIpIHtcbiAgICAgICAgICAgIHRocm93IHJlY29yZC5lcnJvcjtcbiAgICAgICAgICB9IGVsc2UgaWYgKHJlY29yZC5raW5kID09PSBcImNsb3NlXCIpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBPcGVuQUlQcm90b2NvbEVycm9yKFxuICAgICAgICAgICAgICBgT3BlbkFJIFdlYlNvY2tldCBjbG9zZWQgYmVmb3JlIGEgdGVybWluYWwgcmVzcG9uc2UgZXZlbnQgKCR7cmVjb3JkLmNvZGV9JHtyZWNvcmQucmVhc29uID8gYDogJHtyZWNvcmQucmVhc29ufWAgOiBcIlwifSlgLFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhyb3cgbmV3IE9wZW5BSVByb3RvY29sRXJyb3IoXCJPcGVuQUkgV2ViU29ja2V0IGVtaXR0ZWQgYW4gdW5leHBlY3RlZCBoYW5kc2hha2UgZXZlbnRcIik7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9IGZpbmFsbHkge1xuICAgICAgICBpZiAoIWNvbXBsZXRlZCB8fCAhcmV0YWluZWQpIHtcbiAgICAgICAgICBpZiAocmV0YWluZWQpIHRoaXMuYWZmaW5pdHlDb25uZWN0aW9ucy5kZWxldGUocmVxdWVzdC50aHJlYWRJZCk7XG4gICAgICAgICAgZXZlbnRzLmNsZWFudXAoKTtcbiAgICAgICAgICBpZiAoIWNvbXBsZXRlZCkgc29ja2V0LnRlcm1pbmF0ZSgpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChyZXRhaW5Db25uZWN0aW9uKSB0aGlzLmJ1c3lBZmZpbml0aWVzLmRlbGV0ZShyZXF1ZXN0LnRocmVhZElkKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cbn1cblxuYXN5bmMgZnVuY3Rpb24gcmVzcG9uc2VFcnJvcihyZXNwb25zZTogUmVzcG9uc2UpOiBQcm9taXNlPE9wZW5BSVByb3RvY29sRXJyb3I+IHtcbiAgY29uc3QgdGV4dCA9IGF3YWl0IHJlc3BvbnNlLnRleHQoKS5jYXRjaCgoKSA9PiBcIlwiKTtcbiAgbGV0IG1lc3NhZ2UgPSB0ZXh0IHx8IHJlc3BvbnNlLnN0YXR1c1RleHQgfHwgYEhUVFAgJHtyZXNwb25zZS5zdGF0dXN9YDtcbiAgbGV0IGNvZGU6IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgdHJ5IHtcbiAgICBjb25zdCBwYXJzZWQgPSBKU09OLnBhcnNlKHRleHQpIGFzIHtcbiAgICAgIGVycm9yPzogeyBtZXNzYWdlPzogc3RyaW5nOyBjb2RlPzogc3RyaW5nIH0gfCBzdHJpbmc7XG4gICAgICBtZXNzYWdlPzogc3RyaW5nO1xuICAgICAgY29kZT86IHN0cmluZztcbiAgICB9O1xuICAgIGNvbnN0IGVycm9yID0gcGFyc2VkLmVycm9yO1xuICAgIG1lc3NhZ2UgPVxuICAgICAgKHR5cGVvZiBlcnJvciA9PT0gXCJvYmplY3RcIiA/IGVycm9yLm1lc3NhZ2UgOiB1bmRlZmluZWQpID8/XG4gICAgICBwYXJzZWQubWVzc2FnZSA/P1xuICAgICAgKHR5cGVvZiBlcnJvciA9PT0gXCJzdHJpbmdcIiA/IGVycm9yIDogbWVzc2FnZSk7XG4gICAgY29kZSA9ICh0eXBlb2YgZXJyb3IgPT09IFwib2JqZWN0XCIgPyBlcnJvci5jb2RlIDogdW5kZWZpbmVkKSA/PyBwYXJzZWQuY29kZTtcbiAgfSBjYXRjaCB7XG4gICAgY29kZSA9IHVuZGVmaW5lZDtcbiAgfVxuICByZXR1cm4gbmV3IE9wZW5BSVByb3RvY29sRXJyb3IobWVzc2FnZSwgY29kZSwgcmVzcG9uc2Uuc3RhdHVzKTtcbn1cblxuZXhwb3J0IGNsYXNzIE9wZW5BSUh0dHBzVHJhbnNwb3J0IGltcGxlbWVudHMgT3BlbkFJUmVzcG9uc2VzVHJhbnNwb3J0IHtcbiAgY3JlZGVudGlhbHM6IE9wZW5BSURpcmVjdENyZWRlbnRpYWxzO1xuICByZWFkb25seSBmZXRjaEltcGw6IHR5cGVvZiBmZXRjaDtcbiAgcmVhZG9ubHkgcmVmcmVzaENyZWRlbnRpYWxzPzogKCkgPT4gUHJvbWlzZTxPcGVuQUlEaXJlY3RDcmVkZW50aWFscz47XG5cbiAgY29uc3RydWN0b3Iob3B0aW9uczogT3BlbkFJSHR0cHNUcmFuc3BvcnRPcHRpb25zKSB7XG4gICAgdGhpcy5jcmVkZW50aWFscyA9IG9wdGlvbnMuY3JlZGVudGlhbHM7XG4gICAgdGhpcy5mZXRjaEltcGwgPSBvcHRpb25zLmZldGNoID8/IGZldGNoO1xuICAgIHRoaXMucmVmcmVzaENyZWRlbnRpYWxzID0gb3B0aW9ucy5yZWZyZXNoQ3JlZGVudGlhbHM7XG4gIH1cblxuICBhc3luYyAqc3RyZWFtKHJlcXVlc3Q6IE9wZW5BSVRyYW5zcG9ydFJlcXVlc3QpOiBBc3luY0dlbmVyYXRvcjxPcGVuQUlOb3JtYWxpemVkRXZlbnQ+IHtcbiAgICBsZXQgcmVmcmVzaGVkID0gZmFsc2U7XG5cbiAgICB3aGlsZSAodHJ1ZSkge1xuICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCB0aGlzLmZldGNoSW1wbChDSEFUR1BUX0NPREVYX1JFU1BPTlNFU19VUkwsIHtcbiAgICAgICAgbWV0aG9kOiBcIlBPU1RcIixcbiAgICAgICAgaGVhZGVyczogYnVpbGRDb2RleElkZW50aXR5SGVhZGVycyhcbiAgICAgICAgICB0aGlzLmNyZWRlbnRpYWxzLmFjY2Vzc1Rva2VuLFxuICAgICAgICAgIHRoaXMuY3JlZGVudGlhbHMuYWNjb3VudElkLFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIHNlc3Npb25JZDogcmVxdWVzdC5zZXNzaW9uSWQsXG4gICAgICAgICAgICB0aHJlYWRJZDogcmVxdWVzdC50aHJlYWRJZCxcbiAgICAgICAgICAgIGNsaWVudFJlcXVlc3RJZDogcmVxdWVzdC5jbGllbnRSZXF1ZXN0SWQsXG4gICAgICAgICAgfSxcbiAgICAgICAgKSxcbiAgICAgICAgYm9keTogSlNPTi5zdHJpbmdpZnkocmVxdWVzdC5ib2R5KSxcbiAgICAgICAgc2lnbmFsOiByZXF1ZXN0LnNpZ25hbCxcbiAgICAgIH0pO1xuXG4gICAgICBpZiAocmVzcG9uc2Uuc3RhdHVzID09PSA0MDEgJiYgIXJlZnJlc2hlZCAmJiB0aGlzLnJlZnJlc2hDcmVkZW50aWFscykge1xuICAgICAgICBhd2FpdCByZXNwb25zZS5ib2R5Py5jYW5jZWwoKTtcbiAgICAgICAgdGhpcy5jcmVkZW50aWFscyA9IGF3YWl0IHRoaXMucmVmcmVzaENyZWRlbnRpYWxzKCk7XG4gICAgICAgIHJlZnJlc2hlZCA9IHRydWU7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgaWYgKCFyZXNwb25zZS5vaykgdGhyb3cgYXdhaXQgcmVzcG9uc2VFcnJvcihyZXNwb25zZSk7XG4gICAgICBpZiAoIXJlc3BvbnNlLmJvZHkpIHRocm93IG5ldyBPcGVuQUlQcm90b2NvbEVycm9yKFwiT3BlbkFJIHJlc3BvbnNlIGhhZCBubyBib2R5XCIpO1xuXG4gICAgICBmb3IgYXdhaXQgKGNvbnN0IGV2ZW50IG9mIG5vcm1hbGl6ZU9wZW5BSVNTRShyZXNwb25zZS5ib2R5KSkge1xuICAgICAgICB5aWVsZCBldmVudDtcbiAgICAgIH1cbiAgICAgIHJldHVybjtcbiAgICB9XG4gIH1cbn1cblxuZXhwb3J0IGludGVyZmFjZSBPcGVuQUlEaXJlY3RDbGllbnRPcHRpb25zIGV4dGVuZHMgT3BlbkFJSHR0cHNUcmFuc3BvcnRPcHRpb25zIHtcbiAgdHJhbnNwb3J0PzogT3BlbkFJUmVzcG9uc2VzVHJhbnNwb3J0O1xuICB0cmFuc3BvcnRLaW5kPzogXCJodHRwc1wiIHwgXCJ3ZWJzb2NrZXRcIjtcbiAgd2ViU29ja2V0RmFjdG9yeT86IE9wZW5BSVdlYlNvY2tldEZhY3Rvcnk7XG59XG5cbmV4cG9ydCBjbGFzcyBPcGVuQUlEaXJlY3RDbGllbnQge1xuICByZWFkb25seSB0cmFuc3BvcnQ6IE9wZW5BSVJlc3BvbnNlc1RyYW5zcG9ydDtcbiAgaW1hZ2VDcmVkZW50aWFsczogT3BlbkFJRGlyZWN0Q3JlZGVudGlhbHM7XG5cbiAgY29uc3RydWN0b3IocmVhZG9ubHkgb3B0aW9uczogT3BlbkFJRGlyZWN0Q2xpZW50T3B0aW9ucykge1xuICAgIHRoaXMuaW1hZ2VDcmVkZW50aWFscyA9IG9wdGlvbnMuY3JlZGVudGlhbHM7XG4gICAgdGhpcy50cmFuc3BvcnQgPVxuICAgICAgb3B0aW9ucy50cmFuc3BvcnQgPz9cbiAgICAgIChvcHRpb25zLnRyYW5zcG9ydEtpbmQgPT09IFwid2Vic29ja2V0XCJcbiAgICAgICAgPyBuZXcgT3BlbkFJV2ViU29ja2V0VHJhbnNwb3J0KG9wdGlvbnMpXG4gICAgICAgIDogbmV3IE9wZW5BSUh0dHBzVHJhbnNwb3J0KG9wdGlvbnMpKTtcbiAgfVxuXG4gIHJlc3BvbnNlcyhvcHRpb25zOiBPcGVuQUlSZXNwb25zZXNPcHRpb25zLCBzaWduYWw/OiBBYm9ydFNpZ25hbCk6IE9wZW5BSUV2ZW50U3RyZWFtIHtcbiAgICBpZiAoXG4gICAgICBvcHRpb25zLm1vZGVsID09PSBcImdwdC1pbWFnZS0yXCIgfHxcbiAgICAgICh0eXBlb2Ygb3B0aW9ucy5pbWFnZUdlbmVyYXRpb24gPT09IFwib2JqZWN0XCIgJiZcbiAgICAgICAgb3B0aW9ucy5pbWFnZUdlbmVyYXRpb24uYmFja2dyb3VuZCA9PT0gXCJ0cmFuc3BhcmVudFwiKVxuICAgICkge1xuICAgICAgcmV0dXJuIHRoaXMuc3RhbmRhbG9uZUltYWdlcyhvcHRpb25zLCBzaWduYWwpO1xuICAgIH1cbiAgICBjb25zdCBjbGllbnRSZXF1ZXN0SWQgPSBjcnlwdG8ucmFuZG9tVVVJRCgpO1xuICAgIGNvbnN0IGFmZmluaXR5SWQgPSBvcHRpb25zLnByb21wdENhY2hlS2V5XG4gICAgICA/IGNhY2hlQWZmaW5pdHlVdWlkKG9wdGlvbnMucHJvbXB0Q2FjaGVLZXkpXG4gICAgICA6IGNsaWVudFJlcXVlc3RJZDtcbiAgICByZXR1cm4gdGhpcy50cmFuc3BvcnQuc3RyZWFtKHtcbiAgICAgIGJvZHk6IGJ1aWxkT3BlbkFJUmVzcG9uc2VzUmVxdWVzdChcbiAgICAgICAgb3B0aW9ucy5wcm9tcHRDYWNoZUtleSA/IHsgLi4ub3B0aW9ucywgcHJvbXB0Q2FjaGVLZXk6IGFmZmluaXR5SWQgfSA6IG9wdGlvbnMsXG4gICAgICApLFxuICAgICAgc2lnbmFsLFxuICAgICAgc2Vzc2lvbklkOiBhZmZpbml0eUlkLFxuICAgICAgLy8gcHJvbXB0Q2FjaGVLZXkgaXMgYWxyZWFkeSBhIG9uZS13YXkgU0RLIGFmZmluaXR5IHZhbHVlLCBuZXZlciBhIHJhdyBzZXNzaW9uS2V5LlxuICAgICAgdGhyZWFkSWQ6IGFmZmluaXR5SWQsXG4gICAgICBjbGllbnRSZXF1ZXN0SWQsXG4gICAgfSk7XG4gIH1cblxuICBhc3luYyAqc3RhbmRhbG9uZUltYWdlcyhcbiAgICBvcHRpb25zOiBPcGVuQUlSZXNwb25zZXNPcHRpb25zLFxuICAgIHNpZ25hbD86IEFib3J0U2lnbmFsLFxuICApOiBPcGVuQUlFdmVudFN0cmVhbSB7XG4gICAgY29uc3QgcmVxdWVzdCA9IGJ1aWxkU3RhbmRhbG9uZUltYWdlUmVxdWVzdChvcHRpb25zKTtcbiAgICBjb25zdCByZXF1ZXN0SWQgPSBjcnlwdG8ucmFuZG9tVVVJRCgpO1xuICAgIGZvciAobGV0IGF0dGVtcHQgPSAwOyBhdHRlbXB0IDwgMjsgYXR0ZW1wdCsrKSB7XG4gICAgICBzaWduYWw/LnRocm93SWZBYm9ydGVkKCk7XG4gICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0ICh0aGlzLm9wdGlvbnMuZmV0Y2ggPz8gZmV0Y2gpKHJlcXVlc3QudXJsLCB7XG4gICAgICAgIG1ldGhvZDogXCJQT1NUXCIsXG4gICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAuLi5idWlsZENvZGV4SWRlbnRpdHlIZWFkZXJzKFxuICAgICAgICAgICAgdGhpcy5pbWFnZUNyZWRlbnRpYWxzLmFjY2Vzc1Rva2VuLFxuICAgICAgICAgICAgdGhpcy5pbWFnZUNyZWRlbnRpYWxzLmFjY291bnRJZCxcbiAgICAgICAgICApLFxuICAgICAgICAgIEFjY2VwdDogXCJhcHBsaWNhdGlvbi9qc29uXCIsXG4gICAgICAgICAgXCJ4LWNvZGV4LWltYWdlLXR1cm4taWRcIjogcmVxdWVzdElkLFxuICAgICAgICB9LFxuICAgICAgICBib2R5OiBKU09OLnN0cmluZ2lmeShyZXF1ZXN0LmJvZHkpLFxuICAgICAgICBzaWduYWwsXG4gICAgICB9KTtcbiAgICAgIGlmIChyZXNwb25zZS5zdGF0dXMgPT09IDQwMSAmJiBhdHRlbXB0ID09PSAwICYmIHRoaXMub3B0aW9ucy5yZWZyZXNoQ3JlZGVudGlhbHMpIHtcbiAgICAgICAgYXdhaXQgcmVzcG9uc2UuYm9keT8uY2FuY2VsKCk7XG4gICAgICAgIHRoaXMuaW1hZ2VDcmVkZW50aWFscyA9IGF3YWl0IHRoaXMub3B0aW9ucy5yZWZyZXNoQ3JlZGVudGlhbHMoKTtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG4gICAgICBpZiAoIXJlc3BvbnNlLm9rKSB0aHJvdyBhd2FpdCByZXNwb25zZUVycm9yKHJlc3BvbnNlKTtcbiAgICAgIGNvbnN0IGltYWdlcyA9IGF3YWl0IHJlYWRTdGFuZGFsb25lSW1hZ2VSZXNwb25zZShcbiAgICAgICAgcmVzcG9uc2UsXG4gICAgICAgIHR5cGVvZiBvcHRpb25zLmltYWdlR2VuZXJhdGlvbiA9PT0gXCJvYmplY3RcIiAmJlxuICAgICAgICAgIG9wdGlvbnMuaW1hZ2VHZW5lcmF0aW9uLmJhY2tncm91bmQgPT09IFwidHJhbnNwYXJlbnRcIixcbiAgICAgICk7XG4gICAgICBzaWduYWw/LnRocm93SWZBYm9ydGVkKCk7XG4gICAgICB5aWVsZCogaW1hZ2VzO1xuICAgICAgY29uc3QgZmlyc3RJbWFnZSA9IGltYWdlc1swXTtcbiAgICAgIHlpZWxkIHtcbiAgICAgICAgdHlwZTogXCJjb21wbGV0ZWRcIixcbiAgICAgICAgcmVzcG9uc2VJZDogcmVxdWVzdElkLFxuICAgICAgICBtb2RlbDogZmlyc3RJbWFnZT8udHlwZSA9PT0gXCJpbWFnZVwiID8gZmlyc3RJbWFnZS5nZW5lcmF0aW9uPy5tb2RlbCA6IFwiZ3B0LWltYWdlLTJcIixcbiAgICAgIH07XG4gICAgICByZXR1cm47XG4gICAgfVxuICB9XG5cbiAgY2xvc2UoKTogdm9pZCB7XG4gICAgdGhpcy50cmFuc3BvcnQuY2xvc2U/LigpO1xuICB9XG59XG4iXSwibWFwcGluZ3MiOiI7Ozs7OztBQXdFQSxNQUFNLDhCQUE4QjtBQUVwQyxTQUFTLGFBQWEsS0FBcUI7Q0FDekMsSUFBSTtDQUNKLElBQUk7RUFDRixTQUFTLElBQUksSUFBSSxH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
@@ -104,6 +104,7 @@ describe("qgrid run lifecycle start", () => {
104
104
  system_prompt: "system",
105
105
  requested_model_name: "openai/gpt-5-codex",
106
106
  effort: undefined,
107
+ service_tier: undefined,
107
108
  project_name: "project",
108
109
  history: [{ type: "message", role: "user", content: "earlier" }],
109
110
  is_image_generation: undefined,
@@ -111,6 +112,16 @@ describe("qgrid run lifecycle start", () => {
111
112
  });
112
113
  });
113
114
 
115
+ it.each([
116
+ ["openai/gpt-6-sol", "fast", "fast"],
117
+ ["openai/gpt-6-sol", "flex", "flex"],
118
+ ["openai/gpt-6-sol", undefined, undefined],
119
+ ["anthropic/claude-sonnet-5-5", "fast", undefined],
120
+ ] as const)("logs service tier for %s with %s", async (model, serviceTier, expected) => {
121
+ await beforeQuery({ prompt: "hi", model, serviceTier });
122
+ expect(createRunMock).toHaveBeenCalledWith(expect.objectContaining({ service_tier: expected }));
123
+ });
124
+
114
125
  it.each([false, true, undefined])("does not log ignored effort when thinking is %s", async (thinking) => {
115
126
  await beforeQuery({ prompt: "hi", model: "openai/gpt-6-sol", thinking, effort: "high" });
116
127
  expect(createRunMock).toHaveBeenCalledWith(expect.objectContaining({
@@ -270,6 +281,13 @@ describe("qgrid run lifecycle TTFT", () => {
270
281
  );
271
282
  });
272
283
 
284
+ it.each(["fast", "flex", undefined] as const)("records the final turn service tier: %s", async (serviceTier) => {
285
+ await afterQuery(10, 2, { prompt: "hi", model: "openai/gpt-6-sol", serviceTier }, queryOutput());
286
+ expect(finishRunMock).toHaveBeenCalledWith(10, expect.objectContaining({
287
+ service_tier: serviceTier ?? null,
288
+ }));
289
+ });
290
+
273
291
  it("persists an immediate structured final answer as JSON text", async () => {
274
292
  await afterQuery(
275
293
  10,
@@ -89,6 +89,7 @@ export async function beforeQuery(args: QueryInput): Promise<{
89
89
  system_prompt: args.system,
90
90
  requested_model_name: args.model,
91
91
  effort: args.thinking === false ? undefined : args.effort,
92
+ service_tier: args.model?.startsWith("openai/") ? args.serviceTier : undefined,
92
93
  project_name: args.projectName,
93
94
  history: filterHistoryForStorage(args.history),
94
95
  tools: args.tools?.length ? args.tools : undefined,
@@ -197,6 +198,7 @@ export async function afterQuery(
197
198
  requested_model_name: requestedModelName,
198
199
  model_name: servedModelName,
199
200
  fallback_count: agg.fallback_count,
201
+ service_tier: args.model?.startsWith("openai/") ? (args.serviceTier ?? null) : null,
200
202
  cost_usd: agg.cost_usd,
201
203
  cost_source: agg.cost_source,
202
204
  image_cost_usd: imageCostMicroUsd,
@@ -38,6 +38,29 @@ function deeplyNestedOutputSchema(depth: number): string {
38
38
  }
39
39
 
40
40
  describe("QgridDispatcherClass", () => {
41
+ it.each([false, true])("applies Fast pricing to OpenAI query (stream=%s)", async (stream) => {
42
+ const dispatcher = new QgridDispatcherClass();
43
+ const result = providerResult({
44
+ model: "gpt-6.1-sol",
45
+ usage: { totalTokens: 2000, inputTokens: 1000, cachedInputTokens: 500, outputTokens: 1000, reasoningOutputTokens: 0 },
46
+ });
47
+ dispatcher.openaiDispatcher = {
48
+ generate: vi.fn(async () => result),
49
+ generateStream: vi.fn(async (_req, cb) => cb.onComplete(result)),
50
+ } as never;
51
+ const input = { prompt: "hi", model: "openai/gpt-6.1-sol", serviceTier: "fast" as const };
52
+ let output: QueryOutput | undefined;
53
+ if (stream) {
54
+ await dispatcher.queryStream(input, {
55
+ onDelta: () => {}, onComplete: (value) => { output = value; }, onError: (error) => { throw error; },
56
+ });
57
+ } else {
58
+ output = await dispatcher.query(input);
59
+ }
60
+ expect(output?.costUsd).toBeCloseTo(0.0221, 10);
61
+ expect(output?.costSource).toBe("pricing_table");
62
+ });
63
+
41
64
  it("prices only the completed chat driver from an image failure", () => {
42
65
  const error = new ImageGenerationError("incomplete", "images unavailable");
43
66
  error.completedDriver = providerResult({
@@ -52,6 +75,7 @@ describe("QgridDispatcherClass", () => {
52
75
  content: [{ type: "text", text: "ok" }],
53
76
  });
54
77
  expect(result.costUsd).toBeCloseTo(0.0000191, 10);
78
+ expect(completedDriverFromImageFailure(error, "fast")?.costUsd).toBeCloseTo(0.0000382, 10);
55
79
  expect(estimateImageGenerationCostMicroUsd(result, undefined)).toBeNull();
56
80
  expect(result.runContext).toBeUndefined();
57
81
  expect(completedDriverFromImageFailure(new Error("failed"))).toBeUndefined();
@@ -127,7 +127,7 @@ export class QgridDispatcherClass {
127
127
  ? undefined
128
128
  : issueConvContext(result.threadCoord, decision, result.threadCoord.workerId);
129
129
 
130
- return applyToolCallEmulation(toEmulationResult(result), input.tools, {
130
+ return applyToolCallEmulation(toEmulationResult(result, input.serviceTier), input.tools, {
131
131
  threadCoord: coord,
132
132
  images: result.images,
133
133
  answerKind,
@@ -206,14 +206,18 @@ export class QgridDispatcherClass {
206
206
  onComplete: (turnResult) => {
207
207
  this.recordCompleted("openai", turnResult.tokenName);
208
208
  cb.onComplete(
209
- applyToolCallEmulation(toEmulationResult(turnResult), input.tools, {
210
- threadCoord: issueConvContext(
211
- turnResult.threadCoord,
212
- decision,
213
- turnResult.threadCoord.workerId,
214
- ),
215
- answerKind,
216
- }),
209
+ applyToolCallEmulation(
210
+ toEmulationResult(turnResult, input.serviceTier),
211
+ input.tools,
212
+ {
213
+ threadCoord: issueConvContext(
214
+ turnResult.threadCoord,
215
+ decision,
216
+ turnResult.threadCoord.workerId,
217
+ ),
218
+ answerKind,
219
+ },
220
+ ),
217
221
  );
218
222
  },
219
223
  onError: cb.onError,
@@ -328,9 +332,12 @@ function buildRawOutputSchema(
328
332
  : callerOutputSchema;
329
333
  }
330
334
 
331
- export function completedDriverFromImageFailure(error: unknown): QueryOutput | undefined {
335
+ export function completedDriverFromImageFailure(
336
+ error: unknown,
337
+ serviceTier?: string,
338
+ ): QueryOutput | undefined {
332
339
  if (!(error instanceof ImageGenerationError) || !error.completedDriver) return undefined;
333
- return applyToolCallEmulation(toEmulationResult(error.completedDriver), undefined, {
340
+ return applyToolCallEmulation(toEmulationResult(error.completedDriver, serviceTier), undefined, {
334
341
  answerKind: "text",
335
342
  });
336
343
  }
@@ -338,6 +345,7 @@ export function completedDriverFromImageFailure(error: unknown): QueryOutput | u
338
345
  // Anthropic adapter 는 cache creation 을 inputTokens 에 포함해 표준화하고, 별도 필드에도 보존한다.
339
346
  function toEmulationResult(
340
347
  result: GenerateResult,
348
+ serviceTier?: string,
341
349
  ): Omit<QueryOutput, "content" | "finishReason" | "runContext"> {
342
350
  const hasProviderCost = result.costUsd !== undefined && result.costUsd > 0;
343
351
  return {
@@ -359,14 +367,18 @@ function toEmulationResult(
359
367
  ttftMs: result.ttftMs ?? 0,
360
368
  costUsd: hasProviderCost
361
369
  ? result.costUsd!
362
- : calculateCostUsd(result.model, {
363
- inputTokens: result.usage.inputTokens,
364
- outputTokens: result.usage.outputTokens,
365
- cachedInputTokens: result.usage.cachedInputTokens,
366
- cacheCreationInputTokens: result.usage.cacheCreationInputTokens ?? 0,
367
- cacheCreationInputTokens5m: result.usage.cacheCreationInputTokens5m,
368
- cacheCreationInputTokens1h: result.usage.cacheCreationInputTokens1h,
369
- }),
370
+ : calculateCostUsd(
371
+ result.model,
372
+ {
373
+ inputTokens: result.usage.inputTokens,
374
+ outputTokens: result.usage.outputTokens,
375
+ cachedInputTokens: result.usage.cachedInputTokens,
376
+ cacheCreationInputTokens: result.usage.cacheCreationInputTokens ?? 0,
377
+ cacheCreationInputTokens5m: result.usage.cacheCreationInputTokens5m,
378
+ cacheCreationInputTokens1h: result.usage.cacheCreationInputTokens1h,
379
+ },
380
+ serviceTier,
381
+ ),
370
382
  costSource: hasProviderCost ? "provider" : "pricing_table",
371
383
  };
372
384
  }
@@ -405,6 +405,7 @@ describe("QgridFrame.query request logging", () => {
405
405
  });
406
406
  const args = {
407
407
  prompt: "draw", model: "openai/gpt-6-luna", imageGeneration: "auto" as const,
408
+ serviceTier: "fast" as const,
408
409
  ...(mode === "logger-disabled" ? { logger: false } : {}),
409
410
  };
410
411
  await expect(QgridFrame.query(args)).rejects.toBe(error);
@@ -417,7 +418,7 @@ describe("QgridFrame.query request logging", () => {
417
418
  const completedStep = expect.objectContaining({
418
419
  stepIndex: 0,
419
420
  result: expect.objectContaining({
420
- model: "gpt-6-luna", tokenName: "one", costUsd: 0.00002,
421
+ model: "gpt-6-luna", tokenName: "one", costUsd: 0.00004,
421
422
  usage: expect.objectContaining({ input_tokens: 100, output_tokens: 20 }),
422
423
  }),
423
424
  });
@@ -286,7 +286,7 @@ class QgridFrameClass extends BaseFrameClass {
286
286
  try {
287
287
  result = await QgridDispatcher.query(resolvedArgs, disconnect.signal);
288
288
  } catch (e) {
289
- const completedDriver = completedDriverFromImageFailure(e);
289
+ const completedDriver = completedDriverFromImageFailure(e, resolvedArgs.serviceTier);
290
290
  const completedStep = completedDriver
291
291
  ? ([{ stepIndex, result: completedDriver }] as const)
292
292
  : ([] as const);
@@ -143,6 +143,13 @@
143
143
  "nullable": true,
144
144
  "desc": "이미지 비용 계산 방식"
145
145
  },
146
+ {
147
+ "name": "service_tier",
148
+ "type": "string",
149
+ "length": 20,
150
+ "nullable": true,
151
+ "desc": "Requested OpenAI service tier"
152
+ },
146
153
  {
147
154
  "name": "effort",
148
155
  "type": "string",
@@ -288,6 +295,7 @@
288
295
  "image_cost_usd",
289
296
  "image_cost_method",
290
297
  "effort",
298
+ "service_tier",
291
299
  "history",
292
300
  "tools",
293
301
  "status",
@@ -318,6 +326,7 @@
318
326
  "image_cost_usd",
319
327
  "image_cost_method",
320
328
  "effort",
329
+ "service_tier",
321
330
  "status",
322
331
  "response_json_ok",
323
332
  "tool_call_count",
@@ -481,6 +481,7 @@ class RequestLogModelClass extends BaseModelClass<
481
481
  system_prompt?: string | null;
482
482
  requested_model_name?: string | null;
483
483
  effort?: string | null;
484
+ service_tier?: string | null;
484
485
  project_name?: string | null;
485
486
  history?: unknown;
486
487
  tools?: ToolDefinitions;
@@ -496,6 +497,7 @@ class RequestLogModelClass extends BaseModelClass<
496
497
  requested_model_name: params.requested_model_name ?? null,
497
498
  model_name: null,
498
499
  effort: params.effort ?? null,
500
+ service_tier: params.service_tier ?? null,
499
501
  project_name: params.project_name ?? null,
500
502
  status: "running",
501
503
  response: "",
@@ -546,6 +548,7 @@ class RequestLogModelClass extends BaseModelClass<
546
548
  duration_ms?: number;
547
549
  requested_model_name?: string | null;
548
550
  model_name?: string | null;
551
+ service_tier?: string | null;
549
552
  fallback_count?: number | null;
550
553
  cost_usd?: number | null;
551
554
  cost_source?: string | null;
@@ -574,6 +577,7 @@ class RequestLogModelClass extends BaseModelClass<
574
577
  "duration_ms",
575
578
  "requested_model_name",
576
579
  "model_name",
580
+ "service_tier",
577
581
  "fallback_count",
578
582
  "cost_usd",
579
583
  "cost_source",
@@ -43,6 +43,7 @@ export const requestLogSubsetQueries = {
43
43
  image_cost_usd: "request_logs.image_cost_usd",
44
44
  image_cost_method: "request_logs.image_cost_method",
45
45
  effort: "request_logs.effort",
46
+ service_tier: "request_logs.service_tier",
46
47
  history: "request_logs.history",
47
48
  tools: "request_logs.tools",
48
49
  status: "request_logs.status",
@@ -75,6 +76,7 @@ export const requestLogSubsetQueries = {
75
76
  image_cost_usd: "request_logs.image_cost_usd",
76
77
  image_cost_method: "request_logs.image_cost_method",
77
78
  effort: "request_logs.effort",
79
+ service_tier: "request_logs.service_tier",
78
80
  status: "request_logs.status",
79
81
  response_json_ok: "request_logs.response_json_ok",
80
82
  tool_call_count: "request_logs.tool_call_count",
@@ -167,6 +167,7 @@ export const RequestLogBaseSchema = z.object({
167
167
  cost_source: z.string().max(20).nullable(),
168
168
  image_cost_usd: z.int().nullable(),
169
169
  image_cost_method: z.string().max(100).nullable(),
170
+ service_tier: z.string().max(20).nullable(),
170
171
  effort: z.string().max(10).nullable(),
171
172
  history: HistoryItems.nullable(),
172
173
  tools: ToolDefinitions.nullable(),
@@ -201,6 +202,7 @@ export type RequestLogBaseSchema = z.infer<typeof RequestLogBaseSchema> & {
201
202
  "cost_source",
202
203
  "image_cost_usd",
203
204
  "image_cost_method",
205
+ "service_tier",
204
206
  "effort",
205
207
  "history",
206
208
  "tools",
@@ -405,6 +407,7 @@ export const RequestLogSubsetA = z.object({
405
407
  image_cost_usd: z.int().nullable(),
406
408
  image_cost_method: z.string().max(100).nullable(),
407
409
  effort: z.string().max(10).nullable(),
410
+ service_tier: z.string().max(20).nullable(),
408
411
  history: HistoryItems.nullable(),
409
412
  tools: ToolDefinitions.nullable(),
410
413
  status: RequestLogStatus,
@@ -436,6 +439,7 @@ export const RequestLogSubsetP = z.object({
436
439
  image_cost_usd: z.int().nullable(),
437
440
  image_cost_method: z.string().max(100).nullable(),
438
441
  effort: z.string().max(10).nullable(),
442
+ service_tier: z.string().max(20).nullable(),
439
443
  status: RequestLogStatus,
440
444
  response_json_ok: z.boolean().nullable(),
441
445
  tool_call_count: z.int(),
@@ -232,6 +232,7 @@ const entityLabels = {
232
232
  "entity.RequestLog.cost_source": "비용 출처(provider/pricing_table/mixed)",
233
233
  "entity.RequestLog.image_cost_usd": "이미지 생성 비용",
234
234
  "entity.RequestLog.image_cost_method": "이미지 비용 계산 방식",
235
+ "entity.RequestLog.service_tier": "Requested OpenAI service tier",
235
236
  "entity.RequestLog.effort": "effort level",
236
237
  "entity.RequestLog.history": "inject_items 히스토리",
237
238
  "entity.RequestLog.tools": "요청에 장착된 tool 정의 목록",
@@ -0,0 +1,15 @@
1
+ import { type Knex } from "knex";
2
+
3
+ export async function up(knex: Knex): Promise<void> {
4
+ await knex.schema.alterTable("request_logs", (table) => {
5
+ // add
6
+ table.string("service_tier", 20).nullable();
7
+ });
8
+ }
9
+
10
+ export async function down(knex: Knex): Promise<void> {
11
+ await knex.schema.alterTable("request_logs", (table) => {
12
+ // rollback - add
13
+ table.dropColumns("service_tier");
14
+ });
15
+ }
@@ -3,6 +3,34 @@ import { describe, expect, it } from "vitest";
3
3
  import { calculateCostUsd, getModelCosts } from "./model-cost";
4
4
 
5
5
  describe("calculateCostUsd", () => {
6
+ it.each([
7
+ ["gpt-6-astra", 2.6],
8
+ ["gpt-6.1-sol", 0.5],
9
+ ["gpt-6-sol", 0.52],
10
+ ["gpt-6-luna", 0.026],
11
+ ["gpt-5.6-sol", 1.04],
12
+ ["gpt-5.6-terra", 0.56],
13
+ ["gpt-5.6-luna", 0.056],
14
+ ])("prices %s fast input, cached input, cache writes and output", (model, expected) => {
15
+ expect(calculateCostUsd(`openai/${model}`, {
16
+ inputTokens: 160_000, cachedInputTokens: 100_000,
17
+ cacheCreationInputTokens: 40_000, outputTokens: 10_000,
18
+ }, "fast")).toBeCloseTo(expected, 10);
19
+ });
20
+
21
+ it("combines Fast API rates with long-context rates, not subscription usage multipliers", () => {
22
+ expect(calculateCostUsd("openai/gpt-6.1-sol", {
23
+ inputTokens: 300_000, cachedInputTokens: 200_000, outputTokens: 10_000,
24
+ }, "fast")).toBeCloseTo(1.18, 10);
25
+ });
26
+
27
+ it("keeps standard pricing for omitted/flex tiers and Anthropic", () => {
28
+ const usage = { inputTokens: 1_000, outputTokens: 1_000 };
29
+ expect(calculateCostUsd("gpt-6.1-sol", usage)).toBeCloseTo(0.012, 10);
30
+ expect(calculateCostUsd("gpt-6.1-sol", usage, "flex")).toBeCloseTo(0.012, 10);
31
+ expect(calculateCostUsd("claude-sonnet-5-5", usage, "fast")).toBeCloseTo(0.012, 10);
32
+ });
33
+
6
34
  it.each([
7
35
  [272_000, 2.77],
8
36
  [272_001, 5.51502],
@@ -237,6 +237,19 @@ export function getModelCosts(model: string): ModelCosts {
237
237
  return OPENAI_COSTS[normalizedModel] ?? ANTHROPIC_COSTS[normalizedModel] ?? DEFAULT_COSTS;
238
238
  }
239
239
 
240
+ // Verified Fast API rates for the currently served Codex models (2026-10-16).
241
+ // Applies to all token categories and long context; not the 2.5x subscription quota multiplier.
242
+ // https://developers.openai.com/api/docs/pricing
243
+ const OPENAI_FAST_MULTIPLIERS: Record<string, number> = {
244
+ "gpt-6-astra": 2,
245
+ "gpt-6.1-sol": 2,
246
+ "gpt-6-sol": 2,
247
+ "gpt-6-luna": 2,
248
+ "gpt-5.6-sol": 2,
249
+ "gpt-5.6-terra": 2,
250
+ "gpt-5.6-luna": 2,
251
+ };
252
+
240
253
  export function calculateCostUsd(
241
254
  model: string,
242
255
  usage: {
@@ -247,6 +260,7 @@ export function calculateCostUsd(
247
260
  cacheCreationInputTokens5m?: number;
248
261
  cacheCreationInputTokens1h?: number;
249
262
  },
263
+ serviceTier?: string,
250
264
  ): number {
251
265
  const costs = getModelCosts(model);
252
266
  const cachedInput = usage.cachedInputTokens ?? 0;
@@ -281,12 +295,15 @@ export function calculateCostUsd(
281
295
  (isLongContext ? lc.inputMultiplier : 1);
282
296
  const outputRate = costs.outputTokens * (isLongContext ? lc.outputMultiplier : 1);
283
297
 
284
- return (
298
+ const standardCost =
285
299
  (nonCachedInput / 1_000_000) * inputRate +
286
300
  (usage.outputTokens / 1_000_000) * outputRate +
287
301
  (cachedInput / 1_000_000) * cachedRate +
288
302
  (unclassifiedCacheCreationInput / 1_000_000) * cacheCreationFallbackRate +
289
303
  (classifiedCacheCreationInput5m / 1_000_000) * cacheCreation5mRate +
290
- (classifiedCacheCreationInput1h / 1_000_000) * cacheCreation1hRate
304
+ (classifiedCacheCreationInput1h / 1_000_000) * cacheCreation1hRate;
305
+ const normalizedModel = model.split("/").pop() ?? model;
306
+ return (
307
+ standardCost * (serviceTier === "fast" ? (OPENAI_FAST_MULTIPLIERS[normalizedModel] ?? 1) : 1)
291
308
  );
292
309
  }