knx-listener
Version:
A thin client that creates a tunnel to knx gateway to listen to telegrams within knx net
151 lines • 21.3 kB
JavaScript
;
const smart_cursor_1 = require("./utils/smart-cursor");
function header(service, bodyLength) {
const size = 0x06;
const pos = new smart_cursor_1.SmartCursor();
const raw = Buffer.allocUnsafe(size);
raw.writeUInt8(size, pos.next()); // header length
raw.writeUInt8(0x10, pos.next()); // version
raw.writeUInt16BE(service, pos.next(2)); // service type
raw.writeUInt16BE(size + bodyLength, pos.next(2)); // total length
return raw;
}
;
function message(service, includes) {
const size = includes.reduce((acc, item) => acc += item.length, 0);
const head = header(service, size);
const ret = Buffer.concat([head, ...includes]);
return ret;
}
;
function hpai(protocol, ip, port) {
const size = 0x08;
const pos = new smart_cursor_1.SmartCursor();
const raw = Buffer.allocUnsafe(size);
raw.writeUInt8(size, pos.next()); // structure length
raw.writeUInt8(protocol, pos.next()); // protocol
raw.writeUInt32BE(ip, pos.next(4)); // ip
raw.writeUInt16BE(port, pos.next(2)); // port
return raw;
}
;
function tunneling() {
const size = 0x04;
const pos = new smart_cursor_1.SmartCursor();
const raw = Buffer.allocUnsafe(size);
raw.writeUInt8(size, pos.next()); // structure length
raw.writeUInt8(0x04, pos.next()); // TUNNEL_CONNECTION
raw.writeUInt8(0x02, pos.next()); // TUNNEL_LINKLAYER
raw.writeUInt8(0x00, pos.next()); // reserved
return raw;
}
;
function channel(channelId) {
const pos = new smart_cursor_1.SmartCursor();
const raw = Buffer.allocUnsafe(2);
raw.writeUInt8(channelId, pos.next());
raw.writeUInt8(0x00, pos.next()); // reserved
return raw;
}
;
/**
* Creates buffer of sequence counter, channel id and status code
*/
function seqnum(seqn, channelId, status = 0x00) {
const size = 0x04;
const pos = new smart_cursor_1.SmartCursor();
const raw = Buffer.allocUnsafe(size);
raw.writeUInt8(size, pos.next()); // structure length
raw.writeUInt8(channelId, pos.next()); // channelId
raw.writeUInt8(seqn, pos.next()); // sequenceCounter
raw.writeUInt8(status, pos.next()); // reserved or status
return raw;
}
;
// ready to use messages
function ack(seqn, channelId, status) {
return message(1057 /* TunnelingAck */, [
seqnum(seqn, channelId, status),
]);
}
exports.ack = ack;
;
function disconnect(channelId, respondTo) {
return message(521 /* DisconnectRequest */, [
channel(channelId),
hpai(respondTo.protocol, respondTo.ip, respondTo.port),
]);
}
exports.disconnect = disconnect;
;
function ping(channelId, respondTo) {
return message(519 /* ConnectionStateRequest */, [
channel(channelId),
hpai(respondTo.protocol, respondTo.ip, respondTo.port),
]);
}
exports.ping = ping;
;
function openTunnel({ receiveAt, respondTo }) {
return message(517 /* ConnectRequest */, [
hpai(respondTo.protocol, respondTo.ip, respondTo.port),
hpai(receiveAt.protocol, receiveAt.ip, receiveAt.port),
tunneling(),
]);
}
exports.openTunnel = openTunnel;
;
function write({ data, seqn, channelId, source, dest }) {
if (data.length > 16 /* Uint128 */) {
// if data is longer than 16 bytes
throw new Error(`Data is too long, expected maximum ${16 /* Uint128 */} bytes, got ${data.length}`);
}
// cemi
const isUint6 = data.length === 1 /* Uint8 */ && data[0] <= 0x3f;
const size = isUint6 ? 1 /* Uint8 */ : data.length + 1;
const pos = new smart_cursor_1.SmartCursor();
const cemi = Buffer.alloc(0x0A + size);
cemi.writeUInt8(0x11, pos.next()); // L_Data_req
cemi.writeUInt8(0x00, pos.next()); // additional info length
cemi.writeUInt8(0xbc, pos.next()); // control field 1
cemi.writeUInt8(0xe0, pos.next()); // control field 2
cemi.writeUInt16BE(source, pos.next(2)); // source address 0.0.0
cemi.writeUInt16BE(dest, pos.next(2)); // destination address
if (isUint6) {
// data can be merged
cemi.writeUInt8(size, pos.next()); // payload length
cemi.writeUInt16BE(data[0] | 0x80, pos.next(2)); // 0x80 GROUPVALUE_WRITE
}
else {
// data must be appended at the end
cemi.writeUInt8(size, pos.next()); // payload length
cemi.writeUInt16BE(0x80, pos.next(2)); // apci 0x80 GROUPVALUE_WRITE
cemi.set(data, pos.next(size));
}
return message(1056 /* TunnelingRequest */, [
seqnum(seqn, channelId),
cemi,
]);
}
exports.write = write;
;
function read(params) {
// cemi
const pos = new smart_cursor_1.SmartCursor();
const cemi = Buffer.alloc(0x0B);
cemi.writeUInt8(0x11, pos.next()); // L_Data_req
cemi.writeUInt8(0x00, pos.next()); // additional info length
cemi.writeUInt8(0xbc, pos.next()); // control field 1
cemi.writeUInt8(0xe0, pos.next()); // control field 2
cemi.writeUInt16BE(params.source, pos.next(2)); // source address 0.0.0
cemi.writeUInt16BE(params.dest, pos.next(2)); // destination address
cemi.writeUInt8(0x01, pos.next()); // payload length
cemi.writeUInt16BE(0x00, pos.next(2)); // 0x00 GROUPVALUE_READ
return message(1056 /* TunnelingRequest */, [
seqnum(params.seqn, params.channelId),
cemi,
]);
}
exports.read = read;
;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VyaWFsaXplci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9zZXJpYWxpemVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSx1REFFOEI7QUFROUIsZ0JBQWdCLE9BQWdCLEVBQUUsVUFBa0I7SUFDbEQsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDO0lBQ2xCLE1BQU0sR0FBRyxHQUFHLElBQUksMEJBQVcsRUFBRSxDQUFDO0lBQzlCLE1BQU0sR0FBRyxHQUFHLE1BQU0sQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDckMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxJQUFJLEVBQUUsR0FBRyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQyxnQkFBZ0I7SUFDbEQsR0FBRyxDQUFDLFVBQVUsQ0FBQyxJQUFJLEVBQUUsR0FBRyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQyxVQUFVO0lBQzVDLEdBQUcsQ0FBQyxhQUFhLENBQUMsT0FBTyxFQUFFLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLGVBQWU7SUFDeEQsR0FBRyxDQUFDLGFBQWEsQ0FBQyxJQUFJLEdBQUcsVUFBVSxFQUFFLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLGVBQWU7SUFDbEUsTUFBTSxDQUFDLEdBQUcsQ0FBQztBQUNiLENBQUM7QUFBQSxDQUFDO0FBRUYsaUJBQWlCLE9BQWdCLEVBQUUsUUFBa0I7SUFDbkQsTUFBTSxJQUFJLEdBQUcsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDLEdBQUcsRUFBRSxJQUFJLEtBQUssR0FBRyxJQUFJLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFDbkUsTUFBTSxJQUFJLEdBQUcsTUFBTSxDQUFDLE9BQU8sRUFBRSxJQUFJLENBQUMsQ0FBQztJQUNuQyxNQUFNLEdBQUcsR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFD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U0FBUyxDQUFDO1FBQ3JDLElBQUk7S0FDTCxDQUFDLENBQUM7QUFDTCxDQUFDO0FBckJELG9CQXFCQztBQUFBLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBTbWFydEN1cnNvcixcbn0gZnJvbSAnLi91dGlscy9zbWFydC1jdXJzb3InO1xuaW1wb3J0IHtcbiAgU2VydmljZSxcbn0gZnJvbSAnLi9jb25zdGFudHMnO1xuaW1wb3J0IHtcbiAgSHBhaSxcbn0gZnJvbSAnLi9pbnRlcmZhY2VzJztcblxuZnVuY3Rpb24gaGVhZGVyKHNlcnZpY2U6IFNlcnZpY2UsIGJvZHlMZW5ndGg6IG51bWJlcikge1xuICBjb25zdCBzaXplID0gMHgwNjtcbiAgY29uc3QgcG9zID0gbmV3IFNtYXJ0Q3Vyc29yKCk7XG4gIGNvbnN0IHJhdyA9IEJ1ZmZlci5hbGxvY1Vuc2FmZShzaXplKTtcbiAgcmF3LndyaXRlVUludDgoc2l6ZSwgcG9zLm5leHQoKSk7IC8vIGhlYWRlciBsZW5ndGhcbiAgcmF3LndyaXRlVUludDgoMHgxMCwgcG9zLm5leHQoKSk7IC8vIHZlcnNpb25cbiAgcmF3LndyaXRlVUludDE2QkUoc2VydmljZSwgcG9zLm5leHQoMikpOyAvLyBzZXJ2aWNlIHR5cGVcbiAgcmF3LndyaXRlVUludDE2QkUoc2l6ZSArIGJvZHlMZW5ndGgsIHBvcy5uZXh0KDIpKTsgLy8gdG90YWwgbGVuZ3RoXG4gIHJldHVybiByYXc7XG59O1xuXG5mdW5jdGlvbiBtZXNzYWdlKHNlcnZpY2U6IFNlcnZpY2UsIGluY2x1ZGVzOiBCdWZmZXJbXSkge1xuICBjb25zdCBzaXplID0gaW5jbHVkZXMucmVkdWNlKChhY2MsIGl0ZW0pID0+IGFjYyArPSBpdGVtLmxlbmd0aCwgMCk7XG4gIGNvbnN0IGhlYWQgPSBoZWFkZXIoc2VydmljZSwgc2l6ZSk7XG4gIGNvbnN0IHJldCA9IEJ1ZmZlci5jb25jYXQoW2hlYWQsIC4uLmluY2x1ZGVzXSk7XG4gIHJldHVybiByZXQ7XG59O1xuXG5mdW5jdGlvbiBocGFpKHByb3RvY29sOiBudW1iZXIsIGlwOiBudW1iZXIsIHBvcnQ6IG51bWJlcikge1xuICBjb25zdCBzaXplID0gMHgwODtcbiAgY29uc3QgcG9zID0gbmV3IFNtYXJ0Q3Vyc29yKCk7XG4gIGNvbnN0IHJhdyA9IEJ1ZmZlci5hbGxvY1Vuc2FmZShzaXplKTtcbiAgcmF3LndyaXRlVUludDgoc2l6ZSwgcG9zLm5leHQoKSk7IC8vIHN0cnVjdHVyZSBsZW5ndGhcbiAgcmF3LndyaXRlVUludDgocHJvdG9jb2wsIHBvcy5uZXh0KCkpOyAvLyBwcm90b2NvbFxuICByYXcud3JpdGVVSW50MzJCRShpcCwgcG9zLm5leHQoNCkpOyAvLyBpcFxuICByYXcud3JpdGVVSW50MTZCRShwb3J0LCBwb3MubmV4dCgyKSk7IC8vIHBvcnRcbiAgcmV0dXJuIHJhdztcbn07XG5cbmZ1bmN0aW9uIHR1bm5lbGluZygpIHtcbiAgY29uc3Qgc2l6ZSA9IDB4MDQ7XG4gIGNvbnN0IHBvcyA9IG5ldyBTbWFydEN1cnNvcigpO1xuICBjb25zdCByYXcgPSBCdWZmZXIuYWxsb2NVbnNhZmUoc2l6ZSk7XG4gIHJhdy53cml0ZVVJbnQ4KHNpemUsIHBvcy5uZXh0KCkpOyAvLyBzdHJ1Y3R1cmUgbGVuZ3RoXG4gIHJhdy53cml0ZVVJbnQ4KDB4MDQsIHBvcy5uZXh0KCkpOyAvLyBUVU5ORUxfQ09OTkVDVElPTlxuICByYXcud3JpdGVVSW50OCgweDAyLCBwb3MubmV4dCgpKTsgLy8gVFVOTkVMX0xJTktMQVlFUlxuICByYXcud3JpdGVVSW50OCgweDAwLCBwb3MubmV4dCgpKTsgLy8gcmVzZXJ2ZWRcbiAgcmV0dXJuIHJhdztcbn07XG5cbmZ1bmN0aW9uIGNoYW5uZWwoY2hhbm5lbElkOiBudW1iZXIpIHtcbiAgY29uc3QgcG9zID0gbmV3IFNtYXJ0Q3Vyc29yKCk7XG4gIGNvbnN0IHJhdyA9IEJ1ZmZlci5hbGxvY1Vuc2FmZSgyKTtcbiAgcmF3LndyaXRlVUludDgoY2hhbm5lbElkLCBwb3MubmV4dCgpKTtcbiAgcmF3LndyaXRlVUludDgoMHgwMCwgcG9zLm5leHQoKSk7IC8vIHJlc2VydmVkXG4gIHJldHVybiByYXc7XG59O1xuXG4vKipcbiAqIENyZWF0ZXMgYnVmZmVyIG9mIHNlcXVlbmNlIGNvdW50ZXIsIGNoYW5uZWwgaWQgYW5kIHN0YXR1cyBjb2RlXG4gKi9cbmZ1bmN0aW9uIHNlcW51bShzZXFuOiBudW1iZXIsIGNoYW5uZWxJZDogbnVtYmVyLCBzdGF0dXMgPSAweDAwKSB7XG4gIGNvbnN0IHNpemUgPSAweDA0O1xuICBjb25zdCBwb3MgPSBuZXcgU21hcnRDdXJzb3IoKTtcbiAgY29uc3QgcmF3ID0gQnVmZmVyLmFsbG9jVW5zYWZlKHNpemUpO1xuICByYXcud3JpdGVVSW50OChzaXplLCBwb3MubmV4dCgpKTsgLy8gc3RydWN0dXJlIGxlbmd0aFxuICByYXcud3JpdGVVSW50OChjaGFubmVsSWQsIHBvcy5uZXh0KCkpOyAvLyBjaGFubmVsSWRcbiAgcmF3LndyaXRlVUludDgoc2VxbiwgcG9zLm5leHQoKSk7IC8vIHNlcXVlbmNlQ291bnRlclxuICByYXcud3JpdGVVSW50OChzdGF0dXMsIHBvcy5uZXh0KCkpOyAvLyByZXNlcnZlZCBvciBzdGF0dXNcbiAgcmV0dXJuIHJhdztcbn07XG5cbmV4cG9ydCBjb25zdCBlbnVtIERhdGFUeXBlIHtcbiAgVWludDggPSAxLFxuICBVaW50MTYgPSAyLFxuICBVaW50MzIgPSA0LFxuICBVaW50NjQgPSA4LFxuICBVaW50MTI4ID0gMTYsXG59XG5cbi8vIHJlYWR5IHRvIHVzZSBtZXNzYWdlc1xuXG5leHBvcnQgZnVuY3Rpb24gYWNrKHNlcW46IG51bWJlciwgY2hhbm5lbElkOiBudW1iZXIsIHN0YXR1czogbnVtYmVyKSB7XG4gIHJldHVybiBtZXNzYWdlKFNlcnZpY2UuVHVubmVsaW5nQWNrLCBbXG4gICAgc2VxbnVtKHNlcW4sIGNoYW5uZWxJZCwgc3RhdHVzKSxcbiAgXSk7XG59O1xuXG5leHBvcnQgZnVuY3Rpb24gZGlzY29ubmVjdChjaGFubmVsSWQ6IG51bWJlciwgcmVzcG9uZFRvOiBIcGFpKSB7XG4gIHJldHVybiBtZXNzYWdlKFNlcnZpY2UuRGlzY29ubmVjdFJlcXVlc3QsIFtcbiAgICBjaGFubmVsKGNoYW5uZWxJZCksXG4gICAgaHBhaShyZXNwb25kVG8ucHJvdG9jb2wsIHJlc3BvbmRUby5pcCwgcmVzcG9uZFRvLnBvcnQpLFxuICBdKTtcbn07XG5cbmV4cG9ydCBmdW5jdGlvbiBwaW5nKGNoYW5uZWxJZDogbnVtYmVyLCByZXNwb25kVG86IEhwYWkpIHtcbiAgcmV0dXJuIG1lc3NhZ2UoU2VydmljZS5Db25uZWN0aW9uU3RhdGVSZXF1ZXN0LCBbXG4gICAgY2hhbm5lbChjaGFubmVsSWQpLFxuICAgIGhwYWkocmVzcG9uZFRvLnByb3RvY29sLCByZXNwb25kVG8uaXAsIHJlc3BvbmRUby5wb3J0KSxcbiAgXSk7XG59O1xuXG5leHBvcnQgZnVuY3Rpb24gb3BlblR1bm5lbCh7IHJlY2VpdmVBdCwgcmVzcG9uZFRvIH06IHtcbiAgcmVzcG9uZFRvOiBIcGFpO1xuICByZWNlaXZlQXQ6IEhwYWk7XG59KSB7XG4gIHJldHVybiBtZXNzYWdlKFNlcnZpY2UuQ29ubmVjdFJlcXVlc3QsIFtcbiAgICBocGFpKHJlc3BvbmRUby5wcm90b2NvbCwgcmVzcG9uZFRvLmlwLCByZXNwb25kVG8ucG9ydCksXG4gICAgaHBhaShyZWNlaXZlQXQucHJvdG9jb2wsIHJlY2VpdmVBdC5pcCwgcmVjZWl2ZUF0LnBvcnQpLFxuICAgIHR1bm5lbGluZygpLFxuICBdKTtcbn07XG5cbmV4cG9ydCBmdW5jdGlvbiB3cml0ZSh7IGRhdGEsIHNlcW4sIGNoYW5uZWxJZCwgc291cmNlLCBkZXN0IH06IHtcbiAgZGF0YTogQnVmZmVyIHwgVWludDhBcnJheSB8IG51bWJlcltdO1xuICBzZXFuOiBudW1iZXI7XG4gIGNoYW5uZWxJZDogbnVtYmVyO1xuICBzb3VyY2U6IG51bWJlcjtcbiAgZGVzdDogbnVtYmVyO1xufSkge1xuICBpZiAoZGF0YS5sZW5ndGggPiBEYXRhVHlwZS5VaW50MTI4KSB7XG4gICAgLy8gaWYgZGF0YSBpcyBsb25nZXIgdGhhbiAxNiBieXRlc1xuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgIGBEYXRhIGlzIHRvbyBsb25nLCBleHBlY3RlZCBtYXhpbXVtICR7RGF0YVR5cGUuVWludDEyOH0gYnl0ZXMsIGdvdCAke2RhdGEubGVuZ3RofWApO1xuICB9XG4gIC8vIGNlbWlcbiAgY29uc3QgaXNVaW50NiA9IGRhdGEubGVuZ3RoID09PSBEYXRhVHlwZS5VaW50OCAmJiBkYXRhWzBdIDw9IDB4M2Y7XG4gIGNvbnN0IHNpemUgPSBpc1VpbnQ2ID8gRGF0YVR5cGUuVWludDggOiBkYXRhLmxlbmd0aCArIDE7XG4gIGNvbnN0IHBvcyA9IG5ldyBTbWFydEN1cnNvcigpO1xuICBjb25zdCBjZW1pID0gQnVmZmVyLmFsbG9jKDB4MEEgKyBzaXplKTtcbiAgY2VtaS53cml0ZVVJbnQ4KDB4MTEsIHBvcy5uZXh0KCkpOyAvLyBMX0RhdGFfcmVxXG4gIGNlbWkud3JpdGVVSW50OCgweDAwLCBwb3MubmV4dCgpKTsgLy8gYWRkaXRpb25hbCBpbmZvIGxlbmd0aFxuICBjZW1pLndyaXRlVUludDgoMHhiYywgcG9zLm5leHQoKSk7IC8vIGNvbnRyb2wgZmllbGQgMVxuICBjZW1pLndyaXRlVUludDgoMHhlMCwgcG9zLm5leHQoKSk7IC8vIGNvbnRyb2wgZmllbGQgMlxuICBjZW1pLndyaXRlVUludDE2QkUoc291cmNlLCBwb3MubmV4dCgyKSk7IC8vIHNvdXJjZSBhZGRyZXNzIDAuMC4wXG4gIGNlbWkud3JpdGVVSW50MTZCRShkZXN0LCBwb3MubmV4dCgyKSk7IC8vIGRlc3RpbmF0aW9uIGFkZHJlc3NcbiAgaWYgKGlzVWludDYpIHtcbiAgICAvLyBkYXRhIGNhbiBiZSBtZXJnZWRcbiAgICBjZW1pLndyaXRlVUludDgoc2l6ZSwgcG9zLm5leHQoKSk7IC8vIHBheWxvYWQgbGVuZ3RoXG4gICAgY2VtaS53cml0ZVVJbnQxNkJFKGRhdGFbMF0gfCAweDgwLCBwb3MubmV4dCgyKSk7IC8vIDB4ODAgR1JPVVBWQUxVRV9XUklURVxuICB9IGVsc2Uge1xuICAgIC8vIGRhdGEgbXVzdCBiZSBhcHBlbmRlZCBhdCB0aGUgZW5kXG4gICAgY2VtaS53cml0ZVVJbnQ4KHNpemUsIHBvcy5uZXh0KCkpOyAvLyBwYXlsb2FkIGxlbmd0aFxuICAgIGNlbWkud3JpdGVVSW50MTZCRSgweDgwLCBwb3MubmV4dCgyKSk7IC8vIGFwY2kgMHg4MCBHUk9VUFZBTFVFX1dSSVRFXG4gICAgY2VtaS5zZXQoZGF0YSwgcG9zLm5leHQoc2l6ZSkpO1xuICB9XG4gIHJldHVybiBtZXNzYWdlKFNlcnZpY2UuVHVubmVsaW5nUmVxdWVzdCwgW1xuICAgIHNlcW51bShzZXFuLCBjaGFubmVsSWQpLFxuICAgIGNlbWksXG4gIF0pO1xufTtcblxuZXhwb3J0IGZ1bmN0aW9uIHJlYWQocGFyYW1zOiB7XG4gIHNlcW46IG51bWJlcjtcbiAgY2hhbm5lbElkOiBudW1iZXI7XG4gIHNvdXJjZTogbnVtYmVyO1xuICBkZXN0OiBudW1iZXI7XG59KSB7XG4gIC8vIGNlbWlcbiAgY29uc3QgcG9zID0gbmV3IFNtYXJ0Q3Vyc29yKCk7XG4gIGNvbnN0IGNlbWkgPSBCdWZmZXIuYWxsb2MoMHgwQik7XG4gIGNlbWkud3JpdGVVSW50OCgweDExLCBwb3MubmV4dCgpKTsgLy8gTF9EYXRhX3JlcVxuICBjZW1pLndyaXRlVUludDgoMHgwMCwgcG9zLm5leHQoKSk7IC8vIGFkZGl0aW9uYWwgaW5mbyBsZW5ndGhcbiAgY2VtaS53cml0ZVVJbnQ4KDB4YmMsIHBvcy5uZXh0KCkpOyAvLyBjb250cm9sIGZpZWxkIDFcbiAgY2VtaS53cml0ZVVJbnQ4KDB4ZTAsIHBvcy5uZXh0KCkpOyAvLyBjb250cm9sIGZpZWxkIDJcbiAgY2VtaS53cml0ZVVJbnQxNkJFKHBhcmFtcy5zb3VyY2UsIHBvcy5uZXh0KDIpKTsgLy8gc291cmNlIGFkZHJlc3MgMC4wLjBcbiAgY2VtaS53cml0ZVVJbnQxNkJFKHBhcmFtcy5kZXN0LCBwb3MubmV4dCgyKSk7IC8vIGRlc3RpbmF0aW9uIGFkZHJlc3NcbiAgY2VtaS53cml0ZVVJbnQ4KDB4MDEsIHBvcy5uZXh0KCkpOyAvLyBwYXlsb2FkIGxlbmd0aFxuICBjZW1pLndyaXRlVUludDE2QkUoMHgwMCwgcG9zLm5leHQoMikpOyAvLyAweDAwIEdST1VQVkFMVUVfUkVBRFxuICByZXR1cm4gbWVzc2FnZShTZXJ2aWNlLlR1bm5lbGluZ1JlcXVlc3QsIFtcbiAgICBzZXFudW0ocGFyYW1zLnNlcW4sIHBhcmFtcy5jaGFubmVsSWQpLFxuICAgIGNlbWksXG4gIF0pO1xufTtcbiJdfQ==