UNPKG

websocket13

Version:

Simple WebSocket protocol 13 client with no native or heavy dependencies

743 lines 65.8 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const bytebuffer_1 = __importDefault(require("bytebuffer")); const crypto_1 = require("crypto"); const permessage_deflate_1 = __importDefault(require("permessage-deflate")); const tiny_typed_emitter_1 = require("tiny-typed-emitter"); const websocket_extensions_1 = __importDefault(require("websocket-extensions")); const StreamedIncomingMessage_1 = __importDefault(require("./streams/StreamedIncomingMessage")); const StreamedOutgoingMessage_1 = __importDefault(require("./streams/StreamedOutgoingMessage")); const State_1 = __importDefault(require("./enums/State")); const tls_1 = require("tls"); const StatusCode_1 = __importDefault(require("./enums/StatusCode")); const FrameType_1 = __importDefault(require("./enums/FrameType")); class WebSocketBase extends tiny_typed_emitter_1.TypedEmitter { constructor() { super(); this.state = State_1.default.Closed; this._extensions = new websocket_extensions_1.default(); this._extensions.add(permessage_deflate_1.default); this.protocol = null; this.stats = { tx: { wire: 0, preExt: 0 }, rx: { wire: 0, postExt: 0 } }; this.options = { pingInterval: 10000, pingTimeout: 10000, pingFailures: 3 }; this._data = {}; this._outgoingFrames = []; // holds frame objects which we haven't sent yet this._dataBuffer = Buffer.alloc(0); // holds raw TCP data that we haven't processed yet this._incomingStream = null; // StreamedIncomingMessage object for the current message this._extensionProcessingOutgoingFrameId = 0; } _onConnected() { this._pingFailures = 0; this._queuePing(); } /** * Disconnect the websocket gracefully. * @param {number} [code=StatusCode.NormalClosure] - A value from the StatusCode enum to send to the other side * @param {string} [reason] - An optional reason string to send to the other side */ disconnect(code, reason) { if (this.state == State_1.default.Connecting && this._socket) { this._socket.end(); // @ts-ignore this._socket.destroy(); this.state = State_1.default.Closed; } else if (this.state == State_1.default.Connecting && !this._socket) { this.state = State_1.default.Closing; } else if (this.state == State_1.default.Connected) { code = code || StatusCode_1.default.NormalClosure; reason = reason || ''; let buf = new bytebuffer_1.default(2 + reason.length, bytebuffer_1.default.BIG_ENDIAN); buf.writeUint16(code); buf.writeString(reason); this._sendControl(FrameType_1.default.Control.Close, buf.flip().toBuffer()); this._outgoingFrames = []; // empty the queue; we can't send any more data now this.state = State_1.default.Closing; setTimeout(() => { if (this.state != State_1.default.Closed) { this._closeExtensions(() => { this._socket.end(); }); } }, 5000).unref(); } else { throw new Error('Cannot disconnect a WebSocket that is not connected.'); } } /** * Send some data in a single frame (not streamed). * @param {string|Buffer} data - The data to send. If a string, the data will be sent as UTF-8 text. If a Buffer, it will be sent as binary data. */ send(data) { let opcode = (typeof data === 'string' ? FrameType_1.default.Data.Text : FrameType_1.default.Data.Binary); if (bytebuffer_1.default.isByteBuffer(data)) { data = data.toBuffer(); } else if (typeof data === 'string') { data = Buffer.from(data, 'utf8'); } this._sendFrame({ FIN: true, RSV1: false, RSV2: false, RSV3: false, opcode, payloadLength: data.length, payload: data }); } createMessageStream(type) { let frame = new StreamedOutgoingMessage_1.default(this, type); this._outgoingFrames.push(frame); return frame; } data(key, value) { let val = this._data[key]; if (typeof value === 'undefined') { return val; } this._data[key] = value; return val; } getPeerCertificate(detailed) { if (!(this._socket instanceof tls_1.TLSSocket)) { return null; } let socket = this._socket; return socket.getPeerCertificate(detailed); } getSecurityProtocol() { if (!(this._socket instanceof tls_1.TLSSocket)) { return null; } let socket = this._socket; // @ts-ignore return socket.getProtocol(); } _prepSocketEvents() { this.remoteAddress = this._socket.remoteAddress; this._socket.on('data', (data) => { if ([State_1.default.Connected, State_1.default.Closing, State_1.default.ClosingError].includes(this.state)) { this._handleData(data); } }); this._socket.on('close', () => { this._cleanupTimers(); if (this.state == State_1.default.ClosingError) { this.state = State_1.default.Closed; return; } if (this.state == State_1.default.Closed) { this.emit('debug', 'Socket closed after successful websocket closure.'); return; } let state = this.state; this.state = State_1.default.Closed; this.emit('disconnected', StatusCode_1.default.AbnormalTermination, 'Socket closed', state == State_1.default.Closing); this.emit('disconnect', StatusCode_1.default.AbnormalTermination, 'Socket closed', state == State_1.default.Closing); // save people from typos this._closeExtensions(); this._cleanupTimers(); }); this._socket.on('error', (err) => { if (this.state == State_1.default.Closed || this.state == State_1.default.ClosingError) { // Ignore errors that come after the socket is closed (e.g. ECONNRESET when we respond to Close frames) return; } err.state = this.state; this.state = State_1.default.ClosingError; this._closeExtensions(); this._cleanupTimers(); this.emit('error', err); }); } setTimeout(timeout, callback) { if (this._userTimeout) { clearTimeout(this._userTimeout); } delete this._userTimeout; delete this._userTimeoutMs; if (timeout == 0) { return this; } this._userTimeoutMs = timeout; this._resetUserTimeout(); if (typeof callback === 'function') { this.once('timeout', callback); } } _resetUserTimeout() { if (this._userTimeout) { clearTimeout(this._userTimeout); delete this._userTimeout; } if (this._userTimeoutMs) { this._userTimeout = setTimeout(() => { delete this._userTimeout; this.setTimeout(0); // don't keep triggering timeout this.emit('timeout'); }, this._userTimeoutMs); } } sendPing(callback) { this._pingCallbacks = this._pingCallbacks || {}; let pingData, pingNum; do { pingData = (0, crypto_1.randomBytes)(4); pingNum = pingData.readUInt32BE(0); } while (this._pingCallbacks[pingNum]); // eslint-disable-next-line this._pingCallbacks[pingNum] = callback || function () { }; this._sendFrame({ FIN: true, RSV1: false, RSV2: false, RSV3: false, opcode: FrameType_1.default.Control.Ping, payloadLength: pingData.length, payload: pingData }, true); } _queuePing() { clearTimeout(this._pingTimer); clearTimeout(this._pingTimeout); if (this.state != State_1.default.Connected || !this.options.pingInterval || !this.options.pingTimeout || !this.options.pingFailures) { return; } this._pingTimer = setTimeout(() => { if (this.state != State_1.default.Connected) { return; } let time = Date.now(); this.sendPing(() => { this.emit('latency', Date.now() - time); this._pingFailures = 0; this._queuePing(); }); this._pingTimeout = setTimeout(() => { if (this.state != State_1.default.Connected) { return; } this.emit('debug', `Ping timeout #${this._pingFailures + 1}`); if (++this._pingFailures >= this.options.pingFailures) { this._terminateError(StatusCode_1.default.PolicyViolation, 'Ping timeout'); } else { this._queuePing(); } }, this.options.pingTimeout); }, this.options.pingInterval); } _handleData(data) { if (data && data.length > 0) { this._dataBuffer = Buffer.concat([this._dataBuffer, data]); this._queuePing(); // reset the ping timer } if (this._dataBuffer.length == 0) { return; } let buf = bytebuffer_1.default.wrap(this._dataBuffer, bytebuffer_1.default.BIG_ENDIAN); let frame = null; try { let byte = buf.readUint8(); let fin = !!(byte & (1 << 7)); let rsv1 = !!(byte & (1 << 6)); let rsv2 = !!(byte & (1 << 5)); let rsv3 = !!(byte & (1 << 4)); let opcode = byte & 0x0F; byte = buf.readUint8(); let hasMask = !!(byte & (1 << 7)); let payloadLength = byte & 0x7F; if (payloadLength == 126) { payloadLength = buf.readUint16(); } else if (payloadLength == 127) { payloadLength = parseInt(buf.readUint64(), 10); } let maskKey = null; if (hasMask) { maskKey = buf.readUint32(); } if (buf.remaining() < payloadLength) { return; // We don't have the entire payload yet } let payload = buf.slice(buf.offset, buf.offset + payloadLength).toBuffer(); buf.skip(payloadLength); // got the full frame frame = { FIN: fin, RSV1: rsv1, RSV2: rsv2, RSV3: rsv3, opcode, payloadLength, maskKey, payload }; } catch (ex) { // We don't have the full data yet. No worries. return; } // We have a full frame this._dataBuffer = buf.toBuffer(); this._handleFrame(frame); this._handleData(); } _handleFrame(frame) { // Flags: FIN, RSV1, RSV2, RSV3 // Ints: opcode (4 bits), payloadLength (up to 64 bits), maskKey (32 bits) // Binary: payload let overheadLength = getFrameOverheadLength(frame); this.stats.rx.wire += overheadLength + frame.payload.length; this.stats.rx.postExt += overheadLength; // extensions can't change overhead length let debugMsg = `Got frame ${frame.opcode.toString(16).toUpperCase()}, ${frame.FIN ? 'FIN, ' : ''}`; for (let i = 1; i <= 3; i++) { if (frame['RSV' + i]) { debugMsg += `RSV${i}, `; } } debugMsg += (frame.maskKey ? 'MASK, ' : '') + `payload ${frame.payload.length} bytes`; this.emit('debug', debugMsg); if (this.state != State_1.default.Connected && !((this.state == State_1.default.ClosingError || this.state == State_1.default.Closing) && frame.opcode == FrameType_1.default.Control.Close)) { this.emit('debug', `Got frame ${frame.opcode.toString(16)} while in state ${this.state}`); return; } // The RFC requires us to terminate the connection if we get an unmasked frame from a client or a masked frame from // a server. But in the real world, implementations are bad sometimes so for compatibility's sake, just log it. if ((this._type == 'server' && !frame.maskKey && frame.payload.length > 0) || (this._type == 'client' && frame.maskKey)) { this.emit('debug', `Protocol violation: Received ${frame.maskKey ? 'masked' : 'unmasked'} frame ` + `${frame.opcode.toString(16).toUpperCase()} of length ${frame.payload.length} from ${this._type == 'client' ? 'server' : 'client'}`); } // Unmask if applicable if (frame.maskKey !== null && frame.payload && frame.payload.length > 0) { frame.payload = maskOrUnmask(frame.payload, frame.maskKey); } // Check to make sure RSV bits are valid if (this._extensions && !this._extensions.validFrameRsv(getExtensionFrame(frame))) { this._terminateError(StatusCode_1.default.ProtocolError, 'Unexpected reserved bit set'); return; } let payload; // Is this a control frame? They need to be handled before anything else as they can be interjected between // fragmented message frames. if (frame.opcode & (1 << 3)) { // this is a control frame. if (!frame.FIN) { this._terminateError(StatusCode_1.default.ProtocolError, `Got a fragmented control frame ${frame.opcode.toString(16)}`); return; } if (frame.payload.length > 125) { this._terminateError(StatusCode_1.default.ProtocolError, `Got a control frame ${frame.opcode.toString(16)} with invalid payload length ${frame.payload.length}`); return; } // Run it through extensions this._extensions.processIncomingMessage(getExtensionMessage(frame), (err, msg) => { if (err) { this._terminateError(StatusCode_1.default.ProtocolError, err.message || err); return; } frame = fromExtensionMessage(msg); this.stats.rx.postExt += frame.payload.length; switch (frame.opcode) { case FrameType_1.default.Control.Close: let code = StatusCode_1.default.NoStatusCode; let reason = ''; if (frame.payload && frame.payload.length >= 2) { code = frame.payload.readUInt16BE(0); if (frame.payload.length > 2) { reason = frame.payload.toString('utf8', 2); } } let state = this.state; if (state == State_1.default.Closing || state == State_1.default.ClosingError) { this._cleanupTimers(); this._closeExtensions(() => { this._socket.end(); }); // We're all done here } else { if (code != StatusCode_1.default.NoStatusCode) { payload = new bytebuffer_1.default(2 + reason.length, bytebuffer_1.default.BIG_ENDIAN); payload.writeUint16(code); payload.writeString(reason || ''); } else { payload = new bytebuffer_1.default(0, bytebuffer_1.default.BIG_ENDIAN); // don't send anything back } this._sendControl(FrameType_1.default.Control.Close, payload.flip().toBuffer()); this._cleanupTimers(); this._closeExtensions(() => { this._socket.end(); }); } this.state = State_1.default.Closed; if (state != State_1.default.ClosingError) { this.emit('disconnected', code, reason, state == State_1.default.Closing); this.emit('disconnect', code, reason, state == State_1.default.Closing); // save people from typos } break; case FrameType_1.default.Control.Ping: this._sendControl(FrameType_1.default.Control.Pong, frame.payload); break; case FrameType_1.default.Control.Pong: if (frame.payload && frame.payload.length == 4) { let num = frame.payload.readUInt32BE(0); if (this._pingCallbacks[num]) { this._pingCallbacks[num](); delete this._pingCallbacks[num]; } } break; default: this._terminateError(StatusCode_1.default.UnacceptableDataType, `Unknown control frame type ${frame.opcode.toString(16).toUpperCase()}`); } }); return; } // Sanity checks if (!this._incomingStream && frame.opcode == FrameType_1.default.Continuation) { this._terminateError(StatusCode_1.default.ProtocolError, 'Received continuation frame without initial frame.'); return; } else if (this._incomingStream && frame.opcode != FrameType_1.default.Continuation) { this._terminateError(StatusCode_1.default.ProtocolError, 'Received new message without finishing a fragmented one.'); return; } // this is not a control frame. this._resetUserTimeout(); // Is this the first frame of a fragmented message? if (!frame.FIN && !this._incomingStream) { this.emit('debug', 'Got first frame of fragmented message.'); let dispatch = this.listenerCount('streamedMessage') >= 1 && !frame.RSV1 && !frame.RSV2 && !frame.RSV3; this._incomingStream = new StreamedIncomingMessage_1.default(frame, dispatch); if (dispatch) { this.emit('streamedMessage', frame.opcode, this._incomingStream); } this._incomingStream.on('end', data => { if (!dispatch) { let frame = this._incomingStream.frameHeader; frame.payload = data; frame.payloadLength = frame.payload.length; this._dispatchDataFrame(frame); } }); // record this start frame in stats only if we've dispatched the stream. if we haven't, we'll process the whole // message as one. if (dispatch) { this.stats.rx.postExt += frame.payload.length; } return; } if (frame.opcode == FrameType_1.default.Continuation) { this.emit('debug', 'Got continuation frame'); this._incomingStream._frame(frame); // record this frame in stats only if we've dispatched the stream. if we haven't, we'll process the whole // message as one. if (this._incomingStream._dispatched) { this.stats.rx.postExt += frame.payload.length; } if (frame.FIN) { this._incomingStream = null; } return; } // We know that we have this entire frame now. Let's handle it. this._dispatchDataFrame(frame); } _dispatchDataFrame(frame) { this._extensions.processIncomingMessage(getExtensionMessage(frame), (err, msg) => { if (err) { this._terminateError(StatusCode_1.default.ProtocolError, err.message || err); return; } frame = fromExtensionMessage(msg); this.stats.rx.postExt += frame.payload.length; switch (frame.opcode) { case FrameType_1.default.Data.Text: let utf8 = frame.payload.toString('utf8'); // Check that the UTF-8 is valid if (Buffer.compare(Buffer.from(utf8, 'utf8'), frame.payload) !== 0) { // This is invalid. We must tear down the connection. this._terminateError(StatusCode_1.default.InconsistentData, 'Received invalid UTF-8 data in a text frame.'); return; } this.emit('message', FrameType_1.default.Data.Text, utf8); break; case FrameType_1.default.Data.Binary: this.emit('message', FrameType_1.default.Data.Binary, frame.payload); break; default: this._terminateError(StatusCode_1.default.UnacceptableDataType, `Unknown data frame type ${frame.opcode.toString(16).toUpperCase()}`); } }); } _sendFrame(frame, bypassQueue = false) { // eslint-disable-next-line let self = this; let isControl = !!(frame.opcode & (1 << 3)); if (this.state != State_1.default.Connected && !(this.state == State_1.default.Closing && isControl)) { throw new Error(`Cannot send data while not connected (state ${this.state})`); } if (typeof frame.FIN === 'undefined') { frame.FIN = true; } if (isControl) { if (frame.payload && frame.payload.length > 125) { throw new Error(`Cannot send control frame ${frame.opcode.toString(16).toUpperCase()} with ${frame.payload.length} bytes of payload data. Payload must be 125 bytes or fewer.`); } bypassQueue = true; // we can send control messages whenever } frame.payload = frame.payload || Buffer.alloc(0); let maskKey = frame.maskKey; let fin = frame.FIN; let queueId = null; // Calculate how long this frame would be as it stands now // All frames are at least 2 bytes; byte 1 is FIN, RSV1-3, opcode; byte 2 is MASK bit, payload length let preExtLength = 2 + frame.payload.length; if (frame.maskKey) { preExtLength += 4; // mask keys are always 4 bytes } preExtLength += getExtraPayloadLengthFieldSize(frame.payload.length); this.stats.tx.preExt += preExtLength; if (isControl || !frame.FIN || frame.opcode == 0) { // https://github.com/faye/permessage-deflate-node/issues/6 onExtensionsProcessed(frame); } else { if (!bypassQueue) { queueId = ++this._extensionProcessingOutgoingFrameId; this._outgoingFrames.push(queueId); // What is queueId? It's a placeholder. We want to retain the order guarantee, but we still need to pass this message // to extensions. Those might not call back in order. Consequently, we "reserve the message's place" in the outgoing // queue with a number. That array position will be replaced with the actual message when it's ready. if (queueId >= 4294967295) { // just for fun. this is unlikely to ever really happen. 4294967295 is max uint32 and is totally arbitrary, we can go up to 2^53 this._extensionProcessingOutgoingFrameId = 0; } } this._extensions.processOutgoingMessage(getExtensionMessage(frame), (err, msg) => { if (err) { this._terminateError(StatusCode_1.default.ProtocolError, err.message || err); return; } frame = fromExtensionMessage(msg); frame.maskKey = maskKey; frame.FIN = fin; onExtensionsProcessed(frame); }); } function onExtensionsProcessed(frame) { let debugMsg = `${bypassQueue ? 'Sending' : 'Queueing'} frame ${frame.opcode.toString(16).toUpperCase()}, ${frame.FIN ? 'FIN, ' : ''}`; for (let i = 1; i <= 3; i++) { if (frame['RSV' + i]) { debugMsg += `RSV${i}, `; } } debugMsg += (frame.maskKey ? 'MASK, ' : '') + `payload ${frame.payload.length} bytes`; self.emit('debug', debugMsg); let size = 0; size += 1; // FIN, RSV1, RSV2, RSV3, opcode size += 1; // MASK, payload length size += getExtraPayloadLengthFieldSize(frame.payload.length); if (frame.maskKey) { size += 4; } size += frame.payload.length; let buf = new bytebuffer_1.default(size, bytebuffer_1.default.BIG_ENDIAN); let byte = 0; byte |= (frame.FIN ? 1 : 0) << 7; byte |= (frame.RSV1 ? 1 : 0) << 6; byte |= (frame.RSV2 ? 1 : 0) << 5; byte |= (frame.RSV3 ? 1 : 0) << 4; byte |= frame.opcode & 0x0F; buf.writeUint8(byte); byte = 0; byte |= (frame.maskKey ? 1 : 0) << 7; if (frame.payload.length <= 125) { byte |= frame.payload.length; buf.writeUint8(byte); } else if (frame.payload.length <= 65535) { byte |= 126; buf.writeUint8(byte); buf.writeUint16(frame.payload.length); } else { byte |= 127; buf.writeUint8(byte); buf.writeUint64(frame.payload.length); } if (frame.maskKey) { buf.writeUint32(frame.maskKey); buf.append(maskOrUnmask(frame.payload, frame.maskKey)); } else { buf.append(frame.payload); } // we're done building the buffer, so go ahead and convert it to a node Buffer buf = buf.flip().toBuffer(); self.stats.tx.wire += buf.length; if (bypassQueue) { self._socket.write(buf); } else if (queueId) { // This already has a placeholder in the queue let idx = self._outgoingFrames.indexOf(queueId); if (idx == -1) { self._outgoingFrames.push(buf); } else { self._outgoingFrames[idx] = buf; } } else { // No queue placeholder, just stick it in self._outgoingFrames.push(buf); } self._processQueue(); } } _processQueue() { let frames = this._outgoingFrames.slice(0); while (frames.length > 0) { if (typeof frames[0] === 'number') { // This is a placeholder, so we're done break; } if (frames[0] instanceof StreamedOutgoingMessage_1.default) { if (!frames[0].started) { this.emit('debug', 'Starting StreamedOutgoingMessage'); frames[0]._start(); } if (frames[0].finished) { frames.splice(0, 1); continue; } break; } this._socket.write(frames.splice(0, 1)[0]); } this._outgoingFrames = frames; } _sendControl(opcode, payload) { if (this.state == State_1.default.Closed || !this._socket) { return; } this._sendFrame({ opcode, payload, payloadLength: payload.length, FIN: true, RSV1: false, RSV2: false, RSV3: false }); } _closeError(err) { err.state = this.state; this.state = State_1.default.Closed; this._closeExtensions(); this._cleanupTimers(); if (this._socket) { this._socket.end(); // @ts-ignore this._socket.destroy(); } this.emit('error', err); } _terminateError(code, message) { let err = new Error(message); err.state = this.state; err.code = code; this.disconnect(code, message); this.state = State_1.default.ClosingError; this.emit('error', err); } _cleanupTimers() { clearTimeout(this._pingTimeout); clearTimeout(this._pingTimer); clearTimeout(this._userTimeout); } _closeExtensions(callback) { // eslint-disable-next-line callback = callback || function () { }; try { this._extensions.close(callback); } catch (ex) { callback(); } } } exports.default = WebSocketBase; // Util function maskOrUnmask(data, maskKey) { let key = Buffer.alloc(4); key.writeUInt32BE(maskKey, 0); for (let i = 0; i < data.length; i++) { data[i] ^= key[i % 4]; } return data; } function getExtensionFrame(frame) { return { final: frame.FIN, rsv1: frame.RSV1, rsv2: frame.RSV2, rsv3: frame.RSV3, opcode: frame.opcode, masked: !!frame.maskKey, maskingKey: frame.maskKey, payload: frame.payload }; } function getExtensionMessage(frame) { return { rsv1: frame.RSV1, rsv2: frame.RSV2, rsv3: frame.RSV3, opcode: frame.opcode, data: frame.payload }; } function fromExtensionMessage(msg) { return { FIN: true, RSV1: msg.rsv1, RSV2: msg.rsv2, RSV3: msg.rsv3, opcode: msg.opcode, payloadLength: msg.data.length, payload: msg.data }; } function getFrameOverheadLength(frame) { return 2 // byte 1 = FIN, RSV1-3, opcode; byte 2 = MASK flag, payload length + (frame.maskKey ? 4 : 0) // mask keys are always 4 bytes if present + getExtraPayloadLengthFieldSize(frame.payload.length); } function getExtraPayloadLengthFieldSize(payloadLength) { if (payloadLength >= 126 && payloadLength <= 65535) { return 2; // 16-bit payload length } else if (payloadLength > 65535) { return 8; // 64-bit payload length } else { return 0; // no extra payload length field } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiV2ViU29ja2V0QmFzZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9XZWJTb2NrZXRCYXNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsNERBQW9DO0FBQ3BDLG1DQUFtQztBQUNuQyw0RUFBbUQ7QUFDbkQsMkRBQWdEO0FBQ2hELGdGQUF1RDtBQUV2RCxnR0FBd0U7QUFDeEUsZ0dBQXdFO0FBRXhFLDBEQUFrQztBQVVsQyw2QkFBOEI7QUFDOUIsb0VBQTRDO0FBRTVDLGtFQUEwQztBQUUxQyxNQUFxQixhQUFjLFNBQVEsaUNBQTZCO0lBc0J2RTtRQUNDLEtBQUssRUFBRSxDQUFDO1FBRVIsSUFBSSxDQUFDLEtBQUssR0FBRyxlQUFLLENBQUMsTUFBTSxDQUFDO1FBQzFCLElBQUksQ0FBQyxXQUFXLEdBQUcsSUFBSSw4QkFBbUIsRUFBRSxDQUFDO1FBQzdDLElBQUksQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLDRCQUFpQixDQUFDLENBQUM7UUFDeEMsSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUM7UUFDckIsSUFBSSxDQUFDLEtBQUssR0FBRyxFQUFDLEVBQUUsRUFBRSxFQUFDLElBQUksRUFBRSxDQUFDLEVBQUUsTUFBTSxFQUFFLENBQUMsRUFBQyxFQUFFLEVBQUUsRUFBRSxFQUFDLElBQUksRUFBRSxDQUFDLEVBQUUsT0FBTyxFQUFFLENBQUMsRUFBQyxFQUFDLENBQUM7UUFFbkUsSUFBSSxDQUFDLE9BQU8sR0FBRztZQUNkLFlBQVksRUFBRSxLQUFLO1lBQ25CLFdBQVcsRUFBRSxLQUFLO1lBQ2xCLFlBQVksRUFBRSxDQUFDO1NBQ2YsQ0FBQztRQUVGLElBQUksQ0FBQyxLQUFLLEdBQUcsRUFBRSxDQUFDO1FBQ2hCLElBQUksQ0FBQyxlQUFlLEdBQUcsRUFBRSxDQUFDLENBQUMsZ0RBQWdEO1FBQzNFLElBQUksQ0FBQyxXQUFXLEdBQUcsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxD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