velocious 1.0.671 → 1.0.673

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 (51) hide show
  1. package/README.md +2 -2
  2. package/build/database/drivers/base.js +52 -18
  3. package/build/database/drivers/mssql/index.js +48 -3
  4. package/build/database/pool/async-tracked-multi-connection.js +36 -0
  5. package/build/src/database/drivers/base.d.ts +23 -0
  6. package/build/src/database/drivers/base.d.ts.map +1 -1
  7. package/build/src/database/drivers/base.js +51 -21
  8. package/build/src/database/drivers/mssql/index.d.ts +22 -0
  9. package/build/src/database/drivers/mssql/index.d.ts.map +1 -1
  10. package/build/src/database/drivers/mssql/index.js +45 -4
  11. package/build/src/database/pool/async-tracked-multi-connection.d.ts +15 -0
  12. package/build/src/database/pool/async-tracked-multi-connection.d.ts.map +1 -1
  13. package/build/src/database/pool/async-tracked-multi-connection.js +32 -1
  14. package/build/src/sync/local-mutation-log.d.ts +12 -0
  15. package/build/src/sync/local-mutation-log.d.ts.map +1 -1
  16. package/build/src/sync/local-mutation-log.js +45 -1
  17. package/build/src/sync/sync-api-client.d.ts +6 -1
  18. package/build/src/sync/sync-api-client.d.ts.map +1 -1
  19. package/build/src/sync/sync-api-client.js +7 -2
  20. package/build/src/sync/sync-client.d.ts +60 -0
  21. package/build/src/sync/sync-client.d.ts.map +1 -1
  22. package/build/src/sync/sync-client.js +172 -3
  23. package/build/src/sync/sync-coordinator-types.d.ts +190 -0
  24. package/build/src/sync/sync-coordinator-types.d.ts.map +1 -0
  25. package/build/src/sync/sync-coordinator-types.js +65 -0
  26. package/build/src/sync/sync-coordinator.d.ts +246 -0
  27. package/build/src/sync/sync-coordinator.d.ts.map +1 -0
  28. package/build/src/sync/sync-coordinator.js +683 -0
  29. package/build/src/sync/sync-envelope-replay-service.d.ts +90 -2
  30. package/build/src/sync/sync-envelope-replay-service.d.ts.map +1 -1
  31. package/build/src/sync/sync-envelope-replay-service.js +101 -9
  32. package/build/src/sync/sync-realtime-bridge.d.ts.map +1 -1
  33. package/build/src/sync/sync-realtime-bridge.js +8 -1
  34. package/build/sync/local-mutation-log.js +53 -0
  35. package/build/sync/sync-api-client.js +7 -1
  36. package/build/sync/sync-client.js +190 -2
  37. package/build/sync/sync-coordinator-types.js +73 -0
  38. package/build/sync/sync-coordinator.js +738 -0
  39. package/build/sync/sync-envelope-replay-service.js +107 -8
  40. package/build/sync/sync-realtime-bridge.js +9 -0
  41. package/package.json +1 -1
  42. package/src/database/drivers/base.js +52 -18
  43. package/src/database/drivers/mssql/index.js +48 -3
  44. package/src/database/pool/async-tracked-multi-connection.js +36 -0
  45. package/src/sync/local-mutation-log.js +53 -0
  46. package/src/sync/sync-api-client.js +7 -1
  47. package/src/sync/sync-client.js +190 -2
  48. package/src/sync/sync-coordinator-types.js +73 -0
  49. package/src/sync/sync-coordinator.js +738 -0
  50. package/src/sync/sync-envelope-replay-service.js +107 -8
  51. package/src/sync/sync-realtime-bridge.js +9 -0
