@dcl/sdk 7.29.1-36591934525.commit-48aa9b5 → 7.29.1-36625469671.commit-2d5ffac

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 (80) hide show
  1. package/atom.d.ts +19 -0
  2. package/atom.js +83 -0
  3. package/future.d.ts +8 -0
  4. package/future.js +26 -0
  5. package/internal/transports/rendererTransport.js +5 -2
  6. package/network/binary-message-bus.d.ts +6 -3
  7. package/network/binary-message-bus.js +9 -5
  8. package/network/chunking.d.ts +5 -0
  9. package/network/chunking.js +38 -0
  10. package/network/events/implementation.d.ts +93 -0
  11. package/network/events/implementation.js +221 -0
  12. package/network/events/index.d.ts +42 -0
  13. package/network/events/index.js +43 -0
  14. package/network/events/protocol.d.ts +27 -0
  15. package/network/events/protocol.js +66 -0
  16. package/network/events/registry.d.ts +8 -0
  17. package/network/events/registry.js +3 -0
  18. package/network/index.d.ts +8 -2
  19. package/network/index.js +16 -3
  20. package/network/message-bus-sync.d.ts +16 -3
  21. package/network/message-bus-sync.js +164 -103
  22. package/network/server/index.d.ts +14 -0
  23. package/network/server/index.js +219 -0
  24. package/network/server/utils.d.ts +18 -0
  25. package/network/server/utils.js +135 -0
  26. package/network/state.js +3 -5
  27. package/package.json +6 -6
  28. package/server/env-var.d.ts +15 -0
  29. package/server/env-var.js +31 -0
  30. package/server/index.d.ts +2 -0
  31. package/server/index.js +3 -0
  32. package/server/storage/constants.d.ts +80 -0
  33. package/server/storage/constants.js +19 -0
  34. package/server/storage/error-message.d.ts +1 -0
  35. package/server/storage/error-message.js +9 -0
  36. package/server/storage/index.d.ts +54 -0
  37. package/server/storage/index.js +60 -0
  38. package/server/storage/player.d.ts +60 -0
  39. package/server/storage/player.js +244 -0
  40. package/server/storage/scene.d.ts +55 -0
  41. package/server/storage/scene.js +232 -0
  42. package/server/storage/serialize.d.ts +1 -0
  43. package/server/storage/serialize.js +135 -0
  44. package/server/storage/value-cache.d.ts +1 -0
  45. package/server/storage/value-cache.js +67 -0
  46. package/server/storage/write-queue.d.ts +1 -0
  47. package/server/storage/write-queue.js +113 -0
  48. package/server/storage-url.d.ts +13 -0
  49. package/server/storage-url.js +42 -0
  50. package/server/utils.d.ts +35 -0
  51. package/server/utils.js +69 -0
  52. package/src/atom.ts +98 -0
  53. package/src/future.ts +38 -0
  54. package/src/internal/transports/rendererTransport.ts +4 -1
  55. package/src/network/binary-message-bus.ts +9 -4
  56. package/src/network/chunking.ts +45 -0
  57. package/src/network/events/implementation.ts +271 -0
  58. package/src/network/events/index.ts +48 -0
  59. package/src/network/events/protocol.ts +94 -0
  60. package/src/network/events/registry.ts +18 -0
  61. package/src/network/index.ts +40 -3
  62. package/src/network/message-bus-sync.ts +180 -112
  63. package/src/network/server/index.ts +301 -0
  64. package/src/network/server/utils.ts +189 -0
  65. package/src/network/state.ts +3 -4
  66. package/src/server/env-var.ts +36 -0
  67. package/src/server/index.ts +12 -0
  68. package/src/server/storage/constants.ts +112 -0
  69. package/src/server/storage/error-message.ts +8 -0
  70. package/src/server/storage/index.ts +83 -0
  71. package/src/server/storage/player.ts +345 -0
  72. package/src/server/storage/scene.ts +324 -0
  73. package/src/server/storage/serialize.ts +132 -0
  74. package/src/server/storage/value-cache.ts +119 -0
  75. package/src/server/storage/write-queue.ts +174 -0
  76. package/src/server/storage-url.ts +49 -0
  77. package/src/server/utils.ts +83 -0
  78. package/explorer-ui/index.d.ts +0 -118
  79. package/explorer-ui/index.js +0 -235
  80. package/src/explorer-ui/index.ts +0 -398
