@dcl/sdk 7.20.4 → 7.20.5-22638270380.commit-3f48d5e

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/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/network/binary-message-bus.d.ts +6 -3
  6. package/network/binary-message-bus.js +9 -5
  7. package/network/chunking.d.ts +5 -0
  8. package/network/chunking.js +38 -0
  9. package/network/events/implementation.d.ts +93 -0
  10. package/network/events/implementation.js +221 -0
  11. package/network/events/index.d.ts +42 -0
  12. package/network/events/index.js +43 -0
  13. package/network/events/protocol.d.ts +27 -0
  14. package/network/events/protocol.js +66 -0
  15. package/network/events/registry.d.ts +8 -0
  16. package/network/events/registry.js +3 -0
  17. package/network/index.d.ts +8 -2
  18. package/network/index.js +16 -3
  19. package/network/message-bus-sync.d.ts +14 -1
  20. package/network/message-bus-sync.js +152 -103
  21. package/network/server/index.d.ts +14 -0
  22. package/network/server/index.js +219 -0
  23. package/network/server/utils.d.ts +18 -0
  24. package/network/server/utils.js +135 -0
  25. package/network/state.js +3 -5
  26. package/package.json +6 -6
  27. package/server/env-var.d.ts +15 -0
  28. package/server/env-var.js +31 -0
  29. package/server/index.d.ts +2 -0
  30. package/server/index.js +3 -0
  31. package/server/storage/constants.d.ts +23 -0
  32. package/server/storage/constants.js +2 -0
  33. package/server/storage/index.d.ts +22 -0
  34. package/server/storage/index.js +29 -0
  35. package/server/storage/player.d.ts +43 -0
  36. package/server/storage/player.js +92 -0
  37. package/server/storage/scene.d.ts +38 -0
  38. package/server/storage/scene.js +90 -0
  39. package/server/storage-url.d.ts +10 -0
  40. package/server/storage-url.js +29 -0
  41. package/server/utils.d.ts +35 -0
  42. package/server/utils.js +56 -0
  43. package/src/atom.ts +98 -0
  44. package/src/future.ts +38 -0
  45. package/src/network/binary-message-bus.ts +9 -4
  46. package/src/network/chunking.ts +45 -0
  47. package/src/network/events/implementation.ts +271 -0
  48. package/src/network/events/index.ts +48 -0
  49. package/src/network/events/protocol.ts +94 -0
  50. package/src/network/events/registry.ts +18 -0
  51. package/src/network/index.ts +40 -3
  52. package/src/network/message-bus-sync.ts +166 -110
  53. package/src/network/server/index.ts +301 -0
  54. package/src/network/server/utils.ts +189 -0
  55. package/src/network/state.ts +3 -4
  56. package/src/server/env-var.ts +36 -0
  57. package/src/server/index.ts +2 -0
  58. package/src/server/storage/constants.ts +22 -0
  59. package/src/server/storage/index.ts +44 -0
  60. package/src/server/storage/player.ts +156 -0
  61. package/src/server/storage/scene.ts +149 -0
  62. package/src/server/storage-url.ts +34 -0
  63. package/src/server/utils.ts +73 -0
@@ -1,17 +1,38 @@
1
- import { RealmInfo, PlayerIdentityData } from '@dcl/ecs';
1
+ import { RealmInfo } from '@dcl/ecs';
2
2
  import { syncFilter } from './filter';
3
3
  import { engineToCrdt } from './state';
4
- import { BinaryMessageBus, CommsMessage, decodeString, encodeString } from './binary-message-bus';
4
+ import { BinaryMessageBus, CommsMessage } from './binary-message-bus';
5
5
  import { fetchProfile } from './utils';
6
6
  import { entityUtils } from './entities';
7
+ import { createServerValidator } from './server';
7
8
  import { definePlayerHelper } from '../players';
8
9
  import { serializeCrdtMessages } from '../internal/transports/logger';
10
+ import { Atom } from '../atom';
11
+ import { setGlobalRoom, Room } from './events/implementation';
9
12
  // user that we asked for the inital crdt state
