@jsprismarine/client
Version:
Minecraft: Bedrock Edition RakNet client
186 lines (183 loc) • 24.2 kB
JavaScript
import { Logger } from '@jsprismarine/logger';
import { Protocol as Protocol$1 } from '@jsprismarine/prismarine';
import { InetAddress, Protocol, ConnectionPriority, MessageIdentifiers, RakNetSession } from '@jsprismarine/raknet';
import Crypto, { randomBytes } from 'node:crypto';
import Dgram from 'node:dgram';
import { EventEmitter } from 'node:events';
import { c as clearIntervalAsyncExports } from './_virtual/clear-interval-async.es.js';
import { s as setIntervalAsyncExports } from './_virtual/set-interval-async.es.js';
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 EventEmitter {
clientGUID = Crypto.randomBytes(8).readBigInt64BE();
logger = new Logger();
address;
targetAddress;
connection = null;
socket = Dgram.createSocket({ type: "udp4" });
get closed() {
return false;
}
connecting = false;
connected = false;
offlineHandled = false;
loginHandled = false;
constructor() {
super();
this.address = new 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 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 = setIntervalAsyncExports.setIntervalAsync(async () => {
if (this.closed) {
await clearIntervalAsyncExports.clearIntervalAsync(timer);
return;
}
if (!this.connecting) {
const pk = new Protocol.UnconnectedPing();
pk.timestamp = BigInt(Date.now());
pk.encode();
await this.sendBuffer(pk.getBuffer());
}
if (this.connected && !this.loginHandled) {
const pk = new Protocol$1.Packets.LoginPacket();
pk.encode();
const sendPk = new Protocol.Frame();
sendPk.reliability = 0;
sendPk.content = pk.getBuffer();
this.connection.sendFrame(sendPk, 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 MessageIdentifiers.UNCONNECTED_PONG:
buf = this.handleUnconnectedPong(buffer);
await this.sendBuffer(buf);
break;
case MessageIdentifiers.OPEN_CONNECTION_REPLY_1:
buf = this.handleOpenConnectionReply1(buffer);
await this.sendBuffer(buf);
break;
case 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 Protocol.UnconnectedPong(buffer);
decodedPacket.decode();
if (!decodedPacket.isValid()) {
throw new Error("Received an invalid offline message");
}
const packet = new Protocol.OpenConnectionRequest1();
packet.protocol = PROTOCOL;
packet.mtuSize = DEF_MTU_SIZE;
packet.encode();
return packet.getBuffer();
}
handleOpenConnectionReply1(buffer) {
const decodedPacket = new Protocol.OpenConnectionReply1(buffer);
decodedPacket.decode();
if (!decodedPacket.isValid()) {
throw new Error("Received an invalid offline message");
}
const packet = new Protocol.OpenConnectionRequest2();
packet.serverAddress = this.targetAddress;
packet.mtuSize = DEF_MTU_SIZE;
packet.clientGUID = this.clientGUID;
packet.encode();
this.connecting = true;
this.connection = new RakNetSession(
this,
DEF_MTU_SIZE,
{
address: this.address.getAddress(),
port: this.address.getPort(),
family: "IPv4",
size: 0
},
randomBytes(8).readBigInt64BE()
);
return packet.getBuffer();
}
handleOpenConnectionReply2(buffer) {
const decodedPacket = new Protocol.OpenConnectionReply2(buffer);
decodedPacket.decode();
if (!decodedPacket.isValid()) {
throw new Error("Received an invalid offline message");
}
const packet = new Protocol.ConnectionRequest();
packet.clientGUID = this.clientGUID;
packet.requestTimestamp = BigInt(Date.now());
packet.encode();
const sendPacket = new Protocol.Frame();
sendPacket.reliability = 0;
sendPacket.content = packet.getBuffer();
this.connection?.sendFrame(sendPacket, 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.");
}
}
export { Client as default };
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguZXMuanMiLCJzb3VyY2VzIjpbIi4uL3NyYy9pbmRleC50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBMb2dnZXIgfSBmcm9tICdAanNwcmlzbWFyaW5lL2xvZ2dlcic7XG5pbXBvcnQgeyBQcm90b2NvbCBhcyBKU1BQcm90b2NvbCB9IGZyb20gJ0Bqc3ByaXNtYXJpbmUvcHJpc21hcmluZSc7XG5pbXBvcnQgeyBDb25uZWN0aW9uUHJpb3JpdHksIEluZXRBZGRyZXNzLCBNZXNzYWdlSWRlbnRpZmllcnMsIFByb3RvY29sLCBSYWtOZXRTZXNzaW9uIH0gZnJvbSAnQGpzcHJpc21hcmluZS9yYWtuZXQnO1xuaW1wb3J0IENyeXB0bywgeyByYW5kb21CeXRlcyB9IGZyb20gJ25vZGU6Y3J5cHRvJztcbmltcG9ydCBEZ3JhbSwgeyB0eXBlIFNvY2tldCB9IGZyb20gJ25vZGU6ZGdyYW0nO1xuaW1wb3J0IHsgRXZlbnRFbWl0dGVyIH0gZnJvbSAnbm9kZTpldmVudHMnO1xuaW1wb3J0IHsgY2xlYXJJbnRlcnZhbEFzeW5jLCBzZXRJbnRlcnZhbEFzeW5jIH0gZnJvbSAnc2V0LWludGVydmFsLWFzeW5jL2R5bmFtaWMnO1xuXG4vLyBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL2EvMTUyNzgyMC8zMTQyNTUzXG5jb25zdCBnZXRSYW5kb21JbnQgPSAobWluOiBudW1iZXIsIG1heDogbnVtYmVyKSA9PiB7XG4gICAgbWluID0gTWF0aC5jZWlsKG1pbik7XG4gICAgbWF4ID0gTWF0aC5mbG9vcihtYXgpO1xuICAgIHJldHVybiBNYXRoLmZsb29yKE1hdGgucmFuZG9tKCkgKiAobWF4IC0gbWluICsgMSkpICsgbWluO1xufTtcblxuLy8gTWluZWNyYWZ0IHJlbGF0ZWQgcHJvdG9jb2xcbmNvbnN0IFBST1RPQ09MID0gMTA7XG5cbi8vIE1heCBuZXQgdHJhbnNmZXIgdW5pdFxuY29uc3QgREVGX01UVV9TSVpFID0gMTQ1NTtcblxuLy8gUmFrbmV0IHRpY2tzXG5jb25zdCBSQUtORVRfVFBTID0gMTAwO1xuY29uc3QgUkFLTkVUX1RJQ0tfTEVOR1RIID0gMSAvIFJBS05FVF9UUFM7XG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIENsaWVudCBleHRlbmRzIEV2ZW50RW1pdHRlciB7XG4gICAgcHJpdmF0ZSBjbGllbnRHVUlEID0gQ3J5cHRvLnJhbmRvbUJ5dGVzKDgpLnJlYWRCaWdJbnQ2NEJFKCk7XG4gICAgcHJpdmF0ZSByZWFkb25seSBsb2dnZXIgPSBuZXcgTG9nZ2VyKCk7XG4gICAgcHJpdmF0ZSByZWFkb25seSBhZGRyZXNzOiBJbmV0QWRkcmVzcztcbiAgICBwcml2YXRlIHRhcmdldEFkZHJlc3MhOiBJbmV0QWRkcmVzcztcbiAgICBwcml2YXRlIGNvbm5lY3Rpb246IFJha05ldFNlc3Npb24gfCBudWxsID0gbnVsbDtcbiAgICBwcml2YXRlIHJlYWRvbmx5IHNvY2tldCA9IERncmFtLmNyZWF0ZVNvY2tldCh7IHR5cGU6ICd1ZHA0JyB9KTtcbiAgICBwcml2YXRlIGdldCBjbG9zZWQoKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGNvbm5lY3RpbmcgPSBmYWxzZTtcbiAgICBwcml2YXRlIGNvbm5lY3RlZCA9IGZhbHNlO1xuICAgIHByaXZhdGUgb2ZmbGluZUhhbmRsZWQgPSBmYWxzZTtcbiAgICBwcml2YXRlIGxvZ2luSGFuZGxlZCA9IGZhbHNlO1xuXG4gICAgcHVibGljIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICBzdXBlcigpO1xuICAgICAgICB0aGlzLmFkZHJlc3MgPSBuZXcgSW5ldEFkZHJlc3MoJzAuMC4wLjAnLCBnZXRSYW5kb21JbnQoNDYwMDAsIDQ5OTk5KSk7XG4gICAgICAgIHRoaXMuc29ja2V0LmJpbmQodGhpcy5hZGRyZXNzLmdldFBvcnQoKSwgdGhpcy5hZGRyZXNzLmdldEFkZHJlc3MoKSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhIHBhY2tldCBsaXN0ZW5lciBvbiBnaXZlbiBhZGRyZXNzIGFuZCBwb3J0LlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBhZGRyZXNzIC0gVGhlIGFkZHJlc3MgdG8gbGlzdGVuIG9uLlxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBwb3J0IC0gVGhlIHBvcnQgdG8gbGlzdGVuIG9uLlxuICAgICAqIEByZXR1cm5zIHtQcm9taXNlPENsaWVudD59IFRoZSBjbGllbnQgaW5zdGFuY2UuXG4gICAgICogQHB1YmxpY1xuICAgICAqL1xuICAgIHB1YmxpYyBhc3luYyBjb25uZWN0KGFkZHJlc3MgPSAnMC4wLjAuMCcsIHBvcnQgPSAxOTEzMik6IFByb21pc2U8Q2xpZW50PiB7XG4gICAgICAgIHRoaXMudGFyZ2V0QWRkcmVzcyA9IG5ldyBJbmV0QWRkcmVzcyhhZGRyZXNzLCBwb3J0KTtcblxuICAgICAgICB0aGlzLnNvY2tldC5vbignbWVzc2FnZScsIChidWZmZXI6IEJ1ZmZlcikgPT4ge1xuICAgICAgICAgICAgdm9pZCB0aGlzLmhhbmRsZShidWZmZXIpO1xuICAgICAgICB9KTtcblxuICAgICAgICBpZiAodGhpcy5jb25uZWN0aW9uKSB0aHJvdyBuZXcgRXJyb3IoJ0FscmVhZHkgY29ubmVjdGVkL2Nvbm5lY3RpbmcgdG8gc2VydmVyLicpO1xuXG4gICAgICAgIHRoaXMubG9nZ2VyLmluZm8oJ0pTUHJpc21hcmluZSBjbGllbnQgaXMgbm93IGF0dGVtcHRpbmcgdG8gY29ubmVjdC4uLicpO1xuXG4gICAgICAgIGNvbnN0IHRpbWVyID0gc2V0SW50ZXJ2YWxBc3luYyhhc3luYyAoKSA9PiB7XG4gICAgICAgICAgICBpZiAodGhpcy5jbG9zZWQpIHtcbiAgICAgICAgICAgICAgICBhd2FpdCBjbGVhckludGVydmFsQXN5bmModGltZXIpO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gU2VuZCBhIGNsaWVudCBwYWNrZXQgdG8gdGhlIHNlcnZlclxuICAgICAgICAgICAgLy8gc28gdGhlIHNlcnZlciBnb2VzIGluIHRhcmdldCBtb2RlXG4gICAgICAgICAgICAvLyBhbmQgdGhlIGxvZ2luIHByb2Nlc3Mgc3RhcnRzXG4gICAgICAgICAgICBpZiAoIXRoaXMuY29ubmVjdGluZykge1xuICAgICAgICAgICAgICAgIGNvbnN0IHBrID0gbmV3IFByb3RvY29sLlVuY29ubmVjdGVkUGluZygpO1xuICAgICAgICAgICAgICAgIHBrLnRpbWVzdGFtcCA9IEJpZ0ludChEYXRlLm5vdygpKTtcbiAgICAgICAgICAgICAgICAvLyBUT0RPOiBjYW4gYmUgb21pdHRlZC4uLiBway4gPSB0aGlzLmNsaWVudEdVSUQ7XG4gICAgICAgICAgICAgICAgcGsuZW5jb2RlKCk7XG4gICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5zZW5kQnVmZmVyKHBrLmdldEJ1ZmZlcigpKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKHRoaXMuY29ubmVjdGVkICYmICF0aGlzLmxvZ2luSGFuZGxlZCkge1xuICAgICAgICAgICAgICAgIGNvbnN0IHBrID0gbmV3IEpTUFByb3RvY29sLlBhY2tldHMuTG9naW5QYWNrZXQoKTtcbiAgICAgICAgICAgICAgICBway5lbmNvZGUoKTtcblxuICAgICAgICAgICAgICAgIGNvbnN0IHNlbmRQayA9IG5ldyBQcm90b2NvbC5GcmFtZSgpO1xuICAgICAgICAgICAgICAgIHNlbmRQay5yZWxpYWJpbGl0eSA9IDA7XG4gICAgICAgICAgICAgICAgc2VuZFBrLmNvbnRlbnQgPSBway5nZXRCdWZmZXIoKTtcblxuICAgICAgICAgICAgICAgIHRoaXMuY29ubmVjdGlvbiEuc2VuZEZyYW1lKHNlbmRQaywgQ29ubmVjdGlvblByaW9yaXR5Lk5PUk1BTCk7IC8vIFBhY2tldCBuZWVkcyB0byBiZSBzcGxpdHRlZFxuICAgICAgICAgICAgICAgIHRoaXMubG9naW5IYW5kbGVkID0gdHJ1ZTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uPy51cGRhdGUoRGF0ZS5ub3coKSk7XG4gICAgICAgIH0sIFJBS05FVF9USUNLX0xFTkdUSCAqIDEwMDApO1xuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBIYW5kbGVzIHRoZSBpbmNvbWluZyBidWZmZXIuXG4gICAgICogQHBhcmFtIHtCdWZmZXJ9IGJ1ZmZlciAtIFRoZSBidWZmZXIgdG8gaGFuZGxlLlxuICAgICAqIEBwcml2YXRlXG4gICAgICogQGludGVybmFsXG4gICAgICovXG4gICAgcHJpdmF0ZSBhc3luYyBoYW5kbGUoYnVmZmVyOiBCdWZmZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgY29uc3QgaGVhZGVyID0gYnVmZmVyLnJlYWRVSW50OCgpOyAvLyBSZWFkIHBhY2tldCBoZWFkZXJcblxuICAgICAgICBpZiAodGhpcy5jb25uZWN0aW9uICYmIHRoaXMub2ZmbGluZUhhbmRsZWQpIHtcbiAgICAgICAgICAgIHRoaXMuY29ubmVjdGlvbi5oYW5kbGUoYnVmZmVyKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGxldCBidWY7XG4gICAgICAgIHN3aXRjaCAoaGVhZGVyKSB7XG4gICAgICAgICAgICBjYXNlIE1lc3NhZ2VJZGVudGlmaWVycy5VTkNPTk5FQ1RFRF9QT05HOlxuICAgICAgICAgICAgICAgIGJ1ZiA9IHRoaXMuaGFuZGxlVW5jb25uZWN0ZWRQb25nKGJ1ZmZlcik7XG4gICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5zZW5kQnVmZmVyKGJ1Zik7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIE1lc3NhZ2VJZGVudGlmaWVycy5PUEVOX0NPTk5FQ1RJT05fUkVQTFlfMTpcbiAgICAgICAgICAgICAgICBidWYgPSB0aGlzLmhhbmRsZU9wZW5Db25uZWN0aW9uUmVwbHkxKGJ1ZmZlcik7XG4gICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5zZW5kQnVmZmVyKGJ1Zik7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIE1lc3NhZ2VJZGVudGlmaWVycy5PUEVOX0NPTk5FQ1RJT05fUkVQTFlfMjpcbiAgICAgICAgICAgICAgICB0aGlzLmhhbmRsZU9wZW5Db25uZWN0aW9uUmVwbHkyKGJ1ZmZlcik7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICAgIHRoaXMubG9nZ2VyLndhcm4oYFVuaGFuZGxlZCBvZmZsaW5lIHBhY2tldCBJRDogJHtoZWFkZXJ9YCwgJ0NsaWVudC9oYW5kbGUnKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHB1YmxpYyBoYW5kbGVVbmNvbm5lY3RlZFBvbmcoYnVmZmVyOiBCdWZmZXIpOiBCdWZmZXIge1xuICAgICAgICAvLyBEZWNvZGUgc2VydmVyIHBhY2tldFxuICAgICAgICBjb25zdCBkZWNvZGVkUGFja2V0ID0gbmV3IFByb3RvY29sLlVuY29ubmVjdGVkUG9uZyhidWZmZXIpO1xuICAgICAgICBkZWNvZGVkUGFja2V0LmRlY29kZSgpO1xuXG4gICAgICAgIC8vIENoZWNrIHBhY2tldCB2YWxpZGl0eVxuICAgICAgICAvLyBUbyByZWZhY3RvclxuICAgICAgICBpZiAoIWRlY29kZWRQYWNrZXQuaXNWYWxpZCgpKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1JlY2VpdmVkIGFuIGludmFsaWQgb2ZmbGluZSBtZXNzYWdlJyk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBFbmNvZGUgcmVzcG9uc2VcbiAgICAgICAgY29uc3QgcGFja2V0ID0gbmV3IFByb3RvY29sLk9wZW5Db25uZWN0aW9uUmVxdWVzdDEoKTtcbiAgICAgICAgcGFja2V0LnByb3RvY29sID0gUFJPVE9DT0w7XG4gICAgICAgIHBhY2tldC5tdHVTaXplID0gREVGX01UVV9TSVpFO1xuICAgICAgICBwYWNrZXQuZW5jb2RlKCk7XG5cbiAgICAgICAgLy8gVXBkYXRlIHNlc3Npb24gc3RhdHVzXG4gICAgICAgIC8vIHRoaXMuc3RhdHVzID0gQ29ubmVjdGlvblN0YXR1cy5UYXJnZXR0ZWQ7XG5cbiAgICAgICAgcmV0dXJuIHBhY2tldC5nZXRCdWZmZXIoKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgaGFuZGxlT3BlbkNvbm5lY3Rpb25SZXBseTEoYnVmZmVyOiBCdWZmZXIpOiBCdWZmZXIge1xuICAgICAgICAvLyBEZWNvZGUgc2VydmVyIHBhY2tldFxuICAgICAgICBjb25zdCBkZWNvZGVkUGFja2V0ID0gbmV3IFByb3RvY29sLk9wZW5Db25uZWN0aW9uUmVwbHkxKGJ1ZmZlcik7XG4gICAgICAgIGRlY29kZWRQYWNrZXQuZGVjb2RlKCk7XG5cbiAgICAgICAgLy8gQ2hlY2sgcGFja2V0IHZhbGlkaXR5XG4gICAgICAgIC8vIFRvIHJlZmFjdG9yXG4gICAgICAgIGlmICghZGVjb2RlZFBhY2tldC5pc1ZhbGlkKCkpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignUmVjZWl2ZWQgYW4gaW52YWxpZCBvZmZsaW5lIG1lc3NhZ2UnKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEVuY29kZSByZXNwb25zZVxuICAgICAgICBjb25zdCBwYWNrZXQgPSBuZXcgUHJvdG9jb2wuT3BlbkNvbm5lY3Rpb25SZXF1ZXN0MigpO1xuICAgICAgICBwYWNrZXQuc2VydmVyQWRkcmVzcyA9IHRoaXMudGFyZ2V0QWRkcmVzcztcbiAgICAgICAgcGFja2V0Lm10dVNpemUgPSBERUZfTVRVX1NJWkU7XG4gICAgICAgIHBhY2tldC5jbGllbnRHVUlEID0gdGhpcy5jbGllbnRHVUlEO1xuICAgICAgICBwYWNrZXQuZW5jb2RlKCk7XG5cbiAgICAgICAgLy8gVXBkYXRlIHNlc3Npb24gc3RhdHVzXG4gICAgICAgIHRoaXMuY29ubmVjdGluZyA9IHRydWU7XG4gICAgICAgIC8vIFRoaXMuc3RhdHVzID0gQ29ubmVjdGlvblN0YXR1cy5Db25uZWN0ZWQ7XG4gICAgICAgIHRoaXMuY29ubmVjdGlvbiA9IG5ldyBSYWtOZXRTZXNzaW9uKFxuICAgICAgICAgICAgdGhpcyBhcyBhbnksXG4gICAgICAgICAgICBERUZfTVRVX1NJWkUsXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgYWRkcmVzczogdGhpcy5hZGRyZXNzLmdldEFkZHJlc3MoKSxcbiAgICAgICAgICAgICAgICBwb3J0OiB0aGlzLmFkZHJlc3MuZ2V0UG9ydCgpLFxuICAgICAgICAgICAgICAgIGZhbWlseTogJ0lQdjQnLFxuICAgICAgICAgICAgICAgIHNpemU6IDBcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICByYW5kb21CeXRlcyg4KS5yZWFkQmlnSW50NjRCRSgpXG4gICAgICAgICk7XG5cbiAgICAgICAgcmV0dXJuIHBhY2tldC5nZXRCdWZmZXIoKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgaGFuZGxlT3BlbkNvbm5lY3Rpb25SZXBseTIoYnVmZmVyOiBCdWZmZXIpOiB2b2lkIHtcbiAgICAgICAgLy8gRGVjb2RlIHNlcnZlciBwYWNrZXRcbiAgICAgICAgY29uc3QgZGVjb2RlZFBhY2tldCA9IG5ldyBQcm90b2NvbC5PcGVuQ29ubmVjdGlvblJlcGx5MihidWZmZXIpO1xuICAgICAgICBkZWNvZGVkUGFja2V0LmRlY29kZSgpO1xuXG4gICAgICAgIC8vIENoZWNrIHBhY2tldCB2YWxpZGl0eVxuICAgICAgICAvLyBUbyByZWZhY3RvclxuICAgICAgICBpZiAoIWRlY29kZWRQYWNrZXQuaXNWYWxpZCgpKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1JlY2VpdmVkIGFuIGludmFsaWQgb2ZmbGluZSBtZXNzYWdlJyk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBFbmNvZGUgcmVzcG9uc2UgKGVuY2Fwc3VsYXRlZClcbiAgICAgICAgY29uc3QgcGFja2V0ID0gbmV3IFByb3RvY29sLkNvbm5lY3Rpb25SZXF1ZXN0KCk7XG4gICAgICAgIHBhY2tldC5jbGllbnRHVUlEID0gdGhpcy5jbGllbnRHVUlEO1xuICAgICAgICBwYWNrZXQucmVxdWVzdFRpbWVzdGFtcCA9IEJpZ0ludChEYXRlLm5vdygpKTtcbiAgICAgICAgcGFja2V0LmVuY29kZSgpO1xuXG4gICAgICAgIGNvbnN0IHNlbmRQYWNrZXQgPSBuZXcgUHJvdG9jb2wuRnJhbWUoKTtcbiAgICAgICAgc2VuZFBhY2tldC5yZWxpYWJpbGl0eSA9IDA7XG4gICAgICAgIHNlbmRQYWNrZXQuY29udGVudCA9IHBhY2tldC5nZXRCdWZmZXIoKTtcblxuICAgICAgICB0aGlzLmNvbm5lY3Rpb24/LnNlbmRGcmFtZShzZW5kUGFja2V0LCBDb25uZWN0aW9uUHJpb3JpdHkuTk9STUFMKTtcblxuICAgICAgICB0aGlzLm9mZmxpbmVIYW5kbGVkID0gdHJ1ZTtcbiAgICAgICAgdGhpcy5jb25uZWN0ZWQgPSB0cnVlOyAvLyBTaG91bGQgYmUuLi4gd2UgY2FuJ3QgcmVseSBvbiBpdFxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNlbmRzIHRoZSBidWZmZXIgdG8gdGhlIHNlcnZlclxuICAgICAqXG4gICAgICogQHBhcmFtIGJ1ZmZlclxuICAgICAqL1xuICAgIHB1YmxpYyBhc3luYyBzZW5kQnVmZmVyKGJ1ZmZlcjogQnVmZmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIHRoaXMuc29ja2V0LnNlbmQoXG4gICAgICAgICAgICBidWZmZXIgYXMgYW55LFxuICAgICAgICAgICAgMCxcbiAgICAgICAgICAgIGJ1ZmZlci5ieXRlTGVuZ3RoLFxuICAgICAgICAgICAgdGhpcy50YXJnZXRBZGRyZXNzLmdldFBvcnQoKSxcbiAgICAgICAgICAgIHRoaXMudGFyZ2V0QWRkcmVzcy5nZXRBZGRyZXNzKClcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0U29ja2V0KCk6IFNvY2tldCB7XG4gICAgICAgIHJldHVybiB0aGlzLnNvY2tldDtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0QWRkcmVzcygpOiBJbmV0QWRkcmVzcyB7XG4gICAgICAgIHJldHVybiB0aGlzLmFkZHJlc3M7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIHJlbW92ZUNvbm5lY3Rpb24oX2Nvbm5lY3Rpb246IFJha05ldFNlc3Npb24sIF9yZWFzb24/OiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdNZXRob2Qgbm90IGltcGxlbWVudGVkLicpO1xuICAgIH1cbn1cbiJdLCJuYW1lcyI6WyJzZXRJbnRlcnZhbEFzeW5jIiwiY2xlYXJJbnRlcnZhbEFzeW5jIiwiSlNQUHJvdG9jb2wiXSwibWFwcGluZ3MiOiI7Ozs7Ozs7OztBQVNBLE1BQU0sWUFBQSxHQUFlLENBQUMsR0FBQSxFQUFhLEdBQWdCLEtBQUE7QUFDL0MsRUFBTSxHQUFBLEdBQUEsSUFBQSxDQUFLLEtBQUssR0FBRyxDQUFBO0FBQ25CLEVBQU0sR0FBQSxHQUFBLElBQUEsQ0FBSyxNQUFNLEdBQUcsQ0FBQTtBQUNwQixFQUFPLE9BQUEsSUFBQSxDQUFLLE1BQU0sSUFBSyxDQUFBLE1BQUEsTUFBWSxHQUFNLEdBQUEsR0FBQSxHQUFNLEVBQUUsQ0FBSSxHQUFBLEdBQUE7QUFDekQsQ0FBQTtBQUdBLE1BQU0sUUFBVyxHQUFBLEVBQUE7QUFHakIsTUFBTSxZQUFlLEdBQUEsSUFBQTtBQUdyQixNQUFNLFVBQWEsR0FBQSxHQUFBO0FBQ25CLE1BQU0scUJBQXFCLENBQUksR0FBQSxVQUFBO0FBRS9CLE1BQXFCLGVBQWUsWUFBYSxDQUFBO0FBQUEsRUFDckMsVUFBYSxHQUFBLE1BQUEsQ0FBTyxXQUFZLENBQUEsQ0FBQyxFQUFFLGNBQWUsRUFBQTtBQUFBLEVBQ3pDLE1BQUEsR0FBUyxJQUFJLE1BQU8sRUFBQTtBQUFBLEVBQ3BCLE9BQUE7QUFBQSxFQUNULGFBQUE7QUFBQSxFQUNBLFVBQW1DLEdBQUEsSUFBQTtBQUFBLEVBQzFCLFNBQVMsS0FBTSxDQUFBLFlBQUEsQ0FBYSxFQUFFLElBQUEsRUFBTSxRQUFRLENBQUE7QUFBQSxFQUM3RCxJQUFZLE1BQVMsR0FBQTtBQUNq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