@@ -1 +1 @@
1
- {"version":3,"file":"sync-realtime-bridge.d.ts","sourceRoot":"","sources":["../../../src/sync/sync-realtime-bridge.js"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sync-realtime-bridge.d.ts","sourceRoot":"","sources":["../../../src/sync/sync-realtime-bridge.js"],"names":[],"mappings":"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"}
@@ -352,6 +352,13 @@ export default class SyncRealtimeBridge {
352
352
  return;
353
353
  if (this.realtimeConfiguration()?.pullOnReconnect === false)
354
354
  return;
355
+ const coordinatorRun = this.syncClient.requestCoordinatorSync("realtime");
356
+ if (coordinatorRun) {
357
+ this._scheduledPull ||= coordinatorRun.finally(() => {
358
+ this._scheduledPull = null;
359
+ });
360
+ return;
361
+ }
355
362
  this._scheduledPull ||= (async () => {
356
363
  try {
357
364
  await this.syncClient.pull();
@@ -377,4 +384,4 @@ function throwIfAborted(signal) {
377
384
  return;
378
385
  throw signal.reason instanceof Error ? signal.reason : new Error("Sync realtime subscription was aborted");
379
386
  }
380
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3luYy1yZWFsdGltZS1icmlkZ2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvc3luYy9zeW5jLXJlYWx0aW1lLWJyaWRnZS5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxZQUFZO0FBRVosT0FBTyxhQUFhLE1BQU0sK0JBQStCLENBQUE7QUFDekQsT0FBTyxFQUFDLHlCQUF5QixFQUFDLE1BQU0sOEJBQThCLENBQUE7QUFFdEUsT0FBTyxhQUFhLE1BQU0sc0JBQXNCLENBQUE7QUFDaEQsT0FBTyxFQUFDLHNCQUFzQixFQUFDLE1BQU0sd0JBQXdCLENBQUE7QUFFN0QsbUlBQW1JO0FBQ25JLCtIQUErSDtBQUUvSDs7Ozs7Ozs7Ozs7O0dBWUc7QUFDSCxNQUFNLENBQUMsT0FBTyxPQUFPLGtCQUFrQjtJQUNyQzs7O09BR0c7SUFDSCxZQUFZLEVBQUMsVUFBVSxFQUFDO1FBQ3RCLElBQUksQ0FBQyxVQUFVLEdBQUcsVUFBVSxDQUFBO1FBQzVCLHlKQUF5SjtRQUN6SixJQUFJLENBQUMsU0FBUyxHQUFHLEVBQUUsQ0FBQTtRQUNuQiwwREFBMEQ7UUFDMUQsSUFBSSxDQUFDLE9BQU8sR0FBRyxJQUFJLENBQUE7UUFDbkIsdUtBQXVLO1FBQ3ZLLElBQUksQ0FBQyxXQUFXLEdBQUcsS0FBSyxDQUFBO1FBQ3hCLDRCQUE0QjtRQUM1QixJQUFJLENBQUMsYUFBYSxHQUFHLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQTtRQUN0Qyx1SEFBdUg7UUFDdkgsSUFBSSxDQUFDLFdBQVcsR0FBRyxDQUFDLENBQUE7UUFDcEIsbUNBQW1DO1FBQ25DLElBQUksQ0FBQyxjQUFjLEdBQUcsSUFBSSxDQUFBO1FBQzFCLG1DQUFtQztRQUNuQyxJQUFJLENBQUMsaUJBQWlCLEdBQUcsSUFBSSxDQUFBO1FBQzdCLDREQUE0RDtRQUM1RCxJQUFJLENBQUMsTUFBTSxHQUFHLGNBQWMsQ0FBQTtJQUM5QixDQUFDO0lBRUQ7Ozs7Ozs7T0FPRztJQUNI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Q0FBQztnQkFDVCxJQUFJLENBQUMsY0FBYyxHQUFHLElBQUksQ0FBQTtZQUM1QixDQUFDO1FBQ0gsQ0FBQyxDQUFDLEVBQUUsQ0FBQTtJQUNOLENBQUM7Q0FDRjtBQUVEOzs7O0dBSUc7QUFDSCxTQUFTLGNBQWMsQ0FBQyxNQUFNO0lBQzVCLElBQUksQ0FBQyxNQUFNLEVBQUUsT0FBTztRQUFFLE9BQU07SUFFNUIsTUFBTSxNQUFNLENBQUMsTUFBTSxZQUFZLEtBQUssQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsSUFBSSxLQUFLLENBQUMsd0NBQXdDLENBQUMsQ0FBQTtBQUM1RyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQHRzLWNoZWNrXG5cbmltcG9ydCByZWNvcmRDaGFuZ2VzIGZyb20gXCIuLi9kYXRhYmFzZS9yZWNvcmQtY2hhbmdlcy5qc1wiXG5pbXBvcnQge21lcmdlUmVtb3RlUmVxdWVzdENvbnRleHR9IGZyb20gXCIuLi9yZW1vdGUtcmVxdWVzdC1jb250ZXh0LmpzXCJcblxuaW1wb3J0IFN5bmNBcGlDbGllbnQgZnJvbSBcIi4vc3luYy1hcGktY2xpZW50LmpzXCJcbmltcG9ydCB7VkVMT0NJT1VTX1NZTkNfQ0hBTk5FTH0gZnJvbSBcIi4vc3luYy1jaGFubmVsLW5hbWUuanNcIlxuXG4vKiogQHR5cGVkZWYge2ltcG9ydChcIi4uL2NvbmZpZ3VyYXRpb24tdHlwZXMuanNcIikuVmVsb2Npb3VzU3luY1JlYWx0aW1lQ2hhbm5lbERlc2NyaXB0b3J9IFZlbG9jaW91c1N5bmNSZWFsdGltZUNoYW5uZWxEZXNjcmlwdG9yICovXG4vKiogQHR5cGVkZWYge2ltcG9ydChcIi4uL2NvbmZpZ3VyYXRpb24tdHlwZXMuanNcIikuVmVsb2Npb3VzU3luY1JlYWx0aW1lV2Vic29ja2V0Q2xpZW50fSBWZWxvY2lvdXNTeW5jUmVhbHRpbWVXZWJzb2NrZXRDbGllbnQgKi9cblxuLyoqXG4gKiBEZXJpdmVkIHJlYWx0aW1lIHB1c2ggYnJpZGdlIGZvciB0aGUgc3luYyBjbGllbnQuIFN1YnNjcmliZXMgZXZlcnkgZGVjbGFyZWRcbiAqIHB1bGwgc2NvcGUgdG8gdGhlIGZyYW1ld29yayBzeW5jIGNoYW5uZWwgKHtAbGluayBWRUxPQ0lPVVNfU1lOQ19DSEFOTkVMfSlcbiAqIGF1dG9tYXRpY2FsbHkg4oCUIHRoZSBzdWJzY3JpYmUgcGFyYW1zIG1pcnJvciB0aGUgc2NvcGUnc1xuICogYHtyZXNvdXJjZVR5cGUsIGNvbmRpdGlvbnN9YCBzbyB0aGUgc2VydmVyIGF1dGhvcml6ZXMgdGhlbSB0aHJvdWdoIHRoZSBzYW1lXG4gKiBzeW5jIHJlc291cmNlIGF1dGhvcml6YXRpb24gYXMgcHVsbHMg4oCUIHBsdXMgYW55IGRlcHJlY2F0ZWQgbGVnYWN5IGNoYW5uZWxzXG4gKiAoY29uZmlnIGBzeW5jLmNsaWVudC5yZWFsdGltZS5jaGFubmVsc2AgY2FsbGJhY2sgYW5kIG1vZGVsLWxldmVsXG4gKiBgc3RhdGljIHN5bmMgPSB7cmVhbHRpbWU6IHtjaGFubmVsfX1gIGRlY2xhcmF0aW9ucykuIFB1c2hlZCBjaGFuZ2VzIGFwcGx5XG4gKiB0aHJvdWdoIHRoZSBzYW1lIGRlcml2ZWQgcmVzb3VyY2UgYXBwbGllciBhcyBwdWxscyAod2l0aCBlY2hvIHN1cHByZXNzaW9uXG4gKiBhZ2FpbnN0IHRyYWNrZWQgcmUtcXVldWVpbmcpLCBvd24tZGV2aWNlIG1lc3NhZ2VzIGFyZSBkcm9wcGVkIGJ5IGVjaG9cbiAqIG9yaWdpbiwgYW5kIGEgY29hbGVzY2VkIGBwdWxsKClgIGZpcmVzIHdoZW4gc3Vic2NyaXB0aW9ucyBiZWNvbWUgcmVhZHkgb3JcbiAqIHJlc3VtZSBzbyBvZmZsaW5lIGdhcHMgY2xvc2UuXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFN5bmNSZWFsdGltZUJyaWRnZSB7XG4gIC8qKlxuICAgKiBCdWlsZHMgdGhlIGJyaWRnZSBmb3IgYSBzeW5jIGNsaWVudC5cbiAgICogQHBhcmFtIHt7c3luY0NsaWVudDogaW1wb3J0KFwiLi9zeW5jLWNsaWVudC5qc1wiKS5kZWZhdWx0fX0gYXJncyAtIEJyaWRnZSBhcmdzLlxuICAgKi9cbiAgY29uc3RydWN0b3Ioe3N5bmNDbGllbnR9KSB7XG4gICAgdGhpcy5zeW5jQ2xpZW50ID0gc3luY0NsaWVudFxuICAgIC8qKiBAdHlwZSB7QXJyYXk8e2NoYW5uZWw6IHN0cmluZywgcmVzb3VyY2VUeXBlOiBzdHJpbmcgfCBudWxsLCBzdWJzY3JpcHRpb246IGltcG9ydChcIi4uL2NvbmZpZ3VyYXRpb24tdHlwZXMuanNcIikuVmVsb2Npb3VzU3luY1JlYWx0aW1lU3Vic2NyaXB0aW9ufT59ICovXG4gICAgdGhpcy5fY2hhbm5lbHMgPSBbXVxuICAgIC8qKiBAdHlwZSB7VmVsb2Npb3VzU3luY1JlYWx0aW1lV2Vic29ja2V0Q2xpZW50IHwgbnVsbH0gKi9cbiAgICB0aGlzLl9jbGllbnQgPSBudWxsXG4gICAgLyoqIEB0eXBlIHtib29sZWFufSBXaGV0aGVyIHRoZSBicmlkZ2UgY3JlYXRlZCBpdHMgb3duIGNsaWVudCAoZGVwcmVjYXRlZCBwZXItY3ljbGUgcGF0aCkgYW5kIG11c3QgZGlzY29ubmVjdCBpdCBvbiB1bnN1YnNjcmliZS4gQSBzaGFyZWQgY29ubmVjdGlvbiBpcyBuZXZlciBvd25lZC4gKi9cbiAgICB0aGlzLl9vd25zQ2xpZW50ID0gZmFsc2VcbiAgICAvKiogQHR5cGUge1Byb21pc2U8dm9pZD59ICovXG4gICAgdGhpcy5fYXBwbHlQcm9taXNlID0gUHJvbWlzZS5yZXNvbHZlKClcbiAgICAvKiogQHR5cGUge251bWJlcn0gU3Vic2NyaXB0aW9uIGdlbmVyYXRpb24gLSBidW1wZWQgYnkgdW5zdWJzY3JpYmUgc28gaW4tZmxpZ2h0IHN1YnNjcmliZXMgZGV0ZWN0IHRoZXkgYmVjYW1lIHN0YWxlLiAqL1xuICAgIHRoaXMuX2dlbmVyYXRpb24gPSAwXG4gICAgLyoqIEB0eXBlIHtQcm9taXNlPHZvaWQ+IHwgbnVsbH0gKi9cbiAgICB0aGlzLl9zY2hlZHVsZWRQdWxsID0gbnVsbFxuICAgIC8qKiBAdHlwZSB7UHJvbWlzZTx2b2lkPiB8IG51bGx9ICovXG4gICAgdGhpcy5fc3Vic2NyaWJlUHJvbWlzZSA9IG51bGxcbiAgICAvKiogQHR5cGUge1wic3Vic2NyaWJlZFwiIHwgXCJzdWJzY3JpYmluZ1wiIHwgXCJ1bnN1YnNjcmliZWRcIn0gKi9cbiAgICB0aGlzLl9zdGF0ZSA9IFwidW5zdWJzY3JpYmVkXCJcbiAgfVxuXG4gIC8qKlxuICAgKiBTdWJzY3JpYmVzIHRoZSBkZXJpdmVkIHJlYWx0aW1lIGNoYW5uZWxzIChpZGVtcG90ZW50IGFuZCBzaW5nbGUtZmxpZ2h0ZWQpOlxuICAgKiBhbiBhY3RpdmUgc3Vic2NyaXB0aW9uIGlzIGtlcHQgYXMtaXMgYW5kIGEgY29uY3VycmVudCBzdWJzY3JpYmUgYXdhaXRzIHRoZVxuICAgKiBpbi1mbGlnaHQgYXR0ZW1wdC4gQ2FsbCBgdW5zdWJzY3JpYmUoKWAgZmlyc3QgdG8gY2hhbmdlIHRoZSBjb250ZXh0LlxuICAgKiBAcGFyYW0ge1JldHVyblR5cGU8dHlwZW9mIEpTT04ucGFyc2U+fSBbY29udGV4dF0gLSBBcHAgY29udGV4dCBwYXNzZWQgdG8gdGhlIGRlcHJlY2F0ZWQgYHN5bmMuY2xpZW50LnJlYWx0aW1lLmNoYW5uZWxzYCBjYWxsYmFjayAocnVudGltZSBzY29wZSB2YWx1ZXMpLlxuICAgKiBAcGFyYW0ge3tzaWduYWw/OiBBYm9ydFNpZ25hbH19IFtvcHRpb25zXSAtIFN1YnNjcmlwdGlvbiBsaWZlY3ljbGUgb3B0aW9ucy5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59XG4gICAqL1xuICBhc3luYyBzdWJzY3JpYmUoY29udGV4dCwge3NpZ25hbH0gPSB7fSkge1xuICAgIGlmICh0aGlzLl9zdGF0ZSA9PT0gXCJzdWJzY3JpYmVkXCIpIHJldHVyblxuXG4gICAgaWYgKCF0aGlzLl9zdWJzY3JpYmVQcm9taXNlKSB7XG4gICAgICB0aGlzLl9zdWJzY3JpYmVQcm9taXNlID0gdGhpcy5fc3Vic2NyaWJlKGNvbnRleHQsIHNpZ25hbCkuZmluYWxseSgoKSA9PiB7XG4gICAgICAgIHRoaXMuX3N1YnNjcmliZVByb21pc2UgPSBudWxsXG4gICAgICB9KVxuICAgIH1cblxuICAgIGF3YWl0IHRoaXMuX3N1YnNjcmliZVByb21pc2VcbiAgfVxuXG4gIC8qKlxuICAgKiBDb25uZWN0cyB0aGUgd2Vic29ja2V0IGNsaWVudCwgc3Vic2NyaWJlcyBldmVyeSBkZXJpdmVkIGNoYW5uZWwsIGFuZCB3YWl0c1xuICAgKiBmb3IgZWFjaCBzdWJzY3JpcHRpb24ncyBzZXJ2ZXIgYWNrbm93bGVkZ2VtZW50IGJlZm9yZSB0aGUgZ2FwLWNsb3NpbmcgcHVsbCxcbiAgICogc28gbm8gY2hhbmdlIGNhbiBsYW5kIGJldHdlZW4gdGhlIHB1bGwgYW5kIHRoZSBzdWJzY3JpcHRpb25zIGdvaW5nIGxpdmUuXG4gICAqIExvY2FsbHkgY3JlYXRlZCByZXNvdXJjZXMgYXJlIG9ubHkgcHJvbW90ZWQgdG8gdGhlIGJyaWRnZSBvbmNlIGV2ZXJ5dGhpbmdcbiAgICogaXMgbGl2ZTsgYW4gdW5zdWJzY3JpYmUgYXJyaXZpbmcgZHVyaW5nIGFueSBhd2FpdCBtYXJrcyB0aGlzIGF0dGVtcHQgc3RhbGVcbiAgICogYW5kIGl0IHRlYXJzIGl0cyBvd24gcmVzb3VyY2VzIGRvd24gaW5zdGVhZCBvZiByZXN1YnNjcmliaW5nLlxuICAgKiBAcGFyYW0ge1JldHVyblR5cGU8dHlwZW9mIEpTT04ucGFyc2U+fSBjb250ZXh0IC0gQXBwIGNvbnRleHQgcGFzc2VkIHRvIHRoZSBjaGFubmVscyBjYWxsYmFjay5cbiAgICogQHBhcmFtIHtBYm9ydFNpZ25hbCB8IHVuZGVmaW5lZH0gc2lnbmFsIC0gU3Vic2NyaXB0aW9uIGxpZmVjeWNsZSBzaWduYWwuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fVxuICAgKi9cbiAgYXN5bmMgX3N1YnNjcmliZShjb250ZXh0LCBzaWduYWwpIHtcbiAgICBjb25zdCBnZW5lcmF0aW9uID0gdGhpcy5fZ2VuZXJhdGlvblxuXG4gICAgdGhpcy5fc3RhdGUgPSBcInN1YnNjcmliaW5nXCJcblxuICAgIC8qKiBAdHlwZSB7QXJyYXk8e2NoYW5uZWw6IHN0cmluZywgcmVzb3VyY2VUeXBlOiBzdHJpbmcgfCBudWxsLCBzdWJzY3JpcHRpb246IGltcG9ydChcIi4uL2NvbmZpZ3VyYXRpb24tdHlwZXMuanNcIikuVmVsb2Npb3VzU3luY1JlYWx0aW1lU3Vic2NyaXB0aW9ufT59ICovXG4gICAgY29uc3QgY2hhbm5lbHMgPSBbXVxuICAgIC8qKiBAdHlwZSB7VmVsb2Npb3VzU3luY1JlYWx0aW1lV2Vic29ja2V0Q2xpZW50IHwgbnVsbH0gKi9cbiAgICBsZXQgY2xpZW50ID0gbnVsbFxuICAgIC8qKiBAdHlwZSB7Ym9vbGVhbn0gV2hldGhlciB0aGlzIGF0dGVtcHQgY3JlYXRlZCBpdHMgb3duIGNsaWVudCBhbmQgbXVzdCBkaXNjb25uZWN0IGl0IG9uIHRlYXJkb3duLiAqL1xuICAgIGxldCBvd25zQ2xpZW50ID0gZmFsc2VcbiAgICAvKipcbiAgICAgKiBUZWFycyBkb3duIGV2ZXJ5dGhpbmcgdGhpcyBzdGFsZS9mYWlsZWQgc3Vic2NyaWJlIGF0dGVtcHQgY3JlYXRlZCBpdHNlbGY6XG4gICAgICogYWx3YXlzIGNsb3NlcyBpdHMgY2hhbm5lbCBzdWJzY3JpcHRpb25zLCBhbmQgZGlzY29ubmVjdHMgdGhlIHdlYnNvY2tldFxuICAgICAqIG9ubHkgd2hlbiB0aGUgYnJpZGdlIG93bnMgaXQgKGRlcHJlY2F0ZWQgcGVyLWN5Y2xlIHBhdGgpOyBhIHNoYXJlZFxuICAgICAqIGNvbm5lY3Rpb24gc3RheXMgb3Blbi5cbiAgICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn1cbiAgICAgKi9cbiAgICBjb25zdCB0ZWFyZG93biA9IGFzeW5jICgpID0+IHtcbiAgICAgIGZvciAoY29uc3Qge3N1YnNjcmlwdGlvbn0gb2YgY2hhbm5lbHMpIHtcbiAgICAgICAgc3Vic2NyaXB0aW9uLmNsb3NlKClcbiAgICAgIH1cblxuICAgICAgaWYgKGNsaWVudCAmJiBvd25zQ2xpZW50KSBhd2FpdCBjbGllbnQuZGlzY29ubmVjdEFuZFN0b3BSZWNvbm5lY3QoKVxuICAgIH1cblxuICAgIHRyeSB7XG4gICAgICB0aHJvd0lmQWJvcnRlZChzaWduYWwpXG5cbiAgICAgIGNvbnN0IHNoYXJlZENsaWVudCA9IHRoaXMuc3luY0NsaWVudC5zeW5jQ29ubmVjdGlvbigpXG4gICAgICBjb25zdCByZWFsdGltZSA9IHRoaXMucmVxdWlyZUNsaWVudFNvdXJjZShzaGFyZWRDbGllbnQpXG4gICAgICBjb25zdCBjaGFubmVsRGVzY3JpcHRvcnMgPSBhd2FpdCB0aGlzLmNoYW5uZWxEZXNjcmlwdG9ycyhjb250ZXh0KVxuXG4gICAgICB0aHJvd0lmQWJvcnRlZChzaWduYWwpXG4gICAgICBpZiAoZ2VuZXJhdGlvbiAhPT0gdGhpcy5fZ2VuZXJhdGlvbikgcmV0dXJuXG5cbiAgICAgIGlmIChzaGFyZWRDbGllbnQpIHtcbiAgICAgICAgY2xpZW50ID0gc2hhcmVkQ2xpZW50XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyByZXF1aXJlQ2xpZW50U291cmNlIGd1YXJhbnRlZWQgcmVhbHRpbWUuY3JlYXRlQ2xpZW50IHdoZW4gdGhlcmUgaXMgbm8gc2hhcmVkIGNvbm5lY3Rpb24uXG4gICAgICAgIGNsaWVudCA9IGF3YWl0IC8qKiBAdHlwZSB7aW1wb3J0KFwiLi4vY29uZmlndXJhdGlvbi10eXBlcy5qc1wiKS5WZWxvY2lvdXNTeW5jQ2xpZW50UmVhbHRpbWVDb25maWd1cmF0aW9ufSAqLyAocmVhbHRpbWUpLmNyZWF0ZUNsaWVudCgpXG4gICAgICAgIG93bnNDbGllbnQgPSB0cnVlXG4gICAgICB9XG5cbiAgICAgIGlmIChnZW5lcmF0aW9uICE9PSB0aGlzLl9nZW5lcmF0aW9uKSB7XG4gICAgICAgIGF3YWl0IHRlYXJkb3duKClcbiAgICAgICAgcmV0dXJuXG4gICAgICB9XG5cbiAgICAgIGF3YWl0IGNsaWVudC5jb25uZWN0KHtzaWduYWx9KVxuXG4gICAgICB0aHJvd0lmQWJvcnRlZChzaWduYWwpXG4gICAgICBpZiAoZ2VuZXJhdGlvbiAhPT0gdGhpcy5fZ2VuZXJhdGlvbikge1xuICAgICAgICBhd2FpdCB0ZWFyZG93bigpXG4gICAgICAgIHJldHVyblxuICAgICAgfVxuXG4gICAgICBjb25zdCBhdXRoZW50aWNhdGlvblRva2VuID0gYXdhaXQgdGhpcy5zeW5jQ2xpZW50LmNvbmZpZy5hdXRoZW50aWNhdGlvblRva2VuKClcblxuICAgICAgdGhyb3dJZkFib3J0ZWQoc2lnbmFsKVxuICAgICAgaWYgKGdlbmVyYXRpb24gIT09IHRoaXMuX2dlbmVyYXRpb24pIHtcbiAgICAgICAgYXdhaXQgdGVhcmRvd24oKVxuICAgICAgICByZXR1cm5cbiAgICAgIH1cblxuICAgICAgZm9yIChjb25zdCBjaGFubmVsRGVzY3JpcHRvciBvZiBjaGFubmVsRGVzY3JpcHRvcnMpIHtcbiAgICAgICAgaWYgKGNoYW5uZWxEZXNjcmlwdG9yLnBhcmFtcyAmJiBcImF1dGhlbnRpY2F0aW9uVG9rZW5cIiBpbiBjaGFubmVsRGVzY3JpcHRvci5wYXJhbXMpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFJlYWx0aW1lIGNoYW5uZWwgXCIke2NoYW5uZWxEZXNjcmlwdG9yLmNoYW5uZWx9XCIgcGFyYW1zIG11c3Qgbm90IGluY2x1ZGUgYXV0aGVudGljYXRpb25Ub2tlbiAtIHRoZSBmcmFtZXdvcmsgaW5qZWN0cyB0aGUgc3luYy5jbGllbnQgYXV0aGVudGljYXRpb25Ub2tlbiBhdXRvbWF0aWNhbGx5YClcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHJlc291cmNlVHlwZSA9IGNoYW5uZWxEZXNjcmlwdG9yLnJlc291cmNlVHlwZSA/PyBudWxsXG4gICAgICAgIGNvbnN0IHBhcmFtcyA9IG1lcmdlUmVtb3RlUmVxdWVzdENvbnRleHQoe1xuICAgICAgICAgIGNvbnRleHQ6IHRoaXMuc3luY0NsaWVudC5jb25maWcucmVxdWVzdENvbnRleHQsXG4gICAgICAgICAgbGFiZWw6IFwiU3luYyBjbGllbnQgcmVxdWVzdCBjb250ZXh0XCIsXG4gICAgICAgICAgcGFyYW1zOiB7Li4uY2hhbm5lbERlc2NyaXB0b3IucGFyYW1zLCBhdXRoZW50aWNhdGlvblRva2VufVxuICAgICAgICB9KVxuICAgICAgICBjb25zdCBzdWJzY3JpcHRpb24gPSBjbGllbnQuc3Vic2NyaWJlQ2hhbm5lbChjaGFubmVsRGVzY3JpcHRvci5jaGFubmVsLCB7XG4gICAgICAgICAgb25NZXNzYWdlOiAoYm9keSkgPT4gdGhpcy5lbnF1ZXVlQXBwbHkoe2JvZHksIGdlbmVyYXRpb24sIHJlc291cmNlVHlwZX0pLFxuICAgICAgICAgIG9uUmVzdW1lOiAoKSA9PiB0aGlzLnNjaGVkdWxlUHVsbChnZW5lcmF0aW9uKSxcbiAgICAgICAgICBwYXJhbXNcbiAgICAgICAgfSlcblxuICAgICAgICBjaGFubmVscy5wdXNoKHtjaGFubmVsOiBjaGFubmVsRGVzY3JpcHRvci5jaGFubmVsLCByZXNvdXJjZVR5cGUsIHN1YnNjcmlwdGlvbn0pXG4gICAgICB9XG5cbiAgICAgIGF3YWl0IFByb21pc2UuYWxsKGNoYW5uZWxzLm1hcCgoe3N1YnNjcmlwdGlvbn0pID0+IHN1YnNjcmlwdGlvbi53YWl0Rm9yUmVhZHkoe3NpZ25hbH0pKSlcblxuICAgICAgdGhyb3dJZkFib3J0ZWQoc2lnbmFsKVxuICAgICAgaWYgKGdlbmVyYXRpb24gIT09IHRoaXMuX2dlbmVyYXRpb24pIHtcbiAgICAgICAgYXdhaXQgdGVhcmRvd24oKVxuICAgICAgICByZXR1cm5cbiAgICAgIH1cblxuICAgICAgdGhpcy5fY2hhbm5lbHMgPSBjaGFubmVsc1xuICAgICAgdGhpcy5fY2xpZW50ID0gY2xpZW50XG4gICAgICB0aGlzLl9vd25zQ2xpZW50ID0gb3duc0NsaWVudFxuICAgICAgdGhpcy5fc3RhdGUgPSBcInN1YnNjcmliZWRcIlxuICAgICAgdGhpcy5zY2hlZHVsZVB1bGwoZ2VuZXJhdGlvbilcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgYXdhaXQgdGVhcmRvd24oKVxuXG4gICAgICBpZiAoZ2VuZXJhdGlvbiA9PT0gdGhpcy5fZ2VuZXJhdGlvbikgdGhpcy5fc3RhdGUgPSBcInVuc3Vic2NyaWJlZFwiXG5cbiAgICAgIHRocm93IGVycm9yXG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIENsb3NlcyBldmVyeSBjaGFubmVsIHN1YnNjcmlwdGlvbiAoaWRlbXBvdGVudCkuIFRoZSB3ZWJzb2NrZXQgaXNcbiAgICogZGlzY29ubmVjdGVkIG9ubHkgd2hlbiB0aGUgYnJpZGdlIG93bnMgaXQgKGRlcHJlY2F0ZWQgcGVyLWN5Y2xlXG4gICAqIGByZWFsdGltZS5jcmVhdGVDbGllbnRgIHBhdGgpOyBhIHNoYXJlZCBhcHAtbGlmZXRpbWUgY29ubmVjdGlvbiBzdGF5cyBvcGVuXG4gICAqIHNvIHVuc3Vic2NyaWJpbmcgZHJvcHMgc3Vic2NyaXB0aW9ucyB3aXRob3V0IHRlYXJpbmcgZG93biB0aGUgc29ja2V0LiBBbHNvXG4gICAqIG1hcmtzIGFueSBpbi1mbGlnaHQgc3Vic2NyaWJlIGF0dGVtcHQgc3RhbGUgc28gaXQgdGVhcnMgaXRzZWxmIGRvd24gaW5zdGVhZFxuICAgKiBvZiBmaW5pc2hpbmcgdGhlIHN1YnNjcmlwdGlvbiBhZnRlcndhcmRzLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn1cbiAgICovXG4gIGFzeW5jIHVuc3Vic2NyaWJlKCkge1xuICAgIHRoaXMuX2dlbmVyYXRpb24gKz0gMVxuXG4gICAgY29uc3QgY2hhbm5lbHMgPSB0aGlzLl9jaGFubmVsc1xuICAgIGNvbnN0IGNsaWVudCA9IHRoaXMuX2NsaWVudFxuICAgIGNvbnN0IG93bnNDbGllbnQgPSB0aGlzLl9vd25zQ2xpZW50XG5cbiAgICB0aGlzLl9jaGFubmVscyA9IFtdXG4gICAgdGhpcy5fY2xpZW50ID0gbnVsbFxuICAgIHRoaXMuX293bnNDbGllbnQgPSBmYWxzZVxuICAgIHRoaXMuX3N0YXRlID0gXCJ1bnN1YnNjcmliZWRcIlxuXG4gICAgZm9yIChjb25zdCB7c3Vic2NyaXB0aW9ufSBvZiBjaGFubmVscykge1xuICAgICAgc3Vic2NyaXB0aW9uLmNsb3NlKClcbiAgICB9XG5cbiAgICBpZiAoY2xpZW50ICYmIG93bnNDbGllbnQpIGF3YWl0IGNsaWVudC5kaXNjb25uZWN0QW5kU3RvcFJlY29ubmVjdCgpXG4gIH1cblxuICAvKipcbiAgICogUmVwb3J0cyB0aGUgYnJpZGdlIHN1YnNjcmlwdGlvbiBzdGF0ZSBhbmQgcGVyLWNoYW5uZWwgcmVhZGluZXNzLlxuICAgKiBAcmV0dXJucyB7e2NoYW5uZWxzOiBBcnJheTx7Y2hhbm5lbDogc3RyaW5nLCByZWFkeTogYm9vbGVhbiwgcmVzb3VyY2VUeXBlOiBzdHJpbmcgfCBudWxsfT4sIHN0YXRlOiBcInN1YnNjcmliZWRcIiB8IFwic3Vic2NyaWJpbmdcIiB8IFwidW5zdWJzY3JpYmVkXCJ9fSBSZWFsdGltZSBzdGF0dXMuXG4gICAqL1xuICBzdGF0dXMoKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGNoYW5uZWxzOiB0aGlzLl9jaGFubmVscy5tYXAoKHtjaGFubmVsLCByZXNvdXJjZVR5cGUsIHN1YnNjcmlwdGlvbn0pID0+ICh7Y2hhbm5lbCwgcmVhZHk6IHN1YnNjcmlwdGlvbi5pc1JlYWR5KCksIHJlc291cmNlVHlwZX0pKSxcbiAgICAgIHN0YXRlOiB0aGlzLl9zdGF0ZVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBBd2FpdHMgYWxsIGVucXVldWVkIG1lc3NhZ2UgYXBwbGllcyBhbmQgYW55IHNjaGVkdWxlZCBwdWxsICh0ZXN0cywgc2h1dGRvd24gZmxvd3MpLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn1cbiAgICovXG4gIGFzeW5jIHdhaXRGb3JBcHBsaWVkKCkge1xuICAgIGF3YWl0IHRoaXMuX2FwcGx5UHJvbWlzZVxuICAgIGlmICh0aGlzLl9zY2hlZHVsZWRQdWxsKSBhd2FpdCB0aGlzLl9zY2hlZHVsZWRQdWxsXG4gIH1cblxuICAvKipcbiAgICogUmVzb2x2ZXMgdGhlIHJlYWx0aW1lIGNvbmZpZ3VyYXRpb24gYmxvY2ssIG9yIG51bGwgd2hlbiB0aGUgYXBwIGRlY2xhcmVkXG4gICAqIG5vbmUgKHZhbGlkIHdoZW4gYSBzaGFyZWQgY29ubmVjdGlvbiBpcyBjb25maWd1cmVkKS5cbiAgICogQHJldHVybnMge2ltcG9ydChcIi4uL2NvbmZpZ3VyYXRpb24tdHlwZXMuanNcIikuVmVsb2Npb3VzU3luY0NsaWVudFJlYWx0aW1lQ29uZmlndXJhdGlvbiB8IG51bGx9IFJlYWx0aW1lIGNvbmZpZ3VyYXRpb24sIG9yIG51bGwuXG4gICAqL1xuICByZWFsdGltZUNvbmZpZ3VyYXRpb24oKSB7XG4gICAgcmV0dXJuIHRoaXMuc3luY0NsaWVudC5jb25maWcucmVhbHRpbWUgfHwgbnVsbFxuICB9XG5cbiAgLyoqXG4gICAqIFJlc29sdmVzIHRoZSByZWFsdGltZSBjb25maWd1cmF0aW9uIGFuZCBhc3NlcnRzIGEgd2Vic29ja2V0IGNsaWVudCBzb3VyY2VcbiAgICogZXhpc3RzOiBhIHNoYXJlZCBjb25uZWN0aW9uIHJpZGVzIGl0cyBvd24gbGlmZWN5Y2xlLCBvdGhlcndpc2UgdGhlXG4gICAqIGRlcHJlY2F0ZWQgcGVyLWN5Y2xlIGByZWFsdGltZS5jcmVhdGVDbGllbnRgIG11c3QgYmUgY29uZmlndXJlZC5cbiAgICogQHBhcmFtIHtpbXBvcnQoXCIuLi9jb25maWd1cmF0aW9uLXR5cGVzLmpzXCIpLlZlbG9jaW91c1N5bmNSZWFsdGltZVdlYnNvY2tldENsaWVudCB8IG51bGx9IHNoYXJlZENsaWVudCAtIFNoYXJlZCBjb25uZWN0aW9uLCBvciBudWxsLlxuICAgKiBAcmV0dXJucyB7aW1wb3J0KFwiLi4vY29uZmlndXJhdGlvbi10eXBlcy5qc1wiKS5WZWxvY2lvdXNTeW5jQ2xpZW50UmVhbHRpbWVDb25maWd1cmF0aW9uIHwgbnVsbH0gUmVhbHRpbWUgY29uZmlndXJhdGlvbiwgb3IgbnVsbC5cbiAgICovXG4gIHJlcXVpcmVDbGllbnRTb3VyY2Uoc2hhcmVkQ2xpZW50KSB7XG4gICAgY29uc3QgcmVhbHRpbWUgPSB0aGlzLnJlYWx0aW1lQ29uZmlndXJhdGlvbigpXG5cbiAgICBpZiAoIXNoYXJlZENsaWVudCAmJiB0eXBlb2YgcmVhbHRpbWU/LmNyZWF0ZUNsaWVudCAhPT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJzdWJzY3JpYmVSZWFsdGltZSByZXF1aXJlcyBhIHNoYXJlZCBjb25uZWN0aW9uIChzeW5jLmNsaWVudC53ZWJzb2NrZXRVcmwgb3Igc3luYy5jbGllbnQud2Vic29ja2V0Q2xpZW50KSBvciB0aGUgZGVwcmVjYXRlZCBzeW5jLmNsaWVudC5yZWFsdGltZS5jcmVhdGVDbGllbnQgY2FsbGJhY2tcIilcbiAgICB9XG5cbiAgICByZXR1cm4gcmVhbHRpbWVcbiAgfVxuXG4gIC8qKlxuICAgKiBEZXJpdmVzIHRoZSBjaGFubmVsIGRlc2NyaXB0b3JzIHRvIHN1YnNjcmliZTogb25lIGZyYW1ld29yayBzeW5jIGNoYW5uZWxcbiAgICogc3Vic2NyaXB0aW9uIHBlciBkZWNsYXJlZCBwdWxsIHNjb3BlICh0aGUgcGFyYW1zIG1pcnJvciB0aGUgc2NvcGUnc1xuICAgKiBge3Jlc291cmNlVHlwZSwgY29uZGl0aW9uc31gKSwgcGx1cyB0aGUgZGVwcmVjYXRlZCBsZWdhY3kgcGF0aHMg4oCUXG4gICAqIG1vZGVsLWxldmVsIHN0YXRpYyByZWFsdGltZSBkZWNsYXJhdGlvbnMgYW5kIHRoZSBjb25maWcgY2hhbm5lbHMgY2FsbGJhY2suXG4gICAqIEZhaWxzIGxvdWRseSB3aGVuIG5vdGhpbmcgaXMgc3Vic2NyaWJhYmxlLlxuICAgKiBAcGFyYW0ge1JldHVyblR5cGU8dHlwZW9mIEpTT04ucGFyc2U+fSBjb250ZXh0IC0gQXBwIGNvbnRleHQgcGFzc2VkIHRvIHRoZSBkZXByZWNhdGVkIGNoYW5uZWxzIGNhbGxiYWNrLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxBcnJheTxWZWxvY2lvdXNTeW5jUmVhbHRpbWVDaGFubmVsRGVzY3JpcHRvcj4+fSBDaGFubmVsIGRlc2NyaXB0b3JzLlxuICAgKi9cbiAgYXN5bmMgY2hhbm5lbERlc2NyaXB0b3JzKGNvbnRleHQpIHtcbiAgICBjb25zdCByZWFsdGltZSA9IHRoaXMucmVhbHRpbWVDb25maWd1cmF0aW9uKClcbiAgICAvKiogQHR5cGUge0FycmF5PFZlbG9jaW91c1N5bmNSZWFsdGltZUNoYW5uZWxEZXNjcmlwdG9yPn0gKi9cbiAgICBjb25zdCBjaGFubmVsRGVzY3JpcHRvcnMgPSBbXVxuXG4gICAgZm9yIChjb25zdCBzY29wZVJvdyBvZiBhd2FpdCB0aGlzLnN5bmNDbGllbnQuc2NvcGVTdG9yZSgpLmFjdGl2ZVNjb3BlcygpKSB7XG4gICAgICBjaGFubmVsRGVzY3JpcHRvcnMucHVzaCh7XG4gICAgICAgIGNoYW5uZWw6IFZFTE9DSU9VU19TWU5DX0NIQU5ORUwsXG4gICAgICAgIHBhcmFtczoge1xuICAgICAgICAgIGNvbmRpdGlvbnM6IHRoaXMuYXR0cmlidXRlTmFtZWRDb25kaXRpb25zKHNjb3BlUm93KSxcbiAgICAgICAgICByZXNvdXJjZVR5cGU6IHNjb3BlUm93LnJlc291cmNlVHlwZSxcbiAgICAgICAgICAvLyBPbmx5IHRoZSBhbGwtdHlwZXMgc2NvcGUgY2FycmllcyB0aGUgdHlwZSBsaXN0OyBhIHR5cGUtZGVjbGFyZWQgc2NvcGUgbmVlZHMgbm9uZS5cbiAgICAgICAgICAuLi4oc2NvcGVSb3cucmVzb3VyY2VUeXBlID09PSBudWxsID8ge3Jlc291cmNlVHlwZXM6IHRoaXMuc3luY0NsaWVudC51c2VyU2NvcGVSZXNvdXJjZVR5cGVzKCl9IDoge30pXG4gICAgICAgIH1cbiAgICAgIH0pXG4gICAgfVxuXG4gICAgZm9yIChjb25zdCBbcmVzb3VyY2VUeXBlLCByZXNvdXJjZUNvbmZpZ10gb2YgT2JqZWN0LmVudHJpZXModGhpcy5zeW5jQ2xpZW50LmNvbmZpZy5yZXNvdXJjZXMpKSB7XG4gICAgICBpZiAoIXJlc291cmNlQ29uZmlnLnJlYWx0aW1lKSBjb250aW51ZVxuXG4gICAgICBjaGFubmVsRGVzY3JpcHRvcnMucHVzaCh7Y2hhbm5lbDogcmVzb3VyY2VDb25maWcucmVhbHRpbWUuY2hhbm5lbCwgcGFyYW1zOiByZXNvdXJjZUNvbmZpZy5yZWFsdGltZS5wYXJhbXMsIHJlc291cmNlVHlwZX0pXG4gICAgfVxuXG4gICAgaWYgKHJlYWx0aW1lPy5jaGFubmVscykge1xuICAgICAgY2hhbm5lbERlc2NyaXB0b3JzLnB1c2goLi4uYXdhaXQgcmVhbHRpbWUuY2hhbm5lbHMoY29udGV4dCkpXG4gICAgfVxuXG4gICAgaWYgKGNoYW5uZWxEZXNjcmlwdG9ycy5sZW5ndGggPT09IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcInN1YnNjcmliZVJlYWx0aW1lIGZvdW5kIG5vIGNoYW5uZWxzIHRvIHN1YnNjcmliZSAtIGRlY2xhcmUgYSBzeW5jIHNjb3BlIChzeW5jQ2xpZW50KCkuc3luYyhxdWVyeSkpIHNvIGl0cyBmcmFtZXdvcmsgc3luYyBjaGFubmVsIHN1YnNjcmlwdGlvbiBjYW4gYmUgZGVyaXZlZCwgb3IgdGhlIGRlcHJlY2F0ZWQgc3luYy5jbGllbnQucmVhbHRpbWUuY2hhbm5lbHMgY2FsbGJhY2tcIilcbiAgICB9XG5cbiAgICByZXR1cm4gY2hhbm5lbERlc2NyaXB0b3JzXG4gIH1cblxuICAvKipcbiAgICogVHJhbnNsYXRlcyBhIHBlcnNpc3RlZCBzY29wZSdzIGNvbmRpdGlvbiBrZXlzIHRvIHRoZSBtb2RlbCdzIGF0dHJpYnV0ZVxuICAgKiBuYW1lcyBzbyB0aGUgZnJhbWV3b3JrIGNoYW5uZWwgc3Vic2NyaXB0aW9uIG1hdGNoZXMgdGhlIHB1Ymxpc2hlcidzXG4gICAqIGF0dHJpYnV0ZS1uYW1lZCBzY29waW5nIHBhcmFtczogYHNlcmlhbGl6ZWRTY29wZUZyb21RdWVyeWAgcGVyc2lzdHMgdGhlXG4gICAqIHF1ZXJ5J3MgbW9kZWwtbm9ybWFsaXplZCBjb2x1bW4gbmFtZXMgKGZvciBleGFtcGxlIGBwcm9qZWN0X2lkYCksIHdoaWxlXG4gICAqIHNjb3BlLXBhcnRpdGlvbiBicm9hZGNhc3RzIGNhcnJ5IGF0dHJpYnV0ZSBuYW1lcyAoYHByb2plY3RJZGApLiBLZXlzXG4gICAqIHdpdGhvdXQgYSBjb2x1bW4gbWFwcGluZyBhcmUgYWxyZWFkeSBhdHRyaWJ1dGUgbmFtZXMgYW5kIHBhc3MgdGhyb3VnaDtcbiAgICogc2NvcGVzIG9uIG1vZGVscyB3aXRob3V0IGEgZGVjbGFyZWQgc3luYyByZXNvdXJjZSBmYWlsIGxvdWRseSBiZWNhdXNlIG5vXG4gICAqIGF0dHJpYnV0ZSBtYXBwaW5nIGV4aXN0cyBmb3IgdGhlbS5cbiAgICpcbiAgICogVGhlIGFsbC10eXBlcyAodXNlcikgc2NvcGUgaGFzIG5vIHJlc291cmNlIHR5cGUgYW5kIG5vIGNvbmRpdGlvbnMgLSBpdFxuICAgKiBjb3ZlcnMgZXZlcnl0aGluZyB0aGUgc2VydmVyIGF1dGhvcml6ZXMgZm9yIHRoZSBjYWxsZXIgLSBzbyB0aGVyZSBpc1xuICAgKiBub3RoaW5nIHRvIG1hcC5cbiAgICogQHBhcmFtIHt7Y29uZGl0aW9uczogUmVjb3JkPHN0cmluZywgUmV0dXJuVHlwZTx0eXBlb2YgSlNPTi5wYXJzZT4+LCByZXNvdXJjZVR5cGU6IHN0cmluZyB8IG51bGx9fSBzY29wZVJvdyAtIEFjdGl2ZSBzY29wZSByb3cuXG4gICAqIEByZXR1cm5zIHtSZWNvcmQ8c3RyaW5nLCBSZXR1cm5UeXBlPHR5cGVvZiBKU09OLnBhcnNlPj59IEF0dHJpYnV0ZS1uYW1lZCBzY29wZSBjb25kaXRpb25zLlxuICAgKi9cbiAgYXR0cmlidXRlTmFtZWRDb25kaXRpb25zKHNjb3BlUm93KSB7XG4gICAgaWYgKHNjb3BlUm93LnJlc291cmNlVHlwZSA9PT0gbnVsbCkgcmV0dXJuIHt9XG5cbiAgICBjb25zdCByZXNvdXJjZUNvbmZpZyA9IHRoaXMuc3luY0NsaWVudC5jb25maWcucmVzb3VyY2VzW3Njb3BlUm93LnJlc291cmNlVHlwZV1cblxuICAgIGlmICghcmVzb3VyY2VDb25maWcpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgc3Vic2NyaWJlUmVhbHRpbWUgY2FuJ3QgZGVyaXZlIGF0dHJpYnV0ZSBuYW1lcyBmb3IgdGhlIHN5bmMgc2NvcGUgZGVjbGFyZWQgb24gJHtzY29wZVJvdy5yZXNvdXJjZVR5cGV9IC0gZGVjbGFyZSBzdGF0aWMgc3luYyBvbiB0aGF0IG1vZGVsIHNvIGl0cyByZXNvdXJjZSBpcyByZWdpc3RlcmVkYClcbiAgICB9XG5cbiAgICBjb25zdCBjb2x1bW5OYW1lVG9BdHRyaWJ1dGVOYW1lID0gcmVzb3VyY2VDb25maWcubWV0YWRhdGFNb2RlbENsYXNzLmdldENvbHVtbk5hbWVUb0F0dHJpYnV0ZU5hbWVNYXAoKVxuICAgIC8qKiBAdHlwZSB7UmVjb3JkPHN0cmluZywgUmV0dXJuVHlwZTx0eXBlb2YgSlNPTi5wYXJzZT4+fSAqL1xuICAgIGNvbnN0IGNvbmRpdGlvbnMgPSB7fVxuXG4gICAgZm9yIChjb25zdCBbY29uZGl0aW9uTmFtZSwgY29uZGl0aW9uVmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKHNjb3BlUm93LmNvbmRpdGlvbnMpKSB7XG4gICAgICBjb25kaXRpb25zW2NvbHVtbk5hbWVUb0F0dHJpYnV0ZU5hbWVbY29uZGl0aW9uTmFtZV0gfHwgY29uZGl0aW9uTmFtZV0gPSBjb25kaXRpb25WYWx1ZVxuICAgIH1cblxuICAgIHJldHVybiBjb25kaXRpb25zXG4gIH1cblxuICAvKipcbiAgICogQ2hhaW5zIG9uZSBwdXNoZWQgbWVzc2FnZSBvbnRvIHRoZSBzZXJpYWxpemVkIGFwcGx5IHF1ZXVlIHNvIGNoYW5nZXMgYXBwbHlcbiAgICogaW4gYXJyaXZhbCBvcmRlcjsgZmFpbHVyZXMgZ28gdG8gdGhlIHN5bmMgY2xpZW50J3MgZXJyb3IgcmVwb3J0aW5nLlxuICAgKiBAcGFyYW0ge3tib2R5OiBSZXR1cm5UeXBlPHR5cGVvZiBKU09OLnBhcnNlPiwgZ2VuZXJhdGlvbj86IG51bWJlciwgcmVzb3VyY2VUeXBlOiBzdHJpbmcgfCBudWxsfX0gYXJncyAtIE1lc3NhZ2UgYXJncy5cbiAgICogQHJldHVybnMge3ZvaWR9XG4gICAqL1xuICBlbnF1ZXVlQXBwbHkoe2JvZHksIGdlbmVyYXRpb24gPSB0aGlzLl9nZW5lcmF0aW9uLCByZXNvdXJjZVR5cGV9KSB7XG4gICAgdGhpcy5fYXBwbHlQcm9taXNlID0gdGhpcy5fYXBwbHlQcm9taXNlLnRoZW4oYXN5bmMgKCkgPT4ge1xuICAgICAgaWYgKGdlbmVyYXRpb24gIT09IHRoaXMuX2dlbmVyYXRpb24pIHJldHVyblxuXG4gICAgICB0cnkge1xuICAgICAgICBhd2FpdCB0aGlzLmFwcGx5TWVzc2FnZSh7Ym9keSwgcmVzb3VyY2VUeXBlfSlcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIHRoaXMuc3luY0NsaWVudC5yZXBvcnRFcnJvcigvKiogQHR5cGUge0Vycm9yfSAqLyAoZXJyb3IpKVxuICAgICAgfVxuICAgIH0pXG4gIH1cblxuICAvKipcbiAgICogQXBwbGllcyBvbmUgcHVzaGVkIG1lc3NhZ2UgdGhyb3VnaCB0aGUgZGVyaXZlZCByZXNvdXJjZSBhcHBsaWVyOiBkcm9wc1xuICAgKiBvd24tZGV2aWNlIG1lc3NhZ2VzIGJ5IGVjaG8gb3JpZ2luLCBkZWZhdWx0cyB0aGUgY2hhbm5lbCdzIHJlc291cmNlVHlwZSBvbnRvXG4gICAqIGVudmVsb3BlcyB3aXRob3V0IG9uZSwgYW5kIGZhaWxzIGxvdWRseSBvbiB1bmtub3duIHJlc291cmNlIHR5cGVzLlxuICAgKiBAcGFyYW0ge3tib2R5OiBSZXR1cm5UeXBlPHR5cGVvZiBKU09OLnBhcnNlPiwgcmVzb3VyY2VUeXBlOiBzdHJpbmcgfCBudWxsfX0gYXJncyAtIE1lc3NhZ2UgYXJncy5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59XG4gICAqL1xuICBhc3luYyBhcHBseU1lc3NhZ2Uoe2JvZHksIHJlc291cmNlVHlwZX0pIHtcbiAgICBpZiAoIWJvZHkgfHwgdHlwZW9mIGJvZHkgIT09IFwib2JqZWN0XCIgfHwgQXJyYXkuaXNBcnJheShib2R5KSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBSZWFsdGltZSBzeW5jIG1lc3NhZ2VzIG11c3QgYmUgZW52ZWxvcGUgb2JqZWN0cywgZ290OiAke0pTT04uc3RyaW5naWZ5KGJvZHkpfWApXG4gICAgfVxuXG4gICAgY29uc3QgcmVhbHRpbWUgPSB0aGlzLnJlYWx0aW1lQ29uZmlndXJhdGlvbigpXG5cbiAgICBpZiAocmVhbHRpbWU/LmxvY2FsT3JpZ2luICYmIGJvZHkuZWNob09yaWdpbiAhPT0gdW5kZWZpbmVkICYmIGJvZHkuZWNob09yaWdpbiAhPT0gbnVsbCkge1xuICAgICAgY29uc3QgbG9jYWxPcmlnaW4gPSBTdHJpbmcoYXdhaXQgcmVhbHRpbWUubG9jYWxPcmlnaW4oKSlcblxuICAgICAgaWYgKFN0cmluZyhib2R5LmVjaG9PcmlnaW4pID09PSBsb2NhbE9yaWdpbikgcmV0dXJuXG4gICAgfVxuXG4gICAgY29uc3Qgc3luY1BheWxvYWRzID0gQXJyYXkuaXNBcnJheShib2R5LnN5bmNzKSA/IGJvZHkuc3luY3MgOiBbYm9keV1cbiAgICBjb25zdCBhcHBseVN5bmMgPSB0aGlzLnN5bmNDbGllbnQucmVtb3RlQXBwbHlTeW5jKHtzb3VyY2U6IFwicmVtb3RlIGNoYW5nZVwifSlcblxuICAgIC8vIENvYWxlc2NlIHJlY29yZC1jaGFuZ2UgZXZlbnRzIGFjcm9zcyB0aGUgcHVzaGVkIGJhdGNoIHNvIGl0IHRyaWdnZXJzIG9uZSBsaXZlLXF1ZXJ5IHJlLXJ1bi5cbiAgICBhd2FpdCByZWNvcmRDaGFuZ2VzLmJhdGNoKGFzeW5jICgpID0+IHtcbiAgICAgIGZvciAoY29uc3Qgc3luY1BheWxvYWQgb2Ygc3luY1BheWxvYWRzKSB7XG4gICAgICAgIGNvbnN0IHN5bmMgPSBTeW5jQXBpQ2xpZW50LnN5bmNFbnZlbG9wZUZyb21QYXlsb2FkKHtyZXNvdXJjZVR5cGUsIC4uLnN5bmNQYXlsb2FkfSlcblxuICAgICAgICBhd2FpdCBhcHBseVN5bmMoc3luYylcbiAgICAgIH1cbiAgICB9KVxuICB9XG5cbiAgLyoqXG4gICAqIFNjaGVkdWxlcyBhIGNvYWxlc2NlZCBiYWNrZ3JvdW5kIHB1bGwgY2xvc2luZyBvZmZsaW5lIGdhcHMgYWZ0ZXJcbiAgICogKHJlKXN1YnNjcmlwdGlvbiByZWFkaW5lc3MuIFJlc3VtZXMgYXJyaXZpbmcgd2hpbGUgYSBwdWxsIGlzIGFscmVhZHlcbiAgICogc2NoZWR1bGVkIG9yIGluIGZsaWdodCBjb2FsZXNjZSBpbnRvIHRoYXQgcHVsbCBpbnN0ZWFkIG9mIHN0YWNraW5nLlxuICAgKiBAcGFyYW0ge251bWJlcn0gW2dlbmVyYXRpb25dIC0gU3Vic2NyaXB0aW9uIGdlbmVyYXRpb24gb3duaW5nIHRoZSByZXN1bWUvcmVhZGluZXNzIGNhbGxiYWNrLlxuICAgKiBAcmV0dXJucyB7dm9pZH1cbiAgICovXG4gIHNjaGVkdWxlUHVsbChnZW5lcmF0aW9uID0gdGhpcy5fZ2VuZXJhdGlvbikge1xuICAgIGlmIChnZW5lcmF0aW9uICE9PSB0aGlzLl9nZW5lcmF0aW9uKSByZXR1cm5cbiAgICBpZiAodGhpcy5yZWFsdGltZUNvbmZpZ3VyYXRpb24oKT8ucHVsbE9uUmVjb25uZWN0ID09PSBmYWxzZSkgcmV0dXJuXG5cbiAgICB0aGlzLl9zY2hlZHVsZWRQdWxsIHx8PSAoYXN5bmMgKCkgPT4ge1xuICAgICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgdGhpcy5zeW5jQ2xpZW50LnB1bGwoKVxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgaWYgKCF0aGlzLnN5bmNDbGllbnQuaXNMaWZlY3ljbGVBYm9ydChlcnJvcikpIHtcbiAgICAgICAgICB0aGlzLnN5bmNDbGllbnQucmVwb3J0RXJyb3IoLyoqIEB0eXBlIHtFcnJvcn0gKi8gKGVycm9yKSlcbiAgICAgICAgfVxuICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgdGhpcy5fc2NoZWR1bGVkUHVsbCA9IG51bGxcbiAgICAgIH1cbiAgICB9KSgpXG4gIH1cbn1cblxuLyoqXG4gKiBUaHJvd3MgdGhlIGxpZmVjeWNsZSBhYm9ydCByZWFzb24gd2hlbiB0aGUgc3Vic2NyaXB0aW9uIGlzIG5vIGxvbmdlciBvd25lZC5cbiAqIEBwYXJhbSB7QWJvcnRTaWduYWwgfCB1bmRlZmluZWR9IHNpZ25hbCAtIFN1YnNjcmlwdGlvbiBsaWZlY3ljbGUgc2lnbmFsLlxuICogQHJldHVybnMge3ZvaWR9XG4gKi9cbmZ1bmN0aW9uIHRocm93SWZBYm9ydGVkKHNpZ25hbCkge1xuICBpZiAoIXNpZ25hbD8uYWJvcnRlZCkgcmV0dXJuXG5cbiAgdGhyb3cgc2lnbmFsLnJlYXNvbiBpbnN0YW5jZW9mIEVycm9yID8gc2lnbmFsLnJlYXNvbiA6IG5ldyBFcnJvcihcIlN5bmMgcmVhbHRpbWUgc3Vic2NyaXB0aW9uIHdhcyBhYm9ydGVkXCIpXG59XG4iXX0=
387
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3luYy1yZWFsdGltZS1icmlkZ2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvc3luYy9zeW5jLXJlYWx0aW1lLWJyaWRnZS5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxZQUFZO0FBRVosT0FBTyxhQUFhLE1BQU0sK0JBQStCLENBQUE7QUFDekQsT0FBTyxFQUFDLHlCQUF5QixFQUFDLE1BQU0sOEJBQThCLENBQUE7QUFFdEUsT0FBTyxhQUFhLE1BQU0sc0JBQXNCLENBQUE7QUFDaEQsT0FBTyxFQUFDLHNCQUFzQixFQUFDLE1BQU0sd0JBQXdCLENBQUE7QUFFN0QsbUlBQW1JO0FBQ25JLCtIQUErSDtBQUUvSDs7Ozs7Ozs7Ozs7O0dBWUc7QUFDSCxNQUFNLENBQUMsT0FBTyxPQUFPLGtCQUFrQjtJQUNyQzs7O09BR0c7SUFDSCxZQUFZLEVBQUMsVUFBVSxFQUFDO1FBQ3RCLElBQUksQ0FBQyxVQUFVLEdBQUcsVUFBVSxDQUFBO1FBQzVCLHlKQUF5SjtRQUN6SixJQUFJLENBQUMsU0FBUyxHQUFHLEVBQUUsQ0FBQTtRQUNuQiwwREFBMEQ7UUFDMUQsSUFBSSxDQUFDLE9BQU8sR0FBRyxJQUFJLENBQUE7UUFDbkIsdUtBQXVLO1FBQ3ZLLElBQUksQ0FBQyxXQUFXLEdBQUcsS0FBSyxDQUFBO1FBQ3hCLDRCQUE0QjtRQUM1QixJQUFJLENBQUMsYUFBYSxHQUFHLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQTtRQUN0Qyx1SEFBdUg7UUFDdkgsSUFBSSxDQUFDLFdBQVcsR0FBRyxDQUFDLENBQUE7UUFDcEIsbUNBQW1DO1FBQ25DLElBQUksQ0FBQyxjQUFjLEdBQUcsSUFBSSxDQUFBO1FBQzFCLG1DQUFtQztRQUNuQyxJQUFJLENBQUMsaUJBQWlCLEdBQUcsSUFBSSxDQUFBO1FBQzdCLDREQUE0RDtRQUM1RCxJQUFJLENBQUMsTUFBTSxHQUFHLGNBQWMsQ0FBQTtJQUM5QixDQUFDO0lBRUQ7Ozs7Ozs7T0FPRztJQUNI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LENBQUMsSUFBSSxFQUFFLENBQUE7WUFDOUIsQ0FBQztZQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7Z0JBQ2YsSUFBSSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsZ0JBQWdCLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztvQkFDN0MsSUFBSSxDQUFDLFVBQVUsQ0FBQyxXQUFXLENBQUMsb0JBQW9CLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFBO2dCQUMzRCxDQUFDO1lBQ0gsQ0FBQztvQkFBUyxDQUFDO2dCQUNULElBQUksQ0FBQyxjQUFjLEdBQUcsSUFBSSxDQUFBO1lBQzVCLENBQUM7UUFDSCxDQUFDLENBQUMsRUFBRSxDQUFBO0lBQ04sQ0FBQztDQUNGO0FBRUQ7Ozs7R0FJRztBQUNILFNBQVMsY0FBYyxDQUFDLE1BQU07SUFDNUIsSUFBSSxDQUFDLE1BQU0sRUFBRSxPQUFPO1FBQUUsT0FBTTtJQUU1QixNQUFNLE1BQU0sQ0FBQyxNQUFNLFlBQVksS0FBSyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxJQUFJLEtBQUssQ0FBQyx3Q0FBd0MsQ0FBQyxDQUFBO0FBQzVHLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBAdHMtY2hlY2tcblxuaW1wb3J0IHJlY29yZENoYW5nZXMgZnJvbSBcIi4uL2RhdGFiYXNlL3JlY29yZC1jaGFuZ2VzLmpzXCJcbmltcG9ydCB7bWVyZ2VSZW1vdGVSZXF1ZXN0Q29udGV4dH0gZnJvbSBcIi4uL3JlbW90ZS1yZXF1ZXN0LWNvbnRleHQuanNcIlxuXG5pbXBvcnQgU3luY0FwaUNsaWVudCBmcm9tIFwiLi9zeW5jLWFwaS1jbGllbnQuanNcIlxuaW1wb3J0IHtWRUxPQ0lPVVNfU1lOQ19DSEFOTkVMfSBmcm9tIFwiLi9zeW5jLWNoYW5uZWwtbmFtZS5qc1wiXG5cbi8qKiBAdHlwZWRlZiB7aW1wb3J0KFwiLi4vY29uZmlndXJhdGlvbi10eXBlcy5qc1wiKS5WZWxvY2lvdXNTeW5jUmVhbHRpbWVDaGFubmVsRGVzY3JpcHRvcn0gVmVsb2Npb3VzU3luY1JlYWx0aW1lQ2hhbm5lbERlc2NyaXB0b3IgKi9cbi8qKiBAdHlwZWRlZiB7aW1wb3J0KFwiLi4vY29uZmlndXJhdGlvbi10eXBlcy5qc1wiKS5WZWxvY2lvdXNTeW5jUmVhbHRpbWVXZWJzb2NrZXRDbGllbnR9IFZlbG9jaW91c1N5bmNSZWFsdGltZVdlYnNvY2tldENsaWVudCAqL1xuXG4vKipcbiAqIERlcml2ZWQgcmVhbHRpbWUgcHVzaCBicmlkZ2UgZm9yIHRoZSBzeW5jIGNsaWVudC4gU3Vic2NyaWJlcyBldmVyeSBkZWNsYXJlZFxuICogcHVsbCBzY29wZSB0byB0aGUgZnJhbWV3b3JrIHN5bmMgY2hhbm5lbCAoe0BsaW5rIFZFTE9DSU9VU19TWU5DX0NIQU5ORUx9KVxuICogYXV0b21hdGljYWxseSDigJQgdGhlIHN1YnNjcmliZSBwYXJhbXMgbWlycm9yIHRoZSBzY29wZSdzXG4gKiBge3Jlc291cmNlVHlwZSwgY29uZGl0aW9uc31gIHNvIHRoZSBzZXJ2ZXIgYXV0aG9yaXplcyB0aGVtIHRocm91Z2ggdGhlIHNhbWVcbiAqIHN5bmMgcmVzb3VyY2UgYXV0aG9yaXphdGlvbiBhcyBwdWxscyDigJQgcGx1cyBhbnkgZGVwcmVjYXRlZCBsZWdhY3kgY2hhbm5lbHNcbiAqIChjb25maWcgYHN5bmMuY2xpZW50LnJlYWx0aW1lLmNoYW5uZWxzYCBjYWxsYmFjayBhbmQgbW9kZWwtbGV2ZWxcbiAqIGBzdGF0aWMgc3luYyA9IHtyZWFsdGltZToge2NoYW5uZWx9fWAgZGVjbGFyYXRpb25zKS4gUHVzaGVkIGNoYW5nZXMgYXBwbHlcbiAqIHRocm91Z2ggdGhlIHNhbWUgZGVyaXZlZCByZXNvdXJjZSBhcHBsaWVyIGFzIHB1bGxzICh3aXRoIGVjaG8gc3VwcHJlc3Npb25cbiAqIGFnYWluc3QgdHJhY2tlZCByZS1xdWV1ZWluZyksIG93bi1kZXZpY2UgbWVzc2FnZXMgYXJlIGRyb3BwZWQgYnkgZWNob1xuICogb3JpZ2luLCBhbmQgYSBjb2FsZXNjZWQgYHB1bGwoKWAgZmlyZXMgd2hlbiBzdWJzY3JpcHRpb25zIGJlY29tZSByZWFkeSBvclxuICogcmVzdW1lIHNvIG9mZmxpbmUgZ2FwcyBjbG9zZS5cbiAqL1xuZXhwb3J0IGRlZmF1bHQgY2xhc3MgU3luY1JlYWx0aW1lQnJpZGdlIHtcbiAgLyoqXG4gICAqIEJ1aWxkcyB0aGUgYnJpZGdlIGZvciBhIHN5bmMgY2xpZW50LlxuICAgKiBAcGFyYW0ge3tzeW5jQ2xpZW50OiBpbXBvcnQoXCIuL3N5bmMtY2xpZW50LmpzXCIpLmRlZmF1bHR9fSBhcmdzIC0gQnJpZGdlIGFyZ3MuXG4gICAqL1xuICBjb25zdHJ1Y3Rvcih7c3luY0NsaWVudH0pIHtcbiAgICB0aGlzLnN5bmNDbGllbnQgPSBzeW5jQ2xpZW50XG4gICAgLyoqIEB0eXBlIHtBcnJheTx7Y2hhbm5lbDogc3RyaW5nLCByZXNvdXJjZVR5cGU6IHN0cmluZyB8IG51bGwsIHN1YnNjcmlwdGlvbjogaW1wb3J0KFwiLi4vY29uZmlndXJhdGlvbi10eXBlcy5qc1wiKS5WZWxvY2lvdXNTeW5jUmVhbHRpbWVTdWJzY3JpcHRpb259Pn0gKi9cbiAgICB0aGlzLl9jaGFubmVscyA9IFtdXG4gICAgLyoqIEB0eXBlIHtWZWxvY2lvdXNTeW5jUmVhbHRpbWVXZWJzb2NrZXRDbGllbnQgfCBudWxsfSAqL1xuICAgIHRoaXMuX2NsaWVudCA9IG51bGxcbiAgICAvKiogQHR5cGUge2Jvb2xlYW59IFdoZXRoZXIgdGhlIGJyaWRnZSBjcmVhdGVkIGl0cyBvd24gY2xpZW50IChkZXByZWNhdGVkIHBlci1jeWNsZSBwYXRoKSBhbmQgbXVzdCBkaXNjb25uZWN0IGl0IG9uIHVuc3Vic2NyaWJlLiBBIHNoYXJlZCBjb25uZWN0aW9uIGlzIG5ldmVyIG93bmVkLiAqL1xuICAgIHRoaXMuX293bnNDbGllbnQgPSBmYWxzZVxuICAgIC8qKiBAdHlwZSB7UHJvbWlzZTx2b2lkPn0gKi9cbiAgICB0aGlzLl9hcHBseVByb21pc2UgPSBQcm9taXNlLnJlc29sdmUoKVxuICAgIC8qKiBAdHlwZSB7bnVtYmVyfSBTdWJzY3JpcHRpb24gZ2VuZXJhdGlvbiAtIGJ1bXBlZCBieSB1bnN1YnNjcmliZSBzbyBpbi1mbGlnaHQgc3Vic2NyaWJlcyBkZXRlY3QgdGhleSBiZWNhbWUgc3RhbGUuICovXG4gICAgdGhpcy5fZ2VuZXJhdGlvbiA9IDBcbiAgICAvKiogQHR5cGUge1Byb21pc2U8dm9pZD4gfCBudWxsfSAqL1xuICAgIHRoaXMuX3NjaGVkdWxlZFB1bGwgPSBudWxsXG4gICAgLyoqIEB0eXBlIHtQcm9taXNlPHZvaWQ+IHwgbnVsbH0gKi9cbiAgICB0aGlzLl9zdWJzY3JpYmVQcm9taXNlID0gbnVsbFxuICAgIC8qKiBAdHlwZSB7XCJzdWJzY3JpYmVkXCIgfCBcInN1YnNjcmliaW5nXCIgfCBcInVuc3Vic2NyaWJlZFwifSAqL1xuICAgIHRoaXMuX3N0YXRlID0gXCJ1bnN1YnNjcmliZWRcIlxuICB9XG5cbiAgLyoqXG4gICAqIFN1YnNjcmliZXMgdGhlIGRlcml2ZWQgcmVhbHRpbWUgY2hhbm5lbHMgKGlkZW1wb3RlbnQgYW5kIHNpbmdsZS1mbGlnaHRlZCk6XG4gICAqIGFuIGFjdGl2ZSBzdWJzY3JpcHRpb24gaXMga2VwdCBhcy1pcyBhbmQgYSBjb25jdXJyZW50IHN1YnNjcmliZSBhd2FpdHMgdGhlXG4gICAqIGluLWZsaWdodCBhdHRlbXB0LiBDYWxsIGB1bnN1YnNjcmliZSgpYCBmaXJzdCB0byBjaGFuZ2UgdGhlIGNvbnRleHQuXG4gICAqIEBwYXJhbSB7UmV0dXJuVHlwZTx0eXBlb2YgSlNPTi5wYXJzZT59IFtjb250ZXh0XSAtIEFwcCBjb250ZXh0IHBhc3NlZCB0byB0aGUgZGVwcmVjYXRlZCBgc3luYy5jbGllbnQucmVhbHRpbWUuY2hhbm5lbHNgIGNhbGxiYWNrIChydW50aW1lIHNjb3BlIHZhbHVlcykuXG4gICAqIEBwYXJhbSB7e3NpZ25hbD86IEFib3J0U2lnbmFsfX0gW29wdGlvbnNdIC0gU3Vic2NyaXB0aW9uIGxpZmVjeWNsZSBvcHRpb25zLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn1cbiAgICovXG4gIGFzeW5jIHN1YnNjcmliZShjb250ZXh0LCB7c2lnbmFsfSA9IHt9KSB7XG4gICAgaWYgKHRoaXMuX3N0YXRlID09PSBcInN1YnNjcmliZWRcIikgcmV0dXJuXG5cbiAgICBpZiAoIXRoaXMuX3N1YnNjcmliZVByb21pc2UpIHtcbiAgICAgIHRoaXMuX3N1YnNjcmliZVByb21pc2UgPSB0aGlzLl9zdWJzY3JpYmUoY29udGV4dCwgc2lnbmFsKS5maW5hbGx5KCgpID0+IHtcbiAgICAgICAgdGhpcy5fc3Vic2NyaWJlUHJvbWlzZSA9IG51bGxcbiAgICAgIH0pXG4gICAgfVxuXG4gICAgYXdhaXQgdGhpcy5fc3Vic2NyaWJlUHJvbWlzZVxuICB9XG5cbiAgLyoqXG4gICAqIENvbm5lY3RzIHRoZSB3ZWJzb2NrZXQgY2xpZW50LCBzdWJzY3JpYmVzIGV2ZXJ5IGRlcml2ZWQgY2hhbm5lbCwgYW5kIHdhaXRzXG4gICAqIGZvciBlYWNoIHN1YnNjcmlwdGlvbidzIHNlcnZlciBhY2tub3dsZWRnZW1lbnQgYmVmb3JlIHRoZSBnYXAtY2xvc2luZyBwdWxsLFxuICAgKiBzbyBubyBjaGFuZ2UgY2FuIGxhbmQgYmV0d2VlbiB0aGUgcHVsbCBhbmQgdGhlIHN1YnNjcmlwdGlvbnMgZ29pbmcgbGl2ZS5cbiAgICogTG9jYWxseSBjcmVhdGVkIHJlc291cmNlcyBhcmUgb25seSBwcm9tb3RlZCB0byB0aGUgYnJpZGdlIG9uY2UgZXZlcnl0aGluZ1xuICAgKiBpcyBsaXZlOyBhbiB1bnN1YnNjcmliZSBhcnJpdmluZyBkdXJpbmcgYW55IGF3YWl0IG1hcmtzIHRoaXMgYXR0ZW1wdCBzdGFsZVxuICAgKiBhbmQgaXQgdGVhcnMgaXRzIG93biByZXNvdXJjZXMgZG93biBpbnN0ZWFkIG9mIHJlc3Vic2NyaWJpbmcuXG4gICAqIEBwYXJhbSB7UmV0dXJuVHlwZTx0eXBlb2YgSlNPTi5wYXJzZT59IGNvbnRleHQgLSBBcHAgY29udGV4dCBwYXNzZWQgdG8gdGhlIGNoYW5uZWxzIGNhbGxiYWNrLlxuICAgKiBAcGFyYW0ge0Fib3J0U2lnbmFsIHwgdW5kZWZpbmVkfSBzaWduYWwgLSBTdWJzY3JpcHRpb24gbGlmZWN5Y2xlIHNpZ25hbC5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59XG4gICAqL1xuICBhc3luYyBfc3Vic2NyaWJlKGNvbnRleHQsIHNpZ25hbCkge1xuICAgIGNvbnN0IGdlbmVyYXRpb24gPSB0aGlzLl9nZW5lcmF0aW9uXG5cbiAgICB0aGlzLl9zdGF0ZSA9IFwic3Vic2NyaWJpbmdcIlxuXG4gICAgLyoqIEB0eXBlIHtBcnJheTx7Y2hhbm5lbDogc3RyaW5nLCByZXNvdXJjZVR5cGU6IHN0cmluZyB8IG51bGwsIHN1YnNjcmlwdGlvbjogaW1wb3J0KFwiLi4vY29uZmlndXJhdGlvbi10eXBlcy5qc1wiKS5WZWxvY2lvdXNTeW5jUmVhbHRpbWVTdWJzY3JpcHRpb259Pn0gKi9cbiAgICBjb25zdCBjaGFubmVscyA9IFtdXG4gICAgLyoqIEB0eXBlIHtWZWxvY2lvdXNTeW5jUmVhbHRpbWVXZWJzb2NrZXRDbGllbnQgfCBudWxsfSAqL1xuICAgIGxldCBjbGllbnQgPSBudWxsXG4gICAgLyoqIEB0eXBlIHtib29sZWFufSBXaGV0aGVyIHRoaXMgYXR0ZW1wdCBjcmVhdGVkIGl0cyBvd24gY2xpZW50IGFuZCBtdXN0IGRpc2Nvbm5lY3QgaXQgb24gdGVhcmRvd24uICovXG4gICAgbGV0IG93bnNDbGllbnQgPSBmYWxzZVxuICAgIC8qKlxuICAgICAqIFRlYXJzIGRvd24gZXZlcnl0aGluZyB0aGlzIHN0YWxlL2ZhaWxlZCBzdWJzY3JpYmUgYXR0ZW1wdCBjcmVhdGVkIGl0c2VsZjpcbiAgICAgKiBhbHdheXMgY2xvc2VzIGl0cyBjaGFubmVsIHN1YnNjcmlwdGlvbnMsIGFuZCBkaXNjb25uZWN0cyB0aGUgd2Vic29ja2V0XG4gICAgICogb25seSB3aGVuIHRoZSBicmlkZ2Ugb3ducyBpdCAoZGVwcmVjYXRlZCBwZXItY3ljbGUgcGF0aCk7IGEgc2hhcmVkXG4gICAgICogY29ubmVjdGlvbiBzdGF5cyBvcGVuLlxuICAgICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fVxuICAgICAqL1xuICAgIGNvbnN0IHRlYXJkb3duID0gYXN5bmMgKCkgPT4ge1xuICAgICAgZm9yIChjb25zdCB7c3Vic2NyaXB0aW9ufSBvZiBjaGFubmVscykge1xuICAgICAgICBzdWJzY3JpcHRpb24uY2xvc2UoKVxuICAgICAgfVxuXG4gICAgICBpZiAoY2xpZW50ICYmIG93bnNDbGllbnQpIGF3YWl0IGNsaWVudC5kaXNjb25uZWN0QW5kU3RvcFJlY29ubmVjdCgpXG4gICAgfVxuXG4gICAgdHJ5IHtcbiAgICAgIHRocm93SWZBYm9ydGVkKHNpZ25hbClcblxuICAgICAgY29uc3Qgc2hhcmVkQ2xpZW50ID0gdGhpcy5zeW5jQ2xpZW50LnN5bmNDb25uZWN0aW9uKClcbiAgICAgIGNvbnN0IHJlYWx0aW1lID0gdGhpcy5yZXF1aXJlQ2xpZW50U291cmNlKHNoYXJlZENsaWVudClcbiAgICAgIGNvbnN0IGNoYW5uZWxEZXNjcmlwdG9ycyA9IGF3YWl0IHRoaXMuY2hhbm5lbERlc2NyaXB0b3JzKGNvbnRleHQpXG5cbiAgICAgIHRocm93SWZBYm9ydGVkKHNpZ25hbClcbiAgICAgIGlmIChnZW5lcmF0aW9uICE9PSB0aGlzLl9nZW5lcmF0aW9uKSByZXR1cm5cblxuICAgICAgaWYgKHNoYXJlZENsaWVudCkge1xuICAgICAgICBjbGllbnQgPSBzaGFyZWRDbGllbnRcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIHJlcXVpcmVDbGllbnRTb3VyY2UgZ3VhcmFudGVlZCByZWFsdGltZS5jcmVhdGVDbGllbnQgd2hlbiB0aGVyZSBpcyBubyBzaGFyZWQgY29ubmVjdGlvbi5cbiAgICAgICAgY2xpZW50ID0gYXdhaXQgLyoqIEB0eXBlIHtpbXBvcnQoXCIuLi9jb25maWd1cmF0aW9uLXR5cGVzLmpzXCIpLlZlbG9jaW91c1N5bmNDbGllbnRSZWFsdGltZUNvbmZpZ3VyYXRpb259ICovIChyZWFsdGltZSkuY3JlYXRlQ2xpZW50KClcbiAgICAgICAgb3duc0NsaWVudCA9IHRydWVcbiAgICAgIH1cblxuICAgICAgaWYgKGdlbmVyYXRpb24gIT09IHRoaXMuX2dlbmVyYXRpb24pIHtcbiAgICAgICAgYXdhaXQgdGVhcmRvd24oKVxuICAgICAgICByZXR1cm5cbiAgICAgIH1cblxuICAgICAgYXdhaXQgY2xpZW50LmNvbm5lY3Qoe3NpZ25hbH0pXG5cbiAgICAgIHRocm93SWZBYm9ydGVkKHNpZ25hbClcbiAgICAgIGlmIChnZW5lcmF0aW9uICE9PSB0aGlzLl9nZW5lcmF0aW9uKSB7XG4gICAgICAgIGF3YWl0IHRlYXJkb3duKClcbiAgICAgICAgcmV0dXJuXG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGF1dGhlbnRpY2F0aW9uVG9rZW4gPSBhd2FpdCB0aGlzLnN5bmNDbGllbnQuY29uZmlnLmF1dGhlbnRpY2F0aW9uVG9rZW4oKVxuXG4gICAgICB0aHJvd0lmQWJvcnRlZChzaWduYWwpXG4gICAgICBpZiAoZ2VuZXJhdGlvbiAhPT0gdGhpcy5fZ2VuZXJhdGlvbikge1xuICAgICAgICBhd2FpdCB0ZWFyZG93bigpXG4gICAgICAgIHJldHVyblxuICAgICAgfVxuXG4gICAgICBmb3IgKGNvbnN0IGNoYW5uZWxEZXNjcmlwdG9yIG9mIGNoYW5uZWxEZXNjcmlwdG9ycykge1xuICAgICAgICBpZiAoY2hhbm5lbERlc2NyaXB0b3IucGFyYW1zICYmIFwiYXV0aGVudGljYXRpb25Ub2tlblwiIGluIGNoYW5uZWxEZXNjcmlwdG9yLnBhcmFtcykge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgUmVhbHRpbWUgY2hhbm5lbCBcIiR7Y2hhbm5lbERlc2NyaXB0b3IuY2hhbm5lbH1cIiBwYXJhbXMgbXVzdCBub3QgaW5jbHVkZSBhdXRoZW50aWNhdGlvblRva2VuIC0gdGhlIGZyYW1ld29yayBpbmplY3RzIHRoZSBzeW5jLmNsaWVudCBhdXRoZW50aWNhdGlvblRva2VuIGF1dG9tYXRpY2FsbHlgKVxuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgcmVzb3VyY2VUeXBlID0gY2hhbm5lbERlc2NyaXB0b3IucmVzb3VyY2VUeXBlID8/IG51bGxcbiAgICAgICAgY29uc3QgcGFyYW1zID0gbWVyZ2VSZW1vdGVSZXF1ZXN0Q29udGV4dCh7XG4gICAgICAgICAgY29udGV4dDogdGhpcy5zeW5jQ2xpZW50LmNvbmZpZy5yZXF1ZXN0Q29udGV4dCxcbiAgICAgICAgICBsYWJlbDogXCJTeW5jIGNsaWVudCByZXF1ZXN0IGNvbnRleHRcIixcbiAgICAgICAgICBwYXJhbXM6IHsuLi5jaGFubmVsRGVzY3JpcHRvci5wYXJhbXMsIGF1dGhlbnRpY2F0aW9uVG9rZW59XG4gICAgICAgIH0pXG4gICAgICAgIGNvbnN0IHN1YnNjcmlwdGlvbiA9IGNsaWVudC5zdWJzY3JpYmVDaGFubmVsKGNoYW5uZWxEZXNjcmlwdG9yLmNoYW5uZWwsIHtcbiAgICAgICAgICBvbk1lc3NhZ2U6IChib2R5KSA9PiB0aGlzLmVucXVldWVBcHBseSh7Ym9keSwgZ2VuZXJhdGlvbiwgcmVzb3VyY2VUeXBlfSksXG4gICAgICAgICAgb25SZXN1bWU6ICgpID0+IHRoaXMuc2NoZWR1bGVQdWxsKGdlbmVyYXRpb24pLFxuICAgICAgICAgIHBhcmFtc1xuICAgICAgICB9KVxuXG4gICAgICAgIGNoYW5uZWxzLnB1c2goe2NoYW5uZWw6IGNoYW5uZWxEZXNjcmlwdG9yLmNoYW5uZWwsIHJlc291cmNlVHlwZSwgc3Vic2NyaXB0aW9ufSlcbiAgICAgIH1cblxuICAgICAgYXdhaXQgUHJvbWlzZS5hbGwoY2hhbm5lbHMubWFwKCh7c3Vic2NyaXB0aW9ufSkgPT4gc3Vic2NyaXB0aW9uLndhaXRGb3JSZWFkeSh7c2lnbmFsfSkpKVxuXG4gICAgICB0aHJvd0lmQWJvcnRlZChzaWduYWwpXG4gICAgICBpZiAoZ2VuZXJhdGlvbiAhPT0gdGhpcy5fZ2VuZXJhdGlvbikge1xuICAgICAgICBhd2FpdCB0ZWFyZG93bigpXG4gICAgICAgIHJldHVyblxuICAgICAgfVxuXG4gICAgICB0aGlzLl9jaGFubmVscyA9IGNoYW5uZWxzXG4gICAgICB0aGlzLl9jbGllbnQgPSBjbGllbnRcbiAgICAgIHRoaXMuX293bnNDbGllbnQgPSBvd25zQ2xpZW50XG4gICAgICB0aGlzLl9zdGF0ZSA9IFwic3Vic2NyaWJlZFwiXG4gICAgICB0aGlzLnNjaGVkdWxlUHVsbChnZW5lcmF0aW9uKVxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBhd2FpdCB0ZWFyZG93bigpXG5cbiAgICAgIGlmIChnZW5lcmF0aW9uID09PSB0aGlzLl9nZW5lcmF0aW9uKSB0aGlzLl9zdGF0ZSA9IFwidW5zdWJzY3JpYmVkXCJcblxuICAgICAgdGhyb3cgZXJyb3JcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQ2xvc2VzIGV2ZXJ5IGNoYW5uZWwgc3Vic2NyaXB0aW9uIChpZGVtcG90ZW50KS4gVGhlIHdlYnNvY2tldCBpc1xuICAgKiBkaXNjb25uZWN0ZWQgb25seSB3aGVuIHRoZSBicmlkZ2Ugb3ducyBpdCAoZGVwcmVjYXRlZCBwZXItY3ljbGVcbiAgICogYHJlYWx0aW1lLmNyZWF0ZUNsaWVudGAgcGF0aCk7IGEgc2hhcmVkIGFwcC1saWZldGltZSBjb25uZWN0aW9uIHN0YXlzIG9wZW5cbiAgICogc28gdW5zdWJzY3JpYmluZyBkcm9wcyBzdWJzY3JpcHRpb25zIHdpdGhvdXQgdGVhcmluZyBkb3duIHRoZSBzb2NrZXQuIEFsc29cbiAgICogbWFya3MgYW55IGluLWZsaWdodCBzdWJzY3JpYmUgYXR0ZW1wdCBzdGFsZSBzbyBpdCB0ZWFycyBpdHNlbGYgZG93biBpbnN0ZWFkXG4gICAqIG9mIGZpbmlzaGluZyB0aGUgc3Vic2NyaXB0aW9uIGFmdGVyd2FyZHMuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fVxuICAgKi9cbiAgYXN5bmMgdW5zdWJzY3JpYmUoKSB7XG4gICAgdGhpcy5fZ2VuZXJhdGlvbiArPSAxXG5cbiAgICBjb25zdCBjaGFubmVscyA9IHRoaXMuX2NoYW5uZWxzXG4gICAgY29uc3QgY2xpZW50ID0gdGhpcy5fY2xpZW50XG4gICAgY29uc3Qgb3duc0NsaWVudCA9IHRoaXMuX293bnNDbGllbnRcblxuICAgIHRoaXMuX2NoYW5uZWxzID0gW11cbiAgICB0aGlzLl9jbGllbnQgPSBudWxsXG4gICAgdGhpcy5fb3duc0NsaWVudCA9IGZhbHNlXG4gICAgdGhpcy5fc3RhdGUgPSBcInVuc3Vic2NyaWJlZFwiXG5cbiAgICBmb3IgKGNvbnN0IHtzdWJzY3JpcHRpb259IG9mIGNoYW5uZWxzKSB7XG4gICAgICBzdWJzY3JpcHRpb24uY2xvc2UoKVxuICAgIH1cblxuICAgIGlmIChjbGllbnQgJiYgb3duc0NsaWVudCkgYXdhaXQgY2xpZW50LmRpc2Nvbm5lY3RBbmRTdG9wUmVjb25uZWN0KClcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXBvcnRzIHRoZSBicmlkZ2Ugc3Vic2NyaXB0aW9uIHN0YXRlIGFuZCBwZXItY2hhbm5lbCByZWFkaW5lc3MuXG4gICAqIEByZXR1cm5zIHt7Y2hhbm5lbHM6IEFycmF5PHtjaGFubmVsOiBzdHJpbmcsIHJlYWR5OiBib29sZWFuLCByZXNvdXJjZVR5cGU6IHN0cmluZyB8IG51bGx9Piwgc3RhdGU6IFwic3Vic2NyaWJlZFwiIHwgXCJzdWJzY3JpYmluZ1wiIHwgXCJ1bnN1YnNjcmliZWRcIn19IFJlYWx0aW1lIHN0YXR1cy5cbiAgICovXG4gIHN0YXR1cygpIHtcbiAgICByZXR1cm4ge1xuICAgICAgY2hhbm5lbHM6IHRoaXMuX2NoYW5uZWxzLm1hcCgoe2NoYW5uZWwsIHJlc291cmNlVHlwZSwgc3Vic2NyaXB0aW9ufSkgPT4gKHtjaGFubmVsLCByZWFkeTogc3Vic2NyaXB0aW9uLmlzUmVhZHkoKSwgcmVzb3VyY2VUeXBlfSkpLFxuICAgICAgc3RhdGU6IHRoaXMuX3N0YXRlXG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEF3YWl0cyBhbGwgZW5xdWV1ZWQgbWVzc2FnZSBhcHBsaWVzIGFuZCBhbnkgc2NoZWR1bGVkIHB1bGwgKHRlc3RzLCBzaHV0ZG93biBmbG93cykuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fVxuICAgKi9cbiAgYXN5bmMgd2FpdEZvckFwcGxpZWQoKSB7XG4gICAgYXdhaXQgdGhpcy5fYXBwbHlQcm9taXNlXG4gICAgaWYgKHRoaXMuX3NjaGVkdWxlZFB1bGwpIGF3YWl0IHRoaXMuX3NjaGVkdWxlZFB1bGxcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXNvbHZlcyB0aGUgcmVhbHRpbWUgY29uZmlndXJhdGlvbiBibG9jaywgb3IgbnVsbCB3aGVuIHRoZSBhcHAgZGVjbGFyZWRcbiAgICogbm9uZSAodmFsaWQgd2hlbiBhIHNoYXJlZCBjb25uZWN0aW9uIGlzIGNvbmZpZ3VyZWQpLlxuICAgKiBAcmV0dXJucyB7aW1wb3J0KFwiLi4vY29uZmlndXJhdGlvbi10eXBlcy5qc1wiKS5WZWxvY2lvdXNTeW5jQ2xpZW50UmVhbHRpbWVDb25maWd1cmF0aW9uIHwgbnVsbH0gUmVhbHRpbWUgY29uZmlndXJhdGlvbiwgb3IgbnVsbC5cbiAgICovXG4gIHJlYWx0aW1lQ29uZmlndXJhdGlvbigpIHtcbiAgICByZXR1cm4gdGhpcy5zeW5jQ2xpZW50LmNvbmZpZy5yZWFsdGltZSB8fCBudWxsXG4gIH1cblxuICAvKipcbiAgICogUmVzb2x2ZXMgdGhlIHJlYWx0aW1lIGNvbmZpZ3VyYXRpb24gYW5kIGFzc2VydHMgYSB3ZWJzb2NrZXQgY2xpZW50IHNvdXJjZVxuICAgKiBleGlzdHM6IGEgc2hhcmVkIGNvbm5lY3Rpb24gcmlkZXMgaXRzIG93biBsaWZlY3ljbGUsIG90aGVyd2lzZSB0aGVcbiAgICogZGVwcmVjYXRlZCBwZXItY3ljbGUgYHJlYWx0aW1lLmNyZWF0ZUNsaWVudGAgbXVzdCBiZSBjb25maWd1cmVkLlxuICAgKiBAcGFyYW0ge2ltcG9ydChcIi4uL2NvbmZpZ3VyYXRpb24tdHlwZXMuanNcIikuVmVsb2Npb3VzU3luY1JlYWx0aW1lV2Vic29ja2V0Q2xpZW50IHwgbnVsbH0gc2hhcmVkQ2xpZW50IC0gU2hhcmVkIGNvbm5lY3Rpb24sIG9yIG51bGwuXG4gICAqIEByZXR1cm5zIHtpbXBvcnQoXCIuLi9jb25maWd1cmF0aW9uLXR5cGVzLmpzXCIpLlZlbG9jaW91c1N5bmNDbGllbnRSZWFsdGltZUNvbmZpZ3VyYXRpb24gfCBudWxsfSBSZWFsdGltZSBjb25maWd1cmF0aW9uLCBvciBudWxsLlxuICAgKi9cbiAgcmVxdWlyZUNsaWVudFNvdXJjZShzaGFyZWRDbGllbnQpIHtcbiAgICBjb25zdCByZWFsdGltZSA9IHRoaXMucmVhbHRpbWVDb25maWd1cmF0aW9uKClcblxuICAgIGlmICghc2hhcmVkQ2xpZW50ICYmIHR5cGVvZiByZWFsdGltZT8uY3JlYXRlQ2xpZW50ICE9PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcInN1YnNjcmliZVJlYWx0aW1lIHJlcXVpcmVzIGEgc2hhcmVkIGNvbm5lY3Rpb24gKHN5bmMuY2xpZW50LndlYnNvY2tldFVybCBvciBzeW5jLmNsaWVudC53ZWJzb2NrZXRDbGllbnQpIG9yIHRoZSBkZXByZWNhdGVkIHN5bmMuY2xpZW50LnJlYWx0aW1lLmNyZWF0ZUNsaWVudCBjYWxsYmFja1wiKVxuICAgIH1cblxuICAgIHJldHVybiByZWFsdGltZVxuICB9XG5cbiAgLyoqXG4gICAqIERlcml2ZXMgdGhlIGNoYW5uZWwgZGVzY3JpcHRvcnMgdG8gc3Vic2NyaWJlOiBvbmUgZnJhbWV3b3JrIHN5bmMgY2hhbm5lbFxuICAgKiBzdWJzY3JpcHRpb24gcGVyIGRlY2xhcmVkIHB1bGwgc2NvcGUgKHRoZSBwYXJhbXMgbWlycm9yIHRoZSBzY29wZSdzXG4gICAqIGB7cmVzb3VyY2VUeXBlLCBjb25kaXRpb25zfWApLCBwbHVzIHRoZSBkZXByZWNhdGVkIGxlZ2FjeSBwYXRocyDigJRcbiAgICogbW9kZWwtbGV2ZWwgc3RhdGljIHJlYWx0aW1lIGRlY2xhcmF0aW9ucyBhbmQgdGhlIGNvbmZpZyBjaGFubmVscyBjYWxsYmFjay5cbiAgICogRmFpbHMgbG91ZGx5IHdoZW4gbm90aGluZyBpcyBzdWJzY3JpYmFibGUuXG4gICAqIEBwYXJhbSB7UmV0dXJuVHlwZTx0eXBlb2YgSlNPTi5wYXJzZT59IGNvbnRleHQgLSBBcHAgY29udGV4dCBwYXNzZWQgdG8gdGhlIGRlcHJlY2F0ZWQgY2hhbm5lbHMgY2FsbGJhY2suXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPEFycmF5PFZlbG9jaW91c1N5bmNSZWFsdGltZUNoYW5uZWxEZXNjcmlwdG9yPj59IENoYW5uZWwgZGVzY3JpcHRvcnMuXG4gICAqL1xuICBhc3luYyBjaGFubmVsRGVzY3JpcHRvcnMoY29udGV4dCkge1xuICAgIGNvbnN0IHJlYWx0aW1lID0gdGhpcy5yZWFsdGltZUNvbmZpZ3VyYXRpb24oKVxuICAgIC8qKiBAdHlwZSB7QXJyYXk8VmVsb2Npb3VzU3luY1JlYWx0aW1lQ2hhbm5lbERlc2NyaXB0b3I+fSAqL1xuICAgIGNvbnN0IGNoYW5uZWxEZXNjcmlwdG9ycyA9IFtdXG5cbiAgICBmb3IgKGNvbnN0IHNjb3BlUm93IG9mIGF3YWl0IHRoaXMuc3luY0NsaWVudC5zY29wZVN0b3JlKCkuYWN0aXZlU2NvcGVzKCkpIHtcbiAgICAgIGNoYW5uZWxEZXNjcmlwdG9ycy5wdXNoKHtcbiAgICAgICAgY2hhbm5lbDogVkVMT0NJT1VTX1NZTkNfQ0hBTk5FTCxcbiAgICAgICAgcGFyYW1zOiB7XG4gICAgICAgICAgY29uZGl0aW9uczogdGhpcy5hdHRyaWJ1dGVOYW1lZENvbmRpdGlvbnMoc2NvcGVSb3cpLFxuICAgICAgICAgIHJlc291cmNlVHlwZTogc2NvcGVSb3cucmVzb3VyY2VUeXBlLFxuICAgICAgICAgIC8vIE9ubHkgdGhlIGFsbC10eXBlcyBzY29wZSBjYXJyaWVzIHRoZSB0eXBlIGxpc3Q7IGEgdHlwZS1kZWNsYXJlZCBzY29wZSBuZWVkcyBub25lLlxuICAgICAgICAgIC4uLihzY29wZVJvdy5yZXNvdXJjZVR5cGUgPT09IG51bGwgPyB7cmVzb3VyY2VUeXBlczogdGhpcy5zeW5jQ2xpZW50LnVzZXJTY29wZVJlc291cmNlVHlwZXMoKX0gOiB7fSlcbiAgICAgICAgfVxuICAgICAgfSlcbiAgICB9XG5cbiAgICBmb3IgKGNvbnN0IFtyZXNvdXJjZVR5cGUsIHJlc291cmNlQ29uZmlnXSBvZiBPYmplY3QuZW50cmllcyh0aGlzLnN5bmNDbGllbnQuY29uZmlnLnJlc291cmNlcykpIHtcbiAgICAgIGlmICghcmVzb3VyY2VDb25maWcucmVhbHRpbWUpIGNvbnRpbnVlXG5cbiAgICAgIGNoYW5uZWxEZXNjcmlwdG9ycy5wdXNoKHtjaGFubmVsOiByZXNvdXJjZUNvbmZpZy5yZWFsdGltZS5jaGFubmVsLCBwYXJhbXM6IHJlc291cmNlQ29uZmlnLnJlYWx0aW1lLnBhcmFtcywgcmVzb3VyY2VUeXBlfSlcbiAgICB9XG5cbiAgICBpZiAocmVhbHRpbWU/LmNoYW5uZWxzKSB7XG4gICAgICBjaGFubmVsRGVzY3JpcHRvcnMucHVzaCguLi5hd2FpdCByZWFsdGltZS5jaGFubmVscyhjb250ZXh0KSlcbiAgICB9XG5cbiAgICBpZiAoY2hhbm5lbERlc2NyaXB0b3JzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwic3Vic2NyaWJlUmVhbHRpbWUgZm91bmQgbm8gY2hhbm5lbHMgdG8gc3Vic2NyaWJlIC0gZGVjbGFyZSBhIHN5bmMgc2NvcGUgKHN5bmNDbGllbnQoKS5zeW5jKHF1ZXJ5KSkgc28gaXRzIGZyYW1ld29yayBzeW5jIGNoYW5uZWwgc3Vic2NyaXB0aW9uIGNhbiBiZSBkZXJpdmVkLCBvciB0aGUgZGVwcmVjYXRlZCBzeW5jLmNsaWVudC5yZWFsdGltZS5jaGFubmVscyBjYWxsYmFja1wiKVxuICAgIH1cblxuICAgIHJldHVybiBjaGFubmVsRGVzY3JpcHRvcnNcbiAgfVxuXG4gIC8qKlxuICAgKiBUcmFuc2xhdGVzIGEgcGVyc2lzdGVkIHNjb3BlJ3MgY29uZGl0aW9uIGtleXMgdG8gdGhlIG1vZGVsJ3MgYXR0cmlidXRlXG4gICAqIG5hbWVzIHNvIHRoZSBmcmFtZXdvcmsgY2hhbm5lbCBzdWJzY3JpcHRpb24gbWF0Y2hlcyB0aGUgcHVibGlzaGVyJ3NcbiAgICogYXR0cmlidXRlLW5hbWVkIHNjb3BpbmcgcGFyYW1zOiBgc2VyaWFsaXplZFNjb3BlRnJvbVF1ZXJ5YCBwZXJzaXN0cyB0aGVcbiAgICogcXVlcnkncyBtb2RlbC1ub3JtYWxpemVkIGNvbHVtbiBuYW1lcyAoZm9yIGV4YW1wbGUgYHByb2plY3RfaWRgKSwgd2hpbGVcbiAgICogc2NvcGUtcGFydGl0aW9uIGJyb2FkY2FzdHMgY2FycnkgYXR0cmlidXRlIG5hbWVzIChgcHJvamVjdElkYCkuIEtleXNcbiAgICogd2l0aG91dCBhIGNvbHVtbiBtYXBwaW5nIGFyZSBhbHJlYWR5IGF0dHJpYnV0ZSBuYW1lcyBhbmQgcGFzcyB0aHJvdWdoO1xuICAgKiBzY29wZXMgb24gbW9kZWxzIHdpdGhvdXQgYSBkZWNsYXJlZCBzeW5jIHJlc291cmNlIGZhaWwgbG91ZGx5IGJlY2F1c2Ugbm9cbiAgICogYXR0cmlidXRlIG1hcHBpbmcgZXhpc3RzIGZvciB0aGVtLlxuICAgKlxuICAgKiBUaGUgYWxsLXR5cGVzICh1c2VyKSBzY29wZSBoYXMgbm8gcmVzb3VyY2UgdHlwZSBhbmQgbm8gY29uZGl0aW9ucyAtIGl0XG4gICAqIGNvdmVycyBldmVyeXRoaW5nIHRoZSBzZXJ2ZXIgYXV0aG9yaXplcyBmb3IgdGhlIGNhbGxlciAtIHNvIHRoZXJlIGlzXG4gICAqIG5vdGhpbmcgdG8gbWFwLlxuICAgKiBAcGFyYW0ge3tjb25kaXRpb25zOiBSZWNvcmQ8c3RyaW5nLCBSZXR1cm5UeXBlPHR5cGVvZiBKU09OLnBhcnNlPj4sIHJlc291cmNlVHlwZTogc3RyaW5nIHwgbnVsbH19IHNjb3BlUm93IC0gQWN0aXZlIHNjb3BlIHJvdy5cbiAgICogQHJldHVybnMge1JlY29yZDxzdHJpbmcsIFJldHVyblR5cGU8dHlwZW9mIEpTT04ucGFyc2U+Pn0gQXR0cmlidXRlLW5hbWVkIHNjb3BlIGNvbmRpdGlvbnMuXG4gICAqL1xuICBhdHRyaWJ1dGVOYW1lZENvbmRpdGlvbnMoc2NvcGVSb3cpIHtcbiAgICBpZiAoc2NvcGVSb3cucmVzb3VyY2VUeXBlID09PSBudWxsKSByZXR1cm4ge31cblxuICAgIGNvbnN0IHJlc291cmNlQ29uZmlnID0gdGhpcy5zeW5jQ2xpZW50LmNvbmZpZy5yZXNvdXJjZXNbc2NvcGVSb3cucmVzb3VyY2VUeXBlXVxuXG4gICAgaWYgKCFyZXNvdXJjZUNvbmZpZykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBzdWJzY3JpYmVSZWFsdGltZSBjYW4ndCBkZXJpdmUgYXR0cmlidXRlIG5hbWVzIGZvciB0aGUgc3luYyBzY29wZSBkZWNsYXJlZCBvbiAke3Njb3BlUm93LnJlc291cmNlVHlwZX0gLSBkZWNsYXJlIHN0YXRpYyBzeW5jIG9uIHRoYXQgbW9kZWwgc28gaXRzIHJlc291cmNlIGlzIHJlZ2lzdGVyZWRgKVxuICAgIH1cblxuICAgIGNvbnN0IGNvbHVtbk5hbWVUb0F0dHJpYnV0ZU5hbWUgPSByZXNvdXJjZUNvbmZpZy5tZXRhZGF0YU1vZGVsQ2xhc3MuZ2V0Q29sdW1uTmFtZVRvQXR0cmlidXRlTmFtZU1hcCgpXG4gICAgLyoqIEB0eXBlIHtSZWNvcmQ8c3RyaW5nLCBSZXR1cm5UeXBlPHR5cGVvZiBKU09OLnBhcnNlPj59ICovXG4gICAgY29uc3QgY29uZGl0aW9ucyA9IHt9XG5cbiAgICBmb3IgKGNvbnN0IFtjb25kaXRpb25OYW1lLCBjb25kaXRpb25WYWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMoc2NvcGVSb3cuY29uZGl0aW9ucykpIHtcbiAgICAgIGNvbmRpdGlvbnNbY29sdW1uTmFtZVRvQXR0cmlidXRlTmFtZVtjb25kaXRpb25OYW1lXSB8fCBjb25kaXRpb25OYW1lXSA9IGNvbmRpdGlvblZhbHVlXG4gICAgfVxuXG4gICAgcmV0dXJuIGNvbmRpdGlvbnNcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGFpbnMgb25lIHB1c2hlZCBtZXNzYWdlIG9udG8gdGhlIHNlcmlhbGl6ZWQgYXBwbHkgcXVldWUgc28gY2hhbmdlcyBhcHBseVxuICAgKiBpbiBhcnJpdmFsIG9yZGVyOyBmYWlsdXJlcyBnbyB0byB0aGUgc3luYyBjbGllbnQncyBlcnJvciByZXBvcnRpbmcuXG4gICAqIEBwYXJhbSB7e2JvZHk6IFJldHVyblR5cGU8dHlwZW9mIEpTT04ucGFyc2U+LCBnZW5lcmF0aW9uPzogbnVtYmVyLCByZXNvdXJjZVR5cGU6IHN0cmluZyB8IG51bGx9fSBhcmdzIC0gTWVzc2FnZSBhcmdzLlxuICAgKiBAcmV0dXJucyB7dm9pZH1cbiAgICovXG4gIGVucXVldWVBcHBseSh7Ym9keSwgZ2VuZXJhdGlvbiA9IHRoaXMuX2dlbmVyYXRpb24sIHJlc291cmNlVHlwZX0pIHtcbiAgICB0aGlzLl9hcHBseVByb21pc2UgPSB0aGlzLl9hcHBseVByb21pc2UudGhlbihhc3luYyAoKSA9PiB7XG4gICAgICBpZiAoZ2VuZXJhdGlvbiAhPT0gdGhpcy5fZ2VuZXJhdGlvbikgcmV0dXJuXG5cbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IHRoaXMuYXBwbHlNZXNzYWdlKHtib2R5LCByZXNvdXJjZVR5cGV9KVxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgdGhpcy5zeW5jQ2xpZW50LnJlcG9ydEVycm9yKC8qKiBAdHlwZSB7RXJyb3J9ICovIChlcnJvcikpXG4gICAgICB9XG4gICAgfSlcbiAgfVxuXG4gIC8qKlxuICAgKiBBcHBsaWVzIG9uZSBwdXNoZWQgbWVzc2FnZSB0aHJvdWdoIHRoZSBkZXJpdmVkIHJlc291cmNlIGFwcGxpZXI6IGRyb3BzXG4gICAqIG93bi1kZXZpY2UgbWVzc2FnZXMgYnkgZWNobyBvcmlnaW4sIGRlZmF1bHRzIHRoZSBjaGFubmVsJ3MgcmVzb3VyY2VUeXBlIG9udG9cbiAgICogZW52ZWxvcGVzIHdpdGhvdXQgb25lLCBhbmQgZmFpbHMgbG91ZGx5IG9uIHVua25vd24gcmVzb3VyY2UgdHlwZXMuXG4gICAqIEBwYXJhbSB7e2JvZHk6IFJldHVyblR5cGU8dHlwZW9mIEpTT04ucGFyc2U+LCByZXNvdXJjZVR5cGU6IHN0cmluZyB8IG51bGx9fSBhcmdzIC0gTWVzc2FnZSBhcmdzLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn1cbiAgICovXG4gIGFzeW5jIGFwcGx5TWVzc2FnZSh7Ym9keSwgcmVzb3VyY2VUeXBlfSkge1xuICAgIGlmICghYm9keSB8fCB0eXBlb2YgYm9keSAhPT0gXCJvYmplY3RcIiB8fCBBcnJheS5pc0FycmF5KGJvZHkpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYFJlYWx0aW1lIHN5bmMgbWVzc2FnZXMgbXVzdCBiZSBlbnZlbG9wZSBvYmplY3RzLCBnb3Q6ICR7SlNPTi5zdHJpbmdpZnkoYm9keSl9YClcbiAgICB9XG5cbiAgICBjb25zdCByZWFsdGltZSA9IHRoaXMucmVhbHRpbWVDb25maWd1cmF0aW9uKClcblxuICAgIGlmIChyZWFsdGltZT8ubG9jYWxPcmlnaW4gJiYgYm9keS5lY2hvT3JpZ2luICE9PSB1bmRlZmluZWQgJiYgYm9keS5lY2hvT3JpZ2luICE9PSBudWxsKSB7XG4gICAgICBjb25zdCBsb2NhbE9yaWdpbiA9IFN0cmluZyhhd2FpdCByZWFsdGltZS5sb2NhbE9yaWdpbigpKVxuXG4gICAgICBpZiAoU3RyaW5nKGJvZHkuZWNob09yaWdpbikgPT09IGxvY2FsT3JpZ2luKSByZXR1cm5cbiAgICB9XG5cbiAgICBjb25zdCBzeW5jUGF5bG9hZHMgPSBBcnJheS5pc0FycmF5KGJvZHkuc3luY3MpID8gYm9keS5zeW5jcyA6IFtib2R5XVxuICAgIGNvbnN0IGFwcGx5U3luYyA9IHRoaXMuc3luY0NsaWVudC5yZW1vdGVBcHBseVN5bmMoe3NvdXJjZTogXCJyZW1vdGUgY2hhbmdlXCJ9KVxuXG4gICAgLy8gQ29hbGVzY2UgcmVjb3JkLWNoYW5nZSBldmVudHMgYWNyb3NzIHRoZSBwdXNoZWQgYmF0Y2ggc28gaXQgdHJpZ2dlcnMgb25lIGxpdmUtcXVlcnkgcmUtcnVuLlxuICAgIGF3YWl0IHJlY29yZENoYW5nZXMuYmF0Y2goYXN5bmMgKCkgPT4ge1xuICAgICAgZm9yIChjb25zdCBzeW5jUGF5bG9hZCBvZiBzeW5jUGF5bG9hZHMpIHtcbiAgICAgICAgY29uc3Qgc3luYyA9IFN5bmNBcGlDbGllbnQuc3luY0VudmVsb3BlRnJvbVBheWxvYWQoe3Jlc291cmNlVHlwZSwgLi4uc3luY1BheWxvYWR9KVxuXG4gICAgICAgIGF3YWl0IGFwcGx5U3luYyhzeW5jKVxuICAgICAgfVxuICAgIH0pXG4gIH1cblxuICAvKipcbiAgICogU2NoZWR1bGVzIGEgY29hbGVzY2VkIGJhY2tncm91bmQgcHVsbCBjbG9zaW5nIG9mZmxpbmUgZ2FwcyBhZnRlclxuICAgKiAocmUpc3Vic2NyaXB0aW9uIHJlYWRpbmVzcy4gUmVzdW1lcyBhcnJpdmluZyB3aGlsZSBhIHB1bGwgaXMgYWxyZWFkeVxuICAgKiBzY2hlZHVsZWQgb3IgaW4gZmxpZ2h0IGNvYWxlc2NlIGludG8gdGhhdCBwdWxsIGluc3RlYWQgb2Ygc3RhY2tpbmcuXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBbZ2VuZXJhdGlvbl0gLSBTdWJzY3JpcHRpb24gZ2VuZXJhdGlvbiBvd25pbmcgdGhlIHJlc3VtZS9yZWFkaW5lc3MgY2FsbGJhY2suXG4gICAqIEByZXR1cm5zIHt2b2lkfVxuICAgKi9cbiAgc2NoZWR1bGVQdWxsKGdlbmVyYXRpb24gPSB0aGlzLl9nZW5lcmF0aW9uKSB7XG4gICAgaWYgKGdlbmVyYXRpb24gIT09IHRoaXMuX2dlbmVyYXRpb24pIHJldHVyblxuICAgIGlmICh0aGlzLnJlYWx0aW1lQ29uZmlndXJhdGlvbigpPy5wdWxsT25SZWNvbm5lY3QgPT09IGZhbHNlKSByZXR1cm5cblxuICAgIGNvbnN0IGNvb3JkaW5hdG9yUnVuID0gdGhpcy5zeW5jQ2xpZW50LnJlcXVlc3RDb29yZGluYXRvclN5bmMoXCJyZWFsdGltZVwiKVxuXG4gICAgaWYgKGNvb3JkaW5hdG9yUnVuKSB7XG4gICAgICB0aGlzLl9zY2hlZHVsZWRQdWxsIHx8PSBjb29yZGluYXRvclJ1bi5maW5hbGx5KCgpID0+IHtcbiAgICAgICAgdGhpcy5fc2NoZWR1bGVkUHVsbCA9IG51bGxcbiAgICAgIH0pXG4gICAgICByZXR1cm5cbiAgICB9XG5cbiAgICB0aGlzLl9zY2hlZHVsZWRQdWxsIHx8PSAoYXN5bmMgKCkgPT4ge1xuICAgICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgdGhpcy5zeW5jQ2xpZW50LnB1bGwoKVxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgaWYgKCF0aGlzLnN5bmNDbGllbnQuaXNMaWZlY3ljbGVBYm9ydChlcnJvcikpIHtcbiAgICAgICAgICB0aGlzLnN5bmNDbGllbnQucmVwb3J0RXJyb3IoLyoqIEB0eXBlIHtFcnJvcn0gKi8gKGVycm9yKSlcbiAgICAgICAgfVxuICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgdGhpcy5fc2NoZWR1bGVkUHVsbCA9IG51bGxcbiAgICAgIH1cbiAgICB9KSgpXG4gIH1cbn1cblxuLyoqXG4gKiBUaHJvd3MgdGhlIGxpZmVjeWNsZSBhYm9ydCByZWFzb24gd2hlbiB0aGUgc3Vic2NyaXB0aW9uIGlzIG5vIGxvbmdlciBvd25lZC5cbiAqIEBwYXJhbSB7QWJvcnRTaWduYWwgfCB1bmRlZmluZWR9IHNpZ25hbCAtIFN1YnNjcmlwdGlvbiBsaWZlY3ljbGUgc2lnbmFsLlxuICogQHJldHVybnMge3ZvaWR9XG4gKi9cbmZ1bmN0aW9uIHRocm93SWZBYm9ydGVkKHNpZ25hbCkge1xuICBpZiAoIXNpZ25hbD8uYWJvcnRlZCkgcmV0dXJuXG5cbiAgdGhyb3cgc2lnbmFsLnJlYXNvbiBpbnN0YW5jZW9mIEVycm9yID8gc2lnbmFsLnJlYXNvbiA6IG5ldyBFcnJvcihcIlN5bmMgcmVhbHRpbWUgc3Vic2NyaXB0aW9uIHdhcyBhYm9ydGVkXCIpXG59XG4iXX0=
@@ -195,6 +195,42 @@ export default class LocalMutationLog {
195
195
  })
196
196
  }
197
197
 
198
+ /**
199
+ * Resolves a durable conflict explicitly. Keeping the server acknowledges the
200
+ * preserved local intent without replaying it; retrying local intent rebases
201
+ * it onto the conflict's authoritative serverVersion and returns it to the
202
+ * pending queue. The prior conflict result stays attached as audit metadata.
203
+ * @param {{id: string, resolution: "keep-server" | "retry-local"}} args - Resolution.
204
+ * @returns {Promise<LocalMutationLogRecord>} Resolved record.
205
+ */
206
+ async resolveConflict({id, resolution}) {
207
+ if (!["keep-server", "retry-local"].includes(resolution)) throw new Error(`Unknown local mutation conflict resolution '${resolution}'`)
208
+
209
+ return await withStorageKeyLock(this.storageKey, async () => {
210
+ const rawRecord = await this.storage.record(this.storageKey, id)
211
+
212
+ if (!rawRecord) throw new Error(`No local mutation log record '${id}'`)
213
+
214
+ const record = normalizeRecord(rawRecord)
215
+
216
+ if (record.status !== "conflict") throw new Error(`Cannot resolve ${record.status} local mutation '${id}' as a conflict`)
217
+
218
+ if (resolution === "keep-server") {
219
+ record.status = "synced"
220
+ } else {
221
+ const serverVersion = conflictServerVersion(record)
222
+
223
+ record.mutation = {...record.mutation, baseVersion: serverVersion}
224
+ record.status = "pending"
225
+ }
226
+
227
+ record.updatedAt = this.currentTimestamp()
228
+ await this.storage.updateRecord(this.storageKey, cloneRecord(record))
229
+
230
+ return restoreSyncResultTypes(cloneRecord(record))
231
+ })
232
+ }
233
+
198
234
  /**
199
235
  * Prunes terminal records that are no longer needed for replay dependencies.
200
236
  * @param {object} [args] - Compaction options.
@@ -267,6 +303,23 @@ function validStorage(storage) {
267
303
  && typeof storageObject.updateRecord === "function"
268
304
  }
269
305
 
306
+ /**
307
+ * Reads the authoritative version from a conflicted mutation.
308
+ * @param {LocalMutationLogRecord} record - Conflicted record.
309
+ * @returns {string | number | null} - Authoritative version.
310
+ */
311
+ function conflictServerVersion(record) {
312
+ const conflict = record.syncResult?.conflict
313
+
314
+ if (!conflict || conflict instanceof Date || typeof conflict !== "object" || Array.isArray(conflict) || !Object.hasOwn(conflict, "serverVersion")) {
315
+ throw new Error(`Cannot retry local mutation '${record.id}' without a conflict serverVersion`)
316
+ }
317
+
318
+ const conflictMetadata = /** @type {Record<string, unknown>} */ (conflict)
319
+
320
+ return cloneBaseVersion(conflictMetadata.serverVersion)
321
+ }
322
+
270
323
  /**
271
324
  * Sorts records by newest update/sequence first.
272
325
  * @param {LocalMutationLogRecord} left - Left record.
@@ -72,12 +72,13 @@ export default class SyncApiClient {
72
72
  * @param {number} [args.batchSize] - Batch size.
73
73
  * @param {import("./sync-client-types.js").SyncClientConflictTrackingConfig} args.conflictTracking - Tracking configuration.
74
74
  * @param {(payload: {authenticationToken: string, syncs: Array<Record<string, ReturnType<typeof JSON.parse>>>}, options?: {signal?: AbortSignal}) => Promise<SyncReplayResponse>} args.postReplay - Transport boundary.
75
+ * @param {(args: {record: import("./local-mutation-log.js").LocalMutationLogRecord, result: SyncReplayItem}) => Promise<void>} [args.applyConflict] - Applies authoritative conflict state to the local replica before preserving the rejected intent.
75
76
  * @param {(identity: string) => number} args.remoteGeneration - Current remote generation.
76
77
  * @param {string} args.resourceType - Resource whose log records should drain.
77
78
  * @param {AbortSignal} [args.signal] - Lifecycle cancellation signal.
78
79
  * @returns {Promise<void>} Resolves when no ready intent remains.
79
80
  */
80
- static async replayConflictTrackedSyncs({authenticationToken, batchSize, conflictTracking, postReplay, remoteGeneration, resourceType, signal}) {
81
+ static async replayConflictTrackedSyncs({applyConflict, authenticationToken, batchSize, conflictTracking, postReplay, remoteGeneration, resourceType, signal}) {
81
82
  const maxBatchSize = this.normalizedBatchSize(batchSize)
82
83
 
83
84
  while (true) {
@@ -111,6 +112,11 @@ export default class SyncApiClient {
111
112
  throw new Error(`Invalid sync state returned for mutation ${group[0].mutation.clientMutationId}: ${result.syncState}`)
112
113
  }
113
114
 
115
+ if (result.syncState === "conflict" && applyConflict) {
116
+ await applyConflict({record: group[0], result})
117
+ throwIfSyncAborted(signal)
118
+ }
119
+
114
120
  for (const record of group) {
115
121
  await applySyncReplayResultToLocalMutationLog({mutationLog: conflictTracking.mutationLog, record, result: /** @type {Record<string, ReturnType<typeof JSON.parse>>} */ (result)})
116
122
  throwIfSyncAborted(signal)
@@ -180,6 +180,8 @@ export default class SyncClient {
180
180
  this._scopeStore = scopeStore || null
181
181
  /** @type {Promise<void> | null} */
182
182
  this._scheduledReplay = null
183
+ /** @type {((reason: "mutation" | "realtime") => Promise<void>) | null} */
184
+ this._coordinatorTrigger = null
183
185
  /** @type {Record<string, import("./sync-api-client-types.js").SyncResourceConfig> | null} */
184
186
  this._pullResourceConfigs = null
185
187
  /** @type {Array<{callback: (record: ReturnType<typeof JSON.parse>) => Promise<void> | void, callbackName: "afterCreate" | "afterUpdate" | "afterDestroy" | "beforeUpdate" | "beforeDestroy", modelClass: ReturnType<typeof JSON.parse>}>} */
@@ -200,6 +202,7 @@ export default class SyncClient {
200
202
  this._lifecycleTransitionCount = 0
201
203
  /** @type {Promise<void>} */
202
204
  this._lifecycleTransitionPromise = Promise.resolve()
205
+ this._trackingGeneration = 0
203
206
  this._started = false
204
207
  }
205
208
 
@@ -212,7 +215,10 @@ export default class SyncClient {
212
215
  * @returns {Promise<void>}
213
216
  */
214
217
  async start() {
218
+ const trackingGeneration = this._trackingGeneration
219
+
215
220
  await this._lifecycleTransitionPromise
221
+ if (trackingGeneration !== this._trackingGeneration) return
216
222
  this.assertTenantReady()
217
223
  if (this._started) return
218
224
 
@@ -257,6 +263,8 @@ export default class SyncClient {
257
263
  * @returns {Promise<void>}
258
264
  */
259
265
  stop(options = {}) {
266
+ this._trackingGeneration += 1
267
+
260
268
  for (const {callback, callbackName, modelClass} of this._trackedCallbacks) {
261
269
  modelClass.unregisterLifecycleCallback(callbackName, callback)
262
270
  }
@@ -639,6 +647,33 @@ export default class SyncClient {
639
647
  setCurrentSyncClient(this)
640
648
  }
641
649
 
650
+ /**
651
+ * Attaches the one reusable coordinator that owns mutation and reconnect
652
+ * cycles for this client. The returned detach only removes the same owner.
653
+ * @param {(reason: "mutation" | "realtime") => Promise<void>} trigger - Coordinator trigger.
654
+ * @returns {() => void} Idempotent detach callback.
655
+ */
656
+ attachCoordinator(trigger) {
657
+ if (typeof trigger !== "function") throw new Error("SyncClient coordinator trigger must be a function")
658
+ if (this._coordinatorTrigger) throw new Error("SyncClient already has an attached coordinator")
659
+
660
+ this._coordinatorTrigger = trigger
661
+
662
+ return () => {
663
+ if (this._coordinatorTrigger === trigger) this._coordinatorTrigger = null
664
+ }
665
+ }
666
+
667
+ /**
668
+ * Routes framework-owned work through the attached coordinator, or returns
669
+ * null so the legacy direct scheduling owner may run.
670
+ * @param {"mutation" | "realtime"} reason - Trigger reason.
671
+ * @returns {Promise<void> | null} Coordinator flight, or null without an owner.
672
+ */
673
+ requestCoordinatorSync(reason) {
674
+ return this._coordinatorTrigger ? this._coordinatorTrigger(reason) : null
675
+ }
676
+
642
677
  /**
643
678
  * Returns the app's current sync client.
644
679
  * @returns {SyncClient} Current sync client.
@@ -892,6 +927,26 @@ export default class SyncClient {
892
927
  await this._subscribeUserScopePromise
893
928
  }
894
929
 
930
+ /**
931
+ * Declares and activates the server-enumerated user scope without starting
932
+ * realtime or pulling. Use this from SyncCoordinator.prepare() so the
933
+ * coordinator remains the sole network ordering owner.
934
+ * @returns {Promise<void>}
935
+ */
936
+ async activateUserScope() {
937
+ await this._runLifecycleWork(async (signal) => await this._activateUserScope(signal))
938
+ }
939
+
940
+ /**
941
+ * Activates the user scope under the current lifecycle generation.
942
+ * @param {AbortSignal} signal - Lifecycle cancellation signal.
943
+ * @returns {Promise<void>} - Resolves after the scope is durable.
944
+ */
945
+ async _activateUserScope(signal) {
946
+ await this.scopeStore().findOrCreateScope(await this.userScope())
947
+ this._throwIfLifecycleAborted(signal)
948
+ }
949
+
895
950
  /**
896
951
  * Declares and activates the user scope for every pullable resource, then
897
952
  * subscribes realtime and pulls.
@@ -902,8 +957,7 @@ export default class SyncClient {
902
957
  this._userScopeState = "subscribing"
903
958
 
904
959
  try {
905
- await this.scopeStore().findOrCreateScope(await this.userScope())
906
- this._throwIfLifecycleAborted(signal)
960
+ await this._activateUserScope(signal)
907
961
 
908
962
  await this.subscribeRealtime()
909
963
  this._throwIfLifecycleAborted(signal)
@@ -1087,6 +1141,7 @@ export default class SyncClient {
1087
1141
  if (!resourceConfig.conflictTracking) continue
1088
1142
 
1089
1143
  await SyncApiClient.replayConflictTrackedSyncs({
1144
+ applyConflict: async ({record, result}) => await this.applyConflictReplayResult({record, result, resourceType}),
1090
1145
  authenticationToken: await this.config.authenticationToken(),
1091
1146
  batchSize: this.config.batchSize,
1092
1147
  conflictTracking: resourceConfig.conflictTracking,
@@ -1110,6 +1165,97 @@ export default class SyncClient {
1110
1165
  this._throwIfLifecycleAborted(signal)
1111
1166
  }
1112
1167
 
1168
+ /**
1169
+ * Applies an authoritative serverModel returned by a conflict through the
1170
+ * same tenant-bound, tracking-suppressed applier used by pull/realtime.
1171
+ * A conflict result without serverModel has no authoritative state to apply
1172
+ * and remains diagnostic-only.
1173
+ * @param {{record: import("./local-mutation-log.js").LocalMutationLogRecord, resourceType: string, result: import("./sync-api-client-types.js").SyncReplayItem}} args - Conflict result.
1174
+ * @returns {Promise<void>}
1175
+ */
1176
+ async applyConflictReplayResult({record, resourceType, result}) {
1177
+ const conflict = result.conflict
1178
+
1179
+ if (!conflict || !Object.hasOwn(conflict, "serverModel")) return
1180
+
1181
+ const serverModel = conflict.serverModel
1182
+
1183
+ if (serverModel !== null && (typeof serverModel !== "object" || Array.isArray(serverModel))) {
1184
+ throw new Error(`Sync conflict serverModel for ${resourceType} must be an object or null`)
1185
+ }
1186
+
1187
+ const resourceId = record.mutation.payload?.resourceId
1188
+
1189
+ if (typeof resourceId !== "string" || resourceId.length === 0) throw new Error(`Sync conflict for ${resourceType} is missing resourceId`)
1190
+
1191
+ const sync = SyncApiClient.syncEnvelopeFromPayload({
1192
+ data: serverModel,
1193
+ resourceId,
1194
+ resourceType,
1195
+ syncType: serverModel === null ? "delete" : "update"
1196
+ })
1197
+
1198
+ await this.remoteApplySync({source: "conflict server version"})(sync)
1199
+ }
1200
+
1201
+ /**
1202
+ * Returns queue counts and privacy-safe conflicts for coordinator/UI status.
1203
+ * Full local/server payloads remain only in the durable mutation log.
1204
+ * @returns {Promise<import("./sync-coordinator-types.js").SyncClientInspection>} Durable sync state.
1205
+ */
1206
+ async inspectSyncState() {
1207
+ return await this._runLifecycleWork(async (signal) => {
1208
+ this._throwIfLifecycleAborted(signal)
1209
+ let pendingCount = 0
1210
+ let rejectedCount = 0
1211
+ /** @type {import("./sync-coordinator-types.js").SyncConflictDiagnostic[]} */
1212
+ const conflicts = []
1213
+
1214
+ for (const [resourceType, resourceConfig] of Object.entries(this.config.resources)) {
1215
+ if (!resourceConfig.conflictTracking) continue
1216
+
1217
+ for (const record of await resourceConfig.conflictTracking.mutationLog.records()) {
1218
+ if (record.mutation.model !== resourceType) continue
1219
+ if (["pending", "applied-locally", "peer-applied"].includes(record.status)) pendingCount += 1
1220
+ if (record.status === "rejected") rejectedCount += 1
1221
+ if (record.status === "conflict") conflicts.push(syncConflictDiagnostic(record))
1222
+ }
1223
+ this._throwIfLifecycleAborted(signal)
1224
+ }
1225
+
1226
+ pendingCount += await this.withTenantOperation(async (operation) => {
1227
+ const syncModel = operation ? operation.modelClass(this.config.syncModel) : this.config.syncModel
1228
+ const pendingRows = await syncModel.preload({resource: true}).where({state: "pending"}).order("created_at").toArray()
1229
+
1230
+ return pendingRows.length
1231
+ })
1232
+ this._throwIfLifecycleAborted(signal)
1233
+
1234
+ return {conflicts, pendingCount, rejectedCount}
1235
+ })
1236
+ }
1237
+
1238
+ /**
1239
+ * Resolves a durable conflict on its declared resource log. Retry-local is
1240
+ * scheduled through the current coordinator when attached.
1241
+ * @param {{recordId: string, resolution: "keep-server" | "retry-local", resourceType: string}} args - Resolution.
1242
+ * @returns {Promise<import("./local-mutation-log.js").LocalMutationLogRecord>} - Resolved durable record.
1243
+ */
1244
+ async resolveConflict({recordId, resolution, resourceType}) {
1245
+ return await this._runLifecycleWork(async (signal) => {
1246
+ const conflictTracking = this.config.resources[resourceType]?.conflictTracking
1247
+
1248
+ if (!conflictTracking) throw new Error(`No conflict-tracked sync resource configured for: ${resourceType}`)
1249
+
1250
+ const record = await conflictTracking.mutationLog.resolveConflict({id: recordId, resolution})
1251
+
1252
+ this._throwIfLifecycleAborted(signal)
1253
+ if (resolution === "retry-local") this.scheduleReplay()
1254
+
1255
+ return record
1256
+ })
1257
+ }
1258
+
1113
1259
  /**
1114
1260
  * Records an authoritative remote observation so an in-flight acknowledgement
1115
1261
  * cannot rebase a successor across that observation.
@@ -1192,6 +1338,13 @@ export default class SyncClient {
1192
1338
  * @returns {void}
1193
1339
  */
1194
1340
  scheduleReplay() {
1341
+ const coordinatorRun = this.requestCoordinatorSync("mutation")
1342
+
1343
+ if (coordinatorRun) {
1344
+ this._scheduledReplay = coordinatorRun
1345
+ return
1346
+ }
1347
+
1195
1348
  this._scheduledReplay = (async () => {
1196
1349
  try {
1197
1350
  await this.replayPending()
@@ -1414,6 +1567,41 @@ export default class SyncClient {
1414
1567
  }
1415
1568
  }
1416
1569
 
1570
+ /**
1571
+ * Builds privacy-safe conflict metadata from a durable record.
1572
+ * @param {import("./local-mutation-log.js").LocalMutationLogRecord} record - Durable conflict record.
1573
+ * @returns {import("./sync-coordinator-types.js").SyncConflictDiagnostic} - Safe diagnostic.
1574
+ */
1575
+ function syncConflictDiagnostic(record) {
1576
+ const conflict = record.syncResult?.conflict
1577
+ const conflictObject = conflict && !(conflict instanceof Date) && typeof conflict === "object" && !Array.isArray(conflict)
1578
+ ? /** @type {Record<string, unknown>} */ (conflict)
1579
+ : {}
1580
+ const resourceId = record.mutation.payload?.resourceId
1581
+
1582
+ if (typeof resourceId !== "string" || resourceId.length === 0) throw new Error(`Sync conflict ${record.id} is missing a safe resourceId`)
1583
+
1584
+ return {
1585
+ baseVersion: safeConflictVersion(conflictObject.baseVersion ?? record.mutation.baseVersion ?? null),
1586
+ clientMutationId: record.mutation.clientMutationId,
1587
+ localVersion: safeConflictVersion(conflictObject.localVersion ?? null),
1588
+ recordId: record.id,
1589
+ resourceId,
1590
+ resourceType: record.mutation.model,
1591
+ serverVersion: safeConflictVersion(conflictObject.serverVersion ?? null),
1592
+ versionAttribute: typeof conflictObject.versionAttribute === "string" ? conflictObject.versionAttribute : null
1593
+ }
1594
+ }
1595
+
1596
+ /**
1597
+ * Restricts diagnostic versions to safe scalar values.
1598
+ * @param {unknown} value - Version candidate.
1599
+ * @returns {string | number | null} - Safe scalar version.
1600
+ */
1601
+ function safeConflictVersion(value) {
1602
+ return value === null || typeof value === "string" || typeof value === "number" ? value : null
1603
+ }
1604
+
1417
1605
  /**
1418
1606
  * Builds one resource config from a model's `static sync` declaration plus its
1419
1607
  * derived column metadata.
@@ -0,0 +1,73 @@
1
+ // @ts-check
2
+ /* eslint-disable jsdoc/no-undefined-types -- ReadonlyArray is a TypeScript utility type used by checkJs. */
3
+
4
+ /** @typedef {"backoff" | "conflicted" | "failed" | "idle" | "offline" | "pending" | "stopped" | "syncing"} SyncCoordinatorState */
5
+
6
+ /**
7
+ * Privacy-safe conflict metadata for status surfaces. Mutation attributes,
8
+ * authoritative record data, credentials, and rejection reasons are excluded.
9
+ * @typedef {object} SyncConflictDiagnostic
10
+ * @property {string | number | null} baseVersion - Version the local mutation was based on.
11
+ * @property {string} clientMutationId - Durable client idempotency identifier.
12
+ * @property {string | number | null} localVersion - Optional client version returned by the conflict contract.
13
+ * @property {string} recordId - Durable local mutation-log record id.
14
+ * @property {string} resourceId - Stable resource identifier.
15
+ * @property {string} resourceType - Stable resource/model type.
16
+ * @property {string | number | null} serverVersion - Authoritative server version.
17
+ * @property {string | null} versionAttribute - Authoritative version attribute name.
18
+ */
19
+
20
+ /**
21
+ * Safe classified failure metadata. Applications own the classifier and must
22
+ * return only user-safe codes/messages; the original Error is never persisted.
23
+ * @typedef {object} SyncCoordinatorFailure
24
+ * @property {number} attempt - Consecutive cycle attempt number.
25
+ * @property {string} at - ISO timestamp of the failure.
26
+ * @property {string} code - Stable safe error code.
27
+ * @property {string} [message] - Optional safe display message.
28
+ * @property {boolean} retryable - Whether automatic retry is allowed.
29
+ */
30
+
31
+ /**
32
+ * Immutable coordinator status snapshot.
33
+ * @typedef {object} SyncCoordinatorStatus
34
+ * @property {ReadonlyArray<SyncConflictDiagnostic>} conflicts - Privacy-safe unresolved conflicts.
35
+ * @property {SyncCoordinatorFailure | null} failure - Last unresolved cycle failure.
36
+ * @property {string | null} lastSuccessAt - Last successful online cycle timestamp.
37
+ * @property {string | null} nextRetryAt - Scheduled automatic retry timestamp.
38
+ * @property {number} pendingCount - Durable pending mutation count.
39
+ * @property {number} rejectedCount - Durable permanently rejected mutation count.
40
+ * @property {SyncCoordinatorState} state - Observable lifecycle state.
41
+ */
42
+
43
+ /**
44
+ * Durable sync state reported by SyncClient.
45
+ * @typedef {object} SyncClientInspection
46
+ * @property {ReadonlyArray<SyncConflictDiagnostic>} conflicts - Privacy-safe conflict diagnostics.
47
+ * @property {number} pendingCount - Durable pending mutation count.
48
+ * @property {number} rejectedCount - Durable rejected mutation count.
49
+ */
50
+
51
+ /**
52
+ * Application connectivity signal adapter. SyncClient remains the authority
53
+ * for the current online check; this adapter only notifies the coordinator.
54
+ * @typedef {object} SyncCoordinatorConnectivity
55
+ * @property {(listener: (online: boolean) => void) => (() => void)} subscribe - Subscribes to connectivity changes.
56
+ */
57
+
58
+ /**
59
+ * Injected timer ownership for deterministic retry tests and teardown.
60
+ * @typedef {object} SyncCoordinatorScheduler
61
+ * @property {(timer: unknown) => void} clearTimeout - Clears a scheduled retry.
62
+ * @property {(callback: () => void, delayMs: number) => unknown} setTimeout - Schedules a retry.
63
+ */
64
+
65
+ /**
66
+ * Optional durable status metadata store. Conflict payloads remain owned by
67
+ * LocalMutationLog; this store receives only privacy-safe snapshots.
68
+ * @typedef {object} SyncCoordinatorStatusStore
69
+ * @property {() => Promise<SyncCoordinatorStatus | null> | SyncCoordinatorStatus | null} load - Loads the last safe snapshot.
70
+ * @property {(status: SyncCoordinatorStatus) => Promise<void> | void} save - Persists one safe snapshot.
71
+ */
72
+
73
+ export {}