10
- export function addSyncTransport(engine, sendBinary, getUserData) {
11
- const DEBUG_NETWORK_MESSAGES = () => globalThis.DEBUG_NETWORK_MESSAGES ?? false;
13
+ export const AUTH_SERVER_PEER_ID = 'authoritative-server';
14
+ export const DEBUG_NETWORK_MESSAGES = () => globalThis.DEBUG_NETWORK_MESSAGES ?? false;
15
+ // Test environment detection without 'as any'
16
+ const isTestEnvironment = () => {
17
+ try {
18
+ if (typeof globalThis === 'undefined')
19
+ return false;
20
+ const globalWithProcess = globalThis;
21
+ return globalWithProcess.process?.env?.NODE_ENV === 'test';
22
+ }
23
+ catch {
24
+ return false;
25
+ }
26
+ };
27
+ export function addSyncTransport(engine, sendBinary, getUserData, isServerFn, name) {
12
28
  // Profile Info
13
29
  const myProfile = {};
14
30
  fetchProfile(myProfile, getUserData);
31
+ const isServerAtom = Atom();
32
+ const isRoomReadyAtom = Atom(false);
33
+ void isServerFn({}).then(($) => {
34
+ return isServerAtom.swap(!!$.isServer);
35
+ });
15
36
  // Entity utils
16
37
  const entityDefinitions = entityUtils(engine, myProfile);
17
38
  // List of MessageBuss messsages to be sent on every frame to comms
@@ -26,95 +47,162 @@ export function addSyncTransport(engine, sendBinary, getUserData) {
26
47
  }
27
48
  const players = definePlayerHelper(engine);
28
49
  let stateIsSyncronized = false;
29
- let transportInitialzed = false;
50
+ /**
51
+ * We need to wait till 2 ticks that is when the engine is ready to send new messages.
52
+ * The first tick is for the client engine processing the CRDT messages,
53
+ * and the second one are the messages created by the main() function.
54
+ * So to avoid sending those messages, that all the clients have, through the network we put this validation here.
55
+ */
56
+ let tick = 0;
57
+ const TRANSPORT_INITIALIZED_NUMBER = isTestEnvironment() ? 0 : 2;
30
58
  // Add Sync Transport
31
59
  const transport = {
32
60
  filter: syncFilter(engine),
33
61
  send: async (messages) => {
34
- for (const message of [messages].flat()) {
35
- if (message.byteLength && transportInitialzed) {
62
+ if (tick <= TRANSPORT_INITIALIZED_NUMBER)
63
+ tick++;
64
+ for (const message of tick > TRANSPORT_INITIALIZED_NUMBER ? [messages].flat() : []) {
65
+ if (message.byteLength) {
36
66
  DEBUG_NETWORK_MESSAGES() &&
37
67
  console.log(...Array.from(serializeCrdtMessages('[NetworkMessage sent]:', message, engine)));
38
- binaryMessageBus.emit(CommsMessage.CRDT, message);
68
+ // Convert regular messages to network messages for broadcasting with chunking
69
+ for (const chunk of serverValidator.convertRegularToNetworkMessage(message)) {
70
+ binaryMessageBus.emit(CommsMessage.CRDT, chunk);
71
+ }
39
72
  }
40
73
  }
41
74
  const peerMessages = getMessagesToSend();
42
- let totalSize = 0;
43
- for (const message of peerMessages) {
44
- for (const data of message.data) {
45
- totalSize += data.byteLength;
46
- }
47
- }
48
- if (totalSize) {
49
- DEBUG_NETWORK_MESSAGES() && console.log('Sending network messages: ', totalSize / 1024, 'KB');
50
- }
51
75
  const response = await sendBinary({ data: [], peerData: peerMessages });
52
76
  binaryMessageBus.__processMessages(response.data);
53
- transportInitialzed = true;
54
77
  },
55
- type: 'network'
78
+ type: name
56
79
  };
80
+ // Server validation setup
81
+ const serverValidator = createServerValidator({
82
+ engine,
83
+ binaryMessageBus
84
+ });
85
+ // Initialize Event Bus with registered schemas
86
+ const eventBus = new Room(engine, binaryMessageBus, isServerAtom, isRoomReadyAtom);
87
+ // Set global eventBus instance
88
+ setGlobalRoom(eventBus);
57
89
  engine.addTransport(transport);
58
90
  // End add sync transport
59
91
  // Receive & Process CRDT_STATE
60
- binaryMessageBus.on(CommsMessage.RES_CRDT_STATE, (value) => {
61
- const { sender, data } = decodeCRDTState(value);
62
- if (sender !== myProfile.userId)
92
+ binaryMessageBus.on(CommsMessage.REQ_CRDT_STATE, async (data, sender) => {
93
+ DEBUG_NETWORK_MESSAGES() && console.log('[REQ_CRDT_STATE]', sender, Date.now());
94
+ for (const chunk of engineToCrdt(engine)) {
95
+ DEBUG_NETWORK_MESSAGES() && console.log('[Emiting:]', sender, Date.now());
96
+ binaryMessageBus.emit(CommsMessage.RES_CRDT_STATE, chunk, [sender]);
97
+ }
98
+ });
99
+ binaryMessageBus.on(CommsMessage.RES_CRDT_STATE, async (data, sender) => {
100
+ requestingState = false;
101
+ elapsedTimeSinceRequest = 0;
102
+ if (isServerAtom.getOrNull() || sender !== AUTH_SERVER_PEER_ID)
63
103
  return;
64
104
  DEBUG_NETWORK_MESSAGES() && console.log('[Processing CRDT State]', data.byteLength / 1024, 'KB');
65
- transport.onmessage(data);
105
+ transport.onmessage(serverValidator.processClientMessages(data, sender));
66
106
  stateIsSyncronized = true;
67
- });
68
- // Answer to REQ_CRDT_STATE
69
- binaryMessageBus.on(CommsMessage.REQ_CRDT_STATE, async (_, userId) => {
70
- DEBUG_NETWORK_MESSAGES() && console.log(`Sending CRDT State to: ${userId}`);
71
- for (const chunk of engineToCrdt(engine)) {
72
- binaryMessageBus.emit(CommsMessage.RES_CRDT_STATE, encodeCRDTState(userId, chunk), [userId]);
107
+ // IMPORTANT: Only mark room as ready AFTER state is synchronized
108
+ // This ensures comms is truly connected and working
109
+ const realmInfo = RealmInfo.getOrNull(engine.RootEntity);
110
+ if (realmInfo) {
111
+ DEBUG_NETWORK_MESSAGES() && console.log('[isRoomReady] Marking room as ready after state sync');
112
+ isRoomReadyAtom.swap(true);
73
113
  }
74
114
  });
75
- // Process CRDT messages here
76
- binaryMessageBus.on(CommsMessage.CRDT, (value) => {
115
+ // received message from the network
116
+ binaryMessageBus.on(CommsMessage.CRDT, (value, sender) => {
117
+ const isServer = isServerAtom.getOrNull();
77
118
  DEBUG_NETWORK_MESSAGES() &&
78
- console.log(Array.from(serializeCrdtMessages('[NetworkMessage received]:', value, engine)));
79
- transport.onmessage(value);
119
+ console.log(transport.type, ...Array.from(serializeCrdtMessages('[NetworkMessage received]:', value, engine)), isServer);
120
+ if (isServer) {
121
+ transport.onmessage(serverValidator.processServerMessages(value, sender));
122
+ }
123
+ else if (sender === AUTH_SERVER_PEER_ID) {
124
+ // Process network messages from server and convert to regular messages
125
+ transport.onmessage(serverValidator.processClientMessages(value, sender));
126
+ }
80
127
  });
81
- async function requestState(retryCount = 1) {
82
- let players = Array.from(engine.getEntitiesWith(PlayerIdentityData));
83
- DEBUG_NETWORK_MESSAGES() && console.log(`Requesting state. Players connected: ${players.length - 1}`);
84
- if (!RealmInfo.getOrNull(engine.RootEntity)?.isConnectedSceneRoom) {
85
- DEBUG_NETWORK_MESSAGES() && console.log(`Aborting Requesting state?. Disconnected`);
128
+ // received authoritative message from server - force apply to fix invalid local state
129
+ binaryMessageBus.on(CommsMessage.CRDT_AUTHORITATIVE, (value, sender) => {
130
+ // Only accept authoritative messages from authoritative server
131
+ if (sender !== AUTH_SERVER_PEER_ID)
86
132
  return;
133
+ // DEBUG_NETWORK_MESSAGES() &&
134
+ console.log('[AUTHORITATIVE] Received authoritative message from server:', value.byteLength, 'bytes');
135
+ // Process authoritative messages by forcing them through normal CRDT processing
136
+ // but with a timestamp that's guaranteed to be accepted
137
+ const authoritativeBuffer = serverValidator.processClientMessages(value, sender, true);
138
+ if (authoritativeBuffer.byteLength > 0) {
139
+ // Apply authoritative message through normal transport, but the server's messages
140
+ // should be processed as authoritative with special timestamp handling
141
+ transport.onmessage(authoritativeBuffer);
142
+ DEBUG_NETWORK_MESSAGES() && console.log('[AUTHORITATIVE] Applied server authoritative message to local state');
87
143
  }
88
- binaryMessageBus.emit(CommsMessage.REQ_CRDT_STATE, new Uint8Array());
89
- // Wait ~5s for the response.
90
- await sleep(5000);
91
- players = Array.from(engine.getEntitiesWith(PlayerIdentityData));
92
- if (!stateIsSyncronized) {
93
- if (players.length > 1 && retryCount <= 2) {
94
- DEBUG_NETWORK_MESSAGES() &&
95
- console.log(`Requesting state again ${retryCount} (no response). Players connected: ${players.length - 1}`);
96
- void requestState(retryCount + 1);
97
- }
98
- else {
99
- DEBUG_NETWORK_MESSAGES() && console.log('No active players. State syncronized');
100
- stateIsSyncronized = true;
101
- }
102
- }
103
- }
144
+ });
104
145
  players.onEnterScene((player) => {
105
146
  DEBUG_NETWORK_MESSAGES() && console.log('[onEnterScene]', player.userId);
147
+ if (!isServerAtom.getOrNull() && myProfile.userId === player.userId) {
148
+ requestState();
149
+ }
106
150
  });
107
151
  // Asks for the REQ_CRDT_STATE when its connected to comms
108
152
  RealmInfo.onChange(engine.RootEntity, (value) => {
153
+ const isServer = isServerAtom.getOrNull();
109
154
  if (!value?.isConnectedSceneRoom) {
110
- DEBUG_NETWORK_MESSAGES() && console.log('Disconnected from comms');
111
- stateIsSyncronized = false;
155
+ // Only react when actually transitioning from ready to not ready
156
+ if (isRoomReadyAtom.getOrNull() === true) {
157
+ DEBUG_NETWORK_MESSAGES() && console.log('Disconnected from comms');
158
+ isRoomReadyAtom.swap(false);
159
+ if (!isServer) {
160
+ stateIsSyncronized = false;
161
+ }
162
+ }
112
163
  }
113
164
  if (value?.isConnectedSceneRoom) {
114
- DEBUG_NETWORK_MESSAGES() && console.log('Connected to comms');
165
+ requestState();
166
+ // For servers, mark as ready immediately when connected
167
+ // (servers don't need to sync state from anyone)
168
+ if (isServer && isRoomReadyAtom.getOrNull() === false) {
169
+ DEBUG_NETWORK_MESSAGES() && console.log('[isRoomReady] Server marking room as ready');
170
+ isRoomReadyAtom.swap(true);
171
+ }
172
+ // For clients, room will be marked ready after receiving CRDT state (above)
173
+ }
174
+ });
175
+ let requestingState = false;
176
+ let elapsedTimeSinceRequest = 0;
177
+ const STATE_REQUEST_RETRY_INTERVAL = 2.0; // seconds
178
+ /**
179
+ * Why we have to request the state if we have a server that can send us the state when we joined?
180
+ * The thing is that when the server detects a new JOIN_PARTICIPANT on livekit room, it sends automatically the state to that peer.
181
+ * But in unity, it takes more time, so that message is not being delivered to the client.
182
+ * So instead, when we are finally connected to the room, we request the state, and then the server answers with the state :)
183
+ *
184
+ * If no response is received within 2 seconds, the request is automatically retried.
185
+ */
186
+ function requestState() {
187
+ if (isServerAtom.getOrNull())
188
+ return;
189
+ if (RealmInfo.getOrNull(engine.RootEntity)?.isConnectedSceneRoom && !requestingState) {
190
+ requestingState = true;
191
+ elapsedTimeSinceRequest = 0;
192
+ DEBUG_NETWORK_MESSAGES() && console.log('Requesting state...');
193
+ binaryMessageBus.emit(CommsMessage.REQ_CRDT_STATE, new Uint8Array());
115
194
  }
116
- if (value?.isConnectedSceneRoom && !stateIsSyncronized) {
117
- void requestState();
195
+ }
196
+ // System to retry state request if no response is received within the retry interval
197
+ engine.addSystem((dt) => {
198
+ if (requestingState && !stateIsSyncronized) {
199
+ elapsedTimeSinceRequest += dt;
200
+ if (elapsedTimeSinceRequest >= STATE_REQUEST_RETRY_INTERVAL) {
201
+ DEBUG_NETWORK_MESSAGES() && console.log('State request timed out, retrying...');
202
+ elapsedTimeSinceRequest = 0;
203
+ requestingState = false;
204
+ requestState();
205
+ }
118
206
  }
119
207
  });
120
208
  players.onLeaveScene((userId) => {
@@ -123,52 +211,13 @@ export function addSyncTransport(engine, sendBinary, getUserData) {
123
211
  function isStateSyncronized() {
124
212
  return stateIsSyncronized;
125
213
  }
126
- function sleep(ms) {
127
- return new Promise((resolve) => {
128
- let timer = 0;
129
- function sleepSystem(dt) {
130
- timer += dt;
131
- if (timer * 1000 >= ms) {
132
- engine.removeSystem(sleepSystem);
133
- resolve();
134
- }
135
- }
136
- engine.addSystem(sleepSystem);
137
- });
138
- }
139
214
  return {
140
215
  ...entityDefinitions,
141
216
  myProfile,
142
- isStateSyncronized
217
+ isStateSyncronized,
218
+ binaryMessageBus,
219
+ eventBus,
220
+ isRoomReadyAtom
143
221
  };
144
222
  }
145
- /**
146
- * Messages Protocol Encoding
147
- *
148
- * CRDT: Plain Uint8Array
149
- *
150
- * CRDT_STATE_RES { sender: string, data: Uint8Array}
151
- */
152
- function decodeCRDTState(data) {
153
- let offset = 0;
154
- const r = new Uint8Array(data);
155
- const view = new DataView(r.buffer);
156
- const senderLength = view.getUint8(offset);
157
- offset += 1;
158
- const sender = decodeString(data.subarray(1, senderLength + 1));
159
- offset += senderLength;
160
- const state = r.subarray(offset);
161
- return { sender, data: state };
162
- }
163
- function encodeCRDTState(address, data) {
164
- // address to uint8array
165
- const addressBuffer = encodeString(address);
166
- const addressOffset = 1;
167
- const messageLength = addressOffset + addressBuffer.byteLength + data.byteLength;
168
- const serializedMessage = new Uint8Array(messageLength);
169
- serializedMessage.set(new Uint8Array([addressBuffer.byteLength]), 0);
170
- serializedMessage.set(addressBuffer, 1);
171
- serializedMessage.set(data, addressBuffer.byteLength + 1);
172
- return serializedMessage;
173
- }
174
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWVzc2FnZS1idXMtc3luYy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9uZXR3b3JrL21lc3NhZ2UtYnVzLXN5bmMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFzQixTQUFTLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxVQUFVLENBQUE7QUFHNUUsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLFVBQVUsQ0FBQTtBQUNyQyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sU0FBUyxDQUFBO0FBQ3RDLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxZQUFZLEVBQUUsWUFBWSxFQUFFLFlBQVksRUFBRSxNQUFNLHNCQUFzQixDQUFBO0FBQ2pHLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxTQUFTLENBQUE7QUFDdEMsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLFlBQVksQ0FBQTtBQUV4QyxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxZQUFZLENBQUE7QUFDL0MsT0FBTyxFQUFFLHFCQUFxQixFQUFFLE1BQU0sK0JBQStCLENBQUE7QUFHckUsK0NBQStDO0FBQy9DLE1BQU0sVUFBVSxnQkFBZ0IsQ0FDOUIsTUFBZSxFQUNmLFVBQW1FLEVBQ25FLFdBQXdFO0lBRXhFLE1BQU0sc0JBQXNCLEdBQUcsR0FBRyxFQUFFLENBQUUsVUFBa0IsQ0FBQyxzQkFBc0IsSUFBSSxLQUFLLENBQUE7SUFDeEYsZUFBZTtJQUNmLE1BQU0sU0FBUyxHQUFhLEVBQWMsQ0FBQTtJQUMxQyxZQUFZLENBQUMsU0FBVSxFQUFFLFdBQVcsQ0FBQyxDQUFBO0lBRXJDLGVBQWU7SUFDZixNQUFNLGlCQUFpQixHQUFHLFdBQVcsQ0FBQyxNQUFNLEVBQUUsU0FBUyxDQUFDLENBQUE7SUFFeEQsbUVBQW1FO0lBQ25FLE1BQU0sK0JBQStCLEdBQWdELEVBQUUsQ0FBQTtJQUV2RixNQUFNLGdCQUFnQixHQUFHLGdCQUFnQixDQUFDLENBQUMsSUFBSSxFQUFFLE9B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LGFBQWEsQ0FBQyxVQUFVLEdBQUcsQ0FBQyxDQUFDLENBQUE7SUFDekQsT0FBTyxpQkFBaUIsQ0FBQTtBQUMxQixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSUVuZ2luZSwgVHJhbnNwb3J0LCBSZWFsbUluZm8sIFBsYXllcklkZW50aXR5RGF0YSB9IGZyb20gJ0BkY2wvZWNzJ1xuaW1wb3J0IHsgdHlwZSBTZW5kQmluYXJ5UmVxdWVzdCwgdHlwZSBTZW5kQmluYXJ5UmVzcG9uc2UgfSBmcm9tICd+c3lzdGVtL0NvbW11bmljYXRpb25zQ29udHJvbGxlcidcblxuaW1wb3J0IHsgc3luY0ZpbHRlciB9IGZyb20gJy4vZmlsdGVyJ1xuaW1wb3J0IHsgZW5naW5lVG9DcmR0IH0gZnJvbSAnLi9zdGF0ZSdcbmltcG9ydCB7IEJpbmFyeU1lc3NhZ2VCdXMsIENvbW1zTWVzc2FnZSwgZGVjb2RlU3RyaW5nLCBlbmNvZGVTdHJpbmcgfSBmcm9tICcuL2JpbmFyeS1tZXNzYWdlLWJ1cydcbmltcG9ydCB7IGZldGNoUHJvZmlsZSB9IGZyb20gJy4vdXRpbHMnXG5pbXBvcnQgeyBlbnRpdHlVdGlscyB9IGZyb20gJy4vZW50aXRpZXMnXG5pbXBvcnQgeyBHZXRVc2VyRGF0YVJlcXVlc3QsIEdldFVzZXJEYXRhUmVzcG9uc2UgfSBmcm9tICd+c3lzdGVtL1VzZXJJZGVudGl0eSdcbmltcG9ydCB7IGRlZmluZVBsYXllckhlbHBlciB9IGZyb20gJy4uL3BsYXllcnMnXG5pbXBvcnQgeyBzZXJpYWxpemVDcmR0TWVzc2FnZXMgfSBmcm9tICcuLi9pbnRlcm5hbC90cmFuc3BvcnRzL2xvZ2dlcidcblxuZXhwb3J0IHR5cGUgSVByb2ZpbGUgPSB7IG5ldHdvcmtJZDogbnVtYmVyOyB1c2VySWQ6IHN0cmluZyB9XG4vLyB1c2VyIHRoYXQgd2UgYXNrZWQgZm9yIHRoZSBpbml0YWwgY3JkdCBzdGF0ZVxuZXhwb3J0IGZ1bmN0aW9uIGFkZFN5bmNUcmFuc3BvcnQoXG4gIGVuZ2luZTogSUVuZ2luZSxcbiAgc2VuZEJpbmFyeTogKG1zZzogU2VuZEJpbmFyeVJlcXVlc3QpID0+IFByb21pc2U8U2VuZEJpbmFyeVJlc3BvbnNlPixcbiAgZ2V0VXNlckRhdGE6ICh2YWx1ZTogR2V0VXNlckRhdGFSZXF1ZXN0KSA9PiBQcm9taXNlPEdldFVzZXJEYXRhUmVzcG9uc2U+XG4pIHtcbiAgY29uc3QgREVCVUdfTkVUV09SS19NRVNTQUdFUyA9ICgpID0+IChnbG9iYWxUaGlzIGFzIGFueSkuREVCVUdfTkVUV09SS19NRVNTQUdFUyA/PyBmYWxzZVxuICAvLyBQcm9maWxlIEluZm9cbiAgY29uc3QgbXlQcm9maWxlOiBJUHJvZmlsZSA9IHt9IGFzIElQcm9maWxlXG4gIGZldGNoUHJvZmlsZShteVByb2ZpbGUhLCBnZXRVc2VyRGF0YSlcblxuICAvLyBFbnRpdHkgdXRpbHNcbiAgY29uc3QgZW50aXR5RGVmaW5pdGlvbnMgPSBlbnRpdHlVdGlscyhlbmdpbmUsIG15UHJvZmlsZSlcblxuICAvLyBMaXN0IG9mIE1lc3NhZ2VCdXNzIG1lc3NzYWdlcyB0byBiZSBzZW50IG9uIGV2ZXJ5IGZyYW1lIHRvIGNvbW1zXG4gIGNvbnN0IHBlbmRpbmdNZXNzYWdlQnVzTWVzc2FnZXNUb1NlbmQ6IHsgZGF0YTogVWludDhBcnJheVtdOyBhZGRyZXNzOiBzdHJpbmdbXSB9W10gPSBbXVxuXG4gIGNvbnN0IGJpbmFyeU1lc3NhZ2VCdXMgPSBCaW5hcnlNZXNzYWdlQnVzKChkYXRhLCBhZGRyZXNzKSA9PiB7XG4gICAgcGVuZGluZ01lc3NhZ2VCdXNNZXNzYWdlc1RvU2VuZC5wdXNoKHsgZGF0YTogW2RhdGFdLCBhZGRyZXNzOiBhZGRyZXNzID8/IFtdIH0pXG4gIH0pXG5cbiAgZnVuY3Rpb24gZ2V0TWVzc2FnZXNUb1NlbmQoKTogdHlwZW9mIHBlbmRpbmdNZXNzYWdlQnVzTWVzc2FnZXNUb1NlbmQge1xuICAgIGNvbnN0IG1lc3NhZ2VzID0gWy4uLnBlbmRpbmdNZXNzYWdlQnVzTWVzc2FnZXNUb1NlbmRdXG4gICAgcGVuZGluZ01lc3NhZ2VCdXNNZXNzYWdlc1RvU2VuZC5sZW5ndGggPSAwXG4gICAgcmV0dXJuIG1lc3NhZ2VzXG4gIH1cbiAgY29uc3QgcGxheWVycyA9IGRlZmluZVBsYXllckhlbHBlcihlbmdpbmUpXG5cbiAgbGV0IHN0YXRlSXNTeW5jcm9uaXplZCA9IGZhbHNlXG4gIGxldCB0cmFuc3BvcnRJbml0aWFsemVkID0gZmFsc2VcblxuICAvLyBBZGQgU3luYyBUcmFuc3BvcnRcbiAgY29uc3QgdHJhbnNwb3J0OiBUcmFuc3BvcnQgPSB7XG4gICAgZmlsdGVyOiBzeW5jRmlsdGVyKGVuZ2luZSksXG4gICAgc2VuZDogYXN5bmMgKG1lc3NhZ2VzKSA9PiB7XG4gICAgICBmb3IgKGNvbnN0IG1lc3NhZ2Ugb2YgW21lc3NhZ2VzXS5mbGF0KCkpIHtcbiAgICAgICAgaWYgKG1lc3NhZ2UuYnl0ZUxlbmd0aCAmJiB0cmFuc3BvcnRJbml0aWFsemVkKSB7XG4gICAgICAgICAgREVCVUdfTkVUV09SS19NRVNTQUdFUygpICYmXG4gICAgICAgICAgICBjb25zb2xlLmxvZyguLi5BcnJheS5mcm9tKHNlcmlhbGl6ZUNyZHRNZXNzYWdlcygnW05ldHdvcmtNZXNzYWdlIHNlbnRdOicsIG1lc3NhZ2UsIGVuZ2luZSkpKVxuICAgICAgICAgIGJpbmFyeU1lc3NhZ2VCdXMuZW1pdChDb21tc01lc3NhZ2UuQ1JEVCwgbWVzc2FnZSlcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgY29uc3QgcGVlck1lc3NhZ2VzID0gZ2V0TWVzc2FnZXNUb1NlbmQoKVxuICAgICAgbGV0IHRvdGFsU2l6ZSA9IDBcbiAgICAgIGZvciAoY29uc3QgbWVzc2FnZSBvZiBwZWVyTWVzc2FnZXMpIHtcbiAgICAgICAgZm9yIChjb25zdCBkYXRhIG9mIG1lc3NhZ2UuZGF0YSkge1xuICAgICAgICAgIHRvdGFsU2l6ZSArPSBkYXRhLmJ5dGVMZW5ndGhcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgaWYgKHRvdGFsU2l6ZSkge1xuICAgICAgICBERUJVR19ORVRXT1JLX01FU1NBR0VTKCkgJiYgY29uc29sZS5sb2coJ1NlbmRpbmcgbmV0d29yayBtZXNzYWdlczogJywgdG90YWxTaXplIC8gMTAyNCwgJ0tCJylcbiAgICAgIH1cbiAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgc2VuZEJpbmFyeSh7IGRhdGE6IFtdLCBwZWVyRGF0YTogcGVlck1lc3NhZ2VzIH0pXG4gICAgICBiaW5hcnlNZXNzYWdlQnVzLl9fcHJvY2Vzc01lc3NhZ2VzKHJlc3BvbnNlLmRhdGEpXG4gICAgICB0cmFuc3BvcnRJbml0aWFsemVkID0gdHJ1ZVxuICAgIH0sXG4gICAgdHlwZTogJ25ldHdvcmsnXG4gIH1cbiAgZW5naW5lLmFkZFRyYW5zcG9ydCh0cmFuc3BvcnQpXG4gIC8vIEVuZCBhZGQgc3luYyB0cmFuc3BvcnRcblxuICAvLyBSZWNlaXZlICYgUHJvY2VzcyBDUkRUX1NUQVRFXG4gIGJpbmFyeU1lc3NhZ2VCdXMub24oQ29tbXNNZXNzYWdlLlJFU19DUkRUX1NUQVRFLCAodmFsdWUpID0+IHtcbiAgICBjb25zdCB7IHNlbmRlciwgZGF0YSB9ID0gZGVjb2RlQ1JEVFN0YXRlKHZhbHVlKVxuICAgIGlmIChzZW5kZXIgIT09IG15UHJvZmlsZS51c2VySWQpIHJldHVyblxuICAgIERFQlVHX05FVFdPUktfTUVTU0FHRVMoKSAmJiBjb25zb2xlLmxvZygnW1Byb2Nlc3NpbmcgQ1JEVCBTdGF0ZV0nLCBkYXRhLmJ5dGVMZW5ndGggLyAxMDI0LCAnS0InKVxuICAgIHRyYW5zcG9ydC5vbm1lc3NhZ2UhKGRhdGEpXG4gICAgc3RhdGVJc1N5bmNyb25pemVkID0gdHJ1ZVxuICB9KVxuXG4gIC8vIEFuc3dlciB0byBSRVFfQ1JEVF9TVEFURVxuICBiaW5hcnlNZXNzYWdlQnVzLm9uKENvbW1zTWVzc2FnZS5SRVFfQ1JEVF9TVEFURSwgYXN5bmMgKF8sIHVzZXJJZCkgPT4ge1xuICAgIERFQlVHX05FVFdPUktfTUVTU0FHRVMoKSAmJiBjb25zb2xlLmxvZyhgU2VuZGluZyBDUkRUIFN0YXRlIHRvOiAke3VzZXJJZH1gKVxuXG4gICAgZm9yIChjb25zdCBjaHVuayBvZiBlbmdpbmVUb0NyZHQoZW5naW5lKSkge1xuICAgICAgYmluYXJ5TWVzc2FnZUJ1cy5lbWl0KENvbW1zTWVzc2FnZS5SRVNfQ1JEVF9TVEFURSwgZW5jb2RlQ1JEVFN0YXRlKHVzZXJJZCwgY2h1bmspLCBbdXNlcklkXSlcbiAgICB9XG4gIH0pXG5cbiAgLy8gUHJvY2VzcyBDUkRUIG1lc3NhZ2VzIGhlcmVcbiAgYmluYXJ5TWVzc2FnZUJ1cy5vbihDb21tc01lc3NhZ2UuQ1JEVCwgKHZhbHVlKSA9PiB7XG4gICAgREVCVUdfTkVUV09SS19NRVNTQUdFUygpICYmXG4gICAgICBjb25zb2xlLmxvZyhBcnJheS5mcm9tKHNlcmlhbGl6ZUNyZHRNZXNzYWdlcygnW05ldHdvcmtNZXNzYWdlIHJlY2VpdmVkXTonLCB2YWx1ZSwgZW5naW5lKSkpXG4gICAgdHJhbnNwb3J0Lm9ubWVzc2FnZSEodmFsdWUpXG4gIH0pXG5cbiAgYXN5bmMgZnVuY3Rpb24gcmVxdWVzdFN0YXRlKHJldHJ5Q291bnQ6IG51bWJlciA9IDEpIHtcbiAgICBsZXQgcGxheWVycyA9IEFycmF5LmZyb20oZW5naW5lLmdldEVudGl0aWVzV2l0aChQbGF5ZXJJZGVudGl0eURhdGEpKVxuICAgIERFQlVHX05FVFdPUktfTUVTU0FHRVMoKSAmJiBjb25zb2xlLmxvZyhgUmVxdWVzdGluZyBzdGF0ZS4gUGxheWVycyBjb25uZWN0ZWQ6ICR7cGxheWVycy5sZW5ndGggLSAxfWApXG5cbiAgICBpZiAoIVJlYWxtSW5mby5nZXRPck51bGwoZW5naW5lLlJvb3RFbnRpdHkpPy5pc0Nvbm5lY3RlZFNjZW5lUm9vbSkge1xuICAgICAgREVCVUdfTkVUV09SS19NRVNTQUdFUygpICYmIGNvbnNvbGUubG9nKGBBYm9ydGluZyBSZXF1ZXN0aW5nIHN0YXRlPy4gRGlzY29ubmVjdGVkYClcbiAgICAgIHJldHVyblxuICAgIH1cblxuICAgIGJpbmFyeU1lc3NhZ2VCdXMuZW1pdChDb21tc01lc3NhZ2UuUkVRX0NSRFRfU1RBVEUsIG5ldyBVaW50OEFycmF5KCkpXG5cbiAgICAvLyBXYWl0IH41cyBmb3IgdGhlIHJlc3BvbnNlLlxuICAgIGF3YWl0IHNsZWVwKDUwMDApXG5cbiAgICBwbGF5ZXJzID0gQXJyYXkuZnJvbShlbmdpbmUuZ2V0RW50aXRpZXNXaXRoKFBsYXllcklkZW50aXR5RGF0YSkpXG5cbiAgICBpZiAoIXN0YXRlSXNTeW5jcm9uaXplZCkge1xuICAgICAgaWYgKHBsYXllcnMubGVuZ3RoID4gMSAmJiByZXRyeUNvdW50IDw9IDIpIHtcbiAgICAgICAgREVCVUdfTkVUV09SS19NRVNTQUdFUygpICYmXG4gICAgICAgICAgY29uc29sZS5sb2coYFJlcXVlc3Rpbmcgc3RhdGUgYWdhaW4gJHtyZXRyeUNvdW50fSAobm8gcmVzcG9uc2UpLiBQbGF5ZXJzIGNvbm5lY3RlZDogJHtwbGF5ZXJzLmxlbmd0aCAtIDF9YClcbiAgICAgICAgdm9pZCByZXF1ZXN0U3RhdGUocmV0cnlDb3VudCArIDEpXG4gICAgICB9IGVsc2Uge1xuICAgICAgICBERUJVR19ORVRXT1JLX01FU1NBR0VTKCkgJiYgY29uc29sZS5sb2coJ05vIGFjdGl2ZSBwbGF5ZXJzLiBTdGF0ZSBzeW5jcm9uaXplZCcpXG4gICAgICAgIHN0YXRlSXNTeW5jcm9uaXplZCA9IHRydWVcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBwbGF5ZXJzLm9uRW50ZXJTY2VuZSgocGxheWVyKSA9PiB7XG4gICAgREVCVUdfTkVUV09SS19NRVNTQUdFUygpICYmIGNvbnNvbGUubG9nKCdbb25FbnRlclNjZW5lXScsIHBsYXllci51c2VySWQpXG4gIH0pXG5cbiAgLy8gQXNrcyBmb3IgdGhlIFJFUV9DUkRUX1NUQVRFIHdoZW4gaXRzIGNvbm5lY3RlZCB0byBjb21tc1xuICBSZWFsbUluZm8ub25DaGFuZ2UoZW5naW5lLlJvb3RFbnRpdHksICh2YWx1ZSkgPT4ge1xuICAgIGlmICghdmFsdWU/LmlzQ29ubmVjdGVkU2NlbmVSb29tKSB7XG4gICAgICBERUJVR19ORVRXT1JLX01FU1NBR0VTKCkgJiYgY29uc29sZS5sb2coJ0Rpc2Nvbm5lY3RlZCBmcm9tIGNvbW1zJylcbiAgICAgIHN0YXRlSXNTeW5jcm9uaXplZCA9IGZhbHNlXG4gICAgfVxuXG4gICAgaWYgKHZhbHVlPy5pc0Nvbm5lY3RlZFNjZW5lUm9vbSkge1xuICAgICAgREVCVUdfTkVUV09SS19NRVNTQUdFUygpICYmIGNvbnNvbGUubG9nKCdDb25uZWN0ZWQgdG8gY29tbXMnKVxuICAgIH1cblxuICAgIGlmICh2YWx1ZT8uaXNDb25uZWN0ZWRTY2VuZVJvb20gJiYgIXN0YXRlSXNTeW5jcm9uaXplZCkge1xuICAgICAgdm9pZCByZXF1ZXN0U3RhdGUoKVxuICAgIH1cbiAgfSlcblxuICBwbGF5ZXJzLm9uTGVhdmVTY2VuZSgodXNlcklkKSA9PiB7XG4gICAgREVCVUdfTkVUV09SS19NRVNTQUdFUygpICYmIGNvbnNvbGUubG9nKCdbb25MZWF2ZVNjZW5lXScsIHVzZXJJZClcbiAgfSlcblxuICBmdW5jdGlvbiBpc1N0YXRlU3luY3Jvbml6ZWQoKSB7XG4gICAgcmV0dXJuIHN0YXRlSXNTeW5jcm9uaXplZFxuICB9XG5cbiAgZnVuY3Rpb24gc2xlZXAobXM6IG51bWJlcikge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZTx2b2lkPigocmVzb2x2ZSkgPT4ge1xuICAgICAgbGV0IHRpbWVyID0gMFxuICAgICAgZnVuY3Rpb24gc2xlZXBTeXN0ZW0oZHQ6IG51bWJlcikge1xuICAgICAgICB0aW1lciArPSBkdFxuICAgICAgICBpZiAodGltZXIgKiAxMDAwID49IG1zKSB7XG4gICAgICAgICAgZW5naW5lLnJlbW92ZVN5c3RlbShzbGVlcFN5c3RlbSlcbiAgICAgICAgICByZXNvbHZlKClcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgZW5naW5lLmFkZFN5c3RlbShzbGVlcFN5c3RlbSlcbiAgICB9KVxuICB9XG5cbiAgcmV0dXJuIHtcbiAgICAuLi5lbnRpdHlEZWZpbml0aW9ucyxcbiAgICBteVByb2ZpbGUsXG4gICAgaXNTdGF0ZVN5bmNyb25pemVkXG4gIH1cbn1cblxuLyoqXG4gKiBNZXNzYWdlcyBQcm90b2NvbCBFbmNvZGluZ1xuICpcbiAqIENSRFQ6IFBsYWluIFVpbnQ4QXJyYXlcbiAqXG4gKiBDUkRUX1NUQVRFX1JFUyB7IHNlbmRlcjogc3RyaW5nLCBkYXRhOiBVaW50OEFycmF5fVxuICovXG5mdW5jdGlvbiBkZWNvZGVDUkRUU3RhdGUoZGF0YTogVWludDhBcnJheSkge1xuICBsZXQgb2Zmc2V0ID0gMFxuICBjb25zdCByID0gbmV3IFVpbnQ4QXJyYXkoZGF0YSlcbiAgY29uc3QgdmlldyA9IG5ldyBEYXRhVmlldyhyLmJ1ZmZlcilcbiAgY29uc3Qgc2VuZGVyTGVuZ3RoID0gdmlldy5nZXRVaW50OChvZmZzZXQpXG4gIG9mZnNldCArPSAxXG4gIGNvbnN0IHNlbmRlciA9IGRlY29kZVN0cmluZyhkYXRhLnN1YmFycmF5KDEsIHNlbmRlckxlbmd0aCArIDEpKVxuICBvZmZzZXQgKz0gc2VuZGVyTGVuZ3RoXG4gIGNvbnN0IHN0YXRlID0gci5zdWJhcnJheShvZmZzZXQpXG5cbiAgcmV0dXJuIHsgc2VuZGVyLCBkYXRhOiBzdGF0ZSB9XG59XG5cbmZ1bmN0aW9uIGVuY29kZUNSRFRTdGF0ZShhZGRyZXNzOiBzdHJpbmcsIGRhdGE6IFVpbnQ4QXJyYXkpIHtcbiAgLy8gYWRkcmVzcyB0byB1aW50OGFycmF5XG4gIGNvbnN0IGFkZHJlc3NCdWZmZXIgPSBlbmNvZGVTdHJpbmcoYWRkcmVzcylcbiAgY29uc3QgYWRkcmVzc09mZnNldCA9IDFcbiAgY29uc3QgbWVzc2FnZUxlbmd0aCA9IGFkZHJlc3NPZmZzZXQgKyBhZGRyZXNzQnVmZmVyLmJ5dGVMZW5ndGggKyBkYXRhLmJ5dGVMZW5ndGhcblxuICBjb25zdCBzZXJpYWxpemVkTWVzc2FnZSA9IG5ldyBVaW50OEFycmF5KG1lc3NhZ2VMZW5ndGgpXG4gIHNlcmlhbGl6ZWRNZXNzYWdlLnNldChuZXcgVWludDhBcnJheShbYWRkcmVzc0J1ZmZlci5ieXRlTGVuZ3RoXSksIDApXG4gIHNlcmlhbGl6ZWRNZXNzYWdlLnNldChhZGRyZXNzQnVmZmVyLCAxKVxuICBzZXJpYWxpemVkTWVzc2FnZS5zZXQoZGF0YSwgYWRkcmVzc0J1ZmZlci5ieXRlTGVuZ3RoICsgMSlcbiAgcmV0dXJuIHNlcmlhbGl6ZWRNZXNzYWdlXG59XG4iXX0=
223
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWVzc2FnZS1idXMtc3luYy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9uZXR3b3JrL21lc3NhZ2UtYnVzLXN5bmMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFzQixTQUFTLEVBQUUsTUFBTSxVQUFVLENBQUE7QUFHeEQsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLFVBQVUsQ0FBQTtBQUNyQyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sU0FBUyxDQUFBO0FBQ3RDLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxZQUFZLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQTtBQUNyRSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sU0FBUyxDQUFBO0FBQ3RDLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxZQUFZLENBQUE7QUFDeEMsT0FBTyxFQUFFLHFCQUFxQixFQUFFLE1BQU0sVUFBVSxDQUFBO0FBRWhELE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLFlBQVksQ0FBQTtBQUMvQyxPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQTtBQUVyRSxPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0sU0FBUyxDQUFBO0FBQzlCLE9BQU8sRUFBRSxhQUFhLEVBQUUsSUFBSSxFQUFFLE1BQU0seUJBQXlCLENBQUE7QUFHN0QsK0NBQStDO0FBQy9DLE1BQU0sQ0FBQyxNQUFNLG1CQUFtQixHQUFHLHNCQUFzQixDQUFBO0FBQ3pELE1BQU0sQ0FBQyxNQUFNLHNCQUFzQixHQUFHLEdBQUcsRUFBRSxDQUFFLFVBQWtCLENBQUMsc0JBQXNCLElBQUksS0FBSyxDQUFBO0FBRS9GLDhDQUE4QztBQUM5QyxNQUFNLGlCQUFpQixHQUFHLEdBQVksRUFBRTtJQUN0QyxJQUFJO1FBQ0YsSUFBSSxPQUFPLFVBQVUsS0FBSyxXQUFXO1lBQUUsT0FBTyxLQUFLLENBQUE7UUFDbkQsTUFBTSxpQkFBaUIsR0FBRyxVQUFzRSxDQUFBO1FBQ2hH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TyxrQkFBa0IsQ0FBQTtJQUMzQixDQUFDO0lBRUQsT0FBTztRQUNMLEdBQUcsaUJBQWlCO1FBQ3BCLFNBQVM7UUFDVCxrQkFBa0I7UUFDbEIsZ0JBQWdCO1FBQ2hCLFFBQVE7UUFDUixlQUFlO0tBQ2hCLENBQUE7QUFDSCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSUVuZ2luZSwgVHJhbnNwb3J0LCBSZWFsbUluZm8gfSBmcm9tICdAZGNsL2VjcydcbmltcG9ydCB7IHR5cGUgU2VuZEJpbmFyeVJlcXVlc3QsIHR5cGUgU2VuZEJpbmFyeVJlc3BvbnNlIH0gZnJvbSAnfnN5c3RlbS9Db21tdW5pY2F0aW9uc0NvbnRyb2xsZXInXG5cbmltcG9ydCB7IHN5bmNGaWx0ZXIgfSBmcm9tICcuL2ZpbHRlcidcbmltcG9ydCB7IGVuZ2luZVRvQ3JkdCB9IGZyb20gJy4vc3RhdGUnXG5pbXBvcnQgeyBCaW5hcnlNZXNzYWdlQnVzLCBDb21tc01lc3NhZ2UgfSBmcm9tICcuL2JpbmFyeS1tZXNzYWdlLWJ1cydcbmltcG9ydCB7IGZldGNoUHJvZmlsZSB9IGZyb20gJy4vdXRpbHMnXG5pbXBvcnQgeyBlbnRpdHlVdGlscyB9IGZyb20gJy4vZW50aXRpZXMnXG5pbXBvcnQgeyBjcmVhdGVTZXJ2ZXJWYWxpZGF0b3IgfSBmcm9tICcuL3NlcnZlcidcbmltcG9ydCB7IEdldFVzZXJEYXRhUmVxdWVzdCwgR2V0VXNlckRhdGFSZXNwb25zZSB9IGZyb20gJ35zeXN0ZW0vVXNlcklkZW50aXR5J1xuaW1wb3J0IHsgZGVmaW5lUGxheWVySGVscGVyIH0gZnJvbSAnLi4vcGxheWVycydcbmltcG9ydCB7IHNlcmlhbGl6ZUNyZHRNZXNzYWdlcyB9IGZyb20gJy4uL2ludGVybmFsL3RyYW5zcG9ydHMvbG9nZ2VyJ1xuaW1wb3J0IHsgSXNTZXJ2ZXJSZXF1ZXN0LCBJc1NlcnZlclJlc3BvbnNlIH0gZnJvbSAnfnN5c3RlbS9FbmdpbmVBcGknXG5pbXBvcnQgeyBBdG9tIH0gZnJvbSAnLi4vYXRvbSdcbmltcG9ydCB7IHNldEdsb2JhbFJvb20sIFJvb20gfSBmcm9tICcuL2V2ZW50cy9pbXBsZW1lbnRhdGlvbidcblxuZXhwb3J0IHR5cGUgSVByb2ZpbGUgPSB7IG5ldHdvcmtJZDogbnVtYmVyOyB1c2VySWQ6IHN0cmluZyB9XG4vLyB1c2VyIHRoYXQgd2UgYXNrZWQgZm9yIHRoZSBpbml0YWwgY3JkdCBzdGF0ZVxuZXhwb3J0IGNvbnN0IEFVVEhfU0VSVkVSX1BFRVJfSUQgPSAnYXV0aG9yaXRhdGl2ZS1zZXJ2ZXInXG5leHBvcnQgY29uc3QgREVCVUdfTkVUV09SS19NRVNTQUdFUyA9ICgpID0+IChnbG9iYWxUaGlzIGFzIGFueSkuREVCVUdfTkVUV09SS19NRVNTQUdFUyA/PyBmYWxzZVxuXG4vLyBUZXN0IGVudmlyb25tZW50IGRldGVjdGlvbiB3aXRob3V0ICdhcyBhbnknXG5jb25zdCBpc1Rlc3RFbnZpcm9ubWVudCA9ICgpOiBib29sZWFuID0+IHtcbiAgdHJ5IHtcbiAgICBpZiAodHlwZW9mIGdsb2JhbFRoaXMgPT09ICd1bmRlZmluZWQnKSByZXR1cm4gZmFsc2VcbiAgICBjb25zdCBnbG9iYWxXaXRoUHJvY2VzcyA9IGdsb2JhbFRoaXMgYXMgdW5rbm93biBhcyB7IHByb2Nlc3M/OiB7IGVudj86IHsgTk9ERV9FTlY/OiBzdHJpbmcgfSB9IH1cbiAgICByZXR1cm4gZ2xvYmFsV2l0aFByb2Nlc3MucHJvY2Vzcz8uZW52Py5OT0RFX0VOViA9PT0gJ3Rlc3QnXG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiBmYWxzZVxuICB9XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBhZGRTeW5jVHJhbnNwb3J0KFxuICBlbmdpbmU6IElFbmdpbmUsXG4gIHNlbmRCaW5hcnk6IChtc2c6IFNlbmRCaW5hcnlSZXF1ZXN0KSA9PiBQcm9taXNlPFNlbmRCaW5hcnlSZXNwb25zZT4sXG4gIGdldFVzZXJEYXRhOiAodmFsdWU6IEdldFVzZXJEYXRhUmVxdWVzdCkgPT4gUHJvbWlzZTxHZXRVc2VyRGF0YVJlc3BvbnNlPixcbiAgaXNTZXJ2ZXJGbjogKHJlcXVlc3Q6IElzU2VydmVyUmVxdWVzdCkgPT4gUHJvbWlzZTxJc1NlcnZlclJlc3BvbnNlPixcbiAgbmFtZTogc3RyaW5nXG4pIHtcbiAgLy8gUHJvZmlsZSBJbmZvXG4gIGNvbnN0IG15UHJvZmlsZTogSVByb2ZpbGUgPSB7fSBhcyBJUHJvZmlsZVxuICBmZXRjaFByb2ZpbGUobXlQcm9maWxlISwgZ2V0VXNlckRhdGEpXG5cbiAgY29uc3QgaXNTZXJ2ZXJBdG9tID0gQXRvbTxib29sZWFuPigpXG4gIGNvbnN0IGlzUm9vbVJlYWR5QXRvbSA9IEF0b208Ym9vbGVhbj4oZmFsc2UpXG5cbiAgdm9pZCBpc1NlcnZlckZuKHt9KS50aGVuKCgkOiBJc1NlcnZlclJlc3BvbnNlKSA9PiB7XG4gICAgcmV0dXJuIGlzU2VydmVyQXRvbS5zd2FwKCEhJC5pc1NlcnZlcilcbiAgfSlcblxuICAvLyBFbnRpdHkgdXRpbHNcbiAgY29uc3QgZW50aXR5RGVmaW5pdGlvbnMgPSBlbnRpdHlVdGlscyhlbmdpbmUsIG15UHJvZmlsZSlcblxuICAvLyBMaXN0IG9mIE1lc3NhZ2VCdXNzIG1lc3NzYWdlcyB0byBiZSBzZW50IG9uIGV2ZXJ5IGZyYW1lIHRvIGNvbW1zXG4gIGNvbnN0IHBlbmRpbmdNZXNzYWdlQnVzTWVzc2FnZXNUb1NlbmQ6IHsgZGF0YTogVWludDhBcnJheVtdOyBhZGRyZXNzOiBzdHJpbmdbXSB9W10gPSBbXVxuXG4gIGNvbnN0IGJpbmFyeU1lc3NhZ2VCdXMgPSBCaW5hcnlNZXNzYWdlQnVzKChkYXRhLCBhZGRyZXNzKSA9PiB7XG4gICAgcGVuZGluZ01lc3NhZ2VCdXNNZXNzYWdlc1RvU2VuZC5wdXNoKHsgZGF0YTogW2RhdGFdLCBhZGRyZXNzOiBhZGRyZXNzID8/IFtdIH0pXG4gIH0pXG5cbiAgZnVuY3Rpb24gZ2V0TWVzc2FnZXNUb1NlbmQoKTogdHlwZW9mIHBlbmRpbmdNZXNzYWdlQnVzTWVzc2FnZXNUb1NlbmQge1xuICAgIGNvbnN0IG1lc3NhZ2VzID0gWy4uLnBlbmRpbmdNZXNzYWdlQnVzTWVzc2FnZXNUb1NlbmRdXG4gICAgcGVuZGluZ01lc3NhZ2VCdXNNZXNzYWdlc1RvU2VuZC5sZW5ndGggPSAwXG4gICAgcmV0dXJuIG1lc3NhZ2VzXG4gIH1cbiAgY29uc3QgcGxheWVycyA9IGRlZmluZVBsYXllckhlbHBlcihlbmdpbmUpXG5cbiAgbGV0IHN0YXRlSXNTeW5jcm9uaXplZCA9IGZhbHNlXG5cbiAgLyoqXG4gICAqIFdlIG5lZWQgdG8gd2FpdCB0aWxsIDIgdGlja3MgdGhhdCBpcyB3aGVuIHRoZSBlbmdpbmUgaXMgcmVhZHkgdG8gc2VuZCBuZXcgbWVzc2FnZXMuXG4gICAqIFRoZSBmaXJzdCB0aWNrIGlzIGZvciB0aGUgY2xpZW50IGVuZ2luZSBwcm9jZXNzaW5nIHRoZSBDUkRUIG1lc3NhZ2VzLFxuICAgKiBhbmQgdGhlIHNlY29uZCBvbmUgYXJlIHRoZSBtZXNzYWdlcyBjcmVhdGVkIGJ5IHRoZSBtYWluKCkgZnVuY3Rpb24uXG4gICAqIFNvIHRvIGF2b2lkIHNlbmRpbmcgdGhvc2UgbWVzc2FnZXMsIHRoYXQgYWxsIHRoZSBjbGllbnRzIGhhdmUsIHRocm91Z2ggdGhlIG5ldHdvcmsgd2UgcHV0IHRoaXMgdmFsaWRhdGlvbiBoZXJlLlxuICAgKi9cbiAgbGV0IHRpY2sgPSAwXG4gIGNvbnN0IFRSQU5TUE9SVF9JTklUSUFMSVpFRF9OVU1CRVIgPSBpc1Rlc3RFbnZpcm9ubWVudCgpID8gMCA6IDJcbiAgLy8gQWRkIFN5bmMgVHJhbnNwb3J0XG4gIGNvbnN0IHRyYW5zcG9ydDogVHJhbnNwb3J0ID0ge1xuICAgIGZpbHRlcjogc3luY0ZpbHRlcihlbmdpbmUpLFxuICAgIHNlbmQ6IGFzeW5jIChtZXNzYWdlcykgPT4ge1xuICAgICAgaWYgKHRpY2sgPD0gVFJBTlNQT1JUX0lOSVRJQUxJWkVEX05VTUJFUikgdGljaysrXG4gICAgICBmb3IgKGNvbnN0IG1lc3NhZ2Ugb2YgdGljayA+IFRSQU5TUE9SVF9JTklUSUFMSVpFRF9OVU1CRVIgPyBbbWVzc2FnZXNdLmZsYXQoKSA6IFtdKSB7XG4gICAgICAgIGlmIChtZXNzYWdlLmJ5dGVMZW5ndGgpIHtcbiAgICAgICAgICBERUJVR19ORVRXT1JLX01FU1NBR0VTKCkgJiZcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKC4uLkFycmF5LmZyb20oc2VyaWFsaXplQ3JkdE1lc3NhZ2VzKCdbTmV0d29ya01lc3NhZ2Ugc2VudF06JywgbWVzc2FnZSwgZW5naW5lKSkpXG5cbiAgICAgICAgICAvLyBDb252ZXJ0IHJlZ3VsYXIgbWVzc2FnZXMgdG8gbmV0d29yayBtZXNzYWdlcyBmb3IgYnJvYWRjYXN0aW5nIHdpdGggY2h1bmtpbmdcbiAgICAgICAgICBmb3IgKGNvbnN0IGNodW5rIG9mIHNlcnZlclZhbGlkYXRvci5jb252ZXJ0UmVndWxhclRvTmV0d29ya01lc3NhZ2UobWVzc2FnZSkpIHtcbiAgICAgICAgICAgIGJpbmFyeU1lc3NhZ2VCdXMuZW1pdChDb21tc01lc3NhZ2UuQ1JEVCwgY2h1bmspXG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgICBjb25zdCBwZWVyTWVzc2FnZXMgPSBnZXRNZXNzYWdlc1RvU2VuZCgpXG4gICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHNlbmRCaW5hcnkoeyBkYXRhOiBbXSwgcGVlckRhdGE6IHBlZXJNZXNzYWdlcyB9KVxuICAgICAgYmluYXJ5TWVzc2FnZUJ1cy5fX3Byb2Nlc3NNZXNzYWdlcyhyZXNwb25zZS5kYXRhKVxuICAgIH0sXG4gICAgdHlwZTogbmFtZVxuICB9XG5cbiAgLy8gU2VydmVyIHZhbGlkYXRpb24gc2V0dXBcbiAgY29uc3Qgc2VydmVyVmFsaWRhdG9yID0gY3JlYXRlU2VydmVyVmFsaWRhdG9yKHtcbiAgICBlbmdpbmUsXG4gICAgYmluYXJ5TWVzc2FnZUJ1c1xuICB9KVxuXG4gIC8vIEluaXRpYWxpemUgRXZlbnQgQnVzIHdpdGggcmVnaXN0ZXJlZCBzY2hlbWFzXG4gIGNvbnN0IGV2ZW50QnVzID0gbmV3IFJvb20oZW5naW5lLCBiaW5hcnlNZXNzYWdlQnVzLCBpc1NlcnZlckF0b20sIGlzUm9vbVJlYWR5QXRvbSlcblxuICAvLyBTZXQgZ2xvYmFsIGV2ZW50QnVzIGluc3RhbmNlXG4gIHNldEdsb2JhbFJvb20oZXZlbnRCdXMpXG5cbiAgZW5naW5lLmFkZFRyYW5zcG9ydCh0cmFuc3BvcnQpXG4gIC8vIEVuZCBhZGQgc3luYyB0cmFuc3BvcnRcblxuICAvLyBSZWNlaXZlICYgUHJvY2VzcyBDUkRUX1NUQVRFXG4gIGJpbmFyeU1lc3NhZ2VCdXMub24oQ29tbXNNZXNzYWdlLlJFUV9DUkRUX1NUQVRFLCBhc3luYyAoZGF0YSwgc2VuZGVyKSA9PiB7XG4gICAgREVCVUdfTkVUV09SS19NRVNTQUdFUygpICYmIGNvbnNvbGUubG9nKCdbUkVRX0NSRFRfU1RBVEVdJywgc2VuZGVyLCBEYXRlLm5vdygpKVxuICAgIGZvciAoY29uc3QgY2h1bmsgb2YgZW5naW5lVG9DcmR0KGVuZ2luZSkpIHtcbiAgICAgIERFQlVHX05FVFdPUktfTUVTU0FHRVMoKSAmJiBjb25zb2xlLmxvZygnW0VtaXRpbmc6XScsIHNlbmRlciwgRGF0ZS5ub3coKSlcbiAgICAgIGJpbmFyeU1lc3NhZ2VCdXMuZW1pdChDb21tc01lc3NhZ2UuUkVTX0NSRFRfU1RBVEUsIGNodW5rLCBbc2VuZGVyXSlcbiAgICB9XG4gIH0pXG4gIGJpbmFyeU1lc3NhZ2VCdXMub24oQ29tbXNNZXNzYWdlLlJFU19DUkRUX1NUQVRFLCBhc3luYyAoZGF0YSwgc2VuZGVyKSA9PiB7XG4gICAgcmVxdWVzdGluZ1N0YXRlID0gZmFsc2VcbiAgICBlbGFwc2VkVGltZVNpbmNlUmVxdWVzdCA9IDBcbiAgICBpZiAoaXNTZXJ2ZXJBdG9tLmdldE9yTnVsbCgpIHx8IHNlbmRlciAhPT0gQVVUSF9TRVJWRVJfUEVFUl9JRCkgcmV0dXJuXG4gICAgREVCVUdfTkVUV09SS19NRVNTQUdFUygpICYmIGNvbnNvbGUubG9nKCdbUHJvY2Vzc2luZyBDUkRUIFN0YXRlXScsIGRhdGEuYnl0ZUxlbmd0aCAvIDEwMjQsICdLQicpXG4gICAgdHJhbnNwb3J0Lm9ubWVzc2FnZSEoc2VydmVyVmFsaWRhdG9yLnByb2Nlc3NDbGllbnRNZXNzYWdlcyhkYXRhLCBzZW5kZXIpKVxuICAgIHN0YXRlSXNTeW5jcm9uaXplZCA9IHRydWVcblxuICAgIC8vIElNUE9SVEFOVDogT25seSBtYXJrIHJvb20gYXMgcmVhZHkgQUZURVIgc3RhdGUgaXMgc3luY2hyb25pemVkXG4gICAgLy8gVGhpcyBlbnN1cmVzIGNvbW1zIGlzIHRydWx5IGNvbm5lY3RlZCBhbmQgd29ya2luZ1xuICAgIGNvbnN0IHJlYWxtSW5mbyA9IFJlYWxtSW5mby5nZXRPck51bGwoZW5naW5lLlJvb3RFbnRpdHkpXG4gICAgaWYgKHJlYWxtSW5mbykge1xuICAgICAgREVCVUdfTkVUV09SS19NRVNTQUdFUygpICYmIGNvbnNvbGUubG9nKCdbaXNSb29tUmVhZHldIE1hcmtpbmcgcm9vbSBhcyByZWFkeSBhZnRlciBzdGF0ZSBzeW5jJylcbiAgICAgIGlzUm9vbVJlYWR5QXRvbS5zd2FwKHRydWUpXG4gICAgfVxuICB9KVxuXG4gIC8vIHJlY2VpdmVkIG1lc3NhZ2UgZnJvbSB0aGUgbmV0d29ya1xuICBiaW5hcnlNZXNzYWdlQnVzLm9uKENvbW1zTWVzc2FnZS5DUkRULCAodmFsdWUsIHNlbmRlcikgPT4ge1xuICAgIGNvbnN0IGlzU2VydmVyID0gaXNTZXJ2ZXJBdG9tLmdldE9yTnVsbCgpXG4gICAgREVCVUdfTkVUV09SS19NRVNTQUdFUygpICYmXG4gICAgICBjb25zb2xlLmxvZyhcbiAgICAgICAgdHJhbnNwb3J0LnR5cGUsXG4gICAgICAgIC4uLkFycmF5LmZyb20oc2VyaWFsaXplQ3JkdE1lc3NhZ2VzKCdbTmV0d29ya01lc3NhZ2UgcmVjZWl2ZWRdOicsIHZhbHVlLCBlbmdpbmUpKSxcbiAgICAgICAgaXNTZXJ2ZXJcbiAgICAgIClcbiAgICBpZiAoaXNTZXJ2ZXIpIHtcbiAgICAgIHRyYW5zcG9ydC5vbm1lc3NhZ2UhKHNlcnZlclZhbGlkYXRvci5wcm9jZXNzU2VydmVyTWVzc2FnZXModmFsdWUsIHNlbmRlcikpXG4gICAgfSBlbHNlIGlmIChzZW5kZXIgPT09IEFVVEhfU0VSVkVSX1BFRVJfSUQpIHtcbiAgICAgIC8vIFByb2Nlc3MgbmV0d29yayBtZXNzYWdlcyBmcm9tIHNlcnZlciBhbmQgY29udmVydCB0byByZWd1bGFyIG1lc3NhZ2VzXG4gICAgICB0cmFuc3BvcnQub25tZXNzYWdlIShzZXJ2ZXJWYWxpZGF0b3IucHJvY2Vzc0NsaWVudE1lc3NhZ2VzKHZhbHVlLCBzZW5kZXIpKVxuICAgIH1cbiAgfSlcblxuICAvLyByZWNlaXZlZCBhdXRob3JpdGF0aXZlIG1lc3NhZ2UgZnJvbSBzZXJ2ZXIgLSBmb3JjZSBhcHBseSB0byBmaXggaW52YWxpZCBsb2NhbCBzdGF0ZVxuICBiaW5hcnlNZXNzYWdlQnVzLm9uKENvbW1zTWVzc2FnZS5DUkRUX0FVVEhPUklUQVRJVkUsICh2YWx1ZSwgc2VuZGVyKSA9PiB7XG4gICAgLy8gT25seSBhY2NlcHQgYXV0aG9yaXRhdGl2ZSBtZXNzYWdlcyBmcm9tIGF1dGhvcml0YXRpdmUgc2VydmVyXG4gICAgaWYgKHNlbmRlciAhPT0gQVVUSF9TRVJWRVJfUEVFUl9JRCkgcmV0dXJuXG5cbiAgICAvLyBERUJVR19ORVRXT1JLX01FU1NBR0VTKCkgJiZcbiAgICBjb25zb2xlLmxvZygnW0FVVEhPUklUQVRJVkVdIFJlY2VpdmVkIGF1dGhvcml0YXRpdmUgbWVzc2FnZSBmcm9tIHNlcnZlcjonLCB2YWx1ZS5ieXRlTGVuZ3RoLCAnYnl0ZXMnKVxuXG4gICAgLy8gUHJvY2VzcyBhdXRob3JpdGF0aXZlIG1lc3NhZ2VzIGJ5IGZvcmNpbmcgdGhlbSB0aHJvdWdoIG5vcm1hbCBDUkRUIHByb2Nlc3NpbmdcbiAgICAvLyBidXQgd2l0aCBhIHRpbWVzdGFtcCB0aGF0J3MgZ3VhcmFudGVlZCB0byBiZSBhY2NlcHRlZFxuICAgIGNvbnN0IGF1dGhvcml0YXRpdmVCdWZmZXIgPSBzZXJ2ZXJWYWxpZGF0b3IucHJvY2Vzc0NsaWVudE1lc3NhZ2VzKHZhbHVlLCBzZW5kZXIsIHRydWUpXG4gICAgaWYgKGF1dGhvcml0YXRpdmVCdWZmZXIuYnl0ZUxlbmd0aCA+IDApIHtcbiAgICAgIC8vIEFwcGx5IGF1dGhvcml0YXRpdmUgbWVzc2FnZSB0aHJvdWdoIG5vcm1hbCB0cmFuc3BvcnQsIGJ1dCB0aGUgc2VydmVyJ3MgbWVzc2FnZXNcbiAgICAgIC8vIHNob3VsZCBiZSBwcm9jZXNzZWQgYXMgYXV0aG9yaXRhdGl2ZSB3aXRoIHNwZWNpYWwgdGltZXN0YW1wIGhhbmRsaW5nXG4gICAgICB0cmFuc3BvcnQub25tZXNzYWdlIShhdXRob3JpdGF0aXZlQnVmZmVyKVxuXG4gICAgICBERUJVR19ORVRXT1JLX01FU1NBR0VTKCkgJiYgY29uc29sZS5sb2coJ1tBVVRIT1JJVEFUSVZFXSBBcHBsaWVkIHNlcnZlciBhdXRob3JpdGF0aXZlIG1lc3NhZ2UgdG8gbG9jYWwgc3RhdGUnKVxuICAgIH1cbiAgfSlcblxuICBwbGF5ZXJzLm9uRW50ZXJTY2VuZSgocGxheWVyKSA9PiB7XG4gICAgREVCVUdfTkVUV09SS19NRVNTQUdFUygpICYmIGNvbnNvbGUubG9nKCdbb25FbnRlclNjZW5lXScsIHBsYXllci51c2VySWQpXG4gICAgaWYgKCFpc1NlcnZlckF0b20uZ2V0T3JOdWxsKCkgJiYgbXlQcm9maWxlLnVzZXJJZCA9PT0gcGxheWVyLnVzZXJJZCkge1xuICAgICAgcmVxdWVzdFN0YXRlKClcbiAgICB9XG4gIH0pXG5cbiAgLy8gQXNrcyBmb3IgdGhlIFJFUV9DUkRUX1NUQVRFIHdoZW4gaXRzIGNvbm5lY3RlZCB0byBjb21tc1xuICBSZWFsbUluZm8ub25DaGFuZ2UoZW5naW5lLlJvb3RFbnRpdHksICh2YWx1ZSkgPT4ge1xuICAgIGNvbnN0IGlzU2VydmVyID0gaXNTZXJ2ZXJBdG9tLmdldE9yTnVsbCgpXG5cbiAgICBpZiAoIXZhbHVlPy5pc0Nvbm5lY3RlZFNjZW5lUm9vbSkge1xuICAgICAgLy8gT25seSByZWFjdCB3aGVuIGFjdHVhbGx5IHRyYW5zaXRpb25pbmcgZnJvbSByZWFkeSB0byBub3QgcmVhZHlcbiAgICAgIGlmIChpc1Jvb21SZWFkeUF0b20uZ2V0T3JOdWxsKCkgPT09IHRydWUpIHtcbiAgICAgICAgREVCVUdfTkVUV09SS19NRVNTQUdFUygpICYmIGNvbnNvbGUubG9nKCdEaXNjb25uZWN0ZWQgZnJvbSBjb21tcycpXG4gICAgICAgIGlzUm9vbVJlYWR5QXRvbS5zd2FwKGZhbHNlKVxuICAgICAgICBpZiAoIWlzU2VydmVyKSB7XG4gICAgICAgICAgc3RhdGVJc1N5bmNyb25pemVkID0gZmFsc2VcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIGlmICh2YWx1ZT8uaXNDb25uZWN0ZWRTY2VuZVJvb20pIHtcbiAgICAgIHJlcXVlc3RTdGF0ZSgpXG5cbiAgICAgIC8vIEZvciBzZXJ2ZXJzLCBtYXJrIGFzIHJlYWR5IGltbWVkaWF0ZWx5IHdoZW4gY29ubmVjdGVkXG4gICAgICAvLyAoc2VydmVycyBkb24ndCBuZWVkIHRvIHN5bmMgc3RhdGUgZnJvbSBhbnlvbmUpXG4gICAgICBpZiAoaXNTZXJ2ZXIgJiYgaXNSb29tUmVhZHlBdG9tLmdldE9yTnVsbCgpID09PSBmYWxzZSkge1xuICAgICAgICBERUJVR19ORVRXT1JLX01FU1NBR0VTKCkgJiYgY29uc29sZS5sb2coJ1tpc1Jvb21SZWFkeV0gU2VydmVyIG1hcmtpbmcgcm9vbSBhcyByZWFkeScpXG4gICAgICAgIGlzUm9vbVJlYWR5QXRvbS5zd2FwKHRydWUpXG4gICAgICB9XG4gICAgICAvLyBGb3IgY2xpZW50cywgcm9vbSB3aWxsIGJlIG1hcmtlZCByZWFkeSBhZnRlciByZWNlaXZpbmcgQ1JEVCBzdGF0ZSAoYWJvdmUpXG4gICAgfVxuICB9KVxuXG4gIGxldCByZXF1ZXN0aW5nU3RhdGUgPSBmYWxzZVxuICBsZXQgZWxhcHNlZFRpbWVTaW5jZVJlcXVlc3QgPSAwXG4gIGNvbnN0IFNUQVRFX1JFUVVFU1RfUkVUUllfSU5URVJWQUwgPSAyLjAgLy8gc2Vjb25kc1xuXG4gIC8qKlxuICAgKiBXaHkgd2UgaGF2ZSB0byByZXF1ZXN0IHRoZSBzdGF0ZSBpZiB3ZSBoYXZlIGEgc2VydmVyIHRoYXQgY2FuIHNlbmQgdXMgdGhlIHN0YXRlIHdoZW4gd2Ugam9pbmVkP1xuICAgKiBUaGUgdGhpbmcgaXMgdGhhdCB3aGVuIHRoZSBzZXJ2ZXIgZGV0ZWN0cyBhIG5ldyBKT0lOX1BBUlRJQ0lQQU5UIG9uIGxpdmVraXQgcm9vbSwgaXQgc2VuZHMgYXV0b21hdGljYWxseSB0aGUgc3RhdGUgdG8gdGhhdCBwZWVyLlxuICAgKiBCdXQgaW4gdW5pdHksIGl0IHRha2VzIG1vcmUgdGltZSwgc28gdGhhdCBtZXNzYWdlIGlzIG5vdCBiZWluZyBkZWxpdmVyZWQgdG8gdGhlIGNsaWVudC5cbiAgICogU28gaW5zdGVhZCwgd2hlbiB3ZSBhcmUgZmluYWxseSBjb25uZWN0ZWQgdG8gdGhlIHJvb20sIHdlIHJlcXVlc3QgdGhlIHN0YXRlLCBhbmQgdGhlbiB0aGUgc2VydmVyIGFuc3dlcnMgd2l0aCB0aGUgc3RhdGUgOilcbiAgICpcbiAgICogSWYgbm8gcmVzcG9uc2UgaXMgcmVjZWl2ZWQgd2l0aGluIDIgc2Vjb25kcywgdGhlIHJlcXVlc3QgaXMgYXV0b21hdGljYWxseSByZXRyaWVkLlxuICAgKi9cbiAgZnVuY3Rpb24gcmVxdWVzdFN0YXRlKCkge1xuICAgIGlmIChpc1NlcnZlckF0b20uZ2V0T3JOdWxsKCkpIHJldHVyblxuICAgIGlmIChSZWFsbUluZm8uZ2V0T3JOdWxsKGVuZ2luZS5Sb290RW50aXR5KT8uaXNDb25uZWN0ZWRTY2VuZVJvb20gJiYgIXJlcXVlc3RpbmdTdGF0ZSkge1xuICAgICAgcmVxdWVzdGluZ1N0YXRlID0gdHJ1ZVxuICAgICAgZWxhcHNlZFRpbWVTaW5jZVJlcXVlc3QgPSAwXG4gICAgICBERUJVR19ORVRXT1JLX01FU1NBR0VTKCkgJiYgY29uc29sZS5sb2coJ1JlcXVlc3Rpbmcgc3RhdGUuLi4nKVxuICAgICAgYmluYXJ5TWVzc2FnZUJ1cy5lbWl0KENvbW1zTWVzc2FnZS5SRVFfQ1JEVF9TVEFURSwgbmV3IFVpbnQ4QXJyYXkoKSlcbiAgICB9XG4gIH1cblxuICAvLyBTeXN0ZW0gdG8gcmV0cnkgc3RhdGUgcmVxdWVzdCBpZiBubyByZXNwb25zZSBpcyByZWNlaXZlZCB3aXRoaW4gdGhlIHJldHJ5IGludGVydmFsXG4gIGVuZ2luZS5hZGRTeXN0ZW0oKGR0OiBudW1iZXIpID0+IHtcbiAgICBpZiAocmVxdWVzdGluZ1N0YXRlICYmICFzdGF0ZUlzU3luY3Jvbml6ZWQpIHtcbiAgICAgIGVsYXBzZWRUaW1lU2luY2VSZXF1ZXN0ICs9IGR0XG4gICAgICBpZiAoZWxhcHNlZFRpbWVTaW5jZVJlcXVlc3QgPj0gU1RBVEVfUkVRVUVTVF9SRVRSWV9JTlRFUlZBTCkge1xuICAgICAgICBERUJVR19ORVRXT1JLX01FU1NBR0VTKCkgJiYgY29uc29sZS5sb2coJ1N0YXRlIHJlcXVlc3QgdGltZWQgb3V0LCByZXRyeWluZy4uLicpXG4gICAgICAgIGVsYXBzZWRUaW1lU2luY2VSZXF1ZXN0ID0gMFxuICAgICAgICByZXF1ZXN0aW5nU3RhdGUgPSBmYWxzZVxuICAgICAgICByZXF1ZXN0U3RhdGUoKVxuICAgICAgfVxuICAgIH1cbiAgfSlcblxuICBwbGF5ZXJzLm9uTGVhdmVTY2VuZSgodXNlcklkKSA9PiB7XG4gICAgREVCVUdfTkVUV09SS19NRVNTQUdFUygpICYmIGNvbnNvbGUubG9nKCdbb25MZWF2ZVNjZW5lXScsIHVzZXJJZClcbiAgfSlcblxuICBmdW5jdGlvbiBpc1N0YXRlU3luY3Jvbml6ZWQoKSB7XG4gICAgcmV0dXJuIHN0YXRlSXNTeW5jcm9uaXplZFxuICB9XG5cbiAgcmV0dXJuIHtcbiAgICAuLi5lbnRpdHlEZWZpbml0aW9ucyxcbiAgICBteVByb2ZpbGUsXG4gICAgaXNTdGF0ZVN5bmNyb25pemVkLFxuICAgIGJpbmFyeU1lc3NhZ2VCdXMsXG4gICAgZXZlbnRCdXMsXG4gICAgaXNSb29tUmVhZHlBdG9tXG4gIH1cbn1cbiJdfQ==
@@ -0,0 +1,14 @@
1
+ import { IEngine, Entity } from '@dcl/ecs';
2
+ import * as utils from './utils';
3
+ import { type BinaryMessageBus } from '../binary-message-bus';
4
+ export declare const LIVEKIT_MAX_SIZE = 12;
5
+ export interface ServerValidationConfig {
6
+ engine: IEngine;
7
+ binaryMessageBus: ReturnType<typeof BinaryMessageBus>;
8
+ }
9
+ export declare function createServerValidator(config: ServerValidationConfig): {
10
+ findExistingNetworkEntity: (message: utils.NetworkMessage) => Entity | null;
11
+ processClientMessages: (value: Uint8Array, sender: string, forceCorrections?: boolean) => Uint8Array;
12
+ processServerMessages: (value: Uint8Array, sender: string) => Uint8Array;
13
+ convertRegularToNetworkMessage: (regularMessage: Uint8Array) => Uint8Array[];
14
+ };