@jsprismarine/prismarine
Version:
Dedicated Minecraft Bedrock Edition server written in TypeScript
143 lines (142 loc) • 16.6 kB
JavaScript
;
Object.defineProperties(exports, {
__esModule: { value: true },
[Symbol.toStringTag]: { value: "Module" }
});
const require_runtime = require("../../_virtual/_rolldown/runtime.cjs.cjs");
const require_block_BlockMappings = require("../../block/BlockMappings.cjs.cjs");
const require_world_chunk_SubChunk = require("./SubChunk.cjs.cjs");
let _jsprismarine_jsbinaryutils = require("@jsprismarine/jsbinaryutils");
_jsprismarine_jsbinaryutils = require_runtime.__toESM(_jsprismarine_jsbinaryutils, 1);
let _jsprismarine_math = require("@jsprismarine/math");
//#region src/world/chunk/Chunk.ts
var MAX_SUBCHUNKS = 16;
var Chunk = class Chunk {
x;
z;
hasChanged;
subChunks = /* @__PURE__ */ new Map();
static EMPTY_SUBCHUNK = new require_world_chunk_SubChunk.default();
constructor(chunkX = 0, chunkZ = 0, _subChunks = /* @__PURE__ */ new Map()) {
this.x = chunkX;
this.z = chunkZ;
this.hasChanged = false;
}
getX() {
return this.x;
}
getZ() {
return this.z;
}
getHasChanged() {
return this.hasChanged;
}
getHeight() {
return this.subChunks.size;
}
/**
* Returns the highest empty sub chunk (so we don't send empty sub chunks).
* @returns {number} The highest empty sub chunk.
*/
getTopEmpty() {
let topEmpty = MAX_SUBCHUNKS - 1;
while (topEmpty >= 0 && !this.subChunks.has(topEmpty) || this.subChunks.has(topEmpty) && this.subChunks.get(topEmpty).isEmpty()) topEmpty--;
return ++topEmpty;
}
/**
* Returns the Chunk slice at the given layer.
* @param {number} y - The layer to get.
*/
getSubChunk(y) {
if (y < 0 || y > MAX_SUBCHUNKS) throw new Error(`Invalid subchunk height: ${y}`);
return this.subChunks.get(y) ?? null;
}
getOrCreateSubChunk(y) {
const subChunk = new require_world_chunk_SubChunk.default();
this.subChunks.set(y, subChunk);
return subChunk;
}
getSubChunks() {
return this.subChunks;
}
getHighestBlockAt(_x, _z) {
return 100;
}
/**
* Returns block legacy id (DATA) in the corresponding sub chunk.
* Use world to get the actual block instance (this is to keep code clean).
* @param {Vector3 | number} x - block x.
* @param {number} [y=0] - block y.
* @param {number} [z=0] - block z.
* @param {number} [layer=0] - block storage layer (0 for blocks, 1 for liquids).
*/
getBlock(x, y = 0, z = 0, layer = 0) {
if (x instanceof _jsprismarine_math.Vector3) return this.getBlock(x.getX(), x.getY(), x.getZ(), layer);
const subChunk = this.getSubChunk(Math.floor(y / 16));
if (!subChunk) return require_block_BlockMappings.BlockMappings.getLegacyId(require_block_BlockMappings.BlockMappings.getRuntimeId("minecraft:air"));
return subChunk.getBlock(x, y & 15, z, layer);
}
/**
* Sets a block into the chunk by its runtime Id.
* @param {number} x - block x
* @param {number} y - block y
* @param {number} z - block z
* @param {Block} block - block to set
* @param {number} [layer=0] - block storage layer (0 for blocks, 1 for liquids)
*/
setBlock(x, y, z, block, layer = 0) {
let subChunk = this.getSubChunk(Math.floor(y / 16));
if (!subChunk) subChunk = this.getOrCreateSubChunk(y >> 4);
subChunk.setBlock(x, y & 15, z, require_block_BlockMappings.BlockMappings.getRuntimeId(block.getName()), layer);
this.hasChanged = true;
}
/**
* Helper method used to hash into a single 64 bits integer
* both Chunk X and Z coordinates.
* @param {number} chunkX - Target Chunk X coordinate.
* @param {number} chunkZ - Target Chunk Z coordinate.
* @returns {bigint} A 64 bit intger containing a hash of X and Z.
*/
static packXZ(chunkX, chunkZ) {
return (BigInt(chunkX) & 4294967295n) << 32n | BigInt(chunkZ) & 4294967295n;
}
/**
* Helper method used to decode a 64 bit hash containing
* both Chunk X and Z coordinates.
* @param {bigint} packed - Target Chunk coordinate hash.
* @returns {number[]} An array containing decoded Chunk X and Z coordinates.
*/
static unpackXZ(packed) {
return [Number(BigInt.asIntN(32, packed >> 32n)), Number(BigInt.asIntN(32, packed & 4294967295n))];
}
networkSerialize() {
const stream = new _jsprismarine_jsbinaryutils.default();
for (let y = 0; y < 4; ++y) {
stream.writeByte(8);
stream.writeByte(0);
}
for (let y = 0; y < this.getTopEmpty(); ++y) (this.subChunks.get(y) ?? Chunk.EMPTY_SUBCHUNK).networkSerialize(stream);
for (let i = 0; i < 24; i++) {
stream.writeByte(0);
stream.writeUnsignedVarInt(2);
}
stream.writeByte(0);
return stream.getBuffer();
}
/**
* Deserialize network stream into chunk
* useful for client applications and/or our Filesystem impl
* @param {BinaryStream} stream - the network stream
* @param {number} [x] - the chunk x coordinate
* @param {number} [z] - the chunk z coordinate
*/
static networkDeserialize(stream, x, z) {
stream.read(8);
const subChunks = /* @__PURE__ */ new Map();
for (let i = 0; i < MAX_SUBCHUNKS; i++) subChunks.set(i, require_world_chunk_SubChunk.default.networkDeserialize(stream));
return new Chunk(x, z, subChunks);
}
};
//#endregion
exports.default = Chunk;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ2h1bmsuY2pzLmNqcyIsIm5hbWVzIjpbXSwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvd29ybGQvY2h1bmsvQ2h1bmsudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHR5cGUgeyBMZWdhY3lJZCB9IGZyb20gJy4uLy4uL2Jsb2NrL0Jsb2NrTWFwcGluZ3MnO1xuaW1wb3J0IHsgQmxvY2tNYXBwaW5ncyB9IGZyb20gJy4uLy4uL2Jsb2NrL0Jsb2NrTWFwcGluZ3MnO1xuXG5pbXBvcnQgQmluYXJ5U3RyZWFtIGZyb20gJ0Bqc3ByaXNtYXJpbmUvanNiaW5hcnl1dGlscyc7XG5pbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnQGpzcHJpc21hcmluZS9tYXRoJztcbmltcG9ydCB0eXBlIHsgQmxvY2sgfSBmcm9tICcuLi8uLi9ibG9jay9CbG9jayc7XG5pbXBvcnQgU3ViQ2h1bmsgZnJvbSAnLi9TdWJDaHVuayc7XG5cbmNvbnN0IE1BWF9TVUJDSFVOS1MgPSAxNjtcblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgQ2h1bmsge1xuICAgIHByaXZhdGUgeDogbnVtYmVyO1xuICAgIHByaXZhdGUgejogbnVtYmVyO1xuICAgIHByaXZhdGUgaGFzQ2hhbmdlZDogYm9vbGVhbjtcblxuICAgIHByaXZhdGUgc3ViQ2h1bmtzOiBNYXA8bnVtYmVyLCBTdWJDaHVuaz4gPSBuZXcgTWFwKCk7XG4gICAgcHJpdmF0ZSBzdGF0aWMgcmVhZG9ubHkgRU1QVFlfU1VCQ0hVTksgPSBuZXcgU3ViQ2h1bmsoKTtcblxuICAgIHB1YmxpYyBjb25zdHJ1Y3RvcihjaHVua1ggPSAwLCBjaHVua1ogPSAwLCBfc3ViQ2h1bmtzOiBNYXA8bnVtYmVyLCBTdWJDaHVuaz4gPSBuZXcgTWFwKCkpIHtcbiAgICAgICAgdGhpcy54ID0gY2h1bmtYO1xuICAgICAgICB0aGlzLnogPSBjaHVua1o7XG4gICAgICAgIHRoaXMuaGFzQ2hhbmdlZCA9IGZhbHNlO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXRYKCk6IG51bWJlciB7XG4gICAgICAgIHJldHVybiB0aGlzLng7XG4gICAgfVxuXG4gICAgcHVibGljIGdldFooKTogbnVtYmVyIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuejtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0SGFzQ2hhbmdlZCgpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuaGFzQ2hhbmdlZDtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0SGVpZ2h0KCk6IG51bWJlciB7XG4gICAgICAgIHJldHVybiB0aGlzLnN1YkNodW5rcy5zaXplO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIGhpZ2hlc3QgZW1wdHkgc3ViIGNodW5rIChzbyB3ZSBkb24ndCBzZW5kIGVtcHR5IHN1YiBjaHVua3MpLlxuICAgICAqIEByZXR1cm5zIHtudW1iZXJ9IFRoZSBoaWdoZXN0IGVtcHR5IHN1YiBjaHVuay5cbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0VG9wRW1wdHkoKTogbnVtYmVyIHtcbiAgICAgICAgbGV0IHRvcEVtcHR5ID0gTUFYX1NVQkNIVU5LUyAtIDE7XG4gICAgICAgIHdoaWxlIChcbiAgICAgICAgICAgICh0b3BFbXB0eSA+PSAwICYmICF0aGlzLnN1YkNodW5rcy5oYXModG9wRW1wdHkpKSB8fFxuICAgICAgICAgICAgKHRoaXMuc3ViQ2h1bmtzLmhhcyh0b3BFbXB0eSkgJiYgdGhpcy5zdWJDaHVua3MuZ2V0KHRvcEVtcHR5KSEuaXNFbXB0eSgpKVxuICAgICAgICApIHtcbiAgICAgICAgICAgIHRvcEVtcHR5LS07XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuICsrdG9wRW1wdHk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgQ2h1bmsgc2xpY2UgYXQgdGhlIGdpdmVuIGxheWVyLlxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSB5IC0gVGhlIGxheWVyIHRvIGdldC5cbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0U3ViQ2h1bmsoeTogbnVtYmVyKTogU3ViQ2h1bmsgfCBudWxsIHtcbiAgICAgICAgaWYgKHkgPCAwIHx8IHkgPiBNQVhfU1VCQ0hVTktTKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgc3ViY2h1bmsgaGVpZ2h0OiAke3l9YCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXMuc3ViQ2h1bmtzLmdldCh5KSA/PyBudWxsO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXRPckNyZWF0ZVN1YkNodW5rKHk6IG51bWJlcik6IFN1YkNodW5rIHtcbiAgICAgICAgY29uc3Qgc3ViQ2h1bmsgPSBuZXcgU3ViQ2h1bmsoKTtcbiAgICAgICAgdGhpcy5zdWJDaHVua3Muc2V0KHksIHN1YkNodW5rKTtcbiAgICAgICAgcmV0dXJuIHN1YkNodW5rO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXRTdWJDaHVua3MoKTogTWFwPG51bWJlciwgU3ViQ2h1bms+IHtcbiAgICAgICAgcmV0dXJuIHRoaXMuc3ViQ2h1bmtzO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXRIaWdoZXN0QmxvY2tBdChfeDogbnVtYmVyLCBfejogbnVtYmVyKTogbnVtYmVyIHtcbiAgICAgICAgcmV0dXJuIDEwMDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIGJsb2NrIGxlZ2FjeSBpZCAoREFUQSkgaW4gdGhlIGNvcnJlc3BvbmRpbmcgc3ViIGNodW5rLlxuICAgICAqIFVzZSB3b3JsZCB0byBnZXQgdGhlIGFjdHVhbCBibG9jayBpbnN0YW5jZSAodGhpcyBpcyB0byBrZWVwIGNvZGUgY2xlYW4pLlxuICAgICAqIEBwYXJhbSB7VmVjdG9yMyB8IG51bWJlcn0geCAtIGJsb2NrIHguXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IFt5PTBdIC0gYmxvY2sgeS5cbiAgICAgKiBAcGFyYW0ge251bWJlcn0gW3o9MF0gLSBibG9jayB6LlxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbbGF5ZXI9MF0gLSBibG9jayBzdG9yYWdlIGxheWVyICgwIGZvciBibG9ja3MsIDEgZm9yIGxpcXVpZHMpLlxuICAgICAqL1xuICAgIHB1YmxpYyBnZXRCbG9jayh4OiBWZWN0b3IzIHwgbnVtYmVyLCB5OiBudW1iZXIgPSAwLCB6OiBudW1iZXIgPSAwLCBsYXllciA9IDApOiBMZWdhY3lJZCB7XG4gICAgICAgIGlmICh4IGluc3RhbmNlb2YgVmVjdG9yMykge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuZ2V0QmxvY2soeC5nZXRYKCksIHguZ2V0WSgpLCB4LmdldFooKSwgbGF5ZXIpO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3Qgc3ViQ2h1bmsgPSB0aGlzLmdldFN1YkNodW5rKE1hdGguZmxvb3IoeSAvIDE2KSk7XG4gICAgICAgIGlmICghc3ViQ2h1bmspIHJldHVybiBCbG9ja01hcHBpbmdzLmdldExlZ2FjeUlkKEJsb2NrTWFwcGluZ3MuZ2V0UnVudGltZUlkKCdtaW5lY3JhZnQ6YWlyJykpO1xuICAgICAgICByZXR1cm4gc3ViQ2h1bmsuZ2V0QmxvY2soeCwgeSAmIDB4ZiwgeiwgbGF5ZXIpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNldHMgYSBibG9jayBpbnRvIHRoZSBjaHVuayBieSBpdHMgcnVudGltZSBJZC5cbiAgICAgKiBAcGFyYW0ge251bWJlcn0geCAtIGJsb2NrIHhcbiAgICAgKiBAcGFyYW0ge251bWJlcn0geSAtIGJsb2NrIHlcbiAgICAgKiBAcGFyYW0ge251bWJlcn0geiAtIGJsb2NrIHpcbiAgICAgKiBAcGFyYW0ge0Jsb2NrfSBibG9jayAtIGJsb2NrIHRvIHNldFxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbbGF5ZXI9MF0gLSBibG9jayBzdG9yYWdlIGxheWVyICgwIGZvciBibG9ja3MsIDEgZm9yIGxpcXVpZHMpXG4gICAgICovXG4gICAgcHVibGljIHNldEJsb2NrKHg6IG51bWJlciwgeTogbnVtYmVyLCB6OiBudW1iZXIsIGJsb2NrOiBCbG9jaywgbGF5ZXIgPSAwKTogdm9pZCB7XG4gICAgICAgIGxldCBzdWJDaHVuayA9IHRoaXMuZ2V0U3ViQ2h1bmsoTWF0aC5mbG9vcih5IC8gMTYpKTtcbiAgICAgICAgaWYgKCFzdWJDaHVuaykgc3ViQ2h1bmsgPSB0aGlzLmdldE9yQ3JlYXRlU3ViQ2h1bmsoeSA+PiA0KTtcbiAgICAgICAgc3ViQ2h1bmsuc2V0QmxvY2soeCwgeSAmIDB4ZiwgeiwgQmxvY2tNYXBwaW5ncy5nZXRSdW50aW1lSWQoYmxvY2suZ2V0TmFtZSgpKSwgbGF5ZXIpO1xuXG4gICAgICAgIHRoaXMuaGFzQ2hhbmdlZCA9IHRydWU7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogSGVscGVyIG1ldGhvZCB1c2VkIHRvIGhhc2ggaW50byBhIHNpbmdsZSA2NCBiaXRzIGludGVnZXJcbiAgICAgKiBib3RoIENodW5rIFggYW5kIFogY29vcmRpbmF0ZXMuXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IGNodW5rWCAtIFRhcmdldCBDaHVuayBYIGNvb3JkaW5hdGUuXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IGNodW5rWiAtIFRhcmdldCBDaHVuayBaIGNvb3JkaW5hdGUuXG4gICAgICogQHJldHVybnMge2JpZ2ludH0gQSA2NCBiaXQgaW50Z2VyIGNvbnRhaW5pbmcgYSBoYXNoIG9mIFggYW5kIFouXG4gICAgICovXG4gICAgcHVibGljIHN0YXRpYyBwYWNrWFooY2h1bmtYOiBudW1iZXIsIGNodW5rWjogbnVtYmVyKTogYmlnaW50IHtcbiAgICAgICAgcmV0dXJuICgoQmlnSW50KGNodW5rWCkgJiAweGZmZmZmZmZmbikgPDwgMzJuKSB8IChCaWdJbnQoY2h1bmtaKSAmIDB4ZmZmZmZmZmZuKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBIZWxwZXIgbWV0aG9kIHVzZWQgdG8gZGVjb2RlIGEgNjQgYml0IGhhc2ggY29udGFpbmluZ1xuICAgICAqIGJvdGggQ2h1bmsgWCBhbmQgWiBjb29yZGluYXRlcy5cbiAgICAgKiBAcGFyYW0ge2JpZ2ludH0gcGFja2VkIC0gVGFyZ2V0IENodW5rIGNvb3JkaW5hdGUgaGFzaC5cbiAgICAgKiBAcmV0dXJucyB7bnVtYmVyW119IEFuIGFycmF5IGNvbnRhaW5pbmcgZGVjb2RlZCBDaHVuayBYIGFuZCBaIGNvb3JkaW5hdGVzLlxuICAgICAqL1xuICAgIHB1YmxpYyBzdGF0aWMgdW5wYWNrWFoocGFja2VkOiBiaWdpbnQpOiBudW1iZXJbXSB7XG4gICAgICAgIHJldHVybiBbTnVtYmVyKEJpZ0ludC5hc0ludE4oMzIsIHBhY2tlZCA+PiAzMm4pKSwgTnVtYmVyKEJpZ0ludC5hc0ludE4oMzIsIHBhY2tlZCAmIDB4ZmZmZmZmZmZuKSldO1xuICAgIH1cblxuICAgIHB1YmxpYyBuZXR3b3JrU2VyaWFsaXplKCk6IEJ1ZmZlciB7XG4gICAgICAgIGNvbnN0IHN0cmVhbSA9IG5ldyBCaW5hcnlTdHJlYW0oKTtcblxuICAgICAgICAvLyBGb3Igc29tZSByZWFzb25zIHdlIG5lZWQgdGhpcyBoYWNrIHNpbmNlIDEuMTgsXG4gICAgICAgIC8vIHNlZW1zIGxpa2UgdGhlIGNsaWVudCBub3cgaGFzIHNvbWUgbmVnYXRpdmUgc3BhY2UuXG4gICAgICAgIC8vIFRPRE86IGZpZ3VyZSBvdXQgd2hhdCBpcyB0aGlzXG4gICAgICAgIGZvciAobGV0IHkgPSAwOyB5IDwgNDsgKyt5KSB7XG4gICAgICAgICAgICBzdHJlYW0ud3JpdGVCeXRlKDgpOyAvLyBzdWJjaHVuayB2ZXJzaW9uIDhcbiAgICAgICAgICAgIHN0cmVhbS53cml0ZUJ5dGUoMCk7IC8vIDAgbGF5ZXJzIChhbGwgYWlyKVxuICAgICAgICB9XG5cbiAgICAgICAgZm9yIChsZXQgeSA9IDA7IHkgPCB0aGlzLmdldFRvcEVtcHR5KCk7ICsreSkge1xuICAgICAgICAgICAgKHRoaXMuc3ViQ2h1bmtzLmdldCh5KSA/PyBDaHVuay5FTVBUWV9TVUJDSFVOSykubmV0d29ya1NlcmlhbGl6ZShzdHJlYW0pO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gVE9ETzogM0QgYmlvbWVzXG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgMjQ7IGkrKykge1xuICAgICAgICAgICAgc3RyZWFtLndyaXRlQnl0ZSgwKTsgLy8gZmFrZSBiaW9tZSBwYWxldHRlLCBub24gcGVyc2lzdGVudFxuICAgICAgICAgICAgc3RyZWFtLndyaXRlVW5zaWduZWRWYXJJbnQoMSA8PCAxKTsgLy8gcGxhaW5zXG4gICAgICAgIH1cblxuICAgICAgICBzdHJlYW0ud3JpdGVCeXRlKDApOyAvLyBib3JkZXIgP1xuXG4gICAgICAgIC8vIFRPRE86IHRpbGVzXG4gICAgICAgIHJldHVybiBzdHJlYW0uZ2V0QnVmZmVyKCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRGVzZXJpYWxpemUgbmV0d29yayBzdHJlYW0gaW50byBjaHVua1xuICAgICAqIHVzZWZ1bCBmb3IgY2xpZW50IGFwcGxpY2F0aW9ucyBhbmQvb3Igb3VyIEZpbGVzeXN0ZW0gaW1wbFxuICAgICAqIEBwYXJhbSB7QmluYXJ5U3RyZWFtfSBzdHJlYW0gLSB0aGUgbmV0d29yayBzdHJlYW1cbiAgICAgKiBAcGFyYW0ge251bWJlcn0gW3hdIC0gdGhlIGNodW5rIHggY29vcmRpbmF0ZVxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbel0gLSB0aGUgY2h1bmsgeiBjb29yZGluYXRlXG4gICAgICovXG4gICAgcHVibGljIHN0YXRpYyBuZXR3b3JrRGVzZXJpYWxpemUoc3RyZWFtOiBCaW5hcnlTdHJlYW0sIHg/OiBudW1iZXIsIHo/OiBudW1iZXIpOiBDaHVuayB7XG4gICAgICAgIHN0cmVhbS5yZWFkKDgpOyAvLyBza2lwIGZha2Ugc3ViY2h1bmtzXG5cbiAgICAgICAgY29uc3Qgc3ViQ2h1bmtzOiBNYXA8bnVtYmVyLCBTdWJDaHVuaz4gPSBuZXcgTWFwKCk7XG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgTUFYX1NVQkNIVU5LUzsgaSsrKSB7XG4gICAgICAgICAgICBzdWJDaHVua3Muc2V0KGksIFN1YkNodW5rLm5ldHdvcmtEZXNlcmlhbGl6ZShzdHJlYW0pKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGNodW5rID0gbmV3IENodW5rKHgsIHosIHN1YkNodW5rcyk7XG4gICAgICAgIHJldHVybiBjaHVuaztcbiAgICB9XG59XG4iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7OztBQVFBLElBQU0sZ0JBQWdCO0FBRXRCLElBQXFCLFFBQXJCLE1BQXFCLE1BQU07Q0FDdkI7Q0FDQTtDQUNBO0NBRUEsNEJBQTJDLElBQUksSUFBSTtDQUNuRCxPQUF3QixpQkFBaUIsSUFBSSw2QkFBQSxRQUFTO0NBRXRELFlBQW1CLFNBQVMsR0FBRyxTQUFTLEdBQUcsNkJBQW9DLElBQUksSUFBSSxHQUFHO0VBQ3RGLEtBQUssSUFBSTtFQUNULEtBQUssSUFBSTtFQUNULEtBQUssYUFBYTtDQUN0QjtDQUVBLE9BQXNCO0VBQ2xCLE9BQU8sS0FBSztDQUNoQjtDQUVBLE9BQXNCO0VBQ2xCLE9BQU8sS0FBSztDQUNoQjtDQUVBLGdCQUFnQztFQUM1QixPQUFPLEtBQUs7Q0FDaEI7Q0FFQSxZQUEyQjtFQUN2QixPQUFPLEtBQUssVUFBVTtDQUMxQjs7Ozs7Q0FNQSxjQUE2QjtFQUN6QixJQUFJLFdBQVcsZ0JBQWdCO0VBQy9CLE9BQ0ssWUFBWSxLQUFLLENBQUMsS0FBSyxVQUFVLElBQUksUUFBUSxLQUM3QyxLQUFLLFVBQVUsSUFBSSxRQUFRLEtBQUssS0FBSyxVQUFVLElBQUksUUFBUSxFQUFHLFFBQVEsR0FFdkU7RUFFSixPQUFPLEVBQUU7Q0FDYjs7Ozs7Q0FNQSxZQUFtQixHQUE0QjtFQUMzQyxJQUFJLElBQUksS0FBSyxJQUFJLGVBQ2IsTUFBTSxJQUFJLE1BQU0sNEJBQTRCLEdBQUc7RUFFbkQsT0FBTyxLQUFLLFVBQVUsSUFBSSxDQUFDLEtBQUs7Q0FDcEM7Q0FFQSxvQkFBMkIsR0FBcUI7RUFDNUMsTUFBTSxXQUFXLElBQUksNkJBQUEsUUFBUztFQUM5QixLQUFLLFVBQVUsSUFBSSxHQUFHLFFBQVE7RUFDOUIsT0FBTztDQUNYO0NBRUEsZUFBNkM7RUFDekMsT0FBTyxLQUFLO0NBQ2hCO0NBRUEsa0JBQXlCLElBQVksSUFBb0I7RUFDckQsT0FBTztDQUNYOzs7Ozs7Ozs7Q0FVQSxTQUFnQixHQUFxQixJQUFZLEdBQUcsSUFBWSxHQUFHLFFBQVEsR0FBYTtFQUNwRixJQUFJLGFBQWEsbUJBQUEsU0FDYixPQUFPLEtBQUssU0FBUyxFQUFFLEtBQUssR0FBRyxFQUFFLEtBQUssR0FBRyxFQUFFLEtBQUssR0FBRyxLQUFLO0VBRzVELE1BQU0sV0FBVyxLQUFLLFlBQVksS0FBSyxNQUFNLElBQUksRUFBRSxDQUFDO0VBQ3BELElBQUksQ0FBQyxVQUFVLE9BQU8sNEJBQUEsY0FBYyxZQUFZLDRCQUFBLGNBQWMsYUFBYSxlQUFlLENBQUM7RUFDM0YsT0FBTyxTQUFTLFNBQVMsR0FBRyxJQUFJLElBQUssR0FBRyxLQUFLO0NBQ2pEOzs7Ozs7Ozs7Q0FVQSxTQUFnQixHQUFXLEdBQVcsR0FBVyxPQUFjLFFBQVEsR0FBUztFQUM1RSxJQUFJLFdBQVcsS0FBSyxZQUFZLEtBQUssTUFBTSxJQUFJLEVBQUUsQ0FBQztFQUNsRCxJQUFJLENBQUMsVUFBVSxXQUFXLEtBQUssb0JBQW9CLEtBQUssQ0FBQztFQUN6RCxTQUFTLFNBQVMsR0FBRyxJQUFJLElBQUssR0FBRyw0QkFBQSxjQUFjLGFBQWEsTUFBTSxRQUFRLENBQUMsR0FBRyxLQUFLO0VBRW5GLEtBQUssYUFBYTtDQUN0Qjs7Ozs7Ozs7Q0FTQSxPQUFjLE9BQU8sUUFBZ0IsUUFBd0I7RUFDekQsUUFBUyxPQUFPLE1BQU0sSUFBSSxnQkFBZ0IsTUFBUSxPQUFPLE1BQU0sSUFBSTtDQUN2RTs7Ozs7OztDQVFBLE9BQWMsU0FBUyxRQUEwQjtFQUM3QyxPQUFPLENBQUMsT0FBTyxPQUFPLE9BQU8sSUFBSSxVQUFVLEdBQUcsQ0FBQyxHQUFHLE9BQU8sT0FBTyxPQUFPLElBQUksU0FBUyxXQUFXLENBQUMsQ0FBQztDQUNyRztDQUVBLG1CQUFrQztFQUM5QixNQUFNLFNBQVMsSUFBSSw0QkFBQSxRQUFhO0VBS2hDLEtBQUssSUFBSSxJQUFJLEdBQUcsSUFBSSxHQUFHLEVBQUUsR0FBRztHQUN4QixPQUFPLFVBQVUsQ0FBQztHQUNsQixPQUFPLFVBQVUsQ0FBQztFQUN0QjtFQUVBLEtBQUssSUFBSSxJQUFJLEdBQUcsSUFBSSxLQUFLLFlBQVksR0FBRyxFQUFFLEdBQ3RDLENBQUMsS0FBSyxVQUFVLElBQUksQ0FBQyxLQUFLLE1BQU0sZ0JBQWdCLGlCQUFpQixNQUFNO0VBSTNFLEtBQUssSUFBSSxJQUFJLEdBQUcsSUFBSSxJQUFJLEtBQUs7R0FDekIsT0FBTyxVQUFVLENBQUM7R0FDbEIsT0FBTyxvQkFBb0IsQ0FBTTtFQUNyQztFQUVBLE9BQU8sVUFBVSxDQUFDO0VBR2xCLE9BQU8sT0FBTyxVQUFVO0NBQzVCOzs7Ozs7OztDQVNBLE9BQWMsbUJBQW1CLFFBQXNCLEdBQVksR0FBbUI7RUFDbEYsT0FBTyxLQUFLLENBQUM7RUFFYixNQUFNLDRCQUFtQyxJQUFJLElBQUk7RUFDakQsS0FBSyxJQUFJLElBQUksR0FBRyxJQUFJLGVBQWUsS0FDL0IsVUFBVSxJQUFJLEdBQUcsNkJBQUEsUUFBUyxtQkFBbUIsTUFBTSxDQUFDO0VBSXhELE9BQU8sSUFEVyxNQUFNLEdBQUcsR0FBRyxTQUN2QjtDQUNYO0FBQ0oifQ==