@@ -1,235 +0,0 @@
1
- import { engine, ExplorerItemPurchaseResult, ExplorerUi, ExplorerUiEventsResult } from '@dcl/ecs';
2
- import { openExplorerUi, OpenExplorerUiResult } from '~system/RestrictedActions';
3
- export { ExplorerUi, OpenExplorerUiResult };
4
- // What an explorer that does not echo request_id, or a user-initiated action, leaves on the wire.
5
- const UNCORRELATED = 0;
6
- // Panels that can be on screen next to another panel. The `ui` field alone cannot attribute
7
- // their events, so an event on one of these panels must carry a request_id.
8
- const CONCURRENT_PANELS = [7 /* ExplorerUi.EU_ITEM_PURCHASE */];
9
- /**
10
- * Wraps a grow-only result component as a {@link Channel}. The name must be unique within a scene.
11
- * @public
12
- */
13
- export function channel(name, component) {
14
- return { name, component };
15
- }
16
- /** Panel lifecycle events: opened and closed. @public */
17
- export const ExplorerUiEvents = /* @__PURE__ */ channel('explorerUi', ExplorerUiEventsResult);
18
- /** Outcome of an `EU_ITEM_PURCHASE` flow: purchased, dismissed or failed. @public */
19
- export const ItemPurchase = /* @__PURE__ */ channel('itemPurchase', ExplorerItemPurchaseResult);
20
- /** @public */
21
- export function variant(ch, $case) {
22
- return { channel: ch, $case };
23
- }
24
- /** @internal exposed for tests */
25
- export const EXPLORER_UI_WAIT_TIMEOUT_SYSTEM = 'explorer-ui-wait-timeout';
26
- // Lowest priority sorts this system last, so when it removes itself mid-tick it splices the
27
- // last element of the array the engine is iterating and skips no other system.
28
- const TIMEOUT_SYSTEM_PRIORITY = Number.MIN_SAFE_INTEGER;
29
- // ts-proto renders a `oneof` as one wrapper property `{ $case, [$case]: value }`. Finding that
30
- // property by shape keeps the helper independent of the name each message gave it: `event` on
31
- // one message, `status` on another.
32
- function caseOf(event) {
33
- for (const key of Object.keys(event)) {
34
- const value = event[key];
35
- if (value && typeof value === 'object' && typeof value.$case === 'string') {
36
- return value.$case;
37
- }
38
- }
39
- return undefined;
40
- }
41
- function normalizeStop(stop) {
42
- return '$case' in stop ? { channel: stop.channel, $case: stop.$case } : { channel: stop, $case: undefined };
43
- }
44
- /** @internal test seam. The production instance is {@link openExplorerUiAndWait}. */
45
- export function create(deps) {
46
- const { engine: engineInstance, openExplorerUi: openExplorerUiFn, explorerUiEvents } = deps;
47
- const root = engineInstance.RootEntity;
48
- const sessions = new Map();
49
- // Keyed by name, so two wrappers around the same component arm one listener, not two.
50
- const armed = new Map();
51
- // Starts at 1 so a minted id never collides with UNCORRELATED.
52
- let nextRequestId = 1;
53
- let timeoutSystemAdded = false;
54
- function arm(ch) {
55
- const bound = armed.get(ch.name);
56
- if (bound) {
57
- if (bound !== ch.component) {
58
- throw new Error(`openExplorerUiAndWait: channel name '${ch.name}' is already bound to a different component. ` +
59
- `Channel names identify a stream, so they have to be unique within a scene.`);
60
- }
61
- return;
62
- }
63
- armed.set(ch.name, ch.component);
64
- const name = ch.name;
65
- // onChange has no unsubscribe, so one listener per channel lives for the engine's lifetime.
66
- ch.component.onChange(root, (value) => {
67
- // `undefined` arrives on DELETE_ENTITY. Otherwise `value` is one appended element,
68
- // not the whole set.
69
- if (value)
70
- deliver(name, value);
71
- });
72
- }
73
- function attribute(session, name, event) {
74
- if (event.requestId === session.requestId)
75
- return 'yes';
76
- if (event.requestId !== UNCORRELATED)
77
- return 'no';
78
- // Only the lifecycle channel carries a second discriminator, `ui`, and it identifies a
79
- // session only while panels cannot coexist. A second call for the same panel is answered
80
- // WAS_ALREADY_OPEN, so at most one session per non-concurrent panel is ever live.
81
- if (session.correlationRequired || name !== explorerUiEvents.name)
82
- return 'ambiguous';
83
- return event.ui === session.ui ? 'yes' : 'no';
84
- }
85
- function deliver(name, event) {
86
- // Settling deletes from `sessions` mid-iteration, which a Map tolerates. Nothing adds.
87
- for (const session of sessions.values()) {
88
- if (!session.watched.has(name))
89
- continue;
90
- const attribution = attribute(session, name, event);
91
- if (attribution === 'no')
92
- continue;
93
- if (attribution === 'ambiguous') {
94
- failSession(session, new Error(`openExplorerUiAndWait: got a '${name}' event with no request_id, and nothing else identifies ` +
95
- `the call it belongs to. This explorer does not echo OpenExplorerUiRequest.request_id.`));
96
- continue;
97
- }
98
- accept(session, name, event);
99
- }
100
- }
101
- function accept(session, name, event) {
102
- if (session.collect.has(name))
103
- session.events.push({ channel: name, event });
104
- // The close is terminal and wins over `until`, because `matched` would tell the caller
105
- // that the panel is still on screen.
106
- if (name === explorerUiEvents.name && caseOf(event) === 'closed') {
107
- settleSession(session, { $case: 'closed', events: session.events });
108
- return;
109
- }
110
- const until = session.until;
111
- if (!until || until.channel !== name)
112
- return;
113
- if (until.$case === undefined || until.$case === caseOf(event)) {
114
- settleSession(session, { $case: 'matched', events: session.events });
115
- }
116
- }
117
- function settleSession(session, outcome) {
118
- if (session.settled)
119
- return;
120
- session.settled = true;
121
- sessions.delete(session.requestId);
122
- session.settle(outcome);
123
- maybeRemoveTimeoutSystem();
124
- }
125
- function failSession(session, error) {
126
- if (session.settled)
127
- return;
128
- session.settled = true;
129
- sessions.delete(session.requestId);
130
- session.fail(error);
131
- maybeRemoveTimeoutSystem();
132
- }
133
- function hasTimedSession() {
134
- for (const session of sessions.values()) {
135
- if (session.timeoutMs !== undefined)
136
- return true;
137
- }
138
- return false;
139
- }
140
- function maybeRemoveTimeoutSystem() {
141
- if (!timeoutSystemAdded || hasTimedSession())
142
- return;
143
- timeoutSystemAdded = false;
144
- engineInstance.removeSystem(EXPLORER_UI_WAIT_TIMEOUT_SYSTEM);
145
- }
146
- function ensureTimeoutSystem() {
147
- if (timeoutSystemAdded)
148
- return;
149
- timeoutSystemAdded = true;
150
- // The scene runtime has no timers, so elapsed time is accumulated from the engine's dt.
151
- engineInstance.addSystem((dt) => {
152
- for (const session of sessions.values()) {
153
- if (session.timeoutMs === undefined)
154
- continue;
155
- session.elapsedMs += dt * 1000;
156
- if (session.elapsedMs >= session.timeoutMs) {
157
- settleSession(session, { $case: 'timedOut', events: session.events });
158
- }
159
- }
160
- maybeRemoveTimeoutSystem();
161
- }, TIMEOUT_SYSTEM_PRIORITY, EXPLORER_UI_WAIT_TIMEOUT_SYSTEM);
162
- }
163
- async function openExplorerUiAndWait(request, options) {
164
- const { ui, itemPurchase } = typeof request === 'number' ? { ui: request, itemPurchase: undefined } : request;
165
- const requestId = nextRequestId++;
166
- const collect = options?.collect ?? [];
167
- const collectNames = new Set();
168
- for (const ch of collect)
169
- collectNames.add(ch.name);
170
- const stop = options?.until ? normalizeStop(options.until) : undefined;
171
- const watched = new Set(collectNames);
172
- watched.add(explorerUiEvents.name);
173
- if (stop)
174
- watched.add(stop.channel.name);
175
- // Armed before the RPC, because events can land while the RPC is in flight. A listener
176
- // that is already up is what makes replaying the accumulated set unnecessary.
177
- arm(explorerUiEvents);
178
- for (const ch of collect)
179
- arm(ch);
180
- if (stop)
181
- arm(stop.channel);
182
- let settle;
183
- let fail;
184
- const outcome = new Promise((resolve, reject) => {
185
- settle = resolve;
186
- fail = reject;
187
- });
188
- const session = {
189
- requestId,
190
- ui,
191
- correlationRequired: CONCURRENT_PANELS.includes(ui),
192
- collect: collectNames,
193
- watched,
194
- until: stop ? { channel: stop.channel.name, $case: stop.$case } : undefined,
195
- events: [],
196
- timeoutMs: options?.timeoutMs,
197
- elapsedMs: 0,
198
- settled: false,
199
- settle,
200
- fail
201
- };
202
- sessions.set(requestId, session);
203
- if (session.timeoutMs !== undefined)
204
- ensureTimeoutSystem();
205
- try {
206
- const { openResult } = await openExplorerUiFn({ ui, requestId, itemPurchase });
207
- // This call opened nothing, so no event carrying this request id is coming.
208
- if (openResult !== OpenExplorerUiResult.OPENED) {
209
- settleSession(session, { $case: 'notOpened', openResult });
210
- }
211
- }
212
- catch (error) {
213
- // Routed through the session rather than rethrown, so that `outcome` is never left
214
- // pending and unobserved.
215
- failSession(session, error);
216
- }
217
- return outcome;
218
- }
219
- // The implementation takes both argument forms and is blind to `collect`. The cast is what
220
- // gives callers the two overloads that relate them.
221
- return { openExplorerUiAndWait: openExplorerUiAndWait };
222
- }
223
- const helper = /* @__PURE__ */ create({ engine, openExplorerUi, explorerUiEvents: ExplorerUiEvents });
224
- /**
225
- * Opens an explorer panel and waits for the session it started. The wait ends when the panel
226
- * closes. See {@link WaitOptions} to collect events, to stop earlier or to bound the wait.
227
- *
228
- * Every lifecycle outcome resolves, see {@link WaitOutcome}. The promise rejects only when an
229
- * event cannot be attributed to a call at all: an explorer too old to echo `request_id`
230
- * paired with a panel that can coexist with another one.
231
- *
232
- * @public
233
- */
234
- export const openExplorerUiAndWait = helper.openExplorerUiAndWait;
235
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvZXhwbG9yZXItdWkvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLE1BQU0sRUFDTiwwQkFBMEIsRUFDMUIsVUFBVSxFQUNWLHNCQUFzQixFQUt2QixNQUFNLFVBQVUsQ0FBQTtBQUNqQixPQUFPLEVBQUUsY0FBYyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sMkJBQTJCLENBQUE7QUFFaEYsT0FBTyxFQUFFLFVBQVUsRUFBRSxvQkFBb0IsRUFBRSxDQUFBO0FBRTNDLGtHQUFrRztBQUNsRyxNQUFNLFlBQVksR0FBRyxDQUFDLENBQUE7QUFFdEIsNEZBQTRGO0FBQzVGLDRFQUE0RTtBQUM1RSxNQUFNLGlCQUFpQixHQUEwQixxQ0FBNkIsQ0FBQTtBQW9COUU7OztHQUdHO0FBQ0gsTUFBTSxVQUFVLE9BQU8sQ0FDckIsSUFBTyxFQUNQLFNBQWlEO0lBRWpELE9BQU8sRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFLENBQUE7QUFDNUIsQ0FBQztBQUVELHlEQUF5RDtBQUN6RCxNQUFNLENBQUMsTUFBTSxnQkFBZ0IsR0FBb0QsZUFBZSxDQUFDLE9BQU8sQ0FDdEcsWUFBWSxFQUNaLHNCQUFzQixDQUN2QixDQUFBO0FBRUQscUZBQXFGO0FBQ3JGLE1BQU0sQ0FBQyxNQUFNLFlBQVksR0FBMEQsZUFBZSxDQUFDLE9BQU8sQ0FDeEcsY0FBYyxFQUNkLDBCQUEwQixDQUMzQixDQUFBO0FBZUQsY0FBYztBQUNkLE1BQU0sVUFBVSxPQUFPLENBQTRDLEVBQUssRUFBRSxLQUFRO0lBQ2hGLE9BQU8sRUFBRSxPQUFPLEVBQUUsRUFBRSxFQUFFLEtBQUssRUFBRSxDQUFBO0FBQy9CLENBQUM7QUEyREQsa0NBQWtDO0FBQ2xDLE1BQU0sQ0FBQyxNQUFNLCtCQUErQixHQUFHLDBCQUEwQixDQUFBO0FBRXpFLDRGQUE0RjtBQUM1RiwrRUFBK0U7QUFDL0UsTUFBTSx1QkFBdUIsR0FBRyxNQUFNLENBQUMsZ0JBQWdCLENBQUE7QUEyQnZELCtGQUErRjtBQUMvRiw4RkFBOEY7QUFDOUYsb0NBQW9DO0FBQ3BDLFNBQVMsTUFBTSxDQUFDLEtBQXNCO0lBQ3BDLEtBQUssTUFBTSxHQUFHLElBQUksTUFBTSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRTtRQUNwQyxNQUFNLEtBQUssR0FBSSxLQUE0QyxDQUFDLEdBQUcsQ0FBQyxDQUFBO1FBQ2hFLElBQUksS0FBSyxJQUFJLE9BQU8sS0FBSyxLQUFLLFFBQVEsSUFBSSxPQUFRLEtBQTZCLENBQUMsS0FBSyxLQUFLLFFBQVEsRUFBRTtZQUNsRyxPQUFRLEtBQTJCLENBQUMsS0FBSyxDQUFBO1NBQzFDO0tBQ0Y7SUFDRCxPQUFPLFNBQVMsQ0FBQTtBQUNsQixDQUFDO0FBRUQsU0FBUyxhQUFhLENBQUMsSUFBbUI7SUFDeEMsT0FBTyxPQUFPLElBQUksSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLE9BQU8sRUFBRSxJQUFJLENBQUMsT0FBTyxFQUFFLEtBQUssRUFBRSxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsT0FBTyxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsU0FBUyxFQUFFLENBQUE7QUFDN0csQ0FBQztBQUVELHFGQUFxRjtBQUNyRixNQUFNLFVBQVUsTUFBTSxDQUFDLElBSXRCO0lBQ0MsTUFBTSxFQUFFLE1BQU0sRUFBRSxjQUFjLEVBQUUsY0FBYyxFQUFFLGdCQUFnQixFQUFFLGdCQUFnQixFQUFFLEdBQUcsSUFBSSxDQUFBO0lBQzNGLE1BQU0sSUFBSSxHQUFHLGNBQWMsQ0FBQyxVQUFVLENBQUE7SUFFdEMsTUFBTSxRQUFRLEdBQUcsSUFBSSxHQUFHLEVBQW1CLENBQUE7SUFDM0Msc0ZBQXNGO0lBQ3RGLE1BQU0sS0FBSyxHQUFHLElBQUksR0FBRyxFQUFvRCxDQUFBO0lBQ3pFLCtEQUErRDtJQUMvRCxJQUFJLGFBQWEsR0FBRyxDQUFDLENBQUE7SUFDckIsSUFBSSxrQkFBa0IsR0FBRyxLQUFLLENBQUE7SUFFOUIsU0FBUyxHQUFHLENBQUMsRUFBYztRQUN6QixNQUFNLEtBQUssR0FBRyxLQUFLLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQTtRQUNoQyxJQUFJLEtBQUssRUFBRTtZQUNULElBQUksS0FBSyxLQUFLLEVBQUUsQ0FBQyxTQUFTLEVBQUU7Z0JBQzFCLE1BQU0sSUFBSSxLQUFLLENBQ2Isd0NBQXdDLEVBQUUsQ0FBQyxJQUFJLCtDQUErQztvQkFDNUYsNEVBQTRFLENBQy9FLENBQUE7YUFDRjtZQUNELE9BQU07U0FDUDtRQUNELEtBQUssQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsU0FBUyxDQUFDLENBQUE7UUFDaEMsTUFBTSxJQUFJLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQTtRQUNwQiw0RkFBNEY7UUFDNUYsRUFBRSxDQUFDLFNBQVMsQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLENBQUMsS0FBa0MsRUFBRSxFQUFFO1lBQ2pFLG1GQUFtRjtZQUNuRixxQkFBcUI7WUFDckIsSUFBSSxLQUFLO2dCQUFFLE9BQU8sQ0FBQyxJQUFJLEVBQUUsS0FBSyxDQUFDLENBQUE7UUFDakMsQ0FBQyxDQUFDLENBQUE7SUFDSixDQUFDO0lBRUQsU0FBUyxTQUFTLENBQUMsT0FBZ0IsRUFBRSxJQUFZLEVBQUUsS0FBc0I7UUFDdkUsSUFBSSxLQUFLLENBQUMsU0FBUyxLQUFLLE9BQU8sQ0FBQyxTQUFTO1lBQUUsT0FBTyxLQUFLLENBQUE7UUFDdkQsSUFBSSxLQUFLLENBQUMsU0FBUyxLQUFLLFlBQVk7WUFBRSxPQUFPLElBQUksQ0FBQTtRQUNqRCx1RkFBdUY7UUFDdkYseUZBQXlGO1FBQ3pGLGtGQUFrRjtRQUNsRixJQUFJLE9BQU8sQ0FBQyxtQkFBbUIsSUFBSSxJQUFJLEtBQUssZ0JBQWdCLENBQUMsSUFBSTtZQUFFLE9BQU8sV0FBVyxDQUFBO1FBQ3JGLE9BQVEsS0FBa0MsQ0FBQyxFQUFFLEtBQUssT0FBTyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUE7SUFDN0UsQ0FBQztJQUVELFNBQVMsT0FBTyxDQUFDLElBQVksRUFBRSxLQUFzQjtRQUNuRCx1RkFBdUY7UUFDdkYsS0FBSyxNQUFNLE9BQU8sSUFBSSxRQUFRLENBQUMsTUFBTSxFQUFFLEVBQUU7WUFDdkMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQztnQkFBRSxTQUFRO1lBQ3hDLE1BQU0sV0FBVyxHQUFHLFNBQVMsQ0FBQyxPQUFPLEVBQUUsSUFBSSxFQUFFLEtBQUssQ0FBQyxDQUFBO1lBQ25ELElBQUksV0FBVyxLQUFLLElBQUk7Z0JBQUUsU0FBUTtZQUNsQyxJQUFJLFdBQVcsS0FBSyxXQUFXLEVBQUU7Z0JBQy9CLFdBQVcsQ0FDVCxPQUFPLEVBQ1AsSUFBSSxLQUFLLENBQ1AsaUNBQWlDLElBQUksMERBQTBEO29CQUM3Rix1RkFBdUYsQ0FDMUYsQ0FDRixDQUFBO2dCQUNELFNBQVE7YUFDVDtZQUNELE1BQU0sQ0FBQyxPQUFPLEVBQUUsSUFBSSxFQUFFLEtBQUssQ0FBQyxDQUFBO1NBQzdCO0lBQ0gsQ0FBQztJQUVELFNBQVMsTUFBTSxDQUFDLE9BQWdCLEVBQUUsSUFBWSxFQUFFLEtBQXNCO1FBQ3BFLElBQUksT0FBTyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDO1lBQUUsT0FBTyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFBRSxPQUFPLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUE7UUFFNUUsdUZBQXVGO1FBQ3ZGLHFDQUFxQztRQUNyQyxJQUFJLElBQUksS0FBSyxnQkFBZ0IsQ0FBQyxJQUFJLElBQUksTUFBTSxDQUFDLEtBQUssQ0FBQyxLQUFLLFFBQVEsRUFBRTtZQUNoRSxhQUFhLENBQUMsT0FBTyxFQUFFLEVBQUUsS0FBSyxFQUFFLFFBQVEsRUFBRSxNQUFNLEVBQUUsT0FBTyxDQUFDLE1BQWlCLEVBQUUsQ0FBQyxDQUFBO1lBQzlFLE9BQU07U0FDUDtRQUVELE1BQU0sS0FBSyxHQUFHLE9BQU8sQ0FBQyxLQUFLLENBQUE7UUFDM0IsSUFBSSxDQUFDLEtBQUssSUFBSSxLQUFLLENBQUMsT0FBTyxLQUFLLElBQUk7WUFBRSxPQUFNO1FBQzVDLElBQUksS0FBSyxDQUFDLEtBQUssS0FBSyxTQUFTLElBQUksS0FBSyxDQUFDLEtBQUssS0FBSyxNQUFNLENBQUMsS0FBSyxDQUFDLEVBQUU7WUFDOUQsYUFBYSxDQUFDLE9BQU8sRUFBRSxFQUFFLEtBQUssRUFBRSxTQUFTLEVBQUUsTUFBTSxFQUFFLE9BQU8sQ0FBQyxNQUFpQixFQUFFLENBQUMsQ0FBQTtTQUNoRjtJQUNILENBQUM7SUFFRCxTQUFTLGFBQWEsQ0FBQyxPQUFnQixFQUFFLE9BQTZCO1FBQ3BFLElBQUksT0FBTyxDQUFDLE9BQU87WUFBRSxPQUFNO1FBQzNCLE9BQU8sQ0FBQyxPQUFPLEdBQUcsSUFBSSxDQUFBO1FBQ3RCLFFBQVEsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQUFBO1FBQ2xDLE9BQU8sQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUE7UUFDdkIsd0JBQXdCLEVBQUUsQ0FBQTtJQUM1QixDQUFDO0lBRUQsU0FBUyxXQUFXLENBQUMsT0FBZ0IsRUFBRSxLQUFZO1FBQ2pELElBQUksT0FBTyxDQUFDLE9BQU87WUFBRSxPQUFNO1FBQzNCLE9BQU8sQ0FBQyxPQUFPLEdBQUcsSUFBSSxDQUFBO1FBQ3RCLFFBQVEsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQUFBO1FBQ2xDLE9BQU8sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUE7UUFDbkIsd0JBQXdCLEVBQUUsQ0FBQTtJQUM1QixDQUFDO0lBRUQsU0FBUyxlQUFlO1FBQ3RCLEtBQUssTUFBTSxPQUFPLElBQUksUUFBUSxDQUFDLE1BQU0sRUFBRSxFQUFFO1lBQ3ZDLElBQUksT0FBTyxDQUFDLFNBQVMsS0FBSyxTQUFTO2dCQUFFLE9BQU8sSUFBSSxDQUFBO1NBQ2pEO1FBQ0QsT0FBTyxLQUFLLENBQUE7SUFDZCxDQUFDO0lBRUQsU0FBUyx3QkFBd0I7UUFDL0IsSUFBSSxDQUFDLGtCQUFrQixJQUFJLGVBQWUsRUFBRTtZQUFFLE9BQU07UUFDcEQsa0JBQWtCLEdBQUcsS0FBSyxDQUFBO1FBQzFCLGNBQWMsQ0FBQyxZQUFZLENBQUMsK0JBQStCLENBQUMsQ0FBQTtJQUM5RCxDQUFDO0lBRUQsU0FBUyxtQkFBbUI7UUFDMUIsSUFBSSxrQkFBa0I7WUFBRSxPQUFNO1FBQzlCLGtCQUFrQixHQUFHLElBQUksQ0FBQTtRQUN6Qix3RkFBd0Y7UUFDeEYsY0FBYyxDQUFDLFNBQVMsQ0FDdEIsQ0FBQyxFQUFVLEVBQUUsRUFBRTtZQUNiLEtBQUssTUFBTSxPQUFPLElBQUksUUFBUSxDQUFDLE1BQU0sRUFBRSxFQUFFO2dCQUN2QyxJQUFJLE9BQU8sQ0FBQyxTQUFTLEtBQUssU0FBUztvQkFBRSxTQUFRO2dCQUM3QyxPQUFPLENBQUMsU0FBUyxJQUFJLEVBQUUsR0FBRyxJQUFJLENBQUE7Z0JBQzlCLElBQUksT0FBTyxDQUFDLFNBQVMsSUFBSSxPQUFPLENBQUMsU0FBUyxFQUFFO29CQUMxQyxhQUFhLENBQUMsT0FBTyxFQUFFLEVBQUUsS0FBSyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsT0FBTyxDQUFDLE1BQWlCLEVBQUUsQ0FBQyxDQUFBO2lCQUNqRjthQUNGO1lBQ0Qsd0JBQXdCLEVBQUUsQ0FBQTtRQUM1QixDQUFDLEVBQ0QsdUJBQXVCLEVBQ3ZCLCtCQUErQixDQUNoQyxDQUFBO0lBQ0gsQ0FBQztJQUVELEtBQUssVUFBVSxxQkFBcUIsQ0FDbEMsT0FBaUYsRUFDakYsT0FBNEM7UUFFNUMsTUFBTSxFQUFFLEVBQUUsRUFBRSxZQUFZLEVBQUUsR0FBRyxPQUFPLE9BQU8sS0FBSyxRQUFRLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxFQUFFLE9BQU8sRUFBRSxZQUFZLEVBQUUsU0FBUyxFQUFFLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQTtRQUM3RyxNQUFNLFNBQVMsR0FBRyxhQUFhLEVBQUUsQ0FBQTtRQUVqQyxNQUFNLE9BQU8sR0FBRyxPQUFPLEVBQUUsT0FBTyxJQUFJLEVBQUUsQ0FBQTtRQUN0QyxNQUFNLFlBQVksR0FBRyxJQUFJLEdBQUcsRUFBVSxDQUFBO1FBQ3RDLEtBQUssTUFBTSxFQUFFLElBQUksT0FBTztZQUFFLFlBQVksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFBO1FBRW5ELE1BQU0sSUFBSSxHQUFHLE9BQU8sRUFBRSxLQUFLLENBQUMsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQTtRQUN0RSxNQUFNLE9BQU8sR0FBRyxJQUFJLEdBQUcsQ0FBUyxZQUFZLENBQUMsQ0FBQTtRQUM3QyxPQUFPLENBQUMsR0FBRyxDQUFDLGdCQUFnQixDQUFDLElBQUksQ0FBQyxDQUFBO1FBQ2xDLElBQUksSUFBSTtZQUFFLE9BQU8sQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQTtRQUV4Qyx1RkFBdUY7UUFDdkYsOEVBQThFO1FBQzlFLEdBQUcsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFBO1FBQ3JCLEtBQUssTUFBTSxFQUFFLElBQUksT0FBTztZQUFFLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQTtRQUNqQyxJQUFJLElBQUk7WUFBRSxHQUFHLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFBO1FBRTNCLElBQUksTUFBZ0QsQ0FBQTtRQUNwRCxJQUFJLElBQTZCLENBQUE7UUFDakMsTUFBTSxPQUFPLEdBQUcsSUFBSSxPQUFPLENBQXVCLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxFQUFFO1lBQ3BFLE1BQU0sR0FBRyxPQUFPLENBQUE7WUFDaEIsSUFBSSxHQUFHLE1BQU0sQ0FBQTtRQUNmLENBQUMsQ0FBQyxDQUFBO1FBRUYsTUFBTSxPQUFPLEdBQVk7WUFDdkIsU0FBUztZQUNULEVBQUU7WUFDRixtQkFBbUIsRUFBRSxpQkFBaUIsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDO1lBQ25ELE9BQU8sRUFBRSxZQUFZO1lBQ3JCLE9BQU87WUFDUCxLQUFLLEVBQUUsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLE9BQU8sRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRSxLQUFLLEVBQUUsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUMsQ0FBQyxTQUFTO1lBQzNFLE1BQU0sRUFBRSxFQUFFO1lBQ1YsU0FBUyxFQUFFLE9BQU8sRUFBRSxTQUFTO1lBQzdCLFNBQVMsRUFBRSxDQUFDO1lBQ1osT0FBTyxFQUFFLEtBQUs7WUFDZCxNQUFNO1lBQ04sSUFBSTtTQUNMLENBQUE7UUFDRCxRQUFRLENBQUMsR0FBRyxDQUFDLFNBQVMsRUFBRSxPQUFPLENBQUMsQ0FBQTtRQUNoQyxJQUFJLE9BQU8sQ0FBQyxTQUFTLEtBQUssU0FBUztZQUFFLG1CQUFtQixFQUFFLENBQUE7UUFFMUQsSUFBSTtZQUNGLE1BQU0sRUFBRSxVQUFVLEVBQUUsR0FBRyxNQUFNLGdCQUFnQixDQUFDLEVBQUUsRUFBRSxFQUFFLFNBQVMsRUFBRSxZQUFZLEVBQUUsQ0FBQyxDQUFBO1lBQzlFLDRFQUE0RTtZQUM1RSxJQUFJLFVBQVUsS0FBSyxvQkFBb0IsQ0FBQyxNQUFNLEVBQUU7Z0JBQzlDLGFBQWEsQ0FBQyxPQUFPLEVBQUUsRUFBRSxLQUFLLEVBQUUsV0FBVyxFQUFFLFVBQVUsRUFBRSxDQUFDLENBQUE7YUFDM0Q7U0FDRjtRQUFDLE9BQU8sS0FBSyxFQUFFO1lBQ2QsbUZBQW1GO1lBQ25GLDBCQUEwQjtZQUMxQixXQUFXLENBQUMsT0FBTyxFQUFFLEtBQWMsQ0FBQyxDQUFBO1NBQ3JDO1FBRUQsT0FBTyxPQUFPLENBQUE7SUFDaEIsQ0FBQztJQUVELDJGQUEyRjtJQUMzRixvREFBb0Q7SUFDcEQsT0FBTyxFQUFFLHFCQUFxQixFQUFFLHFCQUE4QyxFQUFFLENBQUE7QUFDbEYsQ0FBQztBQUVELE1BQU0sTUFBTSxHQUFHLGVBQWUsQ0FBQyxNQUFNLENBQUMsRUFBRSxNQUFNLEVBQUUsY0FBYyxFQUFFLGdCQUFnQixFQUFFLGdCQUFnQixFQUFFLENBQUMsQ0FBQTtBQUVyRzs7Ozs7Ozs7O0dBU0c7QUFDSCxNQUFNLENBQUMsTUFBTSxxQkFBcUIsR0FBMEIsTUFBTSxDQUFDLHFCQUFxQixDQUFBIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgZW5naW5lLFxuICBFeHBsb3Jlckl0ZW1QdXJjaGFzZVJlc3VsdCxcbiAgRXhwbG9yZXJVaSxcbiAgRXhwbG9yZXJVaUV2ZW50c1Jlc3VsdCxcbiAgR3Jvd09ubHlWYWx1ZVNldENvbXBvbmVudERlZmluaXRpb24sXG4gIElFbmdpbmUsXG4gIFBCRXhwbG9yZXJJdGVtUHVyY2hhc2VSZXN1bHQsXG4gIFBCRXhwbG9yZXJVaUV2ZW50c1Jlc3VsdFxufSBmcm9tICdAZGNsL2VjcydcbmltcG9ydCB7IG9wZW5FeHBsb3JlclVpLCBPcGVuRXhwbG9yZXJVaVJlc3VsdCB9IGZyb20gJ35zeXN0ZW0vUmVzdHJpY3RlZEFjdGlvbnMnXG5cbmV4cG9ydCB7IEV4cGxvcmVyVWksIE9wZW5FeHBsb3JlclVpUmVzdWx0IH1cblxuLy8gV2hhdCBhbiBleHBsb3JlciB0aGF0IGRvZXMgbm90IGVjaG8gcmVxdWVzdF9pZCwgb3IgYSB1c2VyLWluaXRpYXRlZCBhY3Rpb24sIGxlYXZlcyBvbiB0aGUgd2lyZS5cbmNvbnN0IFVOQ09SUkVMQVRFRCA9IDBcblxuLy8gUGFuZWxzIHRoYXQgY2FuIGJlIG9uIHNjcmVlbiBuZXh0IHRvIGFub3RoZXIgcGFuZWwuIFRoZSBgdWlgIGZpZWxkIGFsb25lIGNhbm5vdCBhdHRyaWJ1dGVcbi8vIHRoZWlyIGV2ZW50cywgc28gYW4gZXZlbnQgb24gb25lIG9mIHRoZXNlIHBhbmVscyBtdXN0IGNhcnJ5IGEgcmVxdWVzdF9pZC5cbmNvbnN0IENPTkNVUlJFTlRfUEFORUxTOiByZWFkb25seSBFeHBsb3JlclVpW10gPSBbRXhwbG9yZXJVaS5FVV9JVEVNX1BVUkNIQVNFXVxuXG4vKiogQHB1YmxpYyAqL1xuZXhwb3J0IHR5cGUgQ29ycmVsYXRlZEV2ZW50ID0ge1xuICB0aW1lc3RhbXA6IG51bWJlclxuICByZXF1ZXN0SWQ6IG51bWJlclxufVxuXG4vKipcbiAqIEEgbmFtZWQgc3RyZWFtIG9mIGV2ZW50cyB0aGF0IHRoaXMgaGVscGVyIGNhbiBjb2xsZWN0IGFuZCBzdG9wIG9uLlxuICogQHB1YmxpY1xuICovXG5leHBvcnQgdHlwZSBDaGFubmVsPE4gZXh0ZW5kcyBzdHJpbmcgPSBzdHJpbmcsIFQgZXh0ZW5kcyBDb3JyZWxhdGVkRXZlbnQgPSBDb3JyZWxhdGVkRXZlbnQ+ID0ge1xuICByZWFkb25seSBuYW1lOiBOXG4gIHJlYWRvbmx5IGNvbXBvbmVudDogR3Jvd09ubHlWYWx1ZVNldENvbXBvbmVudERlZmluaXRpb248VD5cbn1cblxuLyoqIEBwdWJsaWMgKi9cbmV4cG9ydCB0eXBlIEFueUNoYW5uZWwgPSBDaGFubmVsPHN0cmluZywgYW55PlxuXG4vKipcbiAqIFdyYXBzIGEgZ3Jvdy1vbmx5IHJlc3VsdCBjb21wb25lbnQgYXMgYSB7QGxpbmsgQ2hhbm5lbH0uIFRoZSBuYW1lIG11c3QgYmUgdW5pcXVlIHdpdGhpbiBhIHNjZW5lLlxuICogQHB1YmxpY1xuICovXG5leHBvcnQgZnVuY3Rpb24gY2hhbm5lbDxOIGV4dGVuZHMgc3RyaW5nLCBUIGV4dGVuZHMgQ29ycmVsYXRlZEV2ZW50PihcbiAgbmFtZTogTixcbiAgY29tcG9uZW50OiBHcm93T25seVZhbHVlU2V0Q29tcG9uZW50RGVmaW5pdGlvbjxUPlxuKTogQ2hhbm5lbDxOLCBUPiB7XG4gIHJldHVybiB7IG5hbWUsIGNvbXBvbmVudCB9XG59XG5cbi8qKiBQYW5lbCBsaWZlY3ljbGUgZXZlbnRzOiBvcGVuZWQgYW5kIGNsb3NlZC4gQHB1YmxpYyAqL1xuZXhwb3J0IGNvbnN0IEV4cGxvcmVyVWlFdmVudHM6IENoYW5uZWw8J2V4cGxvcmVyVWknLCBQQkV4cGxvcmVyVWlFdmVudHNSZXN1bHQ+ID0gLyogQF9fUFVSRV9fICovIGNoYW5uZWwoXG4gICdleHBsb3JlclVpJyxcbiAgRXhwbG9yZXJVaUV2ZW50c1Jlc3VsdFxuKVxuXG4vKiogT3V0Y29tZSBvZiBhbiBgRVVfSVRFTV9QVVJDSEFTRWAgZmxvdzogcHVyY2hhc2VkLCBkaXNtaXNzZWQgb3IgZmFpbGVkLiBAcHVibGljICovXG5leHBvcnQgY29uc3QgSXRlbVB1cmNoYXNlOiBDaGFubmVsPCdpdGVtUHVyY2hhc2UnLCBQQkV4cGxvcmVySXRlbVB1cmNoYXNlUmVzdWx0PiA9IC8qIEBfX1BVUkVfXyAqLyBjaGFubmVsKFxuICAnaXRlbVB1cmNoYXNlJyxcbiAgRXhwbG9yZXJJdGVtUHVyY2hhc2VSZXN1bHRcbilcblxuLyoqXG4gKiBUaGUgYCRjYXNlYCBuYW1lcyBvZiBhIGNoYW5uZWwncyBldmVudCB1bmlvbi5cbiAqIEBwdWJsaWNcbiAqL1xuZXhwb3J0IHR5cGUgQ2FzZU9mPEMgZXh0ZW5kcyBBbnlDaGFubmVsPiA9XG4gIEMgZXh0ZW5kcyBDaGFubmVsPGFueSwgaW5mZXIgVD4gPyBFeHRyYWN0PFRba2V5b2YgVF0sIHsgJGNhc2U6IHN0cmluZyB9PlsnJGNhc2UnXSA6IG5ldmVyXG5cbi8qKiBAcHVibGljICovXG5leHBvcnQgdHlwZSBWYXJpYW50PEMgZXh0ZW5kcyBBbnlDaGFubmVsID0gQW55Q2hhbm5lbCwgSyBleHRlbmRzIHN0cmluZyA9IHN0cmluZz4gPSB7XG4gIHJlYWRvbmx5IGNoYW5uZWw6IENcbiAgcmVhZG9ubHkgJGNhc2U6IEtcbn1cblxuLyoqIEBwdWJsaWMgKi9cbmV4cG9ydCBmdW5jdGlvbiB2YXJpYW50PEMgZXh0ZW5kcyBBbnlDaGFubmVsLCBLIGV4dGVuZHMgQ2FzZU9mPEM+PihjaDogQywgJGNhc2U6IEspOiBWYXJpYW50PEMsIEs+IHtcbiAgcmV0dXJuIHsgY2hhbm5lbDogY2gsICRjYXNlIH1cbn1cblxuLyoqXG4gKiBXaGF0IGVuZHMgdGhlIHdhaXQgYmVmb3JlIHRoZSBwYW5lbCBjbG9zZXM6IGFueSBldmVudCBvbiBhIGNoYW5uZWwsIG9yIG9uZSBgJGNhc2VgIG9mIGl0LlxuICogQHB1YmxpY1xuICovXG5leHBvcnQgdHlwZSBTdG9wQ29uZGl0aW9uID0gQW55Q2hhbm5lbCB8IFZhcmlhbnRcblxuLyoqIEBwdWJsaWMgKi9cbmV4cG9ydCB0eXBlIENvbGxlY3RlZDxDPiA9IEMgZXh0ZW5kcyBDaGFubmVsPGluZmVyIE4sIGluZmVyIFQ+ID8geyBjaGFubmVsOiBOOyBldmVudDogVCB9IDogbmV2ZXJcblxuLyoqXG4gKiBIb3cgdGhlIHdhaXQgZW5kZWQuXG4gKiAtIGBjbG9zZWRgOiB0aGUgcGFuZWwgdGhpcyBjYWxsIG9wZW5lZCB3YXMgY2xvc2VkLlxuICogLSBgbWF0Y2hlZGA6IGB1bnRpbGAgZmlyZWQgZmlyc3QsIHNvIHRoZSBwYW5lbCBtYXkgc3RpbGwgYmUgb24gc2NyZWVuLlxuICogLSBgbm90T3BlbmVkYDogdGhpcyBjYWxsIGRpZCBub3Qgb3BlbiBhbnl0aGluZy4gYG9wZW5SZXN1bHRgIHNheXMgd2h5LlxuICogLSBgdGltZWRPdXRgOiBgdGltZW91dE1zYCBlbGFwc2VkIGZpcnN0LlxuICpcbiAqIGBldmVudHNgIGFsd2F5cyBob2xkcyBldmVyeXRoaW5nIGNvbGxlY3RlZCwgdGhlIGV2ZW50IHRoYXQgc3RvcHBlZCB0aGUgd2FpdCBpbmNsdWRlZC5cbiAqIEBwdWJsaWNcbiAqL1xuZXhwb3J0IHR5cGUgV2FpdE91dGNvbWU8QyBleHRlbmRzIHJlYWRvbmx5IEFueUNoYW5uZWxbXT4gPVxuICB8IHsgJGNhc2U6ICdjbG9zZWQnOyBldmVudHM6IHJlYWRvbmx5IENvbGxlY3RlZDxDW251bWJlcl0+W10gfVxuICB8IHsgJGNhc2U6ICdtYXRjaGVkJzsgZXZlbnRzOiByZWFkb25seSBDb2xsZWN0ZWQ8Q1tudW1iZXJdPltdIH1cbiAgfCB7ICRjYXNlOiAnbm90T3BlbmVkJzsgb3BlblJlc3VsdDogT3BlbkV4cGxvcmVyVWlSZXN1bHQgfVxuICB8IHsgJGNhc2U6ICd0aW1lZE91dCc7IGV2ZW50czogcmVhZG9ubHkgQ29sbGVjdGVkPENbbnVtYmVyXT5bXSB9XG5cbi8qKiBAcHVibGljICovXG5leHBvcnQgdHlwZSBXYWl0T3B0aW9uczxDIGV4dGVuZHMgcmVhZG9ubHkgQW55Q2hhbm5lbFtdPiA9IHtcbiAgLyoqIENoYW5uZWxzIHdob3NlIGV2ZW50cyBsYW5kIGluIGBldmVudHNgLiBEZWZhdWx0cyB0byBub25lLiAqL1xuICBjb2xsZWN0PzogQ1xuICAvKiogU3RvcHMgdGhlIHdhaXQgZWFybHkuIFRoZSBwYW5lbCBjbG9zaW5nIGFsd2F5cyBzdG9wcyBpdCByZWdhcmRsZXNzLiAqL1xuICB1bnRpbD86IFN0b3BDb25kaXRpb25cbiAgLyoqXG4gICAqIEJvdW5kcyB0aGUgd2FpdCwgaW4gbWlsbGlzZWNvbmRzLiBPbiBleHBpcnkgdGhlIHByb21pc2UgcmVzb2x2ZXMgd2l0aCBgJGNhc2U6ICd0aW1lZE91dCdgLlxuICAgKiBObyBkZWZhdWx0LCBiZWNhdXNlIGEgcGFuZWwgY2FuIHN0YXkgb3BlbiBmb3IgbWludXRlcy4gV2l0aG91dCBpdCwgYW4gZXhwbG9yZXIgdGhhdCBvcGVuc1xuICAgKiBhIHBhbmVsIGFuZCB0aGVuIGVtaXRzIG5vIGBjbG9zZWRgIGxlYXZlcyB0aGUgcHJvbWlzZSBwZW5kaW5nIGZvciB0aGUgc2NlbmUncyB3aG9sZSBsaWZlLlxuICAgKi9cbiAgdGltZW91dE1zPzogbnVtYmVyXG59XG5cbi8qKiBAcHVibGljICovXG5leHBvcnQgdHlwZSBPcGVuRXhwbG9yZXJVaVJlcXVlc3QgPVxuICB8IHsgdWk6IEV4Y2x1ZGU8RXhwbG9yZXJVaSwgRXhwbG9yZXJVaS5FVV9JVEVNX1BVUkNIQVNFPjsgaXRlbVB1cmNoYXNlPzogdW5kZWZpbmVkIH1cbiAgfCB7IHVpOiBFeHBsb3JlclVpLkVVX0lURU1fUFVSQ0hBU0U7IGl0ZW1QdXJjaGFzZTogeyB1cm46IHN0cmluZyB9IH1cblxuLyoqXG4gKiBTaWduYXR1cmUgb2Yge0BsaW5rIG9wZW5FeHBsb3JlclVpQW5kV2FpdH0uIFRoZSBzZWNvbmQgb3ZlcmxvYWQgdGFrZXMgYSBiYXJlIGB1aWAsIHNvIGFcbiAqIGNvbXB1dGVkIHBhbmVsIHZhbHVlIG5lZWRzIG5vIG5hcnJvd2luZy5cbiAqIEBwdWJsaWNcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBPcGVuRXhwbG9yZXJVaUFuZFdhaXQge1xuICA8Y29uc3QgQyBleHRlbmRzIHJlYWRvbmx5IEFueUNoYW5uZWxbXSA9IFtdPihcbiAgICByZXF1ZXN0OiBPcGVuRXhwbG9yZXJVaVJlcXVlc3QsXG4gICAgb3B0aW9ucz86IFdhaXRPcHRpb25zPEM+XG4gICk6IFByb21pc2U8V2FpdE91dGNvbWU8Qz4+XG4gICh1aTogRXhjbHVkZTxFeHBsb3JlclVpLCBFeHBsb3JlclVpLkVVX0lURU1fUFVSQ0hBU0U+KTogUHJvbWlzZTxXYWl0T3V0Y29tZTxbXT4+XG59XG5cbi8qKiBAaW50ZXJuYWwgZXhwb3NlZCBmb3IgdGVzdHMgKi9cbmV4cG9ydCBjb25zdCBFWFBMT1JFUl9VSV9XQUlUX1RJTUVPVVRfU1lTVEVNID0gJ2V4cGxvcmVyLXVpLXdhaXQtdGltZW91dCdcblxuLy8gTG93ZXN0IHByaW9yaXR5IHNvcnRzIHRoaXMgc3lzdGVtIGxhc3QsIHNvIHdoZW4gaXQgcmVtb3ZlcyBpdHNlbGYgbWlkLXRpY2sgaXQgc3BsaWNlcyB0aGVcbi8vIGxhc3QgZWxlbWVudCBvZiB0aGUgYXJyYXkgdGhlIGVuZ2luZSBpcyBpdGVyYXRpbmcgYW5kIHNraXBzIG5vIG90aGVyIHN5c3RlbS5cbmNvbnN0IFRJTUVPVVRfU1lTVEVNX1BSSU9SSVRZID0gTnVtYmVyLk1JTl9TQUZFX0lOVEVHRVJcblxudHlwZSBPcGVuRXhwbG9yZXJVaUZuID0gKGJvZHk6IHtcbiAgdWk6IEV4cGxvcmVyVWlcbiAgcmVxdWVzdElkPzogbnVtYmVyXG4gIGl0ZW1QdXJjaGFzZT86IHsgdXJuOiBzdHJpbmcgfVxufSkgPT4gUHJvbWlzZTx7IG9wZW5SZXN1bHQ6IE9wZW5FeHBsb3JlclVpUmVzdWx0IH0+XG5cbnR5cGUgQ29sbGVjdGVkRXZlbnQgPSB7IGNoYW5uZWw6IHN0cmluZzsgZXZlbnQ6IENvcnJlbGF0ZWRFdmVudCB9XG5cbnR5cGUgU2Vzc2lvbiA9IHtcbiAgcmVxdWVzdElkOiBudW1iZXJcbiAgdWk6IEV4cGxvcmVyVWlcbiAgY29ycmVsYXRpb25SZXF1aXJlZDogYm9vbGVhblxuICBjb2xsZWN0OiBSZWFkb25seVNldDxzdHJpbmc+XG4gIHdhdGNoZWQ6IFJlYWRvbmx5U2V0PHN0cmluZz5cbiAgdW50aWw6IHsgY2hhbm5lbDogc3RyaW5nOyAkY2FzZTogc3RyaW5nIHwgdW5kZWZpbmVkIH0gfCB1bmRlZmluZWRcbiAgZXZlbnRzOiBDb2xsZWN0ZWRFdmVudFtdXG4gIHRpbWVvdXRNczogbnVtYmVyIHwgdW5kZWZpbmVkXG4gIGVsYXBzZWRNczogbnVtYmVyXG4gIHNldHRsZWQ6IGJvb2xlYW5cbiAgc2V0dGxlOiAob3V0Y29tZTogV2FpdE91dGNvbWU8bmV2ZXJbXT4pID0+IHZvaWRcbiAgZmFpbDogKGVycm9yOiBFcnJvcikgPT4gdm9pZFxufVxuXG50eXBlIEF0dHJpYnV0aW9uID0gJ3llcycgfCAnbm8nIHwgJ2FtYmlndW91cydcblxuLy8gdHMtcHJvdG8gcmVuZGVycyBhIGBvbmVvZmAgYXMgb25lIHdyYXBwZXIgcHJvcGVydHkgYHsgJGNhc2UsIFskY2FzZV06IHZhbHVlIH1gLiBGaW5kaW5nIHRoYXRcbi8vIHByb3BlcnR5IGJ5IHNoYXBlIGtlZXBzIHRoZSBoZWxwZXIgaW5kZXBlbmRlbnQgb2YgdGhlIG5hbWUgZWFjaCBtZXNzYWdlIGdhdmUgaXQ6IGBldmVudGAgb25cbi8vIG9uZSBtZXNzYWdlLCBgc3RhdHVzYCBvbiBhbm90aGVyLlxuZnVuY3Rpb24gY2FzZU9mKGV2ZW50OiBDb3JyZWxhdGVkRXZlbnQpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICBmb3IgKGNvbnN0IGtleSBvZiBPYmplY3Qua2V5cyhldmVudCkpIHtcbiAgICBjb25zdCB2YWx1ZSA9IChldmVudCBhcyB1bmtub3duIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+KVtrZXldXG4gICAgaWYgKHZhbHVlICYmIHR5cGVvZiB2YWx1ZSA9PT0gJ29iamVjdCcgJiYgdHlwZW9mICh2YWx1ZSBhcyB7ICRjYXNlPzogdW5rbm93biB9KS4kY2FzZSA9PT0gJ3N0cmluZycpIHtcbiAgICAgIHJldHVybiAodmFsdWUgYXMgeyAkY2FzZTogc3RyaW5nIH0pLiRjYXNlXG4gICAgfVxuICB9XG4gIHJldHVybiB1bmRlZmluZWRcbn1cblxuZnVuY3Rpb24gbm9ybWFsaXplU3RvcChzdG9wOiBTdG9wQ29uZGl0aW9uKTogeyBjaGFubmVsOiBBbnlDaGFubmVsOyAkY2FzZTogc3RyaW5nIHwgdW5kZWZpbmVkIH0ge1xuICByZXR1cm4gJyRjYXNlJyBpbiBzdG9wID8geyBjaGFubmVsOiBzdG9wLmNoYW5uZWwsICRjYXNlOiBzdG9wLiRjYXNlIH0gOiB7IGNoYW5uZWw6IHN0b3AsICRjYXNlOiB1bmRlZmluZWQgfVxufVxuXG4vKiogQGludGVybmFsIHRlc3Qgc2VhbS4gVGhlIHByb2R1Y3Rpb24gaW5zdGFuY2UgaXMge0BsaW5rIG9wZW5FeHBsb3JlclVpQW5kV2FpdH0uICovXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlKGRlcHM6IHtcbiAgZW5naW5lOiBJRW5naW5lXG4gIG9wZW5FeHBsb3JlclVpOiBPcGVuRXhwbG9yZXJVaUZuXG4gIGV4cGxvcmVyVWlFdmVudHM6IENoYW5uZWw8J2V4cGxvcmVyVWknLCBQQkV4cGxvcmVyVWlFdmVudHNSZXN1bHQ+XG59KSB7XG4gIGNvbnN0IHsgZW5naW5lOiBlbmdpbmVJbnN0YW5jZSwgb3BlbkV4cGxvcmVyVWk6IG9wZW5FeHBsb3JlclVpRm4sIGV4cGxvcmVyVWlFdmVudHMgfSA9IGRlcHNcbiAgY29uc3Qgcm9vdCA9IGVuZ2luZUluc3RhbmNlLlJvb3RFbnRpdHlcblxuICBjb25zdCBzZXNzaW9ucyA9IG5ldyBNYXA8bnVtYmVyLCBTZXNzaW9uPigpXG4gIC8vIEtleWVkIGJ5IG5hbWUsIHNvIHR3byB3cmFwcGVycyBhcm91bmQgdGhlIHNhbWUgY29tcG9uZW50IGFybSBvbmUgbGlzdGVuZXIsIG5vdCB0d28uXG4gIGNvbnN0IGFybWVkID0gbmV3IE1hcDxzdHJpbmcsIEdyb3dPbmx5VmFsdWVTZXRDb21wb25lbnREZWZpbml0aW9uPGFueT4+KClcbiAgLy8gU3RhcnRzIGF0IDEgc28gYSBtaW50ZWQgaWQgbmV2ZXIgY29sbGlkZXMgd2l0aCBVTkNPUlJFTEFURUQuXG4gIGxldCBuZXh0UmVxdWVzdElkID0gMVxuICBsZXQgdGltZW91dFN5c3RlbUFkZGVkID0gZmFsc2VcblxuICBmdW5jdGlvbiBhcm0oY2g6IEFueUNoYW5uZWwpIHtcbiAgICBjb25zdCBib3VuZCA9IGFybWVkLmdldChjaC5uYW1lKVxuICAgIGlmIChib3VuZCkge1xuICAgICAgaWYgKGJvdW5kICE9PSBjaC5jb21wb25lbnQpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgIGBvcGVuRXhwbG9yZXJVaUFuZFdhaXQ6IGNoYW5uZWwgbmFtZSAnJHtjaC5uYW1lfScgaXMgYWxyZWFkeSBib3VuZCB0byBhIGRpZmZlcmVudCBjb21wb25lbnQuIGAgK1xuICAgICAgICAgICAgYENoYW5uZWwgbmFtZXMgaWRlbnRpZnkgYSBzdHJlYW0sIHNvIHRoZXkgaGF2ZSB0byBiZSB1bmlxdWUgd2l0aGluIGEgc2NlbmUuYFxuICAgICAgICApXG4gICAgICB9XG4gICAgICByZXR1cm5cbiAgICB9XG4gICAgYXJtZWQuc2V0KGNoLm5hbWUsIGNoLmNvbXBvbmVudClcbiAgICBjb25zdCBuYW1lID0gY2gubmFtZVxuICAgIC8vIG9uQ2hhbmdlIGhhcyBubyB1bnN1YnNjcmliZSwgc28gb25lIGxpc3RlbmVyIHBlciBjaGFubmVsIGxpdmVzIGZvciB0aGUgZW5naW5lJ3MgbGlmZXRpbWUuXG4gICAgY2guY29tcG9uZW50Lm9uQ2hhbmdlKHJvb3QsICh2YWx1ZTogQ29ycmVsYXRlZEV2ZW50IHwgdW5kZWZpbmVkKSA9PiB7XG4gICAgICAvLyBgdW5kZWZpbmVkYCBhcnJpdmVzIG9uIERFTEVURV9FTlRJVFkuIE90aGVyd2lzZSBgdmFsdWVgIGlzIG9uZSBhcHBlbmRlZCBlbGVtZW50LFxuICAgICAgLy8gbm90IHRoZSB3aG9sZSBzZXQuXG4gICAgICBpZiAodmFsdWUpIGRlbGl2ZXIobmFtZSwgdmFsdWUpXG4gICAgfSlcbiAgfVxuXG4gIGZ1bmN0aW9uIGF0dHJpYnV0ZShzZXNzaW9uOiBTZXNzaW9uLCBuYW1lOiBzdHJpbmcsIGV2ZW50OiBDb3JyZWxhdGVkRXZlbnQpOiBBdHRyaWJ1dGlvbiB7XG4gICAgaWYgKGV2ZW50LnJlcXVlc3RJZCA9PT0gc2Vzc2lvbi5yZXF1ZXN0SWQpIHJldHVybiAneWVzJ1xuICAgIGlmIChldmVudC5yZXF1ZXN0SWQgIT09IFVOQ09SUkVMQVRFRCkgcmV0dXJuICdubydcbiAgICAvLyBPbmx5IHRoZSBsaWZlY3ljbGUgY2hhbm5lbCBjYXJyaWVzIGEgc2Vjb25kIGRpc2NyaW1pbmF0b3IsIGB1aWAsIGFuZCBpdCBpZGVudGlmaWVzIGFcbiAgICAvLyBzZXNzaW9uIG9ubHkgd2hpbGUgcGFuZWxzIGNhbm5vdCBjb2V4aXN0LiBBIHNlY29uZCBjYWxsIGZvciB0aGUgc2FtZSBwYW5lbCBpcyBhbnN3ZXJlZFxuICAgIC8vIFdBU19BTFJFQURZX09QRU4sIHNvIGF0IG1vc3Qgb25lIHNlc3Npb24gcGVyIG5vbi1jb25jdXJyZW50IHBhbmVsIGlzIGV2ZXIgbGl2ZS5cbiAgICBpZiAoc2Vzc2lvbi5jb3JyZWxhdGlvblJlcXVpcmVkIHx8IG5hbWUgIT09IGV4cGxvcmVyVWlFdmVudHMubmFtZSkgcmV0dXJuICdhbWJpZ3VvdXMnXG4gICAgcmV0dXJuIChldmVudCBhcyBQQkV4cGxvcmVyVWlFdmVudHNSZXN1bHQpLnVpID09PSBzZXNzaW9uLnVpID8gJ3llcycgOiAnbm8nXG4gIH1cblxuICBmdW5jdGlvbiBkZWxpdmVyKG5hbWU6IHN0cmluZywgZXZlbnQ6IENvcnJlbGF0ZWRFdmVudCkge1xuICAgIC8vIFNldHRsaW5nIGRlbGV0ZXMgZnJvbSBgc2Vzc2lvbnNgIG1pZC1pdGVyYXRpb24sIHdoaWNoIGEgTWFwIHRvbGVyYXRlcy4gTm90aGluZyBhZGRzLlxuICAgIGZvciAoY29uc3Qgc2Vzc2lvbiBvZiBzZXNzaW9ucy52YWx1ZXMoKSkge1xuICAgICAgaWYgKCFzZXNzaW9uLndhdGNoZWQuaGFzKG5hbWUpKSBjb250aW51ZVxuICAgICAgY29uc3QgYXR0cmlidXRpb24gPSBhdHRyaWJ1dGUoc2Vzc2lvbiwgbmFtZSwgZXZlbnQpXG4gICAgICBpZiAoYXR0cmlidXRpb24gPT09ICdubycpIGNvbnRpbnVlXG4gICAgICBpZiAoYXR0cmlidXRpb24gPT09ICdhbWJpZ3VvdXMnKSB7XG4gICAgICAgIGZhaWxTZXNzaW9uKFxuICAgICAgICAgIHNlc3Npb24sXG4gICAgICAgICAgbmV3IEVycm9yKFxuICAgICAgICAgICAgYG9wZW5FeHBsb3JlclVpQW5kV2FpdDogZ290IGEgJyR7bmFtZX0nIGV2ZW50IHdpdGggbm8gcmVxdWVzdF9pZCwgYW5kIG5vdGhpbmcgZWxzZSBpZGVudGlmaWVzIGAgK1xuICAgICAgICAgICAgICBgdGhlIGNhbGwgaXQgYmVsb25ncyB0by4gVGhpcyBleHBsb3JlciBkb2VzIG5vdCBlY2hvIE9wZW5FeHBsb3JlclVpUmVxdWVzdC5yZXF1ZXN0X2lkLmBcbiAgICAgICAgICApXG4gICAgICAgIClcbiAgICAgICAgY29udGludWVcbiAgICAgIH1cbiAgICAgIGFjY2VwdChzZXNzaW9uLCBuYW1lLCBldmVudClcbiAgICB9XG4gIH1cblxuICBmdW5jdGlvbiBhY2NlcHQoc2Vzc2lvbjogU2Vzc2lvbiwgbmFtZTogc3RyaW5nLCBldmVudDogQ29ycmVsYXRlZEV2ZW50KSB7XG4gICAgaWYgKHNlc3Npb24uY29sbGVjdC5oYXMobmFtZSkpIHNlc3Npb24uZXZlbnRzLnB1c2goeyBjaGFubmVsOiBuYW1lLCBldmVudCB9KVxuXG4gICAgLy8gVGhlIGNsb3NlIGlzIHRlcm1pbmFsIGFuZCB3aW5zIG92ZXIgYHVudGlsYCwgYmVjYXVzZSBgbWF0Y2hlZGAgd291bGQgdGVsbCB0aGUgY2FsbGVyXG4gICAgLy8gdGhhdCB0aGUgcGFuZWwgaXMgc3RpbGwgb24gc2NyZWVuLlxuICAgIGlmIChuYW1lID09PSBleHBsb3JlclVpRXZlbnRzLm5hbWUgJiYgY2FzZU9mKGV2ZW50KSA9PT0gJ2Nsb3NlZCcpIHtcbiAgICAgIHNldHRsZVNlc3Npb24oc2Vzc2lvbiwgeyAkY2FzZTogJ2Nsb3NlZCcsIGV2ZW50czogc2Vzc2lvbi5ldmVudHMgYXMgbmV2ZXJbXSB9KVxuICAgICAgcmV0dXJuXG4gICAgfVxuXG4gICAgY29uc3QgdW50aWwgPSBzZXNzaW9uLnVudGlsXG4gICAgaWYgKCF1bnRpbCB8fCB1bnRpbC5jaGFubmVsICE9PSBuYW1lKSByZXR1cm5cbiAgICBpZiAodW50aWwuJGNhc2UgPT09IHVuZGVmaW5lZCB8fCB1bnRpbC4kY2FzZSA9PT0gY2FzZU9mKGV2ZW50KSkge1xuICAgICAgc2V0dGxlU2Vzc2lvbihzZXNzaW9uLCB7ICRjYXNlOiAnbWF0Y2hlZCcsIGV2ZW50czogc2Vzc2lvbi5ldmVudHMgYXMgbmV2ZXJbXSB9KVxuICAgIH1cbiAgfVxuXG4gIGZ1bmN0aW9uIHNldHRsZVNlc3Npb24oc2Vzc2lvbjogU2Vzc2lvbiwgb3V0Y29tZTogV2FpdE91dGNvbWU8bmV2ZXJbXT4pIHtcbiAgICBpZiAoc2Vzc2lvbi5zZXR0bGVkKSByZXR1cm5cbiAgICBzZXNzaW9uLnNldHRsZWQgPSB0cnVlXG4gICAgc2Vzc2lvbnMuZGVsZXRlKHNlc3Npb24ucmVxdWVzdElkKVxuICAgIHNlc3Npb24uc2V0dGxlKG91dGNvbWUpXG4gICAgbWF5YmVSZW1vdmVUaW1lb3V0U3lzdGVtKClcbiAgfVxuXG4gIGZ1bmN0aW9uIGZhaWxTZXNzaW9uKHNlc3Npb246IFNlc3Npb24sIGVycm9yOiBFcnJvcikge1xuICAgIGlmIChzZXNzaW9uLnNldHRsZWQpIHJldHVyblxuICAgIHNlc3Npb24uc2V0dGxlZCA9IHRydWVcbiAgICBzZXNzaW9ucy5kZWxldGUoc2Vzc2lvbi5yZXF1ZXN0SWQpXG4gICAgc2Vzc2lvbi5mYWlsKGVycm9yKVxuICAgIG1heWJlUmVtb3ZlVGltZW91dFN5c3RlbSgpXG4gIH1cblxuICBmdW5jdGlvbiBoYXNUaW1lZFNlc3Npb24oKTogYm9vbGVhbiB7XG4gICAgZm9yIChjb25zdCBzZXNzaW9uIG9mIHNlc3Npb25zLnZhbHVlcygpKSB7XG4gICAgICBpZiAoc2Vzc2lvbi50aW1lb3V0TXMgIT09IHVuZGVmaW5lZCkgcmV0dXJuIHRydWVcbiAgICB9XG4gICAgcmV0dXJuIGZhbHNlXG4gIH1cblxuICBmdW5jdGlvbiBtYXliZVJlbW92ZVRpbWVvdXRTeXN0ZW0oKSB7XG4gICAgaWYgKCF0aW1lb3V0U3lzdGVtQWRkZWQgfHwgaGFzVGltZWRTZXNzaW9uKCkpIHJldHVyblxuICAgIHRpbWVvdXRTeXN0ZW1BZGRlZCA9IGZhbHNlXG4gICAgZW5naW5lSW5zdGFuY2UucmVtb3ZlU3lzdGVtKEVYUExPUkVSX1VJX1dBSVRfVElNRU9VVF9TWVNURU0pXG4gIH1cblxuICBmdW5jdGlvbiBlbnN1cmVUaW1lb3V0U3lzdGVtKCkge1xuICAgIGlmICh0aW1lb3V0U3lzdGVtQWRkZWQpIHJldHVyblxuICAgIHRpbWVvdXRTeXN0ZW1BZGRlZCA9IHRydWVcbiAgICAvLyBUaGUgc2NlbmUgcnVudGltZSBoYXMgbm8gdGltZXJzLCBzbyBlbGFwc2VkIHRpbWUgaXMgYWNjdW11bGF0ZWQgZnJvbSB0aGUgZW5naW5lJ3MgZHQuXG4gICAgZW5naW5lSW5zdGFuY2UuYWRkU3lzdGVtKFxuICAgICAgKGR0OiBudW1iZXIpID0+IHtcbiAgICAgICAgZm9yIChjb25zdCBzZXNzaW9uIG9mIHNlc3Npb25zLnZhbHVlcygpKSB7XG4gICAgICAgICAgaWYgKHNlc3Npb24udGltZW91dE1zID09PSB1bmRlZmluZWQpIGNvbnRpbnVlXG4gICAgICAgICAgc2Vzc2lvbi5lbGFwc2VkTXMgKz0gZHQgKiAxMDAwXG4gICAgICAgICAgaWYgKHNlc3Npb24uZWxhcHNlZE1zID49IHNlc3Npb24udGltZW91dE1zKSB7XG4gICAgICAgICAgICBzZXR0bGVTZXNzaW9uKHNlc3Npb24sIHsgJGNhc2U6ICd0aW1lZE91dCcsIGV2ZW50czogc2Vzc2lvbi5ldmVudHMgYXMgbmV2ZXJbXSB9KVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBtYXliZVJlbW92ZVRpbWVvdXRTeXN0ZW0oKVxuICAgICAgfSxcbiAgICAgIFRJTUVPVVRfU1lTVEVNX1BSSU9SSVRZLFxuICAgICAgRVhQTE9SRVJfVUlfV0FJVF9USU1FT1VUX1NZU1RFTVxuICAgIClcbiAgfVxuXG4gIGFzeW5jIGZ1bmN0aW9uIG9wZW5FeHBsb3JlclVpQW5kV2FpdChcbiAgICByZXF1ZXN0OiBPcGVuRXhwbG9yZXJVaVJlcXVlc3QgfCBFeGNsdWRlPEV4cGxvcmVyVWksIEV4cGxvcmVyVWkuRVVfSVRFTV9QVVJDSEFTRT4sXG4gICAgb3B0aW9ucz86IFdhaXRPcHRpb25zPHJlYWRvbmx5IEFueUNoYW5uZWxbXT5cbiAgKTogUHJvbWlzZTxXYWl0T3V0Y29tZTxuZXZlcltdPj4ge1xuICAgIGNvbnN0IHsgdWksIGl0ZW1QdXJjaGFzZSB9ID0gdHlwZW9mIHJlcXVlc3QgPT09ICdudW1iZXInID8geyB1aTogcmVxdWVzdCwgaXRlbVB1cmNoYXNlOiB1bmRlZmluZWQgfSA6IHJlcXVlc3RcbiAgICBjb25zdCByZXF1ZXN0SWQgPSBuZXh0UmVxdWVzdElkKytcblxuICAgIGNvbnN0IGNvbGxlY3QgPSBvcHRpb25zPy5jb2xsZWN0ID8/IFtdXG4gICAgY29uc3QgY29sbGVjdE5hbWVzID0gbmV3IFNldDxzdHJpbmc+KClcbiAgICBmb3IgKGNvbnN0IGNoIG9mIGNvbGxlY3QpIGNvbGxlY3ROYW1lcy5hZGQoY2gubmFtZSlcblxuICAgIGNvbnN0IHN0b3AgPSBvcHRpb25zPy51bnRpbCA/IG5vcm1hbGl6ZVN0b3Aob3B0aW9ucy51bnRpbCkgOiB1bmRlZmluZWRcbiAgICBjb25zdCB3YXRjaGVkID0gbmV3IFNldDxzdHJpbmc+KGNvbGxlY3ROYW1lcylcbiAgICB3YXRjaGVkLmFkZChleHBsb3JlclVpRXZlbnRzLm5hbWUpXG4gICAgaWYgKHN0b3ApIHdhdGNoZWQuYWRkKHN0b3AuY2hhbm5lbC5uYW1lKVxuXG4gICAgLy8gQXJtZWQgYmVmb3JlIHRoZSBSUEMsIGJlY2F1c2UgZXZlbnRzIGNhbiBsYW5kIHdoaWxlIHRoZSBSUEMgaXMgaW4gZmxpZ2h0LiBBIGxpc3RlbmVyXG4gICAgLy8gdGhhdCBpcyBhbHJlYWR5IHVwIGlzIHdoYXQgbWFrZXMgcmVwbGF5aW5nIHRoZSBhY2N1bXVsYXRlZCBzZXQgdW5uZWNlc3NhcnkuXG4gICAgYXJtKGV4cGxvcmVyVWlFdmVudHMpXG4gICAgZm9yIChjb25zdCBjaCBvZiBjb2xsZWN0KSBhcm0oY2gpXG4gICAgaWYgKHN0b3ApIGFybShzdG9wLmNoYW5uZWwpXG5cbiAgICBsZXQgc2V0dGxlITogKG91dGNvbWU6IFdhaXRPdXRjb21lPG5ldmVyW10+KSA9PiB2b2lkXG4gICAgbGV0IGZhaWwhOiAoZXJyb3I6IEVycm9yKSA9PiB2b2lkXG4gICAgY29uc3Qgb3V0Y29tZSA9IG5ldyBQcm9taXNlPFdhaXRPdXRjb21lPG5ldmVyW10+PigocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICBzZXR0bGUgPSByZXNvbHZlXG4gICAgICBmYWlsID0gcmVqZWN0XG4gICAgfSlcblxuICAgIGNvbnN0IHNlc3Npb246IFNlc3Npb24gPSB7XG4gICAgICByZXF1ZXN0SWQsXG4gICAgICB1aSxcbiAgICAgIGNvcnJlbGF0aW9uUmVxdWlyZWQ6IENPTkNVUlJFTlRfUEFORUxTLmluY2x1ZGVzKHVpKSxcbiAgICAgIGNvbGxlY3Q6IGNvbGxlY3ROYW1lcyxcbiAgICAgIHdhdGNoZWQsXG4gICAgICB1bnRpbDogc3RvcCA/IHsgY2hhbm5lbDogc3RvcC5jaGFubmVsLm5hbWUsICRjYXNlOiBzdG9wLiRjYXNlIH0gOiB1bmRlZmluZWQsXG4gICAgICBldmVudHM6IFtdLFxuICAgICAgdGltZW91dE1zOiBvcHRpb25zPy50aW1lb3V0TXMsXG4gICAgICBlbGFwc2VkTXM6IDAsXG4gICAgICBzZXR0bGVkOiBmYWxzZSxcbiAgICAgIHNldHRsZSxcbiAgICAgIGZhaWxcbiAgICB9XG4gICAgc2Vzc2lvbnMuc2V0KHJlcXVlc3RJZCwgc2Vzc2lvbilcbiAgICBpZiAoc2Vzc2lvbi50aW1lb3V0TXMgIT09IHVuZGVmaW5lZCkgZW5zdXJlVGltZW91dFN5c3RlbSgpXG5cbiAgICB0cnkge1xuICAgICAgY29uc3QgeyBvcGVuUmVzdWx0IH0gPSBhd2FpdCBvcGVuRXhwbG9yZXJVaUZuKHsgdWksIHJlcXVlc3RJZCwgaXRlbVB1cmNoYXNlIH0pXG4gICAgICAvLyBUaGlzIGNhbGwgb3BlbmVkIG5vdGhpbmcsIHNvIG5vIGV2ZW50IGNhcnJ5aW5nIHRoaXMgcmVxdWVzdCBpZCBpcyBjb21pbmcuXG4gICAgICBpZiAob3BlblJlc3VsdCAhPT0gT3BlbkV4cGxvcmVyVWlSZXN1bHQuT1BFTkVEKSB7XG4gICAgICAgIHNldHRsZVNlc3Npb24oc2Vzc2lvbiwgeyAkY2FzZTogJ25vdE9wZW5lZCcsIG9wZW5SZXN1bHQgfSlcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgLy8gUm91dGVkIHRocm91Z2ggdGhlIHNlc3Npb24gcmF0aGVyIHRoYW4gcmV0aHJvd24sIHNvIHRoYXQgYG91dGNvbWVgIGlzIG5ldmVyIGxlZnRcbiAgICAgIC8vIHBlbmRpbmcgYW5kIHVub2JzZXJ2ZWQuXG4gICAgICBmYWlsU2Vzc2lvbihzZXNzaW9uLCBlcnJvciBhcyBFcnJvcilcbiAgICB9XG5cbiAgICByZXR1cm4gb3V0Y29tZVxuICB9XG5cbiAgLy8gVGhlIGltcGxlbWVudGF0aW9uIHRha2VzIGJvdGggYXJndW1lbnQgZm9ybXMgYW5kIGlzIGJsaW5kIHRvIGBjb2xsZWN0YC4gVGhlIGNhc3QgaXMgd2hhdFxuICAvLyBnaXZlcyBjYWxsZXJzIHRoZSB0d28gb3ZlcmxvYWRzIHRoYXQgcmVsYXRlIHRoZW0uXG4gIHJldHVybiB7IG9wZW5FeHBsb3JlclVpQW5kV2FpdDogb3BlbkV4cGxvcmVyVWlBbmRXYWl0IGFzIE9wZW5FeHBsb3JlclVpQW5kV2FpdCB9XG59XG5cbmNvbnN0IGhlbHBlciA9IC8qIEBfX1BVUkVfXyAqLyBjcmVhdGUoeyBlbmdpbmUsIG9wZW5FeHBsb3JlclVpLCBleHBsb3JlclVpRXZlbnRzOiBFeHBsb3JlclVpRXZlbnRzIH0pXG5cbi8qKlxuICogT3BlbnMgYW4gZXhwbG9yZXIgcGFuZWwgYW5kIHdhaXRzIGZvciB0aGUgc2Vzc2lvbiBpdCBzdGFydGVkLiBUaGUgd2FpdCBlbmRzIHdoZW4gdGhlIHBhbmVsXG4gKiBjbG9zZXMuIFNlZSB7QGxpbmsgV2FpdE9wdGlvbnN9IHRvIGNvbGxlY3QgZXZlbnRzLCB0byBzdG9wIGVhcmxpZXIgb3IgdG8gYm91bmQgdGhlIHdhaXQuXG4gKlxuICogRXZlcnkgbGlmZWN5Y2xlIG91dGNvbWUgcmVzb2x2ZXMsIHNlZSB7QGxpbmsgV2FpdE91dGNvbWV9LiBUaGUgcHJvbWlzZSByZWplY3RzIG9ubHkgd2hlbiBhblxuICogZXZlbnQgY2Fubm90IGJlIGF0dHJpYnV0ZWQgdG8gYSBjYWxsIGF0IGFsbDogYW4gZXhwbG9yZXIgdG9vIG9sZCB0byBlY2hvIGByZXF1ZXN0X2lkYFxuICogcGFpcmVkIHdpdGggYSBwYW5lbCB0aGF0IGNhbiBjb2V4aXN0IHdpdGggYW5vdGhlciBvbmUuXG4gKlxuICogQHB1YmxpY1xuICovXG5leHBvcnQgY29uc3Qgb3BlbkV4cGxvcmVyVWlBbmRXYWl0OiBPcGVuRXhwbG9yZXJVaUFuZFdhaXQgPSBoZWxwZXIub3BlbkV4cGxvcmVyVWlBbmRXYWl0XG4iXX0=