@dcl/sdk 7.29.1-36591934525.commit-48aa9b5 → 7.29.1-36624944101.commit-bb81ac6

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 +179 -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,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,174 @@ 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
+ // Requests arriving before role resolution are recovered by the requester's retry.
94
+ if (!isServerAtom.getOrNull())
95
+ return;
96
+ DEBUG_NETWORK_MESSAGES() && console.log('[REQ_CRDT_STATE]', sender, Date.now());
97
+ const chunks = engineToCrdt(engine);
98
+ if (chunks.length === 0) {
99
+ DEBUG_NETWORK_MESSAGES() && console.log('[Emiting empty state:]', sender, Date.now());
100
+ binaryMessageBus.emit(CommsMessage.RES_CRDT_STATE, new Uint8Array(), [sender]);
101
+ }
102
+ else {
103
+ for (const chunk of chunks) {
104
+ DEBUG_NETWORK_MESSAGES() && console.log('[Emiting:]', sender, Date.now());
105
+ binaryMessageBus.emit(CommsMessage.RES_CRDT_STATE, chunk, [sender]);
106
+ }
107
+ }
108
+ });
109
+ binaryMessageBus.on(CommsMessage.RES_CRDT_STATE, async (data, sender) => {
110
+ requestingState = false;
111
+ elapsedTimeSinceRequest = 0;
112
+ if (isServerAtom.getOrNull() || sender !== AUTH_SERVER_PEER_ID)
63
113
  return;
64
114
  DEBUG_NETWORK_MESSAGES() && console.log('[Processing CRDT State]', data.byteLength / 1024, 'KB');
65
- transport.onmessage(data);
115
+ if (data.byteLength > 0) {
116
+ transport.onmessage(serverValidator.processClientMessages(data, sender));
117
+ }
66
118
  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]);
119
+ // IMPORTANT: Only mark room as ready AFTER state is synchronized
120
+ // This ensures comms is truly connected and working
121
+ const realmInfo = RealmInfo.getOrNull(engine.RootEntity);
122
+ if (realmInfo) {
123
+ DEBUG_NETWORK_MESSAGES() && console.log('[isRoomReady] Marking room as ready after state sync');
124
+ isRoomReadyAtom.swap(true);
73
125
  }
74
126
  });
