velocious 1.0.396 → 1.0.398

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 (44) hide show
  1. package/README.md +12 -0
  2. package/build/src/configuration.d.ts +9 -0
  3. package/build/src/configuration.d.ts.map +1 -1
  4. package/build/src/configuration.js +19 -7
  5. package/build/src/database/record/instance-relationships/has-many.d.ts +2 -0
  6. package/build/src/database/record/instance-relationships/has-many.d.ts.map +1 -1
  7. package/build/src/database/record/instance-relationships/has-many.js +13 -1
  8. package/build/src/frontend-models/base.d.ts +22 -5
  9. package/build/src/frontend-models/base.d.ts.map +1 -1
  10. package/build/src/frontend-models/base.js +176 -33
  11. package/build/src/frontend-models/clear-pending-debounced-callback.d.ts +6 -0
  12. package/build/src/frontend-models/clear-pending-debounced-callback.d.ts.map +1 -0
  13. package/build/src/frontend-models/clear-pending-debounced-callback.js +12 -0
  14. package/build/src/frontend-models/event-hook-models.d.ts +12 -0
  15. package/build/src/frontend-models/event-hook-models.d.ts.map +1 -0
  16. package/build/src/frontend-models/event-hook-models.js +37 -0
  17. package/build/src/frontend-models/query.d.ts +63 -0
  18. package/build/src/frontend-models/query.d.ts.map +1 -1
  19. package/build/src/frontend-models/query.js +51 -1
  20. package/build/src/frontend-models/use-created-event.d.ts +17 -0
  21. package/build/src/frontend-models/use-created-event.d.ts.map +1 -0
  22. package/build/src/frontend-models/use-created-event.js +19 -0
  23. package/build/src/frontend-models/use-destroyed-event.d.ts +19 -0
  24. package/build/src/frontend-models/use-destroyed-event.d.ts.map +1 -0
  25. package/build/src/frontend-models/use-destroyed-event.js +103 -0
  26. package/build/src/frontend-models/use-model-class-event.d.ts +27 -0
  27. package/build/src/frontend-models/use-model-class-event.d.ts.map +1 -0
  28. package/build/src/frontend-models/use-model-class-event.js +116 -0
  29. package/build/src/frontend-models/use-updated-event.d.ts +20 -0
  30. package/build/src/frontend-models/use-updated-event.d.ts.map +1 -0
  31. package/build/src/frontend-models/use-updated-event.js +105 -0
  32. package/build/src/frontend-models/websocket-channel.d.ts +54 -12
  33. package/build/src/frontend-models/websocket-channel.d.ts.map +1 -1
  34. package/build/src/frontend-models/websocket-channel.js +116 -6
  35. package/build/src/http-server/client/websocket-session.js +2 -2
  36. package/build/src/http-server/websocket-channel.d.ts +29 -9
  37. package/build/src/http-server/websocket-channel.d.ts.map +1 -1
  38. package/build/src/http-server/websocket-channel.js +23 -5
  39. package/build/src/testing/browser-frontend-model-event-hook-scenarios.d.ts +56 -0
  40. package/build/src/testing/browser-frontend-model-event-hook-scenarios.d.ts.map +1 -0
  41. package/build/src/testing/browser-frontend-model-event-hook-scenarios.js +374 -0
  42. package/build/src/testing/browser-test-app.js +3 -1
  43. package/build/tsconfig.tsbuildinfo +1 -1
  44. package/package.json +10 -1
@@ -1,6 +1,16 @@
1
1
  // @ts-check
2
2
  import VelociousWebsocketChannel from "../http-server/websocket-channel.js";
3
3
  import Response from "../http-server/client/response.js";
4
+ import { serializeFrontendModelTransportValue } from "./transport-serialization.js";
5
+ /**
6
+ * @typedef {{action?: string, id?: string | number, record?: import("./query.js").FrontendModelTransportValue, [key: string]: import("./query.js").FrontendModelTransportValue | undefined}} FrontendModelLifecycleBroadcastBody
7
+ */
8
+ /**
9
+ * @typedef {{headers?: () => Record<string, string | string[] | undefined>, remoteAddress?: () => string | undefined}} FrontendModelWebsocketUpgradeRequest
10
+ */
11
+ /**
12
+ * @typedef {{headers: () => Record<string, string | string[] | undefined>, header: (name: string) => string | string[] | undefined, metadata: (key?: string) => Record<string, import("./query.js").FrontendModelTransportValue> | import("./query.js").FrontendModelTransportValue | undefined, path: () => string, httpMethod: () => string, remoteAddress: () => string | undefined, origin: () => string | string[] | undefined}} FrontendModelWebsocketSyntheticRequest
13
+ */
4
14
  /**
5
15
  * Per-session channel subscription for frontend-model lifecycle events.
6
16
  * Replaces the legacy `FrontendModelWebsocketChannel` (Phase 3).
@@ -18,6 +28,8 @@ import Response from "../http-server/client/response.js";
18
28
  * `matches()` routes by model name.
19
29
  */
