UNPKG

@jsprismarine/client

Version:
195 lines (188 loc) • 24.9 kB
'use strict'; Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: 'Module' } }); const logger = require('@jsprismarine/logger'); const prismarine = require('@jsprismarine/prismarine'); const raknet = require('@jsprismarine/raknet'); const Crypto = require('node:crypto'); const Dgram = require('node:dgram'); const node_events = require('node:events'); const clearIntervalAsync = require('./_virtual/clear-interval-async.cjs.cjs'); const setIntervalAsync = require('./_virtual/set-interval-async.cjs.cjs'); const _interopDefault = e => e && e.__esModule ? e : { default: e }; const Crypto__default = /*#__PURE__*/_interopDefault(Crypto); const Dgram__default = /*#__PURE__*/_interopDefault(Dgram); const getRandomInt = (min, max) => { min = Math.ceil(min); max = Math.floor(max); return Math.floor(Math.random() * (max - min + 1)) + min; }; const PROTOCOL = 10; const DEF_MTU_SIZE = 1455; const RAKNET_TPS = 100; const RAKNET_TICK_LENGTH = 1 / RAKNET_TPS; class Client extends node_events.EventEmitter { clientGUID = Crypto__default.default.randomBytes(8).readBigInt64BE(); logger = new logger.Logger(); address; targetAddress; connection = null; socket = Dgram__default.default.createSocket({ type: "udp4" }); get closed() { return false; } connecting = false; connected = false; offlineHandled = false; loginHandled = false; constructor() { super(); this.address = new raknet.InetAddress("0.0.0.0", getRandomInt(46e3, 49999)); this.socket.bind(this.address.getPort(), this.address.getAddress()); } /** * Creates a packet listener on given address and port. * @param {string} address - The address to listen on. * @param {number} port - The port to listen on. * @returns {Promise<Client>} The client instance. * @public */ async connect(address = "0.0.0.0", port = 19132) { this.targetAddress = new raknet.InetAddress(address, port); this.socket.on("message", (buffer) => { void this.handle(buffer); }); if (this.connection) throw new Error("Already connected/connecting to server."); this.logger.info("JSPrismarine client is now attempting to connect..."); const timer = setIntervalAsync.setIntervalAsyncExports.setIntervalAsync(async () => { if (this.closed) { await clearIntervalAsync.clearIntervalAsyncExports.clearIntervalAsync(timer); return; } if (!this.connecting) { const pk = new raknet.Protocol.UnconnectedPing(); pk.timestamp = BigInt(Date.now()); pk.encode(); await this.sendBuffer(pk.getBuffer()); } if (this.connected && !this.loginHandled) { const pk = new prismarine.Protocol.Packets.LoginPacket(); pk.encode(); const sendPk = new raknet.Protocol.Frame(); sendPk.reliability = 0; sendPk.content = pk.getBuffer(); this.connection.sendFrame(sendPk, raknet.ConnectionPriority.NORMAL); this.loginHandled = true; } this.connection?.update(Date.now()); }, RAKNET_TICK_LENGTH * 1e3); return this; } /** * Handles the incoming buffer. * @param {Buffer} buffer - The buffer to handle. * @private * @internal */ async handle(buffer) { const header = buffer.readUInt8(); if (this.connection && this.offlineHandled) { this.connection.handle(buffer); return; } let buf; switch (header) { case raknet.MessageIdentifiers.UNCONNECTED_PONG: buf = this.handleUnconnectedPong(buffer); await this.sendBuffer(buf); break; case raknet.MessageIdentifiers.OPEN_CONNECTION_REPLY_1: buf = this.handleOpenConnectionReply1(buffer); await this.sendBuffer(buf); break; case raknet.MessageIdentifiers.OPEN_CONNECTION_REPLY_2: this.handleOpenConnectionReply2(buffer); break; default: this.logger.warn(`Unhandled offline packet ID: ${header}`, "Client/handle"); } } handleUnconnectedPong(buffer) { const decodedPacket = new raknet.Protocol.UnconnectedPong(buffer); decodedPacket.decode(); if (!decodedPacket.isValid()) { throw new Error("Received an invalid offline message"); } const packet = new raknet.Protocol.OpenConnectionRequest1(); packet.protocol = PROTOCOL; packet.mtuSize = DEF_MTU_SIZE; packet.encode(); return packet.getBuffer(); } handleOpenConnectionReply1(buffer) { const decodedPacket = new raknet.Protocol.OpenConnectionReply1(buffer); decodedPacket.decode(); if (!decodedPacket.isValid()) { throw new Error("Received an invalid offline message"); } const packet = new raknet.Protocol.OpenConnectionRequest2(); packet.serverAddress = this.targetAddress; packet.mtuSize = DEF_MTU_SIZE; packet.clientGUID = this.clientGUID; packet.encode(); this.connecting = true; this.connection = new raknet.RakNetSession( this, DEF_MTU_SIZE, { address: this.address.getAddress(), port: this.address.getPort(), family: "IPv4", size: 0 }, Crypto.randomBytes(8).readBigInt64BE() ); return packet.getBuffer(); } handleOpenConnectionReply2(buffer) { const decodedPacket = new raknet.Protocol.OpenConnectionReply2(buffer); decodedPacket.decode(); if (!decodedPacket.isValid()) { throw new Error("Received an invalid offline message"); } const packet = new raknet.Protocol.ConnectionRequest(); packet.clientGUID = this.clientGUID; packet.requestTimestamp = BigInt(Date.now()); packet.encode(); const sendPacket = new raknet.Protocol.Frame(); sendPacket.reliability = 0; sendPacket.content = packet.getBuffer(); this.connection?.sendFrame(sendPacket, raknet.ConnectionPriority.NORMAL); this.offlineHandled = true; this.connected = true; } /** * Sends the buffer to the server * * @param buffer */ async sendBuffer(buffer) { this.socket.send( buffer, 0, buffer.byteLength, this.targetAddress.getPort(), this.targetAddress.getAddress() ); } getSocket() { return this.socket; } getAddress() { return this.address; } async removeConnection(_connection, _reason) { throw new Error("Method not implemented."); } } exports.default = Client; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguY2pzLmNqcyIsInNvdXJjZXMiOlsiLi4vc3JjL2luZGV4LnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IExvZ2dlciB9IGZyb20gJ0Bqc3ByaXNtYXJpbmUvbG9nZ2VyJztcbmltcG9ydCB7IFByb3RvY29sIGFzIEpTUFByb3RvY29sIH0gZnJvbSAnQGpzcHJpc21hcmluZS9wcmlzbWFyaW5lJztcbmltcG9ydCB7IENvbm5lY3Rpb25Qcmlvcml0eSwgSW5ldEFkZHJlc3MsIE1lc3NhZ2VJZGVudGlmaWVycywgUHJvdG9jb2wsIFJha05ldFNlc3Npb24gfSBmcm9tICdAanNwcmlzbWFyaW5lL3Jha25ldCc7XG5pbXBvcnQgQ3J5cHRvLCB7IHJhbmRvbUJ5dGVzIH0gZnJvbSAnbm9kZTpjcnlwdG8nO1xuaW1wb3J0IERncmFtLCB7IHR5cGUgU29ja2V0IH0gZnJvbSAnbm9kZTpkZ3JhbSc7XG5pbXBvcnQgeyBFdmVudEVtaXR0ZXIgfSBmcm9tICdub2RlOmV2ZW50cyc7XG5pbXBvcnQgeyBjbGVhckludGVydmFsQXN5bmMsIHNldEludGVydmFsQXN5bmMgfSBmcm9tICdzZXQtaW50ZXJ2YWwtYXN5bmMvZHluYW1pYyc7XG5cbi8vIGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vYS8xNTI3ODIwLzMxNDI1NTNcbmNvbnN0IGdldFJhbmRvbUludCA9IChtaW46IG51bWJlciwgbWF4OiBudW1iZXIpID0+IHtcbiAgICBtaW4gPSBNYXRoLmNlaWwobWluKTtcbiAgICBtYXggPSBNYXRoLmZsb29yKG1heCk7XG4gICAgcmV0dXJuIE1hdGguZmxvb3IoTWF0aC5yYW5kb20oKSAqIChtYXggLSBtaW4gKyAxKSkgKyBtaW47XG59O1xuXG4vLyBNaW5lY3JhZnQgcmVsYXRlZCBwcm90b2NvbFxuY29uc3QgUFJPVE9DT0wgPSAxMDtcblxuLy8gTWF4IG5ldCB0cmFuc2ZlciB1bml0XG5jb25zdCBERUZfTVRVX1NJWkUgPSAxNDU1O1xuXG4vLyBSYWtuZXQgdGlja3NcbmNvbnN0IFJBS05FVF9UUFMgPSAxMDA7XG5jb25zdCBSQUtORVRfVElDS19MRU5HVEggPSAxIC8gUkFLTkVUX1RQUztcblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgQ2xpZW50IGV4dGVuZHMgRXZlbnRFbWl0dGVyIHtcbiAgICBwcml2YXRlIGNsaWVudEdVSUQgPSBDcnlwdG8ucmFuZG9tQnl0ZXMoOCkucmVhZEJpZ0ludDY0QkUoKTtcbiAgICBwcml2YXRlIHJlYWRvbmx5IGxvZ2dlciA9IG5ldyBMb2dnZXIoKTtcbiAgICBwcml2YXRlIHJlYWRvbmx5IGFkZHJlc3M6IEluZXRBZGRyZXNzO1xuICAgIHByaXZhdGUgdGFyZ2V0QWRkcmVzcyE6IEluZXRBZGRyZXNzO1xuICAgIHByaXZhdGUgY29ubmVjdGlvbjogUmFrTmV0U2Vzc2lvbiB8IG51bGwgPSBudWxsO1xuICAgIHByaXZhdGUgcmVhZG9ubHkgc29ja2V0ID0gRGdyYW0uY3JlYXRlU29ja2V0KHsgdHlwZTogJ3VkcDQnIH0pO1xuICAgIHByaXZhdGUgZ2V0IGNsb3NlZCgpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIHByaXZhdGUgY29ubmVjdGluZyA9IGZhbHNlO1xuICAgIHByaXZhdGUgY29ubmVjdGVkID0gZmFsc2U7XG4gICAgcHJpdmF0ZSBvZmZsaW5lSGFuZGxlZCA9IGZhbHNlO1xuICAgIHByaXZhdGUgbG9naW5IYW5kbGVkID0gZmFsc2U7XG5cbiAgICBwdWJsaWMgY29uc3RydWN0b3IoKSB7XG4gICAgICAgIHN1cGVyKCk7XG4gICAgICAgIHRoaXMuYWRkcmVzcyA9IG5ldyBJbmV0QWRkcmVzcygnMC4wLjAuMCcsIGdldFJhbmRvbUludCg0NjAwMCwgNDk5OTkpKTtcbiAgICAgICAgdGhpcy5zb2NrZXQuYmluZCh0aGlzLmFkZHJlc3MuZ2V0UG9ydCgpLCB0aGlzLmFkZHJlc3MuZ2V0QWRkcmVzcygpKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGEgcGFja2V0IGxpc3RlbmVyIG9uIGdpdmVuIGFkZHJlc3MgYW5kIHBvcnQuXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGFkZHJlc3MgLSBUaGUgYWRkcmVzcyB0byBsaXN0ZW4gb24uXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IHBvcnQgLSBUaGUgcG9ydCB0byBsaXN0ZW4gb24uXG4gICAgICogQHJldHVybnMge1Byb21pc2U8Q2xpZW50Pn0gVGhlIGNsaWVudCBpbnN0YW5jZS5cbiAgICAgKiBAcHVibGljXG4gICAgICovXG4gICAgcHVibGljIGFzeW5jIGNvbm5lY3QoYWRkcmVzcyA9ICcwLjAuMC4wJywgcG9ydCA9IDE5MTMyKTogUHJvbWlzZTxDbGllbnQ+IHtcbiAgICAgICAgdGhpcy50YXJnZXRBZGRyZXNzID0gbmV3IEluZXRBZGRyZXNzKGFkZHJlc3MsIHBvcnQpO1xuXG4gICAgICAgIHRoaXMuc29ja2V0Lm9uKCdtZXNzYWdlJywgKGJ1ZmZlcjogQnVmZmVyKSA9PiB7XG4gICAgICAgICAgICB2b2lkIHRoaXMuaGFuZGxlKGJ1ZmZlcik7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmICh0aGlzLmNvbm5lY3Rpb24pIHRocm93IG5ldyBFcnJvcignQWxyZWFkeSBjb25uZWN0ZWQvY29ubmVjdGluZyB0byBzZXJ2ZXIuJyk7XG5cbiAgICAgICAgdGhpcy5sb2dnZXIuaW5mbygnSlNQcmlzbWFyaW5lIGNsaWVudCBpcyBub3cgYXR0ZW1wdGluZyB0byBjb25uZWN0Li4uJyk7XG5cbiAgICAgICAgY29uc3QgdGltZXIgPSBzZXRJbnRlcnZhbEFzeW5jKGFzeW5jICgpID0+IHtcbiAgICAgICAgICAgIGlmICh0aGlzLmNsb3NlZCkge1xuICAgICAgICAgICAgICAgIGF3YWl0IGNsZWFySW50ZXJ2YWxBc3luYyh0aW1lcik7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBTZW5kIGEgY2xpZW50IHBhY2tldCB0byB0aGUgc2VydmVyXG4gICAgICAgICAgICAvLyBzbyB0aGUgc2VydmVyIGdvZXMgaW4gdGFyZ2V0IG1vZGVcbiAgICAgICAgICAgIC8vIGFuZCB0aGUgbG9naW4gcHJvY2VzcyBzdGFydHNcbiAgICAgICAgICAgIGlmICghdGhpcy5jb25uZWN0aW5nKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgcGsgPSBuZXcgUHJvdG9jb2wuVW5jb25uZWN0ZWRQaW5nKCk7XG4gICAgICAgICAgICAgICAgcGsudGltZXN0YW1wID0gQmlnSW50KERhdGUubm93KCkpO1xuICAgICAgICAgICAgICAgIC8vIFRPRE86IGNhbiBiZSBvbWl0dGVkLi4uIHBrLiA9IHRoaXMuY2xpZW50R1VJRDtcbiAgICAgICAgICAgICAgICBway5lbmNvZGUoKTtcbiAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLnNlbmRCdWZmZXIocGsuZ2V0QnVmZmVyKCkpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAodGhpcy5jb25uZWN0ZWQgJiYgIXRoaXMubG9naW5IYW5kbGVkKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgcGsgPSBuZXcgSlNQUHJvdG9jb2wuUGFja2V0cy5Mb2dpblBhY2tldCgpO1xuICAgICAgICAgICAgICAgIHBrLmVuY29kZSgpO1xuXG4gICAgICAgICAgICAgICAgY29uc3Qgc2VuZFBrID0gbmV3IFByb3RvY29sLkZyYW1lKCk7XG4gICAgICAgICAgICAgICAgc2VuZFBrLnJlbGlhYmlsaXR5ID0gMDtcbiAgICAgICAgICAgICAgICBzZW5kUGsuY29udGVudCA9IHBrLmdldEJ1ZmZlcigpO1xuXG4gICAgICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uIS5zZW5kRnJhbWUoc2VuZFBrLCBDb25uZWN0aW9uUHJpb3JpdHkuTk9STUFMKTsgLy8gUGFja2V0IG5lZWRzIHRvIGJlIHNwbGl0dGVkXG4gICAgICAgICAgICAgICAgdGhpcy5sb2dpbkhhbmRsZWQgPSB0cnVlO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB0aGlzLmNvbm5lY3Rpb24/LnVwZGF0ZShEYXRlLm5vdygpKTtcbiAgICAgICAgfSwgUkFLTkVUX1RJQ0tfTEVOR1RIICogMTAwMCk7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEhhbmRsZXMgdGhlIGluY29taW5nIGJ1ZmZlci5cbiAgICAgKiBAcGFyYW0ge0J1ZmZlcn0gYnVmZmVyIC0gVGhlIGJ1ZmZlciB0byBoYW5kbGUuXG4gICAgICogQHByaXZhdGVcbiAgICAgKiBAaW50ZXJuYWxcbiAgICAgKi9cbiAgICBwcml2YXRlIGFzeW5jIGhhbmRsZShidWZmZXI6IEJ1ZmZlcik6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBjb25zdCBoZWFkZXIgPSBidWZmZXIucmVhZFVJbnQ4KCk7IC8vIFJlYWQgcGFja2V0IGhlYWRlclxuXG4gICAgICAgIGlmICh0aGlzLmNvbm5lY3Rpb24gJiYgdGhpcy5vZmZsaW5lSGFuZGxlZCkge1xuICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uLmhhbmRsZShidWZmZXIpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IGJ1ZjtcbiAgICAgICAgc3dpdGNoIChoZWFkZXIpIHtcbiAgICAgICAgICAgIGNhc2UgTWVzc2FnZUlkZW50aWZpZXJzLlVOQ09OTkVDVEVEX1BPTkc6XG4gICAgICAgICAgICAgICAgYnVmID0gdGhpcy5oYW5kbGVVbmNvbm5lY3RlZFBvbmcoYnVmZmVyKTtcbiAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLnNlbmRCdWZmZXIoYnVmKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgTWVzc2FnZUlkZW50aWZpZXJzLk9QRU5fQ09OTkVDVElPTl9SRVBMWV8xOlxuICAgICAgICAgICAgICAgIGJ1ZiA9IHRoaXMuaGFuZGxlT3BlbkNvbm5lY3Rpb25SZXBseTEoYnVmZmVyKTtcbiAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLnNlbmRCdWZmZXIoYnVmKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgTWVzc2FnZUlkZW50aWZpZXJzLk9QRU5fQ09OTkVDVElPTl9SRVBMWV8yOlxuICAgICAgICAgICAgICAgIHRoaXMuaGFuZGxlT3BlbkNvbm5lY3Rpb25SZXBseTIoYnVmZmVyKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAgICAgdGhpcy5sb2dnZXIud2FybihgVW5oYW5kbGVkIG9mZmxpbmUgcGFja2V0IElEOiAke2hlYWRlcn1gLCAnQ2xpZW50L2hhbmRsZScpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHVibGljIGhhbmRsZVVuY29ubmVjdGVkUG9uZyhidWZmZXI6IEJ1ZmZlcik6IEJ1ZmZlciB7XG4gICAgICAgIC8vIERlY29kZSBzZXJ2ZXIgcGFja2V0XG4gICAgICAgIGNvbnN0IGRlY29kZWRQYWNrZXQgPSBuZXcgUHJvdG9jb2wuVW5jb25uZWN0ZWRQb25nKGJ1ZmZlcik7XG4gICAgICAgIGRlY29kZWRQYWNrZXQuZGVjb2RlKCk7XG5cbiAgICAgICAgLy8gQ2hlY2sgcGFja2V0IHZhbGlkaXR5XG4gICAgICAgIC8vIFRvIHJlZmFjdG9yXG4gICAgICAgIGlmICghZGVjb2RlZFBhY2tldC5pc1ZhbGlkKCkpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignUmVjZWl2ZWQgYW4gaW52YWxpZCBvZmZsaW5lIG1lc3NhZ2UnKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEVuY29kZSByZXNwb25zZVxuICAgICAgICBjb25zdCBwYWNrZXQgPSBuZXcgUHJvdG9jb2wuT3BlbkNvbm5lY3Rpb25SZXF1ZXN0MSgpO1xuICAgICAgICBwYWNrZXQucHJvdG9jb2wgPSBQUk9UT0NPTDtcbiAgICAgICAgcGFja2V0Lm10dVNpemUgPSBERUZfTVRVX1NJWkU7XG4gICAgICAgIHBhY2tldC5lbmNvZGUoKTtcblxuICAgICAgICAvLyBVcGRhdGUgc2Vzc2lvbiBzdGF0dXNcbiAgICAgICAgLy8gdGhpcy5zdGF0dXMgPSBDb25uZWN0aW9uU3RhdHVzLlRhcmdldHRlZDtcblxuICAgICAgICByZXR1cm4gcGFja2V0LmdldEJ1ZmZlcigpO1xuICAgIH1cblxuICAgIHB1YmxpYyBoYW5kbGVPcGVuQ29ubmVjdGlvblJlcGx5MShidWZmZXI6IEJ1ZmZlcik6IEJ1ZmZlciB7XG4gICAgICAgIC8vIERlY29kZSBzZXJ2ZXIgcGFja2V0XG4gICAgICAgIGNvbnN0IGRlY29kZWRQYWNrZXQgPSBuZXcgUHJvdG9jb2wuT3BlbkNvbm5lY3Rpb25SZXBseTEoYnVmZmVyKTtcbiAgICAgICAgZGVjb2RlZFBhY2tldC5kZWNvZGUoKTtcblxuICAgICAgICAvLyBDaGVjayBwYWNrZXQgdmFsaWRpdHlcbiAgICAgICAgLy8gVG8gcmVmYWN0b3JcbiAgICAgICAgaWYgKCFkZWNvZGVkUGFja2V0LmlzVmFsaWQoKSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdSZWNlaXZlZCBhbiBpbnZhbGlkIG9mZmxpbmUgbWVzc2FnZScpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gRW5jb2RlIHJlc3BvbnNlXG4gICAgICAgIGNvbnN0IHBhY2tldCA9IG5ldyBQcm90b2NvbC5PcGVuQ29ubmVjdGlvblJlcXVlc3QyKCk7XG4gICAgICAgIHBhY2tldC5zZXJ2ZXJBZGRyZXNzID0gdGhpcy50YXJnZXRBZGRyZXNzO1xuICAgICAgICBwYWNrZXQubXR1U2l6ZSA9IERFRl9NVFVfU0laRTtcbiAgICAgICAgcGFja2V0LmNsaWVudEdVSUQgPSB0aGlzLmNsaWVudEdVSUQ7XG4gICAgICAgIHBhY2tldC5lbmNvZGUoKTtcblxuICAgICAgICAvLyBVcGRhdGUgc2Vzc2lvbiBzdGF0dXNcbiAgICAgICAgdGhpcy5jb25uZWN0aW5nID0gdHJ1ZTtcbiAgICAgICAgLy8gVGhpcy5zdGF0dXMgPSBDb25uZWN0aW9uU3RhdHVzLkNvbm5lY3RlZDtcbiAgICAgICAgdGhpcy5jb25uZWN0aW9uID0gbmV3IFJha05ldFNlc3Npb24oXG4gICAgICAgICAgICB0aGlzIGFzIGFueSxcbiAgICAgICAgICAgIERFRl9NVFVfU0laRSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBhZGRyZXNzOiB0aGlzLmFkZHJlc3MuZ2V0QWRkcmVzcygpLFxuICAgICAgICAgICAgICAgIHBvcnQ6IHRoaXMuYWRkcmVzcy5nZXRQb3J0KCksXG4gICAgICAgICAgICAgICAgZmFtaWx5OiAnSVB2NCcsXG4gICAgICAgICAgICAgICAgc2l6ZTogMFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHJhbmRvbUJ5dGVzKDgpLnJlYWRCaWdJbnQ2NEJFKClcbiAgICAgICAgKTtcblxuICAgICAgICByZXR1cm4gcGFja2V0LmdldEJ1ZmZlcigpO1xuICAgIH1cblxuICAgIHB1YmxpYyBoYW5kbGVPcGVuQ29ubmVjdGlvblJlcGx5MihidWZmZXI6IEJ1ZmZlcik6IHZvaWQge1xuICAgICAgICAvLyBEZWNvZGUgc2VydmVyIHBhY2tldFxuICAgICAgICBjb25zdCBkZWNvZGVkUGFja2V0ID0gbmV3IFByb3RvY29sLk9wZW5Db25uZWN0aW9uUmVwbHkyKGJ1ZmZlcik7XG4gICAgICAgIGRlY29kZWRQYWNrZXQuZGVjb2RlKCk7XG5cbiAgICAgICAgLy8gQ2hlY2sgcGFja2V0IHZhbGlkaXR5XG4gICAgICAgIC8vIFRvIHJlZmFjdG9yXG4gICAgICAgIGlmICghZGVjb2RlZFBhY2tldC5pc1ZhbGlkKCkpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignUmVjZWl2ZWQgYW4gaW52YWxpZCBvZmZsaW5lIG1lc3NhZ2UnKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEVuY29kZSByZXNwb25zZSAoZW5jYXBzdWxhdGVkKVxuICAgICAgICBjb25zdCBwYWNrZXQgPSBuZXcgUHJvdG9jb2wuQ29ubmVjdGlvblJlcXVlc3QoKTtcbiAgICAgICAgcGFja2V0LmNsaWVudEdVSUQgPSB0aGlzLmNsaWVudEdVSUQ7XG4gICAgICAgIHBhY2tldC5yZXF1ZXN0VGltZXN0YW1wID0gQmlnSW50KERhdGUubm93KCkpO1xuICAgICAgICBwYWNrZXQuZW5jb2RlKCk7XG5cbiAgICAgICAgY29uc3Qgc2VuZFBhY2tldCA9IG5ldyBQcm90b2NvbC5GcmFtZSgpO1xuICAgICAgICBzZW5kUGFja2V0LnJlbGlhYmlsaXR5ID0gMDtcbiAgICAgICAgc2VuZFBhY2tldC5jb250ZW50ID0gcGFja2V0LmdldEJ1ZmZlcigpO1xuXG4gICAgICAgIHRoaXMuY29ubmVjdGlvbj8uc2VuZEZyYW1lKHNlbmRQYWNrZXQsIENvbm5lY3Rpb25Qcmlvcml0eS5OT1JNQUwpO1xuXG4gICAgICAgIHRoaXMub2ZmbGluZUhhbmRsZWQgPSB0cnVlO1xuICAgICAgICB0aGlzLmNvbm5lY3RlZCA9IHRydWU7IC8vIFNob3VsZCBiZS4uLiB3ZSBjYW4ndCByZWx5IG9uIGl0XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2VuZHMgdGhlIGJ1ZmZlciB0byB0aGUgc2VydmVyXG4gICAgICpcbiAgICAgKiBAcGFyYW0gYnVmZmVyXG4gICAgICovXG4gICAgcHVibGljIGFzeW5jIHNlbmRCdWZmZXIoYnVmZmVyOiBCdWZmZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgdGhpcy5zb2NrZXQuc2VuZChcbiAgICAgICAgICAgIGJ1ZmZlciBhcyBhbnksXG4gICAgICAgICAgICAwLFxuICAgICAgICAgICAgYnVmZmVyLmJ5dGVMZW5ndGgsXG4gICAgICAgICAgICB0aGlzLnRhcmdldEFkZHJlc3MuZ2V0UG9ydCgpLFxuICAgICAgICAgICAgdGhpcy50YXJnZXRBZGRyZXNzLmdldEFkZHJlc3MoKVxuICAgICAgICApO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXRTb2NrZXQoKTogU29ja2V0IHtcbiAgICAgICAgcmV0dXJuIHRoaXMuc29ja2V0O1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXRBZGRyZXNzKCk6IEluZXRBZGRyZXNzIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuYWRkcmVzcztcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgcmVtb3ZlQ29ubmVjdGlvbihfY29ubmVjdGlvbjogUmFrTmV0U2Vzc2lvbiwgX3JlYXNvbj86IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ01ldGhvZCBub3QgaW1wbGVtZW50ZWQuJyk7XG4gICAgfVxufVxuIl0sIm5hbWVzIjpbIkV2ZW50RW1pdHRlciIsIkNyeXB0byIsIkxvZ2dlciIsIkRncmFtIiwiSW5ldEFkZHJlc3MiLCJzZXRJbnRlcnZhbEFzeW5jIiwiY2xlYXJJbnRlcnZhbEFzeW5jIiwiUHJvdG9jb2wiLCJKU1BQcm90b2NvbCIsIkNvbm5lY3Rpb25Qcmlvcml0eSIsIk1lc3NhZ2VJZGVudGlmaWVycyIsIlJha05ldFNlc3Npb24iLCJyYW5kb21CeXRlcyJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBU0EsTUFBTSxZQUFBLEdBQWUsQ0FBQyxHQUFBLEVBQWEsR0FBZ0IsS0FBQTtBQUMvQyxFQUFNLEdBQUEsR0FBQSxJQUFBLENBQUssS0FBSyxHQUFHLENBQUE7QUFDbkIsRUFBTSxHQUFBLEdBQUEsSUFBQSxDQUFLLE1BQU0sR0FBRyxDQUFBO0FBQ3BCLEVBQU8sT0FBQSxJQUFBLENBQUssTUFBTSxJQUFLLENBQUEsTUFBQSxNQUFZLEdBQU0sR0FBQSxHQUFBLEdBQU0sRUFBRSxDQUFJLEdBQUEsR0FBQTtBQUN6RCxDQUFBO0FBR0EsTUFBTSxRQUFXLEdBQUEsRUFBQTtBQUdqQixNQUFNLFlBQWUsR0FBQSxJQUFBO0FBR3JCLE1BQU0sVUFBYSxHQUFBLEdBQUE7QUFDbkIsTUFBTSxxQkFBcUIsQ0FBSSxHQUFBLFVBQUE7QUFFL0IsTUFBcUIsZUFBZUEsd0JBQWEsQ0FBQTtBQUFBLEVBQ3JDLFVBQWEsR0FBQUMsdUJBQUEsQ0FBTyxXQUFZLENBQUEsQ0FBQyxFQUFFLGNBQWUsRUFBQTtBQUFBLEVBQ3pDLE1BQUEsR0FBUyxJQUFJQyxhQUFP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