75
- // Process CRDT messages here
76
- binaryMessageBus.on(CommsMessage.CRDT, (value) => {
127
+ // received message from the network
128
+ binaryMessageBus.on(CommsMessage.CRDT, (value, sender) => {
129
+ const isServer = isServerAtom.getOrNull();
77
130
  DEBUG_NETWORK_MESSAGES() &&
78
- console.log(Array.from(serializeCrdtMessages('[NetworkMessage received]:', value, engine)));
79
- transport.onmessage(value);
131
+ console.log(transport.type, ...Array.from(serializeCrdtMessages('[NetworkMessage received]:', value, engine)), isServer);
132
+ if (isServer) {
133
+ transport.onmessage(serverValidator.processServerMessages(value, sender));
134
+ }
135
+ else if (sender === AUTH_SERVER_PEER_ID) {
136
+ // Process network messages from server and convert to regular messages
137
+ transport.onmessage(serverValidator.processClientMessages(value, sender));
138
+ }
80
139
  });
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`);
140
+ // received authoritative message from server - force apply to fix invalid local state
141
+ binaryMessageBus.on(CommsMessage.CRDT_AUTHORITATIVE, (value, sender) => {
142
+ // Only accept authoritative messages from authoritative server
143
+ if (sender !== AUTH_SERVER_PEER_ID)
86
144
  return;
145
+ // DEBUG_NETWORK_MESSAGES() &&
146
+ console.log('[AUTHORITATIVE] Received authoritative message from server:', value.byteLength, 'bytes');
147
+ // Process authoritative messages by forcing them through normal CRDT processing
148
+ // but with a timestamp that's guaranteed to be accepted
149
+ const authoritativeBuffer = serverValidator.processClientMessages(value, sender, true);
150
+ if (authoritativeBuffer.byteLength > 0) {
151
+ // Apply authoritative message through normal transport, but the server's messages
152
+ // should be processed as authoritative with special timestamp handling
153
+ transport.onmessage(authoritativeBuffer);
154
+ DEBUG_NETWORK_MESSAGES() && console.log('[AUTHORITATIVE] Applied server authoritative message to local state');
87
155
  }
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
- }
156
+ });
104
157
  players.onEnterScene((player) => {
105
158
  DEBUG_NETWORK_MESSAGES() && console.log('[onEnterScene]', player.userId);
159
+ if (!isServerAtom.getOrNull() && myProfile.userId === player.userId) {
160
+ requestState();
161
+ }
106
162
  });
107
163
  // Asks for the REQ_CRDT_STATE when its connected to comms
108
164
  RealmInfo.onChange(engine.RootEntity, (value) => {
165
+ const isServer = isServerAtom.getOrNull();
109
166
  if (!value?.isConnectedSceneRoom) {
110
- DEBUG_NETWORK_MESSAGES() && console.log('Disconnected from comms');
111
- stateIsSyncronized = false;
167
+ // Only react when actually transitioning from ready to not ready
168
+ if (isRoomReadyAtom.getOrNull() === true) {
169
+ DEBUG_NETWORK_MESSAGES() && console.log('Disconnected from comms');
170
+ isRoomReadyAtom.swap(false);
171
+ if (!isServer) {
172
+ stateIsSyncronized = false;
173
+ }
174
+ }
112
175
  }
113
176
  if (value?.isConnectedSceneRoom) {
114
- DEBUG_NETWORK_MESSAGES() && console.log('Connected to comms');
177
+ requestState();
178
+ // For servers, mark as ready immediately when connected
179
+ // (servers don't need to sync state from anyone)
180
+ if (isServer && isRoomReadyAtom.getOrNull() === false) {
181
+ DEBUG_NETWORK_MESSAGES() && console.log('[isRoomReady] Server marking room as ready');
182
+ isRoomReadyAtom.swap(true);
183
+ }
184
+ // For clients, room will be marked ready after receiving CRDT state (above)
115
185
  }
116
- if (value?.isConnectedSceneRoom && !stateIsSyncronized) {
117
- void requestState();
186
+ });
187
+ let requestingState = false;
188
+ let elapsedTimeSinceRequest = 0;
189
+ const STATE_REQUEST_RETRY_INTERVAL = 2.0; // seconds
190
+ /**
191
+ * Why we have to request the state if we have a server that can send us the state when we joined?
192
+ * The thing is that when the server detects a new JOIN_PARTICIPANT on livekit room, it sends automatically the state to that peer.
193
+ * But in unity, it takes more time, so that message is not being delivered to the client.
194
+ * So instead, when we are finally connected to the room, we request the state, and then the server answers with the state :)
195
+ *
196
+ * If no response is received within 2 seconds, the request is automatically retried.
197
+ */
198
+ function requestState() {
199
+ if (isServerAtom.getOrNull())
200
+ return;
201
+ if (RealmInfo.getOrNull(engine.RootEntity)?.isConnectedSceneRoom && !requestingState) {
202
+ requestingState = true;
203
+ elapsedTimeSinceRequest = 0;
204
+ DEBUG_NETWORK_MESSAGES() && console.log('Requesting state...');
205
+ binaryMessageBus.emit(CommsMessage.REQ_CRDT_STATE, new Uint8Array());
206
+ }
207
+ }
208
+ // System to retry state request if no response is received within the retry interval
209
+ engine.addSystem((dt) => {
210
+ if (requestingState && !stateIsSyncronized) {
211
+ elapsedTimeSinceRequest += dt;
212
+ if (elapsedTimeSinceRequest >= STATE_REQUEST_RETRY_INTERVAL) {
213
+ DEBUG_NETWORK_MESSAGES() && console.log('State request timed out, retrying...');
214
+ elapsedTimeSinceRequest = 0;
215
+ requestingState = false;
216
+ requestState();
217
+ }
118
218
  }
119
219
  });
120
220
  players.onLeaveScene((userId) => {
@@ -123,52 +223,13 @@ export function addSyncTransport(engine, sendBinary, getUserData) {
123
223
  function isStateSyncronized() {
124
224
  return stateIsSyncronized;
125
225
  }
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
226
  return {
140
227
  ...entityDefinitions,
141
228
  myProfile,
142
- isStateSyncronized
229
+ isStateSyncronized,
230
+ binaryMessageBus,
231
+ eventBus,
232
+ isRoomReadyAtom
143
233
  };
144
234
  }
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=
235
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWVzc2FnZS1idXMtc3luYy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9uZXR3b3JrL21lc3NhZ2UtYnVzLXN5bmMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFzQixTQUFTLEVBQUUsTUFBTSxVQUFVLENBQUE7QUFHeEQsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLFVBQVUsQ0FBQTtBQUNyQyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sU0FBUyxDQUFBO0FBQ3RDLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxZQUFZLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQTtBQUNyRSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sU0FBUyxDQUFBO0FBQ3RDLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxZQUFZLENBQUE7QUFDeEMsT0FBTyxFQUFFLHFCQUFxQixFQUFFLE1BQU0sVUFBVSxDQUFBO0FBRWhELE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLFlBQVksQ0FBQTtBQUMvQyxPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQTtBQUVyRSxPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0sU0FBUyxDQUFBO0FBQzlCLE9BQU8sRUFBRSxhQUFhLEVBQUUsSUFBSSxFQUFFLE1BQU0seUJBQXlCLENBQUE7QUFHN0QsK0NBQStDO0FBQy9DLE1BQU0sQ0FBQyxNQUFNLG1CQUFtQixHQUFHLHNCQUFzQixDQUFBO0FBQ3pELE1BQU0sQ0FBQyxNQUFNLHNCQUFzQixHQUFHLEdBQUcsRUFBRSxDQUFFLFVBQWtCLENBQUMsc0JBQXNCLElBQUksS0FBSyxDQUFBO0FBRS9GLDhDQUE4QztBQUM5QyxNQUFNLGlCQUFpQixHQUFHLEdBQVksRUFBRTtJQUN0QyxJQUFJO1FBQ0YsSUFBSSxPQUFPLFVBQVUsS0FBSyxXQUFXO1lBQUUsT0FBTyxLQUFLLENBQUE7UUFDbkQsTUFBTSxpQkFBaUIsR0FBRyxVQUFzRSxDQUFBO1FBQ2hH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LElBQUksRUFBRSxDQUFBO1lBQzdCLElBQUksdUJBQXVCLElBQUksNEJBQTRCLEVBQUU7Z0JBQzNELHNCQUFzQixFQUFFLElBQUksT0FBTyxDQUFDLEdBQUcsQ0FBQyxzQ0FBc0MsQ0FBQyxDQUFBO2dCQUMvRSx1QkFBdUIsR0FBRyxDQUFDLENBQUE7Z0JBQzNCLGVBQWUsR0FBRyxLQUFLLENBQUE7Z0JBQ3ZCLFlBQVksRUFBRSxDQUFBO2FBQ2Y7U0FDRjtJQUNILENBQUMsQ0FBQyxDQUFBO0lBRUYsT0FBTyxDQUFDLFlBQVksQ0FBQyxDQUFDLE1BQU0sRUFBRSxFQUFFO1FBQzlCLHNCQUFzQixFQUFFLElBQUksT0FBTyxDQUFDLEdBQUcsQ0FBQyxnQkFBZ0IsRUFBRSxNQUFNLENBQUMsQ0FBQTtJQUNuRSxDQUFDLENBQUMsQ0FBQTtJQUVGLFNBQVMsa0JBQWtCO1FBQ3pCLE9BQU8sa0JBQWtCLENBQUE7SUFDM0IsQ0FBQztJQUVELE9BQU87UUFDTCxHQUFHLGlCQUFpQjtRQUNwQixTQUFTO1FBQ1Qsa0JBQWtCO1FBQ2xCLGdCQUFnQjtRQUNoQixRQUFRO1FBQ1IsZUFBZTtLQUNoQixDQUFBO0FBQ0gsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IElFbmdpbmUsIFRyYW5zcG9ydCwgUmVhbG1JbmZvIH0gZnJvbSAnQGRjbC9lY3MnXG5pbXBvcnQgdHlwZSB7IFNlbmRCaW5hcnlSZXF1ZXN0LCBTZW5kQmluYXJ5UmVzcG9uc2UgfSBmcm9tICd+c3lzdGVtL0NvbW11bmljYXRpb25zQ29udHJvbGxlcidcblxuaW1wb3J0IHsgc3luY0ZpbHRlciB9IGZyb20gJy4vZmlsdGVyJ1xuaW1wb3J0IHsgZW5naW5lVG9DcmR0IH0gZnJvbSAnLi9zdGF0ZSdcbmltcG9ydCB7IEJpbmFyeU1lc3NhZ2VCdXMsIENvbW1zTWVzc2FnZSB9IGZyb20gJy4vYmluYXJ5LW1lc3NhZ2UtYnVzJ1xuaW1wb3J0IHsgZmV0Y2hQcm9maWxlIH0gZnJvbSAnLi91dGlscydcbmltcG9ydCB7IGVudGl0eVV0aWxzIH0gZnJvbSAnLi9lbnRpdGllcydcbmltcG9ydCB7IGNyZWF0ZVNlcnZlclZhbGlkYXRvciB9IGZyb20gJy4vc2VydmVyJ1xuaW1wb3J0IHR5cGUgeyBHZXRVc2VyRGF0YVJlcXVlc3QsIEdldFVzZXJEYXRhUmVzcG9uc2UgfSBmcm9tICd+c3lzdGVtL1VzZXJJZGVudGl0eSdcbmltcG9ydCB7IGRlZmluZVBsYXllckhlbHBlciB9IGZyb20gJy4uL3BsYXllcnMnXG5pbXBvcnQgeyBzZXJpYWxpemVDcmR0TWVzc2FnZXMgfSBmcm9tICcuLi9pbnRlcm5hbC90cmFuc3BvcnRzL2xvZ2dlcidcbmltcG9ydCB7IElzU2VydmVyUmVxdWVzdCwgSXNTZXJ2ZXJSZXNwb25zZSB9IGZyb20gJ35zeXN0ZW0vRW5naW5lQXBpJ1xuaW1wb3J0IHsgQXRvbSB9IGZyb20gJy4uL2F0b20nXG5pbXBvcnQgeyBzZXRHbG9iYWxSb29tLCBSb29tIH0gZnJvbSAnLi9ldmVudHMvaW1wbGVtZW50YXRpb24nXG5cbmV4cG9ydCB0eXBlIElQcm9maWxlID0geyBuZXR3b3JrSWQ6IG51bWJlcjsgdXNlcklkOiBzdHJpbmcgfVxuLy8gdXNlciB0aGF0IHdlIGFza2VkIGZvciB0aGUgaW5pdGFsIGNyZHQgc3RhdGVcbmV4cG9ydCBjb25zdCBBVVRIX1NFUlZFUl9QRUVSX0lEID0gJ2F1dGhvcml0YXRpdmUtc2VydmVyJ1xuZXhwb3J0IGNvbnN0IERFQlVHX05FVFdPUktfTUVTU0FHRVMgPSAoKSA9PiAoZ2xvYmFsVGhpcyBhcyBhbnkpLkRFQlVHX05FVFdPUktfTUVTU0FHRVMgPz8gZmFsc2VcblxuLy8gVGVzdCBlbnZpcm9ubWVudCBkZXRlY3Rpb24gd2l0aG91dCAnYXMgYW55J1xuY29uc3QgaXNUZXN0RW52aXJvbm1lbnQgPSAoKTogYm9vbGVhbiA9PiB7XG4gIHRyeSB7XG4gICAgaWYgKHR5cGVvZiBnbG9iYWxUaGlzID09PSAndW5kZWZpbmVkJykgcmV0dXJuIGZhbHNlXG4gICAgY29uc3QgZ2xvYmFsV2l0aFByb2Nlc3MgPSBnbG9iYWxUaGlzIGFzIHVua25vd24gYXMgeyBwcm9jZXNzPzogeyBlbnY/OiB7IE5PREVfRU5WPzogc3RyaW5nIH0gfSB9XG4gICAgcmV0dXJuIGdsb2JhbFdpdGhQcm9jZXNzLnByb2Nlc3M/LmVudj8uTk9ERV9FTlYgPT09ICd0ZXN0J1xuICB9IGNhdGNoIHtcbiAgICByZXR1cm4gZmFsc2VcbiAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gYWRkU3luY1RyYW5zcG9ydChcbiAgZW5naW5lOiBJRW5naW5lLFxuICBzZW5kQmluYXJ5OiAobXNnOiBTZW5kQmluYXJ5UmVxdWVzdCkgPT4gUHJvbWlzZTxTZW5kQmluYXJ5UmVzcG9uc2U+LFxuICBnZXRVc2VyRGF0YTogKHZhbHVlOiBHZXRVc2VyRGF0YVJlcXVlc3QpID0+IFByb21pc2U8R2V0VXNlckRhdGFSZXNwb25zZT4sXG4gIGlzU2VydmVyRm46IChyZXF1ZXN0OiBJc1NlcnZlclJlcXVlc3QpID0+IFByb21pc2U8SXNTZXJ2ZXJSZXNwb25zZT4sXG4gIG5hbWU6IHN0cmluZ1xuKSB7XG4gIC8vIFByb2ZpbGUgSW5mb1xuICBjb25zdCBteVByb2ZpbGU6IElQcm9maWxlID0ge30gYXMgSVByb2ZpbGVcbiAgZmV0Y2hQcm9maWxlKG15UHJvZmlsZSEsIGdldFVzZXJEYXRhKVxuXG4gIGNvbnN0IGlzU2VydmVyQXRvbSA9IEF0b208Ym9vbGVhbj4oKVxuICBjb25zdCBpc1Jvb21SZWFkeUF0b20gPSBBdG9tPGJvb2xlYW4+KGZhbHNlKVxuXG4gIHZvaWQgaXNTZXJ2ZXJGbih7fSkudGhlbigoJDogSXNTZXJ2ZXJSZXNwb25zZSkgPT4ge1xuICAgIHJldHVybiBpc1NlcnZlckF0b20uc3dhcCghISQuaXNTZXJ2ZXIpXG4gIH0pXG5cbiAgLy8gRW50aXR5IHV0aWxzXG4gIGNvbnN0IGVudGl0eURlZmluaXRpb25zID0gZW50aXR5VXRpbHMoZW5naW5lLCBteVByb2ZpbGUpXG5cbiAgLy8gTGlzdCBvZiBNZXNzYWdlQnVzcyBtZXNzc2FnZXMgdG8gYmUgc2VudCBvbiBldmVyeSBmcmFtZSB0byBjb21tc1xuICBjb25zdCBwZW5kaW5nTWVzc2FnZUJ1c01lc3NhZ2VzVG9TZW5kOiB7IGRhdGE6IFVpbnQ4QXJyYXlbXTsgYWRkcmVzczogc3RyaW5nW10gfVtdID0gW11cblxuICBjb25zdCBiaW5hcnlNZXNzYWdlQnVzID0gQmluYXJ5TWVzc2FnZUJ1cygoZGF0YSwgYWRkcmVzcykgPT4ge1xuICAgIHBlbmRpbmdNZXNzYWdlQnVzTWVzc2FnZXNUb1NlbmQucHVzaCh7IGRhdGE6IFtkYXRhXSwgYWRkcmVzczogYWRkcmVzcyA/PyBbXSB9KVxuICB9KVxuXG4gIGZ1bmN0aW9uIGdldE1lc3NhZ2VzVG9TZW5kKCk6IHR5cGVvZiBwZW5kaW5nTWVzc2FnZUJ1c01lc3NhZ2VzVG9TZW5kIHtcbiAgICBjb25zdCBtZXNzYWdlcyA9IFsuLi5wZW5kaW5nTWVzc2FnZUJ1c01lc3NhZ2VzVG9TZW5kXVxuICAgIHBlbmRpbmdNZXNzYWdlQnVzTWVzc2FnZXNUb1NlbmQubGVuZ3RoID0gMFxuICAgIHJldHVybiBtZXNzYWdlc1xuICB9XG4gIGNvbnN0IHBsYXllcnMgPSBkZWZpbmVQbGF5ZXJIZWxwZXIoZW5naW5lKVxuXG4gIGxldCBzdGF0ZUlzU3luY3Jvbml6ZWQgPSBmYWxzZVxuXG4gIC8qKlxuICAgKiBXZSBuZWVkIHRvIHdhaXQgdGlsbCAyIHRpY2tzIHRoYXQgaXMgd2hlbiB0aGUgZW5naW5lIGlzIHJlYWR5IHRvIHNlbmQgbmV3IG1lc3NhZ2VzLlxuICAgKiBUaGUgZmlyc3QgdGljayBpcyBmb3IgdGhlIGNsaWVudCBlbmdpbmUgcHJvY2Vzc2luZyB0aGUgQ1JEVCBtZXNzYWdlcyxcbiAgICogYW5kIHRoZSBzZWNvbmQgb25lIGFyZSB0aGUgbWVzc2FnZXMgY3JlYXRlZCBieSB0aGUgbWFpbigpIGZ1bmN0aW9uLlxuICAgKiBTbyB0byBhdm9pZCBzZW5kaW5nIHRob3NlIG1lc3NhZ2VzLCB0aGF0IGFsbCB0aGUgY2xpZW50cyBoYXZlLCB0aHJvdWdoIHRoZSBuZXR3b3JrIHdlIHB1dCB0aGlzIHZhbGlkYXRpb24gaGVyZS5cbiAgICovXG4gIGxldCB0aWNrID0gMFxuICBjb25zdCBUUkFOU1BPUlRfSU5JVElBTElaRURfTlVNQkVSID0gaXNUZXN0RW52aXJvbm1lbnQoKSA/IDAgOiAyXG4gIC8vIEFkZCBTeW5jIFRyYW5zcG9ydFxuICBjb25zdCB0cmFuc3BvcnQ6IFRyYW5zcG9ydCA9IHtcbiAgICBmaWx0ZXI6IHN5bmNGaWx0ZXIoZW5naW5lKSxcbiAgICBzZW5kOiBhc3luYyAobWVzc2FnZXMpID0+IHtcbiAgICAgIGlmICh0aWNrIDw9IFRSQU5TUE9SVF9JTklUSUFMSVpFRF9OVU1CRVIpIHRpY2srK1xuICAgICAgZm9yIChjb25zdCBtZXNzYWdlIG9mIHRpY2sgPiBUUkFOU1BPUlRfSU5JVElBTElaRURfTlVNQkVSID8gW21lc3NhZ2VzXS5mbGF0KCkgOiBbXSkge1xuICAgICAgICBpZiAobWVzc2FnZS5ieXRlTGVuZ3RoKSB7XG4gICAgICAgICAgREVCVUdfTkVUV09SS19NRVNTQUdFUygpICYmXG4gICAgICAgICAgICBjb25zb2xlLmxvZyguLi5BcnJheS5mcm9tKHNlcmlhbGl6ZUNyZHRNZXNzYWdlcygnW05ldHdvcmtNZXNzYWdlIHNlbnRdOicsIG1lc3NhZ2UsIGVuZ2luZSkpKVxuXG4gICAgICAgICAgLy8gQ29udmVydCByZWd1bGFyIG1lc3NhZ2VzIHRvIG5ldHdvcmsgbWVzc2FnZXMgZm9yIGJyb2FkY2FzdGluZyB3aXRoIGNodW5raW5nXG4gICAgICAgICAgZm9yIChjb25zdCBjaHVuayBvZiBzZXJ2ZXJWYWxpZGF0b3IuY29udmVydFJlZ3VsYXJUb05ldHdvcmtNZXNzYWdlKG1lc3NhZ2UpKSB7XG4gICAgICAgICAgICBiaW5hcnlNZXNzYWdlQnVzLmVtaXQoQ29tbXNNZXNzYWdlLkNSRFQsIGNodW5rKVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgY29uc3QgcGVlck1lc3NhZ2VzID0gZ2V0TWVzc2FnZXNUb1NlbmQoKVxuICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBzZW5kQmluYXJ5KHsgZGF0YTogW10sIHBlZXJEYXRhOiBwZWVyTWVzc2FnZXMgfSlcbiAgICAgIGJpbmFyeU1lc3NhZ2VCdXMuX19wcm9jZXNzTWVzc2FnZXMocmVzcG9uc2UuZGF0YSlcbiAgICB9LFxuICAgIHR5cGU6IG5hbWVcbiAgfVxuXG4gIC8vIFNlcnZlciB2YWxpZGF0aW9uIHNldHVwXG4gIGNvbnN0IHNlcnZlclZhbGlkYXRvciA9IGNyZWF0ZVNlcnZlclZhbGlkYXRvcih7XG4gICAgZW5naW5lLFxuICAgIGJpbmFyeU1lc3NhZ2VCdXNcbiAgfSlcblxuICAvLyBJbml0aWFsaXplIEV2ZW50IEJ1cyB3aXRoIHJlZ2lzdGVyZWQgc2NoZW1hc1xuICBjb25zdCBldmVudEJ1cyA9IG5ldyBSb29tKGVuZ2luZSwgYmluYXJ5TWVzc2FnZUJ1cywgaXNTZXJ2ZXJBdG9tLCBpc1Jvb21SZWFkeUF0b20pXG5cbiAgLy8gU2V0IGdsb2JhbCBldmVudEJ1cyBpbnN0YW5jZVxuICBzZXRHbG9iYWxSb29tKGV2ZW50QnVzKVxuXG4gIGVuZ2luZS5hZGRUcmFuc3BvcnQodHJhbnNwb3J0KVxuICAvLyBFbmQgYWRkIHN5bmMgdHJhbnNwb3J0XG5cbiAgLy8gUmVjZWl2ZSAmIFByb2Nlc3MgQ1JEVF9TVEFURVxuICBiaW5hcnlNZXNzYWdlQnVzLm9uKENvbW1zTWVzc2FnZS5SRVFfQ1JEVF9TVEFURSwgYXN5bmMgKGRhdGEsIHNlbmRlcikgPT4ge1xuICAgIC8vIFJlcXVlc3RzIGFycml2aW5nIGJlZm9yZSByb2xlIHJlc29sdXRpb24gYXJlIHJlY292ZXJlZCBieSB0aGUgcmVxdWVzdGVyJ3MgcmV0cnkuXG4gICAgaWYgKCFpc1NlcnZlckF0b20uZ2V0T3JOdWxsKCkpIHJldHVyblxuXG4gICAgREVCVUdfTkVUV09SS19NRVNTQUdFUygpICYmIGNvbnNvbGUubG9nKCdbUkVRX0NSRFRfU1RBVEVdJywgc2VuZGVyLCBEYXRlLm5vdygpKVxuICAgIGNvbnN0IGNodW5rcyA9IGVuZ2luZVRvQ3JkdChlbmdpbmUpXG4gICAgaWYgKGNodW5rcy5sZW5ndGggPT09IDApIHtcbiAgICAgIERFQlVHX05FVFdPUktfTUVTU0FHRVMoKSAmJiBjb25zb2xlLmxvZygnW0VtaXRpbmcgZW1wdHkgc3RhdGU6XScsIHNlbmRlciwgRGF0ZS5ub3coKSlcbiAgICAgIGJpbmFyeU1lc3NhZ2VCdXMuZW1pdChDb21tc01lc3NhZ2UuUkVTX0NSRFRfU1RBVEUsIG5ldyBVaW50OEFycmF5KCksIFtzZW5kZXJdKVxuICAgIH0gZWxzZSB7XG4gICAgICBmb3IgKGNvbnN0IGNodW5rIG9mIGNodW5rcykge1xuICAgICAgICBERUJVR19ORVRXT1JLX01FU1NBR0VTKCkgJiYgY29uc29sZS5sb2coJ1tFbWl0aW5nOl0nLCBzZW5kZXIsIERhdGUubm93KCkpXG4gICAgICAgIGJpbmFyeU1lc3NhZ2VCdXMuZW1pdChDb21tc01lc3NhZ2UuUkVTX0NSRFRfU1RBVEUsIGNodW5rLCBbc2VuZGVyXSlcbiAgICAgIH1cbiAgICB9XG4gIH0pXG4gIGJpbmFyeU1lc3NhZ2VCdXMub24oQ29tbXNNZXNzYWdlLlJFU19DUkRUX1NUQVRFLCBhc3luYyAoZGF0YSwgc2VuZGVyKSA9PiB7XG4gICAgcmVxdWVzdGluZ1N0YXRlID0gZmFsc2VcbiAgICBlbGFwc2VkVGltZVNpbmNlUmVxdWVzdCA9IDBcbiAgICBpZiAoaXNTZXJ2ZXJBdG9tLmdldE9yTnVsbCgpIHx8IHNlbmRlciAhPT0gQVVUSF9TRVJWRVJfUEVFUl9JRCkgcmV0dXJuXG4gICAgREVCVUdfTkVUV09SS19NRVNTQUdFUygpICYmIGNvbnNvbGUubG9nKCdbUHJvY2Vzc2luZyBDUkRUIFN0YXRlXScsIGRhdGEuYnl0ZUxlbmd0aCAvIDEwMjQsICdLQicpXG4gICAgaWYgKGRhdGEuYnl0ZUxlbmd0aCA+IDApIHtcbiAgICAgIHRyYW5zcG9ydC5vbm1lc3NhZ2UhKHNlcnZlclZhbGlkYXRvci5wcm9jZXNzQ2xpZW50TWVzc2FnZXMoZGF0YSwgc2VuZGVyKSlcbiAgICB9XG4gICAgc3RhdGVJc1N5bmNyb25pemVkID0gdHJ1ZVxuXG4gICAgLy8gSU1QT1JUQU5UOiBPbmx5IG1hcmsgcm9vbSBhcyByZWFkeSBBRlRFUiBzdGF0ZSBpcyBzeW5jaHJvbml6ZWRcbiAgICAvLyBUaGlzIGVuc3VyZXMgY29tbXMgaXMgdHJ1bHkgY29ubmVjdGVkIGFuZCB3b3JraW5nXG4gICAgY29uc3QgcmVhbG1JbmZvID0gUmVhbG1JbmZvLmdldE9yTnVsbChlbmdpbmUuUm9vdEVudGl0eSlcbiAgICBpZiAocmVhbG1JbmZvKSB7XG4gICAgICBERUJVR19ORVRXT1JLX01FU1NBR0VTKCkgJiYgY29uc29sZS5sb2coJ1tpc1Jvb21SZWFkeV0gTWFya2luZyByb29tIGFzIHJlYWR5IGFmdGVyIHN0YXRlIHN5bmMnKVxuICAgICAgaXNSb29tUmVhZHlBdG9tLnN3YXAodHJ1ZSlcbiAgICB9XG4gIH0pXG5cbiAgLy8gcmVjZWl2ZWQgbWVzc2FnZSBmcm9tIHRoZSBuZXR3b3JrXG4gIGJpbmFyeU1lc3NhZ2VCdXMub24oQ29tbXNNZXNzYWdlLkNSRFQsICh2YWx1ZSwgc2VuZGVyKSA9PiB7XG4gICAgY29uc3QgaXNTZXJ2ZXIgPSBpc1NlcnZlckF0b20uZ2V0T3JOdWxsKClcbiAgICBERUJVR19ORVRXT1JLX01FU1NBR0VTKCkgJiZcbiAgICAgIGNvbnNvbGUubG9nKFxuICAgICAgICB0cmFuc3BvcnQudHlwZSxcbiAgICAgICAgLi4uQXJyYXkuZnJvbShzZXJpYWxpemVDcmR0TWVzc2FnZXMoJ1tOZXR3b3JrTWVzc2FnZSByZWNlaXZlZF06JywgdmFsdWUsIGVuZ2luZSkpLFxuICAgICAgICBpc1NlcnZlclxuICAgICAgKVxuICAgIGlmIChpc1NlcnZlcikge1xuICAgICAgdHJhbnNwb3J0Lm9ubWVzc2FnZSEoc2VydmVyVmFsaWRhdG9yLnByb2Nlc3NTZXJ2ZXJNZXNzYWdlcyh2YWx1ZSwgc2VuZGVyKSlcbiAgICB9IGVsc2UgaWYgKHNlbmRlciA9PT0gQVVUSF9TRVJWRVJfUEVFUl9JRCkge1xuICAgICAgLy8gUHJvY2VzcyBuZXR3b3JrIG1lc3NhZ2VzIGZyb20gc2VydmVyIGFuZCBjb252ZXJ0IHRvIHJlZ3VsYXIgbWVzc2FnZXNcbiAgICAgIHRyYW5zcG9ydC5vbm1lc3NhZ2UhKHNlcnZlclZhbGlkYXRvci5wcm9jZXNzQ2xpZW50TWVzc2FnZXModmFsdWUsIHNlbmRlcikpXG4gICAgfVxuICB9KVxuXG4gIC8vIHJlY2VpdmVkIGF1dGhvcml0YXRpdmUgbWVzc2FnZSBmcm9tIHNlcnZlciAtIGZvcmNlIGFwcGx5IHRvIGZpeCBpbnZhbGlkIGxvY2FsIHN0YXRlXG4gIGJpbmFyeU1lc3NhZ2VCdXMub24oQ29tbXNNZXNzYWdlLkNSRFRfQVVUSE9SSVRBVElWRSwgKHZhbHVlLCBzZW5kZXIpID0+IHtcbiAgICAvLyBPbmx5IGFjY2VwdCBhdXRob3JpdGF0aXZlIG1lc3NhZ2VzIGZyb20gYXV0aG9yaXRhdGl2ZSBzZXJ2ZXJcbiAgICBpZiAoc2VuZGVyICE9PSBBVVRIX1NFUlZFUl9QRUVSX0lEKSByZXR1cm5cblxuICAgIC8vIERFQlVHX05FVFdPUktfTUVTU0FHRVMoKSAmJlxuICAgIGNvbnNvbGUubG9nKCdbQVVUSE9SSVRBVElWRV0gUmVjZWl2ZWQgYXV0aG9yaXRhdGl2ZSBtZXNzYWdlIGZyb20gc2VydmVyOicsIHZhbHVlLmJ5dGVMZW5ndGgsICdieXRlcycpXG5cbiAgICAvLyBQcm9jZXNzIGF1dGhvcml0YXRpdmUgbWVzc2FnZXMgYnkgZm9yY2luZyB0aGVtIHRocm91Z2ggbm9ybWFsIENSRFQgcHJvY2Vzc2luZ1xuICAgIC8vIGJ1dCB3aXRoIGEgdGltZXN0YW1wIHRoYXQncyBndWFyYW50ZWVkIHRvIGJlIGFjY2VwdGVkXG4gICAgY29uc3QgYXV0aG9yaXRhdGl2ZUJ1ZmZlciA9IHNlcnZlclZhbGlkYXRvci5wcm9jZXNzQ2xpZW50TWVzc2FnZXModmFsdWUsIHNlbmRlciwgdHJ1ZSlcbiAgICBpZiAoYXV0aG9yaXRhdGl2ZUJ1ZmZlci5ieXRlTGVuZ3RoID4gMCkge1xuICAgICAgLy8gQXBwbHkgYXV0aG9yaXRhdGl2ZSBtZXNzYWdlIHRocm91Z2ggbm9ybWFsIHRyYW5zcG9ydCwgYnV0IHRoZSBzZXJ2ZXIncyBtZXNzYWdlc1xuICAgICAgLy8gc2hvdWxkIGJlIHByb2Nlc3NlZCBhcyBhdXRob3JpdGF0aXZlIHdpdGggc3BlY2lhbCB0aW1lc3RhbXAgaGFuZGxpbmdcbiAgICAgIHRyYW5zcG9ydC5vbm1lc3NhZ2UhKGF1dGhvcml0YXRpdmVCdWZmZXIpXG5cbiAgICAgIERFQlVHX05FVFdPUktfTUVTU0FHRVMoKSAmJiBjb25zb2xlLmxvZygnW0FVVEhPUklUQVRJVkVdIEFwcGxpZWQgc2VydmVyIGF1dGhvcml0YXRpdmUgbWVzc2FnZSB0byBsb2NhbCBzdGF0ZScpXG4gICAgfVxuICB9KVxuXG4gIHBsYXllcnMub25FbnRlclNjZW5lKChwbGF5ZXIpID0+IHtcbiAgICBERUJVR19ORVRXT1JLX01FU1NBR0VTKCkgJiYgY29uc29sZS5sb2coJ1tvbkVudGVyU2NlbmVdJywgcGxheWVyLnVzZXJJZClcbiAgICBpZiAoIWlzU2VydmVyQXRvbS5nZXRPck51bGwoKSAmJiBteVByb2ZpbGUudXNlcklkID09PSBwbGF5ZXIudXNlcklkKSB7XG4gICAgICByZXF1ZXN0U3RhdGUoKVxuICAgIH1cbiAgfSlcblxuICAvLyBBc2tzIGZvciB0aGUgUkVRX0NSRFRfU1RBVEUgd2hlbiBpdHMgY29ubmVjdGVkIHRvIGNvbW1zXG4gIFJlYWxtSW5mby5vbkNoYW5nZShlbmdpbmUuUm9vdEVudGl0eSwgKHZhbHVlKSA9PiB7XG4gICAgY29uc3QgaXNTZXJ2ZXIgPSBpc1NlcnZlckF0b20uZ2V0T3JOdWxsKClcblxuICAgIGlmICghdmFsdWU/LmlzQ29ubmVjdGVkU2NlbmVSb29tKSB7XG4gICAgICAvLyBPbmx5IHJlYWN0IHdoZW4gYWN0dWFsbHkgdHJhbnNpdGlvbmluZyBmcm9tIHJlYWR5IHRvIG5vdCByZWFkeVxuICAgICAgaWYgKGlzUm9vbVJlYWR5QXRvbS5nZXRPck51bGwoKSA9PT0gdHJ1ZSkge1xuICAgICAgICBERUJVR19ORVRXT1JLX01FU1NBR0VTKCkgJiYgY29uc29sZS5sb2coJ0Rpc2Nvbm5lY3RlZCBmcm9tIGNvbW1zJylcbiAgICAgICAgaXNSb29tUmVhZHlBdG9tLnN3YXAoZmFsc2UpXG4gICAgICAgIGlmICghaXNTZXJ2ZXIpIHtcbiAgICAgICAgICBzdGF0ZUlzU3luY3Jvbml6ZWQgPSBmYWxzZVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKHZhbHVlPy5pc0Nvbm5lY3RlZFNjZW5lUm9vbSkge1xuICAgICAgcmVxdWVzdFN0YXRlKClcblxuICAgICAgLy8gRm9yIHNlcnZlcnMsIG1hcmsgYXMgcmVhZHkgaW1tZWRpYXRlbHkgd2hlbiBjb25uZWN0ZWRcbiAgICAgIC8vIChzZXJ2ZXJzIGRvbid0IG5lZWQgdG8gc3luYyBzdGF0ZSBmcm9tIGFueW9uZSlcbiAgICAgIGlmIChpc1NlcnZlciAmJiBpc1Jvb21SZWFkeUF0b20uZ2V0T3JOdWxsKCkgPT09IGZhbHNlKSB7XG4gICAgICAgIERFQlVHX05FVFdPUktfTUVTU0FHRVMoKSAmJiBjb25zb2xlLmxvZygnW2lzUm9vbVJlYWR5XSBTZXJ2ZXIgbWFya2luZyByb29tIGFzIHJlYWR5JylcbiAgICAgICAgaXNSb29tUmVhZHlBdG9tLnN3YXAodHJ1ZSlcbiAgICAgIH1cbiAgICAgIC8vIEZvciBjbGllbnRzLCByb29tIHdpbGwgYmUgbWFya2VkIHJlYWR5IGFmdGVyIHJlY2VpdmluZyBDUkRUIHN0YXRlIChhYm92ZSlcbiAgICB9XG4gIH0pXG5cbiAgbGV0IHJlcXVlc3RpbmdTdGF0ZSA9IGZhbHNlXG4gIGxldCBlbGFwc2VkVGltZVNpbmNlUmVxdWVzdCA9IDBcbiAgY29uc3QgU1RBVEVfUkVRVUVTVF9SRVRSWV9JTlRFUlZBTCA9IDIuMCAvLyBzZWNvbmRzXG5cbiAgLyoqXG4gICAqIFdoeSB3ZSBoYXZlIHRvIHJlcXVlc3QgdGhlIHN0YXRlIGlmIHdlIGhhdmUgYSBzZXJ2ZXIgdGhhdCBjYW4gc2VuZCB1cyB0aGUgc3RhdGUgd2hlbiB3ZSBqb2luZWQ/XG4gICAqIFRoZSB0aGluZyBpcyB0aGF0IHdoZW4gdGhlIHNlcnZlciBkZXRlY3RzIGEgbmV3IEpPSU5fUEFSVElDSVBBTlQgb24gbGl2ZWtpdCByb29tLCBpdCBzZW5kcyBhdXRvbWF0aWNhbGx5IHRoZSBzdGF0ZSB0byB0aGF0IHBlZXIuXG4gICAqIEJ1dCBpbiB1bml0eSwgaXQgdGFrZXMgbW9yZSB0aW1lLCBzbyB0aGF0IG1lc3NhZ2UgaXMgbm90IGJlaW5nIGRlbGl2ZXJlZCB0byB0aGUgY2xpZW50LlxuICAgKiBTbyBpbnN0ZWFkLCB3aGVuIHdlIGFyZSBmaW5hbGx5IGNvbm5lY3RlZCB0byB0aGUgcm9vbSwgd2UgcmVxdWVzdCB0aGUgc3RhdGUsIGFuZCB0aGVuIHRoZSBzZXJ2ZXIgYW5zd2VycyB3aXRoIHRoZSBzdGF0ZSA6KVxuICAgKlxuICAgKiBJZiBubyByZXNwb25zZSBpcyByZWNlaXZlZCB3aXRoaW4gMiBzZWNvbmRzLCB0aGUgcmVxdWVzdCBpcyBhdXRvbWF0aWNhbGx5IHJldHJpZWQuXG4gICAqL1xuICBmdW5jdGlvbiByZXF1ZXN0U3RhdGUoKSB7XG4gICAgaWYgKGlzU2VydmVyQXRvbS5nZXRPck51bGwoKSkgcmV0dXJuXG4gICAgaWYgKFJlYWxtSW5mby5nZXRPck51bGwoZW5naW5lLlJvb3RFbnRpdHkpPy5pc0Nvbm5lY3RlZFNjZW5lUm9vbSAmJiAhcmVxdWVzdGluZ1N0YXRlKSB7XG4gICAgICByZXF1ZXN0aW5nU3RhdGUgPSB0cnVlXG4gICAgICBlbGFwc2VkVGltZVNpbmNlUmVxdWVzdCA9IDBcbiAgICAgIERFQlVHX05FVFdPUktfTUVTU0FHRVMoKSAmJiBjb25zb2xlLmxvZygnUmVxdWVzdGluZyBzdGF0ZS4uLicpXG4gICAgICBiaW5hcnlNZXNzYWdlQnVzLmVtaXQoQ29tbXNNZXNzYWdlLlJFUV9DUkRUX1NUQVRFLCBuZXcgVWludDhBcnJheSgpKVxuICAgIH1cbiAgfVxuXG4gIC8vIFN5c3RlbSB0byByZXRyeSBzdGF0ZSByZXF1ZXN0IGlmIG5vIHJlc3BvbnNlIGlzIHJlY2VpdmVkIHdpdGhpbiB0aGUgcmV0cnkgaW50ZXJ2YWxcbiAgZW5naW5lLmFkZFN5c3RlbSgoZHQ6IG51bWJlcikgPT4ge1xuICAgIGlmIChyZXF1ZXN0aW5nU3RhdGUgJiYgIXN0YXRlSXNTeW5jcm9uaXplZCkge1xuICAgICAgZWxhcHNlZFRpbWVTaW5jZVJlcXVlc3QgKz0gZHRcbiAgICAgIGlmIChlbGFwc2VkVGltZVNpbmNlUmVxdWVzdCA+PSBTVEFURV9SRVFVRVNUX1JFVFJZX0lOVEVSVkFMKSB7XG4gICAgICAgIERFQlVHX05FVFdPUktfTUVTU0FHRVMoKSAmJiBjb25zb2xlLmxvZygnU3RhdGUgcmVxdWVzdCB0aW1lZCBvdXQsIHJldHJ5aW5nLi4uJylcbiAgICAgICAgZWxhcHNlZFRpbWVTaW5jZVJlcXVlc3QgPSAwXG4gICAgICAgIHJlcXVlc3RpbmdTdGF0ZSA9IGZhbHNlXG4gICAgICAgIHJlcXVlc3RTdGF0ZSgpXG4gICAgICB9XG4gICAgfVxuICB9KVxuXG4gIHBsYXllcnMub25MZWF2ZVNjZW5lKCh1c2VySWQpID0+IHtcbiAgICBERUJVR19ORVRXT1JLX01FU1NBR0VTKCkgJiYgY29uc29sZS5sb2coJ1tvbkxlYXZlU2NlbmVdJywgdXNlcklkKVxuICB9KVxuXG4gIGZ1bmN0aW9uIGlzU3RhdGVTeW5jcm9uaXplZCgpIHtcbiAgICByZXR1cm4gc3RhdGVJc1N5bmNyb25pemVkXG4gIH1cblxuICByZXR1cm4ge1xuICAgIC4uLmVudGl0eURlZmluaXRpb25zLFxuICAgIG15UHJvZmlsZSxcbiAgICBpc1N0YXRlU3luY3Jvbml6ZWQsXG4gICAgYmluYXJ5TWVzc2FnZUJ1cyxcbiAgICBldmVudEJ1cyxcbiAgICBpc1Jvb21SZWFkeUF0b21cbiAgfVxufVxuIl19
@@ -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
+ };