20
30
  export default class FrontendModelWebsocketChannel extends VelociousWebsocketChannel {
31
+ /** @type {import("../authorization/ability.js").default | null} */
32
+ _ability = null;
21
33
  /** @returns {Promise<boolean>} Whether the frontend-model subscription is authorized. */
22
34
  async canSubscribe() {
23
35
  const modelName = this._modelName();
@@ -30,11 +42,12 @@ export default class FrontendModelWebsocketChannel extends VelociousWebsocketCha
30
42
  return false;
31
43
  const ability = await configuration.resolveAbility?.({
32
44
  params: { model: modelName },
33
- request: /** @type {any} */ (this._syntheticRequest()),
45
+ request: /** @type {import("../http-server/client/request.js").default} */ (this._syntheticRequest()),
34
46
  response: new Response({ configuration })
35
47
  });
36
48
  if (!ability)
37
49
  return false;
50
+ this._ability = ability;
38
51
  // Load resource-declared rules for this model class before checking,
39
52
  // otherwise `rulesFor` returns empty for abilities whose resources
40
53
  // register rules lazily via `abilities()`.
@@ -47,7 +60,34 @@ export default class FrontendModelWebsocketChannel extends VelociousWebsocketCha
47
60
  return readRules.some((/** @type {{effect: string}} */ rule) => rule.effect === "allow");
48
61
  }
49
62
  /**
50
- * @param {Record<string, any>} broadcastParams - Params from `broadcastToChannel`.
63
+ * @param {FrontendModelLifecycleBroadcastBody} body - Broadcast body.
64
+ * @param {{eventId?: string}} [meta] - Optional event metadata.
65
+ * @returns {Promise<void>} Resolves after delivery.
66
+ */
67
+ async deliverBroadcast(body, meta) {
68
+ if (!this._hasProjectionParams()) {
69
+ this.sendMessage(body, meta);
70
+ return;
71
+ }
72
+ if (!body || typeof body !== "object" || body.action === "destroy") {
73
+ this.sendMessage(body, meta);
74
+ return;
75
+ }
76
+ if (body.id === undefined || body.id === null) {
77
+ this.sendMessage(body, meta);
78
+ return;
79
+ }
80
+ const projectedRecord = await this._projectedRecordForEventId(body.id);
81
+ if (!projectedRecord) {
82
+ return;
83
+ }
84
+ this.sendMessage({
85
+ ...body,
86
+ record: serializeFrontendModelTransportValue(projectedRecord)
87
+ }, meta);
88
+ }
89
+ /**
90
+ * @param {Record<string, import("./query.js").FrontendModelTransportValue>} broadcastParams - Params from `broadcastToChannel`.
51
91
  * @returns {boolean} Whether the broadcast matches this subscriber's model.
52
92
  */
53
93
  matches(broadcastParams) {
@@ -59,6 +99,76 @@ export default class FrontendModelWebsocketChannel extends VelociousWebsocketCha
59
99
  ? this.params.model
60
100
  : null;
61
101
  }
102
+ /** @returns {boolean} - Whether this subscription requested per-event record projection. */
103
+ _hasProjectionParams() {
104
+ return this.params.select !== undefined
105
+ || this.params.preload !== undefined
106
+ || this.params.withCount !== undefined
107
+ || this.params.abilities !== undefined
108
+ || this.params.queryData !== undefined;
109
+ }
110
+ /**
111
+ * @param {typeof import("../frontend-model-controller.js").default} FrontendModelController - Server-side frontend-model controller class.
112
+ * @returns {import("../frontend-model-controller.js").default} - Synthetic controller used for resource serialization.
113
+ */
114
+ _frontendModelController(FrontendModelController) {
115
+ const configuration = this.session.configuration;
116
+ const controller = new FrontendModelController({
117
+ action: "websocketEvent",
118
+ configuration,
119
+ controller: "frontend-models",
120
+ params: {
121
+ abilities: this.params.abilities,
122
+ model: this._modelName(),
123
+ preload: this.params.preload,
124
+ queryData: this.params.queryData,
125
+ select: this.params.select,
126
+ withCount: this.params.withCount
127
+ },
128
+ request: /** @type {import("../http-server/client/request.js").default} */ (this._syntheticRequest()),
129
+ response: new Response({ configuration }),
130
+ viewPath: "/"
131
+ });
132
+ controller._frontendModelAbilityOverride = this._ability || undefined;
133
+ return controller;
134
+ }
135
+ /**
136
+ * @param {string | number} id - Event record id.
137
+ * @returns {Promise<Record<string, import("./query.js").FrontendModelTransportValue> | null>} - Serialized projected record.
138
+ */
139
+ async _projectedRecordForEventId(id) {
140
+ const frontendModelControllerPath = "../frontend-model-controller.js";
141
+ const { default: FrontendModelController } = await import(frontendModelControllerPath);
142
+ const controller = this._frontendModelController(FrontendModelController);
143
+ await controller.ensureFrontendModelClassInitialized();
144
+ const ModelClass = controller.frontendModelClass();
145
+ const primaryKey = ModelClass.primaryKey();
146
+ let query = ModelClass.where({ [primaryKey]: id });
147
+ const preload = controller.frontendModelPreload();
148
+ if (preload)
149
+ query = query.preload(preload);
150
+ for (const entry of controller.frontendModelWithCount()) {
151
+ /** @type {Record<string, boolean | {relationship?: string, where?: Record<string, import("./query.js").FrontendModelTransportValue>}>} */
152
+ const spec = {};
153
+ spec[entry.attributeName] = {
154
+ relationship: entry.relationshipName,
155
+ where: entry.where ? /** @type {Record<string, import("./query.js").FrontendModelTransportValue>} */ (entry.where) : undefined
156
+ };
157
+ query.withCount(spec);
158
+ }
159
+ const queryData = controller.frontendModelQueryData();
160
+ if (queryData !== null)
161
+ query.queryData(queryData);
162
+ query = controller.applyFrontendModelTranslatedAttributePreloads({ query });
163
+ const model = await query.first();
164
+ if (!model)
165
+ return null;
166
+ if (this.params.abilities !== undefined) {
167
+ await controller.frontendModelComputeAbilities([model]);
168
+ }
169
+ controller._frontendModelAbilityOverride = undefined;
170
+ return await controller.frontendModelResourceInstance().serialize(model, "find");
171
+ }
62
172
  /**
63
173
  * Minimal Request-like stub used only for ability resolution. Avoids
64
174
  * importing `WebsocketRequest` here because its `node:querystring`
@@ -69,14 +179,14 @@ export default class FrontendModelWebsocketChannel extends VelociousWebsocketCha
69
179
  * map uses `"Cookie"` or `"cookie"`. Session metadata stays separate
70
180
  * from headers and is exposed through `metadata(...)` for ability
71
181
  * resolvers that need websocket-delivered session data.
72
- * @returns {{headers: () => Record<string, any>, header: (name: string) => any, metadata: (key?: string) => any, path: () => string, httpMethod: () => string, remoteAddress: () => string | undefined, origin: () => any}} Request-like object for ability resolution.
182
+ * @returns {FrontendModelWebsocketSyntheticRequest} Request-like object for ability resolution.
73
183
  */
74
184
  _syntheticRequest() {
75
- const upgradeRequest = /** @type {any} */ (this.session.upgradeRequest);
185
+ const upgradeRequest = /** @type {FrontendModelWebsocketUpgradeRequest} */ (this.session.upgradeRequest);
76
186
  const rawHeaders = typeof upgradeRequest?.headers === "function" ? upgradeRequest.headers() : {};
77
187
  const metadata = typeof this.session.getMetadata === "function" ? this.session.getMetadata() : {};
78
188
  const remoteAddress = typeof upgradeRequest?.remoteAddress === "function" ? upgradeRequest.remoteAddress() : undefined;
79
- /** @type {Record<string, any>} */
189
+ /** @type {Record<string, string | string[] | undefined>} */
80
190
  const headerMap = {};
81
191
  for (const key of Object.keys(rawHeaders || {})) {
82
192
  headerMap[key.toLowerCase()] = rawHeaders[key];
@@ -92,4 +202,4 @@ export default class FrontendModelWebsocketChannel extends VelociousWebsocketCha
92
202
  };
93
203
  }
94
204
  }
95
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2Vic29ja2V0LWNoYW5uZWwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvZnJvbnRlbmQtbW9kZWxzL3dlYnNvY2tldC1jaGFubmVsLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLFlBQVk7QUFFWixPQUFPLHlCQUF5QixNQUFNLHFDQUFxQyxDQUFBO0FBQzNFLE9BQU8sUUFBUSxNQUFNLG1DQUFtQyxDQUFBO0FBRXhEOzs7Ozs7Ozs7Ozs7Ozs7R0FlRztBQUNILE1BQU0sQ0FBQyxPQUFPLE9BQU8sNkJBQThCLFNBQVEseUJBQXlCO0lBQ2xGLHlGQUF5RjtJQUN6RixLQUFLLENBQUMsWUFBWTtRQUNoQixNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUE7UUFFbkMsSUFBSSxDQUFDLFNBQVM7WUFBRSxPQUFPLEtBQUssQ0FBQTtRQUU1QixNQUFNLGFBQWEsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLGFBQWEsQ0FBQTtRQUNoRCxNQUFNLFlBQVksR0FBRyxhQUFhLENBQUMsZUFBZSxFQUFFLEVBQUUsSUFBSSxFQUFFLENBQUE7UUFDNUQsTUFBTSxVQUFVLEdBQUcsWUFBWSxDQUFDLFNBQVMsQ0FBQyxDQUFBO1FBRTFDLElBQUksQ0FBQyxVQUFVO1lBQUUsT0FBTyxLQUFLLENBQUE7UUFFN0IsTUFBTSxPQUFPLEdBQUcsTUFBTSxhQUFhLENBQUMsY0FBYyxFQUFFLENBQUM7WUFDbkQsTUFBTSxFQUFFLEVBQUMsS0FBSyxFQUFFLFNBQVMsRUFBQztZQUMxQixPQUFPLEVBQUUsa0JBQWtCLENBQUMsQ0FBQyxJQUFJLENBQUMsaUJBQWlCLEVBQUUsQ0FBQztZQUN0RCxRQUFRLEVBQUUsSUFBSSxRQUFRLENBQUMsRUFBQyxhQUFhLEVBQUMsQ0FBQztTQUN4QyxDQUFDLENBQUE7UUFFRixJQUFJLENBQUMsT0FBTztZQUFFLE9BQU8sS0FBSyxDQUFBO1FBRTFCLHFFQUFxRTtRQUNyRSxtRUFBbUU7UUFD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Y2VzQ29udGVudCI6WyIvLyBAdHMtY2hlY2tcblxuaW1wb3J0IFZlbG9jaW91c1dlYnNvY2tldENoYW5uZWwgZnJvbSBcIi4uL2h0dHAtc2VydmVyL3dlYnNvY2tldC1jaGFubmVsLmpzXCJcbmltcG9ydCBSZXNwb25zZSBmcm9tIFwiLi4vaHR0cC1zZXJ2ZXIvY2xpZW50L3Jlc3BvbnNlLmpzXCJcblxuLyoqXG4gKiBQZXItc2Vzc2lvbiBjaGFubmVsIHN1YnNjcmlwdGlvbiBmb3IgZnJvbnRlbmQtbW9kZWwgbGlmZWN5Y2xlIGV2ZW50cy5cbiAqIFJlcGxhY2VzIHRoZSBsZWdhY3kgYEZyb250ZW5kTW9kZWxXZWJzb2NrZXRDaGFubmVsYCAoUGhhc2UgMykuXG4gKlxuICogQXV0aCBtb2RlbDogc3Vic2NyaWJlLXRpbWUgb25seS4gYGNhblN1YnNjcmliZWAgcmVzb2x2ZXMgdGhlIGNhbGxlcidzXG4gKiBhYmlsaXR5IG9uY2UsIGNoZWNrcyB0aGF0IGF0IGxlYXN0IG9uZSBgYWxsb3dgIHJ1bGUgZXhpc3RzIGZvclxuICogYHJlYWRgIG9uIHRoZSByZXF1ZXN0ZWQgbW9kZWwgY2xhc3MsIGFuZCB0aGVuIGRlbGl2ZXJzIGV2ZXJ5IGZ1dHVyZVxuICogbGlmZWN5Y2xlIGJyb2FkY2FzdCBmb3IgdGhhdCBtb2RlbCB3aXRob3V0IHJlLWF1dGhvcml6aW5nIHBlciBldmVudC5cbiAqIFRoaXMgbWF0Y2hlcyB0aGUgZXhwbGljaXQgZGVzaWduIGRlY2lzaW9uIGluIFBoYXNlIDMgdG8gdHJhZGVcbiAqIHBlci1yZWNvcmQgdmlzaWJpbGl0eSBndWFyYW50ZWVzIGZvciBtYXNzaXZlbHkgY2hlYXBlciBicm9hZGNhc3QgZmFuLW91dC5cbiAqXG4gKiBXaXJlOiBzdWJzY3JpYmUgd2l0aCBgc3Vic2NyaWJlQ2hhbm5lbChcImZyb250ZW5kLW1vZGVsc1wiLCB7cGFyYW1zOiB7bW9kZWw6IE1vZGVsTmFtZX19KWAuXG4gKiBCYWNrZW5kIHB1Ymxpc2hlcyBge2FjdGlvbiwgaWQsIHJlY29yZH1gIHZpYVxuICogYGNvbmZpZ3VyYXRpb24uYnJvYWRjYXN0VG9DaGFubmVsKFwiZnJvbnRlbmQtbW9kZWxzXCIsIHttb2RlbDogTW9kZWxOYW1lfSwgYm9keSlgO1xuICogYG1hdGNoZXMoKWAgcm91dGVzIGJ5IG1vZGVsIG5hbWUuXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIEZyb250ZW5kTW9kZWxXZWJzb2NrZXRDaGFubmVsIGV4dGVuZHMgVmVsb2Npb3VzV2Vic29ja2V0Q2hhbm5lbCB7XG4gIC8qKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gV2hldGhlciB0aGUgZnJvbnRlbmQtbW9kZWwgc3Vic2NyaXB0aW9uIGlzIGF1dGhvcml6ZWQuICovXG4gIGFzeW5jIGNhblN1YnNjcmliZSgpIHtcbiAgICBjb25zdCBtb2RlbE5hbWUgPSB0aGlzLl9tb2RlbE5hbWUoKVxuXG4gICAgaWYgKCFtb2RlbE5hbWUpIHJldHVybiBmYWxzZVxuXG4gICAgY29uc3QgY29uZmlndXJhdGlvbiA9IHRoaXMuc2Vzc2lvbi5jb25maWd1cmF0aW9uXG4gICAgY29uc3QgbW9kZWxDbGFzc2VzID0gY29uZmlndXJhdGlvbi5nZXRNb2RlbENsYXNzZXM/LigpIHx8IHt9XG4gICAgY29uc3QgTW9kZWxDbGFzcyA9IG1vZGVsQ2xhc3Nlc1ttb2RlbE5hbWVdXG5cbiAgICBpZiAoIU1vZGVsQ2xhc3MpIHJldHVybiBmYWxzZVxuXG4gICAgY29uc3QgYWJpbGl0eSA9IGF3YWl0IGNvbmZpZ3VyYXRpb24ucmVzb2x2ZUFiaWxpdHk/Lih7XG4gICAgICBwYXJhbXM6IHttb2RlbDogbW9kZWxOYW1lfSxcbiAgICAgIHJlcXVlc3Q6IC8qKiBAdHlwZSB7YW55fSAqLyAodGhpcy5fc3ludGhldGljUmVxdWVzdCgpKSxcbiAgICAgIHJlc3BvbnNlOiBuZXcgUmVzcG9uc2Uoe2NvbmZpZ3VyYXRpb259KVxuICAgIH0pXG5cbiAgICBpZiAoIWFiaWxpdHkpIHJldHVybiBmYWxzZVxuXG4gICAgLy8gTG9hZCByZXNvdXJjZS1kZWNsYXJlZCBydWxlcyBmb3IgdGhpcyBtb2RlbCBjbGFzcyBiZWZvcmUgY2hlY2tpbmcsXG4gICAgLy8gb3RoZXJ3aXNlIGBydWxlc0ZvcmAgcmV0dXJucyBlbXB0eSBmb3IgYWJpbGl0aWVzIHdob3NlIHJlc291cmNlc1xuICAgIC8vIHJlZ2lzdGVyIHJ1bGVzIGxhemlseSB2aWEgYGFiaWxpdGllcygpYC5cbiAgICBpZiAodHlwZW9mIGFiaWxpdHkubG9hZEFiaWxpdGllc0Zvck1vZGVsQ2xhc3MgPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgYWJpbGl0eS5sb2FkQWJpbGl0aWVzRm9yTW9kZWxDbGFzcyhNb2RlbENsYXNzKVxuICAgIH1cblxuICAgIGNvbnN0IHJlYWRSdWxlcyA9IHR5cGVvZiBhYmlsaXR5LnJ1bGVzRm9yID09PSBcImZ1bmN0aW9uXCJcbiAgICAgID8gYWJpbGl0eS5ydWxlc0Zvcih7YWN0aW9uOiBcInJlYWRcIiwgbW9kZWxDbGFzczogTW9kZWxDbGFzc30pXG4gICAgICA6IFtdXG5cbiAgICByZXR1cm4gcmVhZFJ1bGVzLnNvbWUoKC8qKiBAdHlwZSB7e2VmZmVjdDogc3RyaW5nfX0gKi8gcnVsZSkgPT4gcnVsZS5lZmZlY3QgPT09IFwiYWxsb3dcIilcbiAgfVxuXG4gIC8qKlxuICAgKiBAcGFyYW0ge1JlY29yZDxzdHJpbmcsIGFueT59IGJyb2FkY2FzdFBhcmFtcyAtIFBhcmFtcyBmcm9tIGBicm9hZGNhc3RUb0NoYW5uZWxgLlxuICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gV2hldGhlciB0aGUgYnJvYWRjYXN0IG1hdGNoZXMgdGhpcyBzdWJzY3JpYmVyJ3MgbW9kZWwuXG4gICAqL1xuICBtYXRjaGVzKGJyb2FkY2FzdFBhcmFtcykge1xuICAgIHJldHVybiBicm9hZGNhc3RQYXJhbXM/Lm1vZGVsID09PSB0aGlzLl9tb2RlbE5hbWUoKVxuICB9XG5cbiAgLyoqIEByZXR1cm5zIHtzdHJpbmcgfCBudWxsfSAtIFJlcXVlc3RlZCBmcm9udGVuZC1tb2RlbCBuYW1lIG9yIG51bGwuICovXG4gIF9tb2RlbE5hbWUoKSB7XG4gICAgcmV0dXJuIHR5cGVvZiB0aGlzLnBhcmFtcz8ubW9kZWwgPT09IFwic3RyaW5nXCIgJiYgdGhpcy5wYXJhbXMubW9kZWwubGVuZ3RoID4gMFxuICAgICAgPyB0aGlzLnBhcmFtcy5tb2RlbFxuICAgICAgOiBudWxsXG4gIH1cblxuICAvKipcbiAgICogTWluaW1hbCBSZXF1ZXN0LWxpa2Ugc3R1YiB1c2VkIG9ubHkgZm9yIGFiaWxpdHkgcmVzb2x1dGlvbi4gQXZvaWRzXG4gICAqIGltcG9ydGluZyBgV2Vic29ja2V0UmVxdWVzdGAgaGVyZSBiZWNhdXNlIGl0cyBgbm9kZTpxdWVyeXN0cmluZ2BcbiAgICogZGVwZW5kZW5jeSB3b3VsZCBwdWxsIHNlcnZlci1vbmx5IGNvZGUgaW50byBicm93c2VyIGJ1bmRsZXMgdmlhXG4gICAqIHRoZSBgY29uZmlndXJhdGlvbiDihpIgbG9nZ2VyIOKGkiB3ZWJzb2NrZXQtcHVibGlzaGVyc2AgaW1wb3J0IGNoYWluLlxuICAgKiBIZWFkZXIgbmFtZXMgYXJlIG5vcm1hbGl6ZWQgdG8gbG93ZXJjYXNlIHNvIGBoZWFkZXIoXCJjb29raWVcIilgXG4gICAqIGZpbmRzIGEgdmFsdWUgcmVnYXJkbGVzcyBvZiB3aGV0aGVyIHRoZSB1cGdyYWRlLXJlcXVlc3QgaGVhZGVyc1xuICAgKiBtYXAgdXNlcyBgXCJDb29raWVcImAgb3IgYFwiY29va2llXCJgLiBTZXNzaW9uIG1ldGFkYXRhIHN0YXlzIHNlcGFyYXRlXG4gICAqIGZyb20gaGVhZGVycyBhbmQgaXMgZXhwb3NlZCB0aHJvdWdoIGBtZXRhZGF0YSguLi4pYCBmb3IgYWJpbGl0eVxuICAgKiByZXNvbHZlcnMgdGhhdCBuZWVkIHdlYnNvY2tldC1kZWxpdmVyZWQgc2Vzc2lvbiBkYXRhLlxuICAgKiBAcmV0dXJucyB7e2hlYWRlcnM6ICgpID0+IFJlY29yZDxzdHJpbmcsIGFueT4sIGhlYWRlcjogKG5hbWU6IHN0cmluZykgPT4gYW55LCBtZXRhZGF0YTogKGtleT86IHN0cmluZykgPT4gYW55LCBwYXRoOiAoKSA9PiBzdHJpbmcsIGh0dHBNZXRob2Q6ICgpID0+IHN0cmluZywgcmVtb3RlQWRkcmVzczogKCkgPT4gc3RyaW5nIHwgdW5kZWZpbmVkLCBvcmlnaW46ICgpID0+IGFueX19IFJlcXVlc3QtbGlrZSBvYmplY3QgZm9yIGFiaWxpdHkgcmVzb2x1dGlvbi5cbiAgICovXG4gIF9zeW50aGV0aWNSZXF1ZXN0KCkge1xuICAgIGNvbnN0IHVwZ3JhZGVSZXF1ZXN0ID0gLyoqIEB0eXBlIHthbnl9ICovICh0aGlzLnNlc3Npb24udXBncmFkZVJlcXVlc3QpXG4gICAgY29uc3QgcmF3SGVhZGVycyA9IHR5cGVvZiB1cGdyYWRlUmVxdWVzdD8uaGVhZGVycyA9PT0gXCJmdW5jdGlvblwiID8gdXBncmFkZVJlcXVlc3QuaGVhZGVycygpIDoge31cbiAgICBjb25zdCBtZXRhZGF0YSA9IHR5cGVvZiB0aGlzLnNlc3Npb24uZ2V0TWV0YWRhdGEgPT09IFwiZnVuY3Rpb25cIiA/IHRoaXMuc2Vzc2lvbi5nZXRNZXRhZGF0YSgpIDoge31cbiAgICBjb25zdCByZW1vdGVBZGRyZXNzID0gdHlwZW9mIHVwZ3JhZGVSZXF1ZXN0Py5yZW1vdGVBZGRyZXNzID09PSBcImZ1bmN0aW9uXCIgPyB1cGdyYWRlUmVxdWVzdC5yZW1vdGVBZGRyZXNzKCkgOiB1bmRlZmluZWRcbiAgICAvKiogQHR5cGUge1JlY29yZDxzdHJpbmcsIGFueT59ICovXG4gICAgY29uc3QgaGVhZGVyTWFwID0ge31cblxuICAgIGZvciAoY29uc3Qga2V5IG9mIE9iamVjdC5rZXlzKHJhd0hlYWRlcnMgfHwge30pKSB7XG4gICAgICBoZWFkZXJNYXBba2V5LnRvTG93ZXJDYXNlKCldID0gcmF3SGVhZGVyc1trZXldXG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIGhlYWRlcnM6ICgpID0+IGhlYWRlck1hcCxcbiAgICAgIGhlYWRlcjogKG5hbWUpID0+IGhlYWRlck1hcFtTdHJpbmcobmFtZSkudG9Mb3dlckNhc2UoKV0sXG4gICAgICBtZXRhZGF0YTogKGtleSkgPT4ga2V5ID09PSB1bmRlZmluZWQgPyB7Li4ubWV0YWRhdGF9IDogbWV0YWRhdGFba2V5XSxcbiAgICAgIHBhdGg6ICgpID0+IFwiL2Zyb250ZW5kLW1vZGVsc1wiLFxuICAgICAgaHR0cE1ldGhvZDogKCkgPT4gXCJQT1NUXCIsXG4gICAgICByZW1vdGVBZGRyZXNzOiAoKSA9PiByZW1vdGVBZGRyZXNzLFxuICAgICAgb3JpZ2luOiAoKSA9PiBoZWFkZXJNYXAub3JpZ2luXG4gICAgfVxuICB9XG59XG4iXX0=
205
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2Vic29ja2V0LWNoYW5uZWwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvZnJvbnRlbmQtbW9kZWxzL3dlYnNvY2tldC1jaGFubmVsLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLFlBQVk7QUFFWixPQUFPLHlCQUF5QixNQUFNLHFDQUFxQyxDQUFBO0FBQzNFLE9BQU8sUUFBUSxNQUFNLG1DQUFtQyxDQUFBO0FBQ3hELE9BQU8sRUFBQyxvQ0FBb0MsRUFBQyxNQUFNLDhCQUE4QixDQUFBO0FBRWpGOztHQUVHO0FBQ0g7O0dBRUc7QUFDSDs7R0FFRztBQUVIOzs7Ozs7Ozs7Ozs7Ozs7R0FlRztBQUNILE1BQU0sQ0FBQyxPQUFPLE9BQU8sNkJBQThCLFNBQVEseUJBQXlCO0lBQ2xGLG1FQUFtRTtJQUNuRSxRQUFRLEdBQUcsSUFBSSxDQUFBO0lBRWYseUZBQXlGO0lBQ3pGLEtBQUssQ0FBQyxZQUFZO1FBQ2hCLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQTtRQUVuQyxJQUFJLENBQUMsU0FBUztZQUFFLE9BQU8sS0FBSyxDQUFBO1FBRTVCLE1BQU0sYUFBYSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsYUFBYSxDQUFBO1FBQ2hELE1BQU0sWUFBWSxHQUFHLGFBQWEsQ0FBQyxlQUFlLEVBQUUsRUFBRSxJQUFJLEVBQUUsQ0FBQTtRQUM1RCxNQUFNLFVBQVUsR0FBRyxZQUFZLENBQUMsU0FBUyxDQUFDLENBQUE7UUFFMUMsSUFBSSxDQUFDLFVBQVU7WUFBRSxPQUFPLEtBQUssQ0FBQTtRQUU3QixNQUFNLE9BQU8sR0FBRyxNQUFNLGFBQWEsQ0FBQyxjQUFjLEVBQUUsQ0FBQztZQUNuRCxNQUFNLEVBQUUsRUFBQyxLQUFLLEVBQUUsU0FBUyxFQUFDO1lBQzFCLE9BQU8sRUFBRSxpRUFBaUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1lBQ3JHLFFBQVEsRUFBRSxJQUFJ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QUFDLFdBQVcsRUFBRSxDQUFDLEdBQUcsVUFBVSxDQUFDLEdBQUcsQ0FBQyxDQUFBO1FBQ2hELENBQUM7UUFFRCxPQUFPO1lBQ0wsT0FBTyxFQUFFLEdBQUcsRUFBRSxDQUFDLFNBQVM7WUFDeEIsTUFBTSxFQUFFLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLFdBQVcsRUFBRSxDQUFDO1lBQ3ZELFFBQVEsRUFBRSxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsR0FBRyxLQUFLLFNBQVMsQ0FBQyxDQUFDLENBQUMsRUFBQyxHQUFHLFFBQVEsRUFBQyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDO1lBQ3BFLElBQUksRUFBRSxHQUFHLEVBQUUsQ0FBQyxrQkFBa0I7WUFDOUIsVUFBVSxFQUFFLEdBQUcsRUFBRSxDQUFDLE1BQU07WUFDeEIsYUFBYSxFQUFFLEdBQUcsRUFBRSxDQUFDLGFBQWE7WUFDbEMsTUFBTSxFQUFFLEdBQUcsRUFBRSxDQUFDLFNBQVMsQ0FBQyxNQUFNO1NBQy9CLENBQUE7SUFDSCxDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBAdHMtY2hlY2tcblxuaW1wb3J0IFZlbG9jaW91c1dlYnNvY2tldENoYW5uZWwgZnJvbSBcIi4uL2h0dHAtc2VydmVyL3dlYnNvY2tldC1jaGFubmVsLmpzXCJcbmltcG9ydCBSZXNwb25zZSBmcm9tIFwiLi4vaHR0cC1zZXJ2ZXIvY2xpZW50L3Jlc3BvbnNlLmpzXCJcbmltcG9ydCB7c2VyaWFsaXplRnJvbnRlbmRNb2RlbFRyYW5zcG9ydFZhbHVlfSBmcm9tIFwiLi90cmFuc3BvcnQtc2VyaWFsaXphdGlvbi5qc1wiXG5cbi8qKlxuICogQHR5cGVkZWYge3thY3Rpb24/OiBzdHJpbmcsIGlkPzogc3RyaW5nIHwgbnVtYmVyLCByZWNvcmQ/OiBpbXBvcnQoXCIuL3F1ZXJ5LmpzXCIpLkZyb250ZW5kTW9kZWxUcmFuc3BvcnRWYWx1ZSwgW2tleTogc3RyaW5nXTogaW1wb3J0KFwiLi9xdWVyeS5qc1wiKS5Gcm9udGVuZE1vZGVsVHJhbnNwb3J0VmFsdWUgfCB1bmRlZmluZWR9fSBGcm9udGVuZE1vZGVsTGlmZWN5Y2xlQnJvYWRjYXN0Qm9keVxuICovXG4vKipcbiAqIEB0eXBlZGVmIHt7aGVhZGVycz86ICgpID0+IFJlY29yZDxzdHJpbmcsIHN0cmluZyB8IHN0cmluZ1tdIHwgdW5kZWZpbmVkPiwgcmVtb3RlQWRkcmVzcz86ICgpID0+IHN0cmluZyB8IHVuZGVmaW5lZH19IEZyb250ZW5kTW9kZWxXZWJzb2NrZXRVcGdyYWRlUmVxdWVzdFxuICovXG4vKipcbiAqIEB0eXBlZGVmIHt7aGVhZGVyczogKCkgPT4gUmVjb3JkPHN0cmluZywgc3RyaW5nIHwgc3RyaW5nW10gfCB1bmRlZmluZWQ+LCBoZWFkZXI6IChuYW1lOiBzdHJpbmcpID0+IHN0cmluZyB8IHN0cmluZ1tdIHwgdW5kZWZpbmVkLCBtZXRhZGF0YTogKGtleT86IHN0cmluZykgPT4gUmVjb3JkPHN0cmluZywgaW1wb3J0KFwiLi9xdWVyeS5qc1wiKS5Gcm9udGVuZE1vZGVsVHJhbnNwb3J0VmFsdWU+IHwgaW1wb3J0KFwiLi9xdWVyeS5qc1wiKS5Gcm9udGVuZE1vZGVsVHJhbnNwb3J0VmFsdWUgfCB1bmRlZmluZWQsIHBhdGg6ICgpID0+IHN0cmluZywgaHR0cE1ldGhvZDogKCkgPT4gc3RyaW5nLCByZW1vdGVBZGRyZXNzOiAoKSA9PiBzdHJpbmcgfCB1bmRlZmluZWQsIG9yaWdpbjogKCkgPT4gc3RyaW5nIHwgc3RyaW5nW10gfCB1bmRlZmluZWR9fSBGcm9udGVuZE1vZGVsV2Vic29ja2V0U3ludGhldGljUmVxdWVzdFxuICovXG5cbi8qKlxuICogUGVyLXNlc3Npb24gY2hhbm5lbCBzdWJzY3JpcHRpb24gZm9yIGZyb250ZW5kLW1vZGVsIGxpZmVjeWNsZSBldmVudHMuXG4gKiBSZXBsYWNlcyB0aGUgbGVnYWN5IGBGcm9udGVuZE1vZGVsV2Vic29ja2V0Q2hhbm5lbGAgKFBoYXNlIDMpLlxuICpcbiAqIEF1dGggbW9kZWw6IHN1YnNjcmliZS10aW1lIG9ubHkuIGBjYW5TdWJzY3JpYmVgIHJlc29sdmVzIHRoZSBjYWxsZXInc1xuICogYWJpbGl0eSBvbmNlLCBjaGVja3MgdGhhdCBhdCBsZWFzdCBvbmUgYGFsbG93YCBydWxlIGV4aXN0cyBmb3JcbiAqIGByZWFkYCBvbiB0aGUgcmVxdWVzdGVkIG1vZGVsIGNsYXNzLCBhbmQgdGhlbiBkZWxpdmVycyBldmVyeSBmdXR1cmVcbiAqIGxpZmVjeWNsZSBicm9hZGNhc3QgZm9yIHRoYXQgbW9kZWwgd2l0aG91dCByZS1hdXRob3JpemluZyBwZXIgZXZlbnQuXG4gKiBUaGlzIG1hdGNoZXMgdGhlIGV4cGxpY2l0IGRlc2lnbiBkZWNpc2lvbiBpbiBQaGFzZSAzIHRvIHRyYWRlXG4gKiBwZXItcmVjb3JkIHZpc2liaWxpdHkgZ3VhcmFudGVlcyBmb3IgbWFzc2l2ZWx5IGNoZWFwZXIgYnJvYWRjYXN0IGZhbi1vdXQuXG4gKlxuICogV2lyZTogc3Vic2NyaWJlIHdpdGggYHN1YnNjcmliZUNoYW5uZWwoXCJmcm9udGVuZC1tb2RlbHNcIiwge3BhcmFtczoge21vZGVsOiBNb2RlbE5hbWV9fSlgLlxuICogQmFja2VuZCBwdWJsaXNoZXMgYHthY3Rpb24sIGlkLCByZWNvcmR9YCB2aWFcbiAqIGBjb25maWd1cmF0aW9uLmJyb2FkY2FzdFRvQ2hhbm5lbChcImZyb250ZW5kLW1vZGVsc1wiLCB7bW9kZWw6IE1vZGVsTmFtZX0sIGJvZHkpYDtcbiAqIGBtYXRjaGVzKClgIHJvdXRlcyBieSBtb2RlbCBuYW1lLlxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBGcm9udGVuZE1vZGVsV2Vic29ja2V0Q2hhbm5lbCBleHRlbmRzIFZlbG9jaW91c1dlYnNvY2tldENoYW5uZWwge1xuICAvKiogQHR5cGUge2ltcG9ydChcIi4uL2F1dGhvcml6YXRpb24vYWJpbGl0eS5qc1wiKS5kZWZhdWx0IHwgbnVsbH0gKi9cbiAgX2FiaWxpdHkgPSBudWxsXG5cbiAgLyoqIEByZXR1cm5zIHtQcm9taXNlPGJvb2xlYW4+fSBXaGV0aGVyIHRoZSBmcm9udGVuZC1tb2RlbCBzdWJzY3JpcHRpb24gaXMgYXV0aG9yaXplZC4gKi9cbiAgYXN5bmMgY2FuU3Vic2NyaWJlKCkge1xuICAgIGNvbnN0IG1vZGVsTmFtZSA9IHRoaXMuX21vZGVsTmFtZSgpXG5cbiAgICBpZiAoIW1vZGVsTmFtZSkgcmV0dXJuIGZhbHNlXG5cbiAgICBjb25zdCBjb25maWd1cmF0aW9uID0gdGhpcy5zZXNzaW9uLmNvbmZpZ3VyYXRpb25cbiAgICBjb25zdCBtb2RlbENsYXNzZXMgPSBjb25maWd1cmF0aW9uLmdldE1vZGVsQ2xhc3Nlcz8uKCkgfHwge31cbiAgICBjb25zdCBNb2RlbENsYXNzID0gbW9kZWxDbGFzc2VzW21vZGVsTmFtZV1cblxuICAgIGlmICghTW9kZWxDbGFzcykgcmV0dXJuIGZhbHNlXG5cbiAgICBjb25zdCBhYmlsaXR5ID0gYXdhaXQgY29uZmlndXJhdGlvbi5yZXNvbHZlQWJpbGl0eT8uKHtcbiAgICAgIHBhcmFtczoge21vZGVsOiBtb2RlbE5hbWV9LFxuICAgICAgcmVxdWVzdDogLyoqIEB0eXBlIHtpbXBvcnQoXCIuLi9odHRwLXNlcnZlci9jbGllbnQvcmVxdWVzdC5qc1wiKS5kZWZhdWx0fSAqLyAodGhpcy5fc3ludGhldGljUmVxdWVzdCgpKSxcbiAgICAgIHJlc3BvbnNlOiBuZXcgUmVzcG9uc2Uoe2NvbmZpZ3VyYXRpb259KVxuICAgIH0pXG5cbiAgICBpZiAoIWFiaWxpdHkpIHJldHVybiBmYWxzZVxuICAgIHRoaXMuX2FiaWxpdHkgPSBhYmlsaXR5XG5cbiAgICAvLyBMb2FkIHJlc291cmNlLWRlY2xhcmVkIHJ1bGVzIGZvciB0aGlzIG1vZGVsIGNsYXNzIGJlZm9yZSBjaGVja2luZyxcbiAgICAvLyBvdGhlcndpc2UgYHJ1bGVzRm9yYCByZXR1cm5zIGVtcHR5IGZvciBhYmlsaXRpZXMgd2hvc2UgcmVzb3VyY2VzXG4gICAgLy8gcmVnaXN0ZXIgcnVsZXMgbGF6aWx5IHZpYSBgYWJpbGl0aWVzKClgLlxuICAgIGlmICh0eXBlb2YgYWJpbGl0eS5sb2FkQWJpbGl0aWVzRm9yTW9kZWxDbGFzcyA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICBhYmlsaXR5LmxvYWRBYmlsaXRpZXNGb3JNb2RlbENsYXNzKE1vZGVsQ2xhc3MpXG4gICAgfVxuXG4gICAgY29uc3QgcmVhZFJ1bGVzID0gdHlwZW9mIGFiaWxpdHkucnVsZXNGb3IgPT09IFwiZnVuY3Rpb25cIlxuICAgICAgPyBhYmlsaXR5LnJ1bGVzRm9yKHthY3Rpb246IFwicmVhZFwiLCBtb2RlbENsYXNzOiBNb2RlbENsYXNzfSlcbiAgICAgIDogW11cblxuICAgIHJldHVybiByZWFkUnVsZXMuc29tZSgoLyoqIEB0eXBlIHt7ZWZmZWN0OiBzdHJpbmd9fSAqLyBydWxlKSA9PiBydWxlLmVmZmVjdCA9PT0gXCJhbGxvd1wiKVxuICB9XG5cbiAgLyoqXG4gICAqIEBwYXJhbSB7RnJvbnRlbmRNb2RlbExpZmVjeWNsZUJyb2FkY2FzdEJvZHl9IGJvZHkgLSBCcm9hZGNhc3QgYm9keS5cbiAgICogQHBhcmFtIHt7ZXZlbnRJZD86IHN0cmluZ319IFttZXRhXSAtIE9wdGlvbmFsIGV2ZW50IG1ldGFkYXRhLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gUmVzb2x2ZXMgYWZ0ZXIgZGVsaXZlcnkuXG4gICAqL1xuICBhc3luYyBkZWxpdmVyQnJvYWRjYXN0KGJvZHksIG1ldGEpIHtcbiAgICBpZiAoIXRoaXMuX2hhc1Byb2plY3Rpb25QYXJhbXMoKSkge1xuICAgICAgdGhpcy5zZW5kTWVzc2FnZShib2R5LCBtZXRhKVxuICAgICAgcmV0dXJuXG4gICAgfVxuXG4gICAgaWYgKCFib2R5IHx8IHR5cGVvZiBib2R5ICE9PSBcIm9iamVjdFwiIHx8IGJvZHkuYWN0aW9uID09PSBcImRlc3Ryb3lcIikge1xuICAgICAgdGhpcy5zZW5kTWVzc2FnZShib2R5LCBtZXRhKVxuICAgICAgcmV0dXJuXG4gICAgfVxuXG4gICAgaWYgKGJvZHkuaWQgPT09IHVuZGVmaW5lZCB8fCBib2R5LmlkID09PSBudWxsKSB7XG4gICAgICB0aGlzLnNlbmRNZXNzYWdlKGJvZHksIG1ldGEpXG4gICAgICByZXR1cm5cbiAgICB9XG5cbiAgICBjb25zdCBwcm9qZWN0ZWRSZWNvcmQgPSBhd2FpdCB0aGlzLl9wcm9qZWN0ZWRSZWNvcmRGb3JFdmVudElkKGJvZHkuaWQpXG5cbiAgICBpZiAoIXByb2plY3RlZFJlY29yZCkge1xuICAgICAgcmV0dXJuXG4gICAgfVxuXG4gICAgdGhpcy5zZW5kTWVzc2FnZSh7XG4gICAgICAuLi5ib2R5LFxuICAgICAgcmVjb3JkOiBzZXJpYWxpemVGcm9udGVuZE1vZGVsVHJhbnNwb3J0VmFsdWUocHJvamVjdGVkUmVjb3JkKVxuICAgIH0sIG1ldGEpXG4gIH1cblxuICAvKipcbiAgICogQHBhcmFtIHtSZWNvcmQ8c3RyaW5nLCBpbXBvcnQoXCIuL3F1ZXJ5LmpzXCIpLkZyb250ZW5kTW9kZWxUcmFuc3BvcnRWYWx1ZT59IGJyb2FkY2FzdFBhcmFtcyAtIFBhcmFtcyBmcm9tIGBicm9hZGNhc3RUb0NoYW5uZWxgLlxuICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gV2hldGhlciB0aGUgYnJvYWRjYXN0IG1hdGNoZXMgdGhpcyBzdWJzY3JpYmVyJ3MgbW9kZWwuXG4gICAqL1xuICBtYXRjaGVzKGJyb2FkY2FzdFBhcmFtcykge1xuICAgIHJldHVybiBicm9hZGNhc3RQYXJhbXM/Lm1vZGVsID09PSB0aGlzLl9tb2RlbE5hbWUoKVxuICB9XG5cbiAgLyoqIEByZXR1cm5zIHtzdHJpbmcgfCBudWxsfSAtIFJlcXVlc3RlZCBmcm9udGVuZC1tb2RlbCBuYW1lIG9yIG51bGwuICovXG4gIF9tb2RlbE5hbWUoKSB7XG4gICAgcmV0dXJuIHR5cGVvZiB0aGlzLnBhcmFtcz8ubW9kZWwgPT09IFwic3RyaW5nXCIgJiYgdGhpcy5wYXJhbXMubW9kZWwubGVuZ3RoID4gMFxuICAgICAgPyB0aGlzLnBhcmFtcy5tb2RlbFxuICAgICAgOiBudWxsXG4gIH1cblxuICAvKiogQHJldHVybnMge2Jvb2xlYW59IC0gV2hldGhlciB0aGlzIHN1YnNjcmlwdGlvbiByZXF1ZXN0ZWQgcGVyLWV2ZW50IHJlY29yZCBwcm9qZWN0aW9uLiAqL1xuICBfaGFzUHJvamVjdGlvblBhcmFtcygpIHtcbiAgICByZXR1cm4gdGhpcy5wYXJhbXMuc2VsZWN0ICE9PSB1bmRlZmluZWRcbiAgICAgIHx8IHRoaXMucGFyYW1zLnByZWxvYWQgIT09IHVuZGVmaW5lZFxuICAgICAgfHwgdGhpcy5wYXJhbXMud2l0aENvdW50ICE9PSB1bmRlZmluZWRcbiAgICAgIHx8IHRoaXMucGFyYW1zLmFiaWxpdGllcyAhPT0gdW5kZWZpbmVkXG4gICAgICB8fCB0aGlzLnBhcmFtcy5xdWVyeURhdGEgIT09IHVuZGVmaW5lZFxuICB9XG5cbiAgLyoqXG4gICAqIEBwYXJhbSB7dHlwZW9mIGltcG9ydChcIi4uL2Zyb250ZW5kLW1vZGVsLWNvbnRyb2xsZXIuanNcIikuZGVmYXVsdH0gRnJvbnRlbmRNb2RlbENvbnRyb2xsZXIgLSBTZXJ2ZXItc2lkZSBmcm9udGVuZC1tb2RlbCBjb250cm9sbGVyIGNsYXNzLlxuICAgKiBAcmV0dXJucyB7aW1wb3J0KFwiLi4vZnJvbnRlbmQtbW9kZWwtY29udHJvbGxlci5qc1wiKS5kZWZhdWx0fSAtIFN5bnRoZXRpYyBjb250cm9sbGVyIHVzZWQgZm9yIHJlc291cmNlIHNlcmlhbGl6YXRpb24uXG4gICAqL1xuICBfZnJvbnRlbmRNb2RlbENvbnRyb2xsZXIoRnJvbnRlbmRNb2RlbENvbnRyb2xsZXIpIHtcbiAgICBjb25zdCBjb25maWd1cmF0aW9uID0gdGhpcy5zZXNzaW9uLmNvbmZpZ3VyYXRpb25cbiAgICBjb25zdCBjb250cm9sbGVyID0gbmV3IEZyb250ZW5kTW9kZWxDb250cm9sbGVyKHtcbiAgICAgIGFjdGlvbjogXCJ3ZWJzb2NrZXRFdmVudFwiLFxuICAgICAgY29uZmlndXJhdGlvbixcbiAgICAgIGNvbnRyb2xsZXI6IFwiZnJvbnRlbmQtbW9kZWxzXCIsXG4gICAgICBwYXJhbXM6IHtcbiAgICAgICAgYWJpbGl0aWVzOiB0aGlzLnBhcmFtcy5hYmlsaXRpZXMsXG4gICAgICAgIG1vZGVsOiB0aGlzLl9tb2RlbE5hbWUoKSxcbiAgICAgICAgcHJlbG9hZDogdGhpcy5wYXJhbXMucHJlbG9hZCxcbiAgICAgICAgcXVlcnlEYXRhOiB0aGlzLnBhcmFtcy5xdWVyeURhdGEsXG4gICAgICAgIHNlbGVjdDogdGhpcy5wYXJhbXMuc2VsZWN0LFxuICAgICAgICB3aXRoQ291bnQ6IHRoaXMucGFyYW1zLndpdGhDb3VudFxuICAgICAgfSxcbiAgICAgIHJlcXVlc3Q6IC8qKiBAdHlwZSB7aW1wb3J0KFwiLi4vaHR0cC1zZXJ2ZXIvY2xpZW50L3JlcXVlc3QuanNcIikuZGVmYXVsdH0gKi8gKHRoaXMuX3N5bnRoZXRpY1JlcXVlc3QoKSksXG4gICAgICByZXNwb25zZTogbmV3IFJlc3BvbnNlKHtjb25maWd1cmF0aW9ufSksXG4gICAgICB2aWV3UGF0aDogXCIvXCJcbiAgICB9KVxuXG4gICAgY29udHJvbGxlci5fZnJvbnRlbmRNb2RlbEFiaWxpdHlPdmVycmlkZSA9IHRoaXMuX2FiaWxpdHkgfHwgdW5kZWZpbmVkXG5cbiAgICByZXR1cm4gY29udHJvbGxlclxuICB9XG5cbiAgLyoqXG4gICAqIEBwYXJhbSB7c3RyaW5nIHwgbnVtYmVyfSBpZCAtIEV2ZW50IHJlY29yZCBpZC5cbiAgICogQHJldHVybnMge1Byb21pc2U8UmVjb3JkPHN0cmluZywgaW1wb3J0KFwiLi9xdWVyeS5qc1wiKS5Gcm9udGVuZE1vZGVsVHJhbnNwb3J0VmFsdWU+IHwgbnVsbD59IC0gU2VyaWFsaXplZCBwcm9qZWN0ZWQgcmVjb3JkLlxuICAgKi9cbiAgYXN5bmMgX3Byb2plY3RlZFJlY29yZEZvckV2ZW50SWQoaWQpIHtcbiAgICBjb25zdCBmcm9udGVuZE1vZGVsQ29udHJvbGxlclBhdGggPSBcIi4uL2Zyb250ZW5kLW1vZGVsLWNvbnRyb2xsZXIuanNcIlxuICAgIGNvbnN0IHtkZWZhdWx0OiBGcm9udGVuZE1vZGVsQ29udHJvbGxlcn0gPSBhd2FpdCBpbXBvcnQoZnJvbnRlbmRNb2RlbENvbnRyb2xsZXJQYXRoKVxuICAgIGNvbnN0IGNvbnRyb2xsZXIgPSB0aGlzLl9mcm9udGVuZE1vZGVsQ29udHJvbGxlcihGcm9udGVuZE1vZGVsQ29udHJvbGxlcilcblxuICAgIGF3YWl0IGNvbnRyb2xsZXIuZW5zdXJlRnJvbnRlbmRNb2RlbENsYXNzSW5pdGlhbGl6ZWQoKVxuXG4gICAgY29uc3QgTW9kZWxDbGFzcyA9IGNvbnRyb2xsZXIuZnJvbnRlbmRNb2RlbENsYXNzKClcbiAgICBjb25zdCBwcmltYXJ5S2V5ID0gTW9kZWxDbGFzcy5wcmltYXJ5S2V5KClcbiAgICBsZXQgcXVlcnkgPSBNb2RlbENsYXNzLndoZXJlKHtbcHJpbWFyeUtleV06IGlkfSlcbiAgICBjb25zdCBwcmVsb2FkID0gY29udHJvbGxlci5mcm9udGVuZE1vZGVsUHJlbG9hZCgpXG5cbiAgICBpZiAocHJlbG9hZCkgcXVlcnkgPSBxdWVyeS5wcmVsb2FkKHByZWxvYWQpXG5cbiAgICBmb3IgKGNvbnN0IGVudHJ5IG9mIGNvbnRyb2xsZXIuZnJvbnRlbmRNb2RlbFdpdGhDb3VudCgpKSB7XG4gICAgICAvKiogQHR5cGUge1JlY29yZDxzdHJpbmcsIGJvb2xlYW4gfCB7cmVsYXRpb25zaGlwPzogc3RyaW5nLCB3aGVyZT86IFJlY29yZDxzdHJpbmcsIGltcG9ydChcIi4vcXVlcnkuanNcIikuRnJvbnRlbmRNb2RlbFRyYW5zcG9ydFZhbHVlPn0+fSAqL1xuICAgICAgY29uc3Qgc3BlYyA9IHt9XG5cbiAgICAgIHNwZWNbZW50cnkuYXR0cmlidXRlTmFtZV0gPSB7XG4gICAgICAgIHJlbGF0aW9uc2hpcDogZW50cnkucmVsYXRpb25zaGlwTmFtZSxcbiAgICAgICAgd2hlcmU6IGVudHJ5LndoZXJlID8gLyoqIEB0eXBlIHtSZWNvcmQ8c3RyaW5nLCBpbXBvcnQoXCIuL3F1ZXJ5LmpzXCIpLkZyb250ZW5kTW9kZWxUcmFuc3BvcnRWYWx1ZT59ICovIChlbnRyeS53aGVyZSkgOiB1bmRlZmluZWRcbiAgICAgIH1cbiAgICAgIHF1ZXJ5LndpdGhDb3VudChzcGVjKVxuICAgIH1cblxuICAgIGNvbnN0IHF1ZXJ5RGF0YSA9IGNvbnRyb2xsZXIuZnJvbnRlbmRNb2RlbFF1ZXJ5RGF0YSgpXG5cbiAgICBpZiAocXVlcnlEYXRhICE9PSBudWxsKSBxdWVyeS5xdWVyeURhdGEocXVlcnlEYXRhKVxuXG4gICAgcXVlcnkgPSBjb250cm9sbGVyLmFwcGx5RnJvbnRlbmRNb2RlbFRyYW5zbGF0ZWRBdHRyaWJ1dGVQcmVsb2Fkcyh7cXVlcnl9KVxuXG4gICAgY29uc3QgbW9kZWwgPSBhd2FpdCBxdWVyeS5maXJzdCgpXG5cbiAgICBpZiAoIW1vZGVsKSByZXR1cm4gbnVsbFxuXG4gICAgaWYgKHRoaXMucGFyYW1zLmFiaWxpdGllcyAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBhd2FpdCBjb250cm9sbGVyLmZyb250ZW5kTW9kZWxDb21wdXRlQWJpbGl0aWVzKFttb2RlbF0pXG4gICAgfVxuXG4gICAgY29udHJvbGxlci5fZnJvbnRlbmRNb2RlbEFiaWxpdHlPdmVycmlkZSA9IHVuZGVmaW5lZFxuXG4gICAgcmV0dXJuIGF3YWl0IGNvbnRyb2xsZXIuZnJvbnRlbmRNb2RlbFJlc291cmNlSW5zdGFuY2UoKS5zZXJpYWxpemUobW9kZWwsIFwiZmluZFwiKVxuICB9XG5cbiAgLyoqXG4gICAqIE1pbmltYWwgUmVxdWVzdC1saWtlIHN0dWIgdXNlZCBvbmx5IGZvciBhYmlsaXR5IHJlc29sdXRpb24uIEF2b2lkc1xuICAgKiBpbXBvcnRpbmcgYFdlYnNvY2tldFJlcXVlc3RgIGhlcmUgYmVjYXVzZSBpdHMgYG5vZGU6cXVlcnlzdHJpbmdgXG4gICAqIGRlcGVuZGVuY3kgd291bGQgcHVsbCBzZXJ2ZXItb25seSBjb2RlIGludG8gYnJvd3NlciBidW5kbGVzIHZpYVxuICAgKiB0aGUgYGNvbmZpZ3VyYXRpb24g4oaSIGxvZ2dlciDihpIgd2Vic29ja2V0LXB1Ymxpc2hlcnNgIGltcG9ydCBjaGFpbi5cbiAgICogSGVhZGVyIG5hbWVzIGFyZSBub3JtYWxpemVkIHRvIGxvd2VyY2FzZSBzbyBgaGVhZGVyKFwiY29va2llXCIpYFxuICAgKiBmaW5kcyBhIHZhbHVlIHJlZ2FyZGxlc3Mgb2Ygd2hldGhlciB0aGUgdXBncmFkZS1yZXF1ZXN0IGhlYWRlcnNcbiAgICogbWFwIHVzZXMgYFwiQ29va2llXCJgIG9yIGBcImNvb2tpZVwiYC4gU2Vzc2lvbiBtZXRhZGF0YSBzdGF5cyBzZXBhcmF0ZVxuICAgKiBmcm9tIGhlYWRlcnMgYW5kIGlzIGV4cG9zZWQgdGhyb3VnaCBgbWV0YWRhdGEoLi4uKWAgZm9yIGFiaWxpdHlcbiAgICogcmVzb2x2ZXJzIHRoYXQgbmVlZCB3ZWJzb2NrZXQtZGVsaXZlcmVkIHNlc3Npb24gZGF0YS5cbiAgICogQHJldHVybnMge0Zyb250ZW5kTW9kZWxXZWJzb2NrZXRTeW50aGV0aWNSZXF1ZXN0fSBSZXF1ZXN0LWxpa2Ugb2JqZWN0IGZvciBhYmlsaXR5IHJlc29sdXRpb24uXG4gICAqL1xuICBfc3ludGhldGljUmVxdWVzdCgpIHtcbiAgICBjb25zdCB1cGdyYWRlUmVxdWVzdCA9IC8qKiBAdHlwZSB7RnJvbnRlbmRNb2RlbFdlYnNvY2tldFVwZ3JhZGVSZXF1ZXN0fSAqLyAodGhpcy5zZXNzaW9uLnVwZ3JhZGVSZXF1ZXN0KVxuICAgIGNvbnN0IHJhd0hlYWRlcnMgPSB0eXBlb2YgdXBncmFkZVJlcXVlc3Q/LmhlYWRlcnMgPT09IFwiZnVuY3Rpb25cIiA/IHVwZ3JhZGVSZXF1ZXN0LmhlYWRlcnMoKSA6IHt9XG4gICAgY29uc3QgbWV0YWRhdGEgPSB0eXBlb2YgdGhpcy5zZXNzaW9uLmdldE1ldGFkYXRhID09PSBcImZ1bmN0aW9uXCIgPyB0aGlzLnNlc3Npb24uZ2V0TWV0YWRhdGEoKSA6IHt9XG4gICAgY29uc3QgcmVtb3RlQWRkcmVzcyA9IHR5cGVvZiB1cGdyYWRlUmVxdWVzdD8ucmVtb3RlQWRkcmVzcyA9PT0gXCJmdW5jdGlvblwiID8gdXBncmFkZVJlcXVlc3QucmVtb3RlQWRkcmVzcygpIDogdW5kZWZpbmVkXG4gICAgLyoqIEB0eXBlIHtSZWNvcmQ8c3RyaW5nLCBzdHJpbmcgfCBzdHJpbmdbXSB8IHVuZGVmaW5lZD59ICovXG4gICAgY29uc3QgaGVhZGVyTWFwID0ge31cblxuICAgIGZvciAoY29uc3Qga2V5IG9mIE9iamVjdC5rZXlzKHJhd0hlYWRlcnMgfHwge30pKSB7XG4gICAgICBoZWFkZXJNYXBba2V5LnRvTG93ZXJDYXNlKCldID0gcmF3SGVhZGVyc1trZXldXG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIGhlYWRlcnM6ICgpID0+IGhlYWRlck1hcCxcbiAgICAgIGhlYWRlcjogKG5hbWUpID0+IGhlYWRlck1hcFtTdHJpbmcobmFtZSkudG9Mb3dlckNhc2UoKV0sXG4gICAgICBtZXRhZGF0YTogKGtleSkgPT4ga2V5ID09PSB1bmRlZmluZWQgPyB7Li4ubWV0YWRhdGF9IDogbWV0YWRhdGFba2V5XSxcbiAgICAgIHBhdGg6ICgpID0+IFwiL2Zyb250ZW5kLW1vZGVsc1wiLFxuICAgICAgaHR0cE1ldGhvZDogKCkgPT4gXCJQT1NUXCIsXG4gICAgICByZW1vdGVBZGRyZXNzOiAoKSA9PiByZW1vdGVBZGRyZXNzLFxuICAgICAgb3JpZ2luOiAoKSA9PiBoZWFkZXJNYXAub3JpZ2luXG4gICAgfVxuICB9XG59XG4iXX0=