@selfage/message
Version:
Runtime lib for generated messages to parse, copy, serialize and deserialize messages.
222 lines • 29.8 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.initBuffer = initBuffer;
exports.toBufferFromValue = toBufferFromValue;
exports.toBufferFromMessage = toBufferFromMessage;
exports.serializeMessage = serializeMessage;
exports.toEnumFromNumber = toEnumFromNumber;
exports.toValueFromBinary = toValueFromBinary;
exports.toMessageFromBinary = toMessageFromBinary;
exports.deserializeMessage = deserializeMessage;
const descriptor_1 = require("./descriptor");
// Binary format example.
// From {1: 1, 2: true, 3: {}, 4: {1: 1}, 5: "a", 6: [1]}
// To <6 (Uint32 for number of fields)><1 (Uint32 for index)><1 (Float64 for number value)><2 (Uint32 for index)><1 (Uint8 for boolean value)><3 (Uint32 for index)><0 (Uint32 for byte size)><4 (Uint32 for index)><12 (Uint32 for byte size)><1 (Uint32 for index)><1 (Float64 for number value)><5 (Uint32 for index)><1 (Uint32 for byte length)><97 (Uint8 for UTF8 encoding)><6 (Uint32 for index)><1 (Uint32 for array size)><1 (Float64 for number value)>
//
// Requirements:
// 1. Index, enum value, and array length must be < 2^32.
// 2. Number of fields, and string byte length must be < 2^32 - 1 (NOTE!).
// 3. Field index and enum value must be > 0.
//
// Handling `undefined` and `null`:
// 1. If a field is undefined/null, it's ignored when serialized.
// 2. If an element of an array is undefined/null, it will be kept as undefined in the array.
//
// Maximum byte size by default is 16MB, but can be changed globally using `initBuffer(maxBytes: number)`.
let UINT32_VALUE_FOR_UNDEFINED = 4294967295;
let BOOLEAN_VALUE_FOR_UNDEFINED = 2;
let RESERVED_UINT8_ARRAY;
let DATA_VIEW_OF_RESERVED_ARRAY;
let TEXT_ENCODER = new TextEncoder();
let TEXT_DECODER = new TextDecoder();
function initBuffer(maxBytes = 1024 * 1024 * 16) {
RESERVED_UINT8_ARRAY = new Uint8Array(maxBytes);
DATA_VIEW_OF_RESERVED_ARRAY = new DataView(RESERVED_UINT8_ARRAY.buffer);
}
initBuffer();
function toBufferFromValue(value, field, uint8Array, dataView, byteOffset) {
if (field.primitiveType) {
switch (field.primitiveType) {
case descriptor_1.PrimitiveType.NUMBER:
if (value == null) {
dataView.setFloat64(byteOffset, NaN, true);
}
else {
dataView.setFloat64(byteOffset, value, true);
}
byteOffset += 8;
break;
case descriptor_1.PrimitiveType.BOOLEAN:
if (value == null) {
dataView.setUint8(byteOffset, BOOLEAN_VALUE_FOR_UNDEFINED);
}
else {
dataView.setUint8(byteOffset, value);
}
byteOffset += 1;
break;
case descriptor_1.PrimitiveType.STRING:
if (value == null) {
dataView.setUint32(byteOffset, UINT32_VALUE_FOR_UNDEFINED, true);
byteOffset += 4;
}
else {
let res = TEXT_ENCODER.encodeInto(value, uint8Array.subarray(byteOffset + 4));
dataView.setUint32(byteOffset, res.written, true);
byteOffset += 4 + res.written;
}
break;
}
}
else if (field.enumType) {
if (value == null) {
dataView.setUint32(byteOffset, 0, true);
}
else {
dataView.setUint32(byteOffset, value, true);
}
byteOffset += 4;
}
else {
// message type
byteOffset = toBufferFromMessage(value, field.messageType, uint8Array, dataView, byteOffset);
}
return byteOffset;
}
function toBufferFromMessage(message, descriptor, uint8Array, dataView, byteOffset) {
if (!message) {
dataView.setUint32(byteOffset, UINT32_VALUE_FOR_UNDEFINED, true);
return byteOffset + 4;
}
let numOfFields = 0;
let byteOffsetForNumOfFields = byteOffset;
byteOffset += 4;
for (let field of descriptor.fields) {
if (message[field.name] == null) {
continue;
}
numOfFields += 1;
dataView.setUint32(byteOffset, field.index, true);
byteOffset += 4;
if (field.isArray) {
dataView.setUint32(byteOffset, message[field.name].length, true);
byteOffset += 4;
for (let value of message[field.name]) {
byteOffset = toBufferFromValue(value, field, uint8Array, dataView, byteOffset);
}
}
else {
byteOffset = toBufferFromValue(message[field.name], field, uint8Array, dataView, byteOffset);
}
}
dataView.setUint32(byteOffsetForNumOfFields, numOfFields, true);
return byteOffset;
}
function serializeMessage(message, descriptor) {
let byteOffset = toBufferFromMessage(message, descriptor, RESERVED_UINT8_ARRAY, DATA_VIEW_OF_RESERVED_ARRAY, 0);
return RESERVED_UINT8_ARRAY.slice(0, byteOffset);
}
function toEnumFromNumber(sourceValue, enumType) {
let found = enumType.values.find((enumValue) => {
return enumValue.value === sourceValue;
});
if (found === undefined) {
return undefined;
}
else {
return sourceValue;
}
}
function toValueFromBinary(dataView, byteOffset, field) {
let value;
if (field.primitiveType) {
switch (field.primitiveType) {
case descriptor_1.PrimitiveType.NUMBER:
value = dataView.getFloat64(byteOffset, true);
if (isNaN(value)) {
value = undefined;
}
byteOffset += 8;
break;
case descriptor_1.PrimitiveType.BOOLEAN:
value = dataView.getUint8(byteOffset);
if (value === BOOLEAN_VALUE_FOR_UNDEFINED) {
value = undefined;
}
else {
value = Boolean(value);
}
byteOffset += 1;
break;
case descriptor_1.PrimitiveType.STRING:
let stringByteLength = dataView.getUint32(byteOffset, true);
byteOffset += 4;
if (stringByteLength === UINT32_VALUE_FOR_UNDEFINED) {
value = undefined;
}
else {
value = TEXT_DECODER.decode(new Uint8Array(dataView.buffer, dataView.byteOffset + byteOffset, stringByteLength));
byteOffset += stringByteLength;
}
break;
}
}
else if (field.enumType) {
let enumSourceValue = dataView.getUint32(byteOffset, true);
byteOffset += 4;
value = toEnumFromNumber(enumSourceValue, field.enumType);
}
else {
// message type
let messageAndByteOffset = toMessageFromBinary(dataView, byteOffset, field.messageType);
value = messageAndByteOffset.message;
byteOffset = messageAndByteOffset.byteOffset;
}
return { value, byteOffset };
}
function toMessageFromBinary(dataView, byteOffset, descriptor) {
let numOfFields = dataView.getUint32(byteOffset, true);
byteOffset += 4;
if (numOfFields === UINT32_VALUE_FOR_UNDEFINED) {
return {
byteOffset,
};
}
let message = {};
let i = 0;
for (let j = 0; j < numOfFields; j++) {
let index = dataView.getUint32(byteOffset, true);
byteOffset += 4;
while (descriptor.fields[i].index < index) {
i++;
}
if (index !== descriptor.fields[i].index) {
throw new Error(`Index ${index} is not found in the message descriptor of ${descriptor.name}.`);
}
let field = descriptor.fields[i];
if (field.isArray) {
let arrayLength = dataView.getUint32(byteOffset, true);
byteOffset += 4;
let arrayField = new Array();
message[field.name] = arrayField;
for (let m = 0; m < arrayLength; m++) {
let valueAndByteOffset = toValueFromBinary(dataView, byteOffset, field);
arrayField.push(valueAndByteOffset.value);
byteOffset = valueAndByteOffset.byteOffset;
}
}
else {
let valueAndByteOffset = toValueFromBinary(dataView, byteOffset, field);
message[field.name] = valueAndByteOffset.value;
byteOffset = valueAndByteOffset.byteOffset;
}
}
return { message, byteOffset };
}
function deserializeMessage(binary, descriptor) {
if (!binary) {
return undefined;
}
return toMessageFromBinary(new DataView(binary.buffer, binary.byteOffset, binary.byteLength), 0, descriptor).message;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VyaWFsaXplci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInNlcmlhbGl6ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUE2QkEsZ0NBR0M7QUFJRCw4Q0F5REM7QUFFRCxrREFnREM7QUFFRCw0Q0FZQztBQUVELDRDQVlDO0FBRUQsOENBd0RDO0FBRUQsa0RBNENDO0FBRUQsZ0RBWUM7QUFqU0QsNkNBS3NCO0FBRXRCLHlCQUF5QjtBQUN6Qix5REFBeUQ7QUFDekQsa2NBQWtjO0FBQ2xjLEVBQUU7QUFDRixnQkFBZ0I7QUFDaEIsMkRBQTJEO0FBQzNELDRFQUE0RTtBQUM1RSwrQ0FBK0M7QUFDL0MsRUFBRTtBQUNGLG1DQUFtQztBQUNuQyxtRUFBbUU7QUFDbkUsK0ZBQStGO0FBQy9GLEVBQUU7QUFDRiwwR0FBMEc7QUFFMUcsSUFBSSwwQkFBMEIsR0FBRyxVQUFVLENBQUM7QUFDNUMsSUFBSSwyQkFBMkIsR0FBRyxDQUFDLENBQUM7QUFDcEMsSUFBSSxvQkFBZ0MsQ0FBQztBQUNyQyxJQUFJLDJCQUFxQyxDQUFDO0FBQzFDLElBQUksWUFBWSxHQUFHLElBQUksV0FBVyxFQUFFLENBQUM7QUFDckMsSUFBSSxZQUFZLEdBQUcsSUFBSSxXQUFXLEVBQUUsQ0FBQztBQUVyQyxTQUFnQixVQUFVLENBQUMsUUFBUSxHQUFHLElBQUksR0FBRyxJQUFJLEdBQUcsRUFBRTtJQUNwRCxvQkFBb0IsR0FBRyxJQUFJLFVBQVUsQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUNoRCwyQkFBMkIsR0FBRyxJQUFJLFFBQVEsQ0FBQyxvQkFBb0IsQ0FBQyxNQUFNLENBQUMsQ0FBQztBQUMxRSxDQUFDO0FBRUQsVUFBVSxFQUFFLENBQUM7QUFFYixTQUFnQixpQkFBaUIsQ0FDL0IsS0FBVSxFQUNWLEtBQW1CLEVBQ25CLFVBQXNCLEVBQ3RCLFFBQWtCLEVBQ2xCLFVBQWtCO0lBRWxCLElBQUksS0FBSyxDQUFDLGFBQWEsRUFBRSxDQUFDO1FBQ3hCLFFBQVEsS0FB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QyxLQUFLLENBQUMsSUFBSSxDQUFDLEdBQUcsVUFBVSxDQUFDO1lBQ2pDLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxXQUFXLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQztnQkFDckMsSUFBSSxrQkFBa0IsR0FBRyxpQkFBaUIsQ0FBQyxRQUFRLEVBQUUsVUFBVSxFQUFFLEtBQUssQ0FBQyxDQUFDO2dCQUN4RSxVQUFVLENBQUMsSUFBSSxDQUFDLGtCQUFrQixDQUFDLEtBQUssQ0FBQyxDQUFDO2dCQUMxQyxVQUFVLEdBQUcsa0JBQWtCLENBQUMsVUFBVSxDQUFDO1lBQzdDLENBQUM7UUFDSCxDQUFDO2FBQU0sQ0FBQztZQUNOLElBQUksa0JBQWtCLEdBQUcsaUJBQWlCLENBQUMsUUFBUSxFQUFFLFVBQVUsRUFBRSxLQUFLLENBQUMsQ0FBQztZQUN4RSxPQUFPLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxHQUFHLGtCQUFrQixDQUFDLEtBQUssQ0FBQztZQUMvQyxVQUFVLEdBQUcsa0JBQWtCLENBQUMsVUFBVSxDQUFDO1FBQzdDLENBQUM7SUFDSCxDQUFDO0lBQ0QsT0FBTyxFQUFFLE9BQU8sRUFBRSxVQUFVLEVBQUUsQ0FBQztBQUNqQyxDQUFDO0FBRUQsU0FBZ0Isa0JBQWtCLENBQ2hDLE1BQXFDLEVBQ3JDLFVBQWdDO0lBRWhDLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztRQUNaLE9BQU8sU0FBUyxDQUFDO0lBQ25CLENBQUM7SUFDRCxPQUFPLG1CQUFtQixDQUN4QixJQUFJLFFBQVEsQ0FBQyxNQUFNLENBQUMsTUFBTSxFQUFFLE1BQU0sQ0FBQyxVQUFVLEVBQUUsTUFBTSxDQUFDLFVBQVUsQ0FBQyxFQUNqRSxDQUFDLEVBQ0QsVUFBVSxDQUNYLENBQUMsT0FBTyxDQUFDO0FBQ1osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIEVudW1EZXNjcmlwdG9yLFxuICBNZXNzYWdlRGVzY3JpcHRvcixcbiAgTWVzc2FnZUZpZWxkLFxuICBQcmltaXRpdmVUeXBlLFxufSBmcm9tIFwiLi9kZXNjcmlwdG9yXCI7XG5cbi8vIEJpbmFyeSBmb3JtYXQgZXhhbXBsZS5cbi8vIEZyb20gezE6IDEsIDI6IHRydWUsIDM6IHt9LCA0OiB7MTogMX0sIDU6IFwiYVwiLCA2OiBbMV19XG4vLyBUbyA8NiAoVWludDMyIGZvciBudW1iZXIgb2YgZmllbGRzKT48MSAoVWludDMyIGZvciBpbmRleCk+PDEgKEZsb2F0NjQgZm9yIG51bWJlciB2YWx1ZSk+PDIgKFVpbnQzMiBmb3IgaW5kZXgpPjwxIChVaW50OCBmb3IgYm9vbGVhbiB2YWx1ZSk+PDMgKFVpbnQzMiBmb3IgaW5kZXgpPjwwIChVaW50MzIgZm9yIGJ5dGUgc2l6ZSk+PDQgKFVpbnQzMiBmb3IgaW5kZXgpPjwxMiAoVWludDMyIGZvciBieXRlIHNpemUpPjwxIChVaW50MzIgZm9yIGluZGV4KT48MSAoRmxvYXQ2NCBmb3IgbnVtYmVyIHZhbHVlKT48NSAoVWludDMyIGZvciBpbmRleCk+PDEgKFVpbnQzMiBmb3IgYnl0ZSBsZW5ndGgpPjw5NyAoVWludDggZm9yIFVURjggZW5jb2RpbmcpPjw2IChVaW50MzIgZm9yIGluZGV4KT48MSAoVWludDMyIGZvciBhcnJheSBzaXplKT48MSAoRmxvYXQ2NCBmb3IgbnVtYmVyIHZhbHVlKT5cbi8vXG4vLyBSZXF1aXJlbWVudHM6XG4vLyAgIDEuIEluZGV4LCBlbnVtIHZhbHVlLCBhbmQgYXJyYXkgbGVuZ3RoIG11c3QgYmUgPCAyXjMyLlxuLy8gICAyLiBOdW1iZXIgb2YgZmllbGRzLCBhbmQgc3RyaW5nIGJ5dGUgbGVuZ3RoIG11c3QgYmUgPCAyXjMyIC0gMSAoTk9URSEpLlxuLy8gICAzLiBGaWVsZCBpbmRleCBhbmQgZW51bSB2YWx1ZSBtdXN0IGJlID4gMC5cbi8vXG4vLyBIYW5kbGluZyBgdW5kZWZpbmVkYCBhbmQgYG51bGxgOlxuLy8gICAxLiBJZiBhIGZpZWxkIGlzIHVuZGVmaW5lZC9udWxsLCBpdCdzIGlnbm9yZWQgd2hlbiBzZXJpYWxpemVkLlxuLy8gICAyLiBJZiBhbiBlbGVtZW50IG9mIGFuIGFycmF5IGlzIHVuZGVmaW5lZC9udWxsLCBpdCB3aWxsIGJlIGtlcHQgYXMgdW5kZWZpbmVkIGluIHRoZSBhcnJheS5cbi8vXG4vLyBNYXhpbXVtIGJ5dGUgc2l6ZSBieSBkZWZhdWx0IGlzIDE2TUIsIGJ1dCBjYW4gYmUgY2hhbmdlZCBnbG9iYWxseSB1c2luZyBgaW5pdEJ1ZmZlcihtYXhCeXRlczogbnVtYmVyKWAuXG5cbmxldCBVSU5UMzJfVkFMVUVfRk9SX1VOREVGSU5FRCA9IDQyOTQ5NjcyOTU7XG5sZXQgQk9PTEVBTl9WQUxVRV9GT1JfVU5ERUZJTkVEID0gMjtcbmxldCBSRVNFUlZFRF9VSU5UOF9BUlJBWTogVWludDhBcnJheTtcbmxldCBEQVRBX1ZJRVdfT0ZfUkVTRVJWRURfQVJSQVk6IERhdGFWaWV3O1xubGV0IFRFWFRfRU5DT0RFUiA9IG5ldyBUZXh0RW5jb2RlcigpO1xubGV0IFRFWFRfREVDT0RFUiA9IG5ldyBUZXh0RGVjb2RlcigpO1xuXG5leHBvcnQgZnVuY3Rpb24gaW5pdEJ1ZmZlcihtYXhCeXRlcyA9IDEwMjQgKiAxMDI0ICogMTYpOiB2b2lkIHtcbiAgUkVTRVJWRURfVUlOVDhfQVJSQVkgPSBuZXcgVWludDhBcnJheShtYXhCeXRlcyk7XG4gIERBVEFfVklFV19PRl9SRVNFUlZFRF9BUlJBWSA9IG5ldyBEYXRhVmlldyhSRVNFUlZFRF9VSU5UOF9BUlJBWS5idWZmZXIpO1xufVxuXG5pbml0QnVmZmVyKCk7XG5cbmV4cG9ydCBmdW5jdGlvbiB0b0J1ZmZlckZyb21WYWx1ZShcbiAgdmFsdWU6IGFueSxcbiAgZmllbGQ6IE1lc3NhZ2VGaWVsZCxcbiAgdWludDhBcnJheTogVWludDhBcnJheSxcbiAgZGF0YVZpZXc6IERhdGFWaWV3LFxuICBieXRlT2Zmc2V0OiBudW1iZXIsXG4pOiBudW1iZXIge1xuICBpZiAoZmllbGQucHJpbWl0aXZlVHlwZSkge1xuICAgIHN3aXRjaCAoZmllbGQucHJpbWl0aXZlVHlwZSkge1xuICAgICAgY2FzZSBQcmltaXRpdmVUeXBlLk5VTUJFUjpcbiAgICAgICAgaWYgKHZhbHVlID09IG51bGwpIHtcbiAgICAgICAgICBkYXRhVmlldy5zZXRGbG9hdDY0KGJ5dGVPZmZzZXQsIE5hTiwgdHJ1ZSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgZGF0YVZpZXcuc2V0RmxvYXQ2NChieXRlT2Zmc2V0LCB2YWx1ZSwgdHJ1ZSk7XG4gICAgICAgIH1cbiAgICAgICAgYnl0ZU9mZnNldCArPSA4O1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgUHJpbWl0aXZlVHlwZS5CT09MRUFOOlxuICAgICAgICBpZiAodmFsdWUgPT0gbnVsbCkge1xuICAgICAgICAgIGRhdGFWaWV3LnNldFVpbnQ4KGJ5dGVPZmZzZXQsIEJPT0xFQU5fVkFMVUVfRk9SX1VOREVGSU5FRCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgZGF0YVZpZXcuc2V0VWludDgoYnl0ZU9mZnNldCwgdmFsdWUpO1xuICAgICAgICB9XG4gICAgICAgIGJ5dGVPZmZzZXQgKz0gMTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIFByaW1pdGl2ZVR5cGUuU1RSSU5HOlxuICAgICAgICBpZiAodmFsdWUgPT0gbnVsbCkge1xuICAgICAgICAgIGRhdGFWaWV3LnNldFVpbnQzMihieXRlT2Zmc2V0LCBVSU5UMzJfVkFMVUVfRk9SX1VOREVGSU5FRCwgdHJ1ZSk7XG4gICAgICAgICAgYnl0ZU9mZnNldCArPSA0O1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGxldCByZXMgPSBURVhUX0VOQ09ERVIuZW5jb2RlSW50byhcbiAgICAgICAgICAgIHZhbHVlLFxuICAgICAgICAgICAgdWludDhBcnJheS5zdWJhcnJheShieXRlT2Zmc2V0ICsgNCksXG4gICAgICAgICAgKTtcbiAgICAgICAgICBkYXRhVmlldy5zZXRVaW50MzIoYnl0ZU9mZnNldCwgcmVzLndyaXR0ZW4sIHRydWUpO1xuICAgICAgICAgIGJ5dGVPZmZzZXQgKz0gNCArIHJlcy53cml0dGVuO1xuICAgICAgICB9XG4gICAgICAgIGJyZWFrO1xuICAgIH1cbiAgfSBlbHNlIGlmIChmaWVsZC5lbnVtVHlwZSkge1xuICAgIGlmICh2YWx1ZSA9PSBudWxsKSB7XG4gICAgICBkYXRhVmlldy5zZXRVaW50MzIoYnl0ZU9mZnNldCwgMCwgdHJ1ZSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGRhdGFWaWV3LnNldFVpbnQzMihieXRlT2Zmc2V0LCB2YWx1ZSwgdHJ1ZSk7XG4gICAgfVxuICAgIGJ5dGVPZmZzZXQgKz0gNDtcbiAgfSBlbHNlIHtcbiAgICAvLyBtZXNzYWdlIHR5cGVcbiAgICBieXRlT2Zmc2V0ID0gdG9CdWZmZXJGcm9tTWVzc2FnZShcbiAgICAgIHZhbHVlLFxuICAgICAgZmllbGQubWVzc2FnZVR5cGUsXG4gICAgICB1aW50OEFycmF5LFxuICAgICAgZGF0YVZpZXcsXG4gICAgICBieXRlT2Zmc2V0LFxuICAgICk7XG4gIH1cbiAgcmV0dXJuIGJ5dGVPZmZzZXQ7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiB0b0J1ZmZlckZyb21NZXNzYWdlKFxuICBtZXNzYWdlOiBhbnksXG4gIGRlc2NyaXB0b3I6IE1lc3NhZ2VEZXNjcmlwdG9yPGFueT4sXG4gIHVpbnQ4QXJyYXk6IFVpbnQ4QXJyYXksXG4gIGRhdGFWaWV3OiBEYXRhVmlldyxcbiAgYnl0ZU9mZnNldDogbnVtYmVyLFxuKTogbnVtYmVyIHtcbiAgaWYgKCFtZXNzYWdlKSB7XG4gICAgZGF0YVZpZXcuc2V0VWludDMyKGJ5dGVPZmZzZXQsIFVJTlQzMl9WQUxVRV9GT1JfVU5ERUZJTkVELCB0cnVlKTtcbiAgICByZXR1cm4gYnl0ZU9mZnNldCArIDQ7XG4gIH1cblxuICBsZXQgbnVtT2ZGaWVsZHMgPSAwO1xuICBsZXQgYnl0ZU9mZnNldEZvck51bU9mRmllbGRzID0gYnl0ZU9mZnNldDtcbiAgYnl0ZU9mZnNldCArPSA0O1xuICBmb3IgKGxldCBmaWVsZCBvZiBkZXNjcmlwdG9yLmZpZWxkcykge1xuICAgIGlmIChtZXNzYWdlW2ZpZWxkLm5hbWVdID09IG51bGwpIHtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cbiAgICBudW1PZkZpZWxkcyArPSAxO1xuXG4gICAgZGF0YVZpZXcuc2V0VWludDMyKGJ5dGVPZmZzZXQsIGZpZWxkLmluZGV4LCB0cnVlKTtcbiAgICBieXRlT2Zmc2V0ICs9IDQ7XG5cbiAgICBpZiAoZmllbGQuaXNBcnJheSkge1xuICAgICAgZGF0YVZpZXcuc2V0VWludDMyKGJ5dGVPZmZzZXQsIG1lc3NhZ2VbZmllbGQubmFtZV0ubGVuZ3RoLCB0cnVlKTtcbiAgICAgIGJ5dGVPZmZzZXQgKz0gNDtcbiAgICAgIGZvciAobGV0IHZhbHVlIG9mIG1lc3NhZ2VbZmllbGQubmFtZV0pIHtcbiAgICAgICAgYnl0ZU9mZnNldCA9IHRvQnVmZmVyRnJvbVZhbHVlKFxuICAgICAgICAgIHZhbHVlLFxuICAgICAgICAgIGZpZWxkLFxuICAgICAgICAgIHVpbnQ4QXJyYXksXG4gICAgICAgICAgZGF0YVZpZXcsXG4gICAgICAgICAgYnl0ZU9mZnNldCxcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgYnl0ZU9mZnNldCA9IHRvQnVmZmVyRnJvbVZhbHVlKFxuICAgICAgICBtZXNzYWdlW2ZpZWxkLm5hbWVdLFxuICAgICAgICBmaWVsZCxcbiAgICAgICAgdWludDhBcnJheSxcbiAgICAgICAgZGF0YVZpZXcsXG4gICAgICAgIGJ5dGVPZmZzZXQsXG4gICAgICApO1xuICAgIH1cbiAgfVxuICBkYXRhVmlldy5zZXRVaW50MzIoYnl0ZU9mZnNldEZvck51bU9mRmllbGRzLCBudW1PZkZpZWxkcywgdHJ1ZSk7XG4gIHJldHVybiBieXRlT2Zmc2V0O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gc2VyaWFsaXplTWVzc2FnZTxUPihcbiAgbWVzc2FnZTogVCxcbiAgZGVzY3JpcHRvcjogTWVzc2FnZURlc2NyaXB0b3I8VD4sXG4pOiBVaW50OEFycmF5IHtcbiAgbGV0IGJ5dGVPZmZzZXQgPSB0b0J1ZmZlckZyb21NZXNzYWdlKFxuICAgIG1lc3NhZ2UsXG4gICAgZGVzY3JpcHRvcixcbiAgICBSRVNFUlZFRF9VSU5UOF9BUlJBWSxcbiAgICBEQVRBX1ZJRVdfT0ZfUkVTRVJWRURfQVJSQVksXG4gICAgMCxcbiAgKTtcbiAgcmV0dXJuIFJFU0VSVkVEX1VJTlQ4X0FSUkFZLnNsaWNlKDAsIGJ5dGVPZmZzZXQpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gdG9FbnVtRnJvbU51bWJlcihcbiAgc291cmNlVmFsdWU6IG51bWJlcixcbiAgZW51bVR5cGU6IEVudW1EZXNjcmlwdG9yPGFueT4sXG4pOiBudW1iZXIge1xuICBsZXQgZm91bmQgPSBlbnVtVHlwZS52YWx1ZXMuZmluZCgoZW51bVZhbHVlKTogYm9vbGVhbiA9PiB7XG4gICAgcmV0dXJuIGVudW1WYWx1ZS52YWx1ZSA9PT0gc291cmNlVmFsdWU7XG4gIH0pO1xuICBpZiAoZm91bmQgPT09IHVuZGVmaW5lZCkge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH0gZWxzZSB7XG4gICAgcmV0dXJuIHNvdXJjZVZhbHVlO1xuICB9XG59XG5cbmV4cG9ydCBmdW5jdGlvbiB0b1ZhbHVlRnJvbUJpbmFyeShcbiAgZGF0YVZpZXc6IERhdGFWaWV3LFxuICBieXRlT2Zmc2V0OiBudW1iZXIsXG4gIGZpZWxkOiBNZXNzYWdlRmllbGQsXG4pOiB7IHZhbHVlOiBhbnk7IGJ5dGVPZmZzZXQ6IG51bWJlciB9IHtcbiAgbGV0IHZhbHVlOiBhbnk7XG4gIGlmIChmaWVsZC5wcmltaXRpdmVUeXBlKSB7XG4gICAgc3dpdGNoIChmaWVsZC5wcmltaXRpdmVUeXBlKSB7XG4gICAgICBjYXNlIFByaW1pdGl2ZVR5cGUuTlVNQkVSOlxuICAgICAgICB2YWx1ZSA9IGRhdGFWaWV3LmdldEZsb2F0NjQoYnl0ZU9mZnNldCwgdHJ1ZSk7XG4gICAgICAgIGlmIChpc05hTih2YWx1ZSkpIHtcbiAgICAgICAgICB2YWx1ZSA9IHVuZGVmaW5lZDtcbiAgICAgICAgfVxuICAgICAgICBieXRlT2Zmc2V0ICs9IDg7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSBQcmltaXRpdmVUeXBlLkJPT0xFQU46XG4gICAgICAgIHZhbHVlID0gZGF0YVZpZXcuZ2V0VWludDgoYnl0ZU9mZnNldCk7XG4gICAgICAgIGlmICh2YWx1ZSA9PT0gQk9PTEVBTl9WQUxVRV9GT1JfVU5ERUZJTkVEKSB7XG4gICAgICAgICAgdmFsdWUgPSB1bmRlZmluZWQ7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdmFsdWUgPSBCb29sZWFuKHZhbHVlKTtcbiAgICAgICAgfVxuICAgICAgICBieXRlT2Zmc2V0ICs9IDE7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSBQcmltaXRpdmVUeXBlLlNUUklORzpcbiAgICAgICAgbGV0IHN0cmluZ0J5dGVMZW5ndGggPSBkYXRhVmlldy5nZXRVaW50MzIoYnl0ZU9mZnNldCwgdHJ1ZSk7XG4gICAgICAgIGJ5dGVPZmZzZXQgKz0gNDtcbiAgICAgICAgaWYgKHN0cmluZ0J5dGVMZW5ndGggPT09IFVJTlQzMl9WQUxVRV9GT1JfVU5ERUZJTkVEKSB7XG4gICAgICAgICAgdmFsdWUgPSB1bmRlZmluZWQ7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdmFsdWUgPSBURVhUX0RFQ09ERVIuZGVjb2RlKFxuICAgICAgICAgICAgbmV3IFVpbnQ4QXJyYXkoXG4gICAgICAgICAgICAgIGRhdGFWaWV3LmJ1ZmZlcixcbiAgICAgICAgICAgICAgZGF0YVZpZXcuYnl0ZU9mZnNldCArIGJ5dGVPZmZzZXQsXG4gICAgICAgICAgICAgIHN0cmluZ0J5dGVMZW5ndGgsXG4gICAgICAgICAgICApLFxuICAgICAgICAgICk7XG4gICAgICAgICAgYnl0ZU9mZnNldCArPSBzdHJpbmdCeXRlTGVuZ3RoO1xuICAgICAgICB9XG4gICAgICAgIGJyZWFrO1xuICAgIH1cbiAgfSBlbHNlIGlmIChmaWVsZC5lbnVtVHlwZSkge1xuICAgIGxldCBlbnVtU291cmNlVmFsdWUgPSBkYXRhVmlldy5nZXRVaW50MzIoYnl0ZU9mZnNldCwgdHJ1ZSk7XG4gICAgYnl0ZU9mZnNldCArPSA0O1xuICAgIHZhbHVlID0gdG9FbnVtRnJvbU51bWJlcihlbnVtU291cmNlVmFsdWUsIGZpZWxkLmVudW1UeXBlKTtcbiAgfSBlbHNlIHtcbiAgICAvLyBtZXNzYWdlIHR5cGVcbiAgICBsZXQgbWVzc2FnZUFuZEJ5dGVPZmZzZXQgPSB0b01lc3NhZ2VGcm9tQmluYXJ5KFxuICAgICAgZGF0YVZpZXcsXG4gICAgICBieXRlT2Zmc2V0LFxuICAgICAgZmllbGQubWVzc2FnZVR5cGUsXG4gICAgKTtcbiAgICB2YWx1ZSA9IG1lc3NhZ2VBbmRCeXRlT2Zmc2V0Lm1lc3NhZ2U7XG4gICAgYnl0ZU9mZnNldCA9IG1lc3NhZ2VBbmRCeXRlT2Zmc2V0LmJ5dGVPZmZzZXQ7XG4gIH1cbiAgcmV0dXJuIHsgdmFsdWUsIGJ5dGVPZmZzZXQgfTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHRvTWVzc2FnZUZyb21CaW5hcnk8VD4oXG4gIGRhdGFWaWV3OiBEYXRhVmlldyxcbiAgYnl0ZU9mZnNldDogbnVtYmVyLFxuICBkZXNjcmlwdG9yOiBNZXNzYWdlRGVzY3JpcHRvcjxUPixcbik6IHsgbWVzc2FnZT86IFQ7IGJ5dGVPZmZzZXQ6IG51bWJlciB9IHtcbiAgbGV0IG51bU9mRmllbGRzID0gZGF0YVZpZXcuZ2V0VWludDMyKGJ5dGVPZmZzZXQsIHRydWUpO1xuICBieXRlT2Zmc2V0ICs9IDQ7XG4gIGlmIChudW1PZkZpZWxkcyA9PT0gVUlOVDMyX1ZBTFVFX0ZPUl9VTkRFRklORUQpIHtcbiAgICByZXR1cm4ge1xuICAgICAgYnl0ZU9mZnNldCxcbiAgICB9O1xuICB9XG5cbiAgbGV0IG1lc3NhZ2U6IGFueSA9IHt9O1xuICBsZXQgaSA9IDA7XG4gIGZvciAobGV0IGogPSAwOyBqIDwgbnVtT2ZGaWVsZHM7IGorKykge1xuICAgIGxldCBpbmRleCA9IGRhdGFWaWV3LmdldFVpbnQzMihieXRlT2Zmc2V0LCB0cnVlKTtcbiAgICBieXRlT2Zmc2V0ICs9IDQ7XG4gICAgd2hpbGUgKGRlc2NyaXB0b3IuZmllbGRzW2ldLmluZGV4IDwgaW5kZXgpIHtcbiAgICAgIGkrKztcbiAgICB9XG4gICAgaWYgKGluZGV4ICE9PSBkZXNjcmlwdG9yLmZpZWxkc1tpXS5pbmRleCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgSW5kZXggJHtpbmRleH0gaXMgbm90IGZvdW5kIGluIHRoZSBtZXNzYWdlIGRlc2NyaXB0b3Igb2YgJHtkZXNjcmlwdG9yLm5hbWV9LmAsXG4gICAgICApO1xuICAgIH1cbiAgICBsZXQgZmllbGQgPSBkZXNjcmlwdG9yLmZpZWxkc1tpXTtcbiAgICBpZiAoZmllbGQuaXNBcnJheSkge1xuICAgICAgbGV0IGFycmF5TGVuZ3RoID0gZGF0YVZpZXcuZ2V0VWludDMyKGJ5dGVPZmZzZXQsIHRydWUpO1xuICAgICAgYnl0ZU9mZnNldCArPSA0O1xuICAgICAgbGV0IGFycmF5RmllbGQgPSBuZXcgQXJyYXk8YW55PigpO1xuICAgICAgbWVzc2FnZVtmaWVsZC5uYW1lXSA9IGFycmF5RmllbGQ7XG4gICAgICBmb3IgKGxldCBtID0gMDsgbSA8IGFycmF5TGVuZ3RoOyBtKyspIHtcbiAgICAgICAgbGV0IHZhbHVlQW5kQnl0ZU9mZnNldCA9IHRvVmFsdWVGcm9tQmluYXJ5KGRhdGFWaWV3LCBieXRlT2Zmc2V0LCBmaWVsZCk7XG4gICAgICAgIGFycmF5RmllbGQucHVzaCh2YWx1ZUFuZEJ5dGVPZmZzZXQudmFsdWUpO1xuICAgICAgICBieXRlT2Zmc2V0ID0gdmFsdWVBbmRCeXRlT2Zmc2V0LmJ5dGVPZmZzZXQ7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIGxldCB2YWx1ZUFuZEJ5dGVPZmZzZXQgPSB0b1ZhbHVlRnJvbUJpbmFyeShkYXRhVmlldywgYnl0ZU9mZnNldCwgZmllbGQpO1xuICAgICAgbWVzc2FnZVtmaWVsZC5uYW1lXSA9IHZhbHVlQW5kQnl0ZU9mZnNldC52YWx1ZTtcbiAgICAgIGJ5dGVPZmZzZXQgPSB2YWx1ZUFuZEJ5dGVPZmZzZXQuYnl0ZU9mZnNldDtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHsgbWVzc2FnZSwgYnl0ZU9mZnNldCB9O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZGVzZXJpYWxpemVNZXNzYWdlPFQ+KFxuICBiaW5hcnk6IFVpbnQ4QXJyYXkgfCB1bmRlZmluZWQgfCBudWxsLFxuICBkZXNjcmlwdG9yOiBNZXNzYWdlRGVzY3JpcHRvcjxUPixcbik6IFQge1xuICBpZiAoIWJpbmFyeSkge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbiAgcmV0dXJuIHRvTWVzc2FnZUZyb21CaW5hcnkoXG4gICAgbmV3IERhdGFWaWV3KGJpbmFyeS5idWZmZXIsIGJpbmFyeS5ieXRlT2Zmc2V0LCBiaW5hcnkuYnl0ZUxlbmd0aCksXG4gICAgMCxcbiAgICBkZXNjcmlwdG9yLFxuICApLm1lc3NhZ2U7XG59XG4iXX0=