@neo-one/smart-contract-compiler
Version:
NEO•ONE TypeScript smart contract compiler.
265 lines (263 loc) • 36 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const pc_1 = require("../pc");
const KnownProgramCounter_1 = require("../pc/KnownProgramCounter");
const MAX_JUMP = 32000;
class CodePoint {
constructor(node, tags) {
this.node = node;
this.tags = tags;
}
get pc() {
return this.resolvePC();
}
get prev() {
return this.mutablePrev;
}
set prev(prev) {
this.mutablePC = undefined;
this.mutablePrev = prev;
}
get next() {
return this.mutableNext;
}
set next(next) {
this.mutableNext = next;
}
resolveAllPCs() {
let current = this;
while (current !== undefined) {
current.resolvePC(true);
current = current.next;
}
}
resolvePC(force = false) {
if (force || this.mutablePC === undefined || (this.prev !== undefined && this.prev.mutablePC === undefined)) {
this.mutablePC = this.prev === undefined ? 0 : this.prev.pc + this.prev.length;
}
return this.mutablePC;
}
}
class JumpCodePoint extends CodePoint {
constructor(node, tags, type) {
super(node, tags);
this.type = type;
this.length = 3;
}
get target() {
if (this.mutableTarget === undefined) {
throw new Error('Target not set');
}
return this.mutableTarget;
}
set target(target) {
this.mutableTarget = target;
}
get isForwardJump() {
return this.target.pc > this.pc;
}
get isReverseJump() {
return this.target.pc < this.pc;
}
}
class LineCodePoint extends CodePoint {
constructor() {
super(...arguments);
this.length = 5;
}
}
class BufferCodePoint extends CodePoint {
constructor(node, tags, value) {
super(node, tags);
this.value = value;
this.length = value.length;
}
}
class JumpStationCodePoint extends CodePoint {
constructor(node, hasForward, reverseTarget) {
super(node, ['JumpStation']);
this.reverseTarget = reverseTarget;
this.length = hasForward ? 9 : 6;
}
get target() {
return this.mutableTarget;
}
set target(target) {
this.mutableTarget = target;
}
}
const getCodePoint = (bytecode) => {
const mutableSources = {};
const mutableCodePoints = {};
const [firstNode, firstTags, firstBytecode] = bytecode[0];
if (!(firstBytecode instanceof pc_1.Jump)) {
throw new Error('Expected first bytecode to be a jump.');
}
const first = new JumpCodePoint(firstNode, firstTags, firstBytecode.op);
const jumpTargetPC = firstBytecode.pc.getPC();
mutableSources[jumpTargetPC] = [first];
mutableCodePoints[0] = first;
let pc = first.length;
let mutablePrev = first;
bytecode.slice(1).forEach(([node, tags, value]) => {
let mutableCodePoint;
if (value instanceof pc_1.Jump) {
const targetPC = value.pc.getPC();
let mutableJumpCodePoint;
if (targetPC < pc) {
mutableJumpCodePoint = new JumpCodePoint(node, tags, value.op);
mutableJumpCodePoint.target = mutableCodePoints[targetPC];
}
else {
mutableJumpCodePoint = new JumpCodePoint(node, tags, value.op);
if (mutableSources[targetPC] === undefined) {
mutableSources[targetPC] = [];
}
mutableSources[targetPC].push(mutableJumpCodePoint);
}
mutableCodePoint = mutableJumpCodePoint;
}
else if (value instanceof pc_1.Line) {
mutableCodePoint = new LineCodePoint(node, tags);
}
else {
mutableCodePoint = new BufferCodePoint(node, tags, value);
}
const pcSources = mutableSources[pc];
if (pcSources !== undefined) {
pcSources.forEach((mutableSource) => {
mutableSource.target = mutableCodePoint;
});
}
mutableCodePoints[pc] = mutableCodePoint;
pc += mutableCodePoint.length;
mutableCodePoint.prev = mutablePrev;
mutablePrev.next = mutableCodePoint;
mutablePrev = mutableCodePoint;
});
return first;
};
const addJumpStations = (node, codePoint, maxOffset) => {
codePoint.resolveAllPCs();
const mutableFirstCodePoint = codePoint;
if (!(mutableFirstCodePoint instanceof JumpCodePoint)) {
throw new Error('Expected first codepoint to be a jump');
}
const secondCodePoint = codePoint.next;
if (secondCodePoint === undefined) {
throw new Error('Expected at least two codepoints');
}
let mutableReverseTarget = secondCodePoint;
let forwardDone = false;
let mutableCurrent = mutableFirstCodePoint;
let firstJumpStation;
while (mutableCurrent !== undefined) {
if (mutableCurrent instanceof JumpCodePoint &&
mutableCurrent.isReverseJump &&
mutableCurrent.pc - mutableCurrent.target.pc > maxOffset) {
mutableCurrent.target = mutableReverseTarget;
}
const reversePC = mutableReverseTarget.pc + (firstJumpStation === undefined ? 0 : 3);
const mutableNext = mutableCurrent.next;
if (mutableNext !== undefined && mutableNext.pc - reversePC + 9 > maxOffset) {
const hasForward = !forwardDone && mutableFirstCodePoint.target.pc - maxOffset >= mutableNext.pc;
let mutableJumpStation;
if (!hasForward && !forwardDone) {
mutableJumpStation = new JumpStationCodePoint(node, true, mutableReverseTarget);
mutableJumpStation.target = mutableFirstCodePoint.target;
if (mutableReverseTarget instanceof JumpStationCodePoint) {
mutableReverseTarget.target = mutableJumpStation;
}
forwardDone = true;
}
else {
mutableJumpStation = new JumpStationCodePoint(node, hasForward, mutableReverseTarget);
if (hasForward && mutableReverseTarget instanceof JumpStationCodePoint) {
mutableReverseTarget.target = mutableJumpStation;
}
}
if (firstJumpStation === undefined) {
firstJumpStation = mutableJumpStation;
}
mutableReverseTarget = mutableJumpStation;
const mutablePrev = mutableCurrent.prev;
if (mutablePrev !== undefined) {
mutablePrev.next = mutableJumpStation;
}
mutableCurrent.prev = mutableJumpStation;
mutableJumpStation.next = mutableCurrent;
mutableJumpStation.prev = mutablePrev;
}
mutableCurrent = mutableCurrent.next;
}
if (firstJumpStation !== undefined) {
mutableFirstCodePoint.target = firstJumpStation;
}
};
const getTargetPC = (codePoint, target) => {
if (target instanceof JumpStationCodePoint) {
if (target.pc > codePoint.pc) {
return new KnownProgramCounter_1.KnownProgramCounter(target.pc + 6);
}
return new KnownProgramCounter_1.KnownProgramCounter(target.pc + 3);
}
return new KnownProgramCounter_1.KnownProgramCounter(target.pc);
};
const getBytecode = (first) => {
first.resolveAllPCs();
let current = first;
const mutableOut = [];
while (current !== undefined) {
if (current instanceof JumpCodePoint) {
const pc = getTargetPC(current, current.target);
if (current.type === 'CALL') {
mutableOut.push([current.node, current.tags, new pc_1.Call(pc)]);
}
else {
mutableOut.push([current.node, current.tags, new pc_1.Jmp(current.type, pc)]);
}
}
else if (current instanceof BufferCodePoint) {
mutableOut.push([current.node, current.tags, current.value]);
}
else if (current instanceof JumpStationCodePoint) {
const target = current.target;
const reverseTarget = new pc_1.Jmp('JMP', getTargetPC(current, current.reverseTarget));
if (target === undefined) {
mutableOut.push([
current.node,
current.tags,
new pc_1.Jmp('JMP', new KnownProgramCounter_1.KnownProgramCounter(current.pc + current.length)),
]);
mutableOut.push([current.node, current.tags, reverseTarget]);
}
else {
mutableOut.push([
current.node,
current.tags,
new pc_1.Jmp('JMP', new KnownProgramCounter_1.KnownProgramCounter(current.pc + current.length)),
]);
mutableOut.push([current.node, current.tags, reverseTarget]);
mutableOut.push([current.node, current.tags, new pc_1.Jmp('JMP', getTargetPC(current, target))]);
}
}
else if (current instanceof LineCodePoint) {
mutableOut.push([current.node, current.tags, new pc_1.Line()]);
}
else {
throw new Error('Something went wrong.');
}
current = current.next;
}
return mutableOut;
};
exports.resolveJumps = (bytecode, maxOffset = MAX_JUMP) => {
const length = bytecode.reduce((acc, value) => (value instanceof pc_1.Jump ? acc + 3 : value instanceof pc_1.Line ? acc + 5 : acc + value.length), 0);
if (length < MAX_JUMP) {
return bytecode;
}
const codePoint = getCodePoint(bytecode);
addJumpStations(bytecode[0][0], codePoint, maxOffset);
return getBytecode(codePoint);
};
//# sourceMappingURL=data:application/json;charset=utf8;base64,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O1lBQzNDLFVBQVUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxPQUFPLENBQUMsSUFBSSxFQUFFLE9BQU8sQ0FBQyxJQUFJLEVBQUUsSUFBSSxTQUFJLEVBQUUsQ0FBVSxDQUFDLENBQUM7U0FDcEU7YUFBTTtZQUNMLE1BQU0sSUFBSSxLQUFLLENBQUMsdUJBQXVCLENBQUMsQ0FBQztTQUMxQztRQUNELE9BQU8sR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDO0tBQ3hCO0lBRUQsT0FBTyxVQUFVLENBQUM7QUFDcEIsQ0FBQyxDQUFDO0FBRVcsUUFBQSxZQUFZLEdBQUcsQ0FBQyxRQUFrQixFQUFFLFlBQW9CLFFBQVEsRUFBWSxFQUFFO0lBQ3pGLE1BQU0sTUFBTSxHQUFHLFFBQVEsQ0FBQyxNQUFNLENBQzVCLENBQUMsR0FBRyxFQUFFLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQyxLQUFLLFlBQVksU0FBSSxDQUFDLENBQUMsQ0FBQyxHQUFHLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLFlBQVksU0FBSSxDQUFDLENBQUMsQ0FBQyxHQUFHLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLEdBQUcsS0FBSyxDQUFDLE1BQU0sQ0FBQyxFQUN4RyxDQUFDLENBQ0YsQ0FBQztJQUNGLElBQUksTUFBTSxHQUFHLFFBQVEsRUFBRTtRQUNyQixPQUFPLFFBQVEsQ0FBQztLQUNqQjtJQUVELE1BQU0sU0FBUyxHQUFHLFlBQVksQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUN6QyxlQUFlLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLFNBQVMsRUFBRSxTQUFTLENBQUMsQ0FBQztJQUV0RCxPQUFPLFdBQVcsQ0FBQyxTQUFTLENBQUMsQ0FBQztBQUNoQyxDQUFDLENBQUMiLCJmaWxlIjoibmVvLW9uZS1zbWFydC1jb250cmFjdC1jb21waWxlci9zcmMvY29tcGlsZS9zYi9yZXNvbHZlSnVtcHMuanMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgdHMgZnJvbSAndHlwZXNjcmlwdCc7XG5pbXBvcnQgeyBDYWxsLCBKbXAsIEp1bXAsIExpbmUgfSBmcm9tICcuLi9wYyc7XG5pbXBvcnQgeyBLbm93blByb2dyYW1Db3VudGVyIH0gZnJvbSAnLi4vcGMvS25vd25Qcm9ncmFtQ291bnRlcic7XG5pbXBvcnQgeyBCeXRlY29kZSwgU2luZ2xlQnl0ZWNvZGUsIFRhZ3MgfSBmcm9tICcuL1NjcmlwdEJ1aWxkZXInO1xuXG4vLyBjb25zdCBNQVhfSlVNUCA9IDMyNzY3O1xuY29uc3QgTUFYX0pVTVAgPSAzMjAwMDtcblxuYWJzdHJhY3QgY2xhc3MgQ29kZVBvaW50IHtcbiAgcHVibGljIGFic3RyYWN0IHJlYWRvbmx5IGxlbmd0aDogbnVtYmVyO1xuICBwcml2YXRlIG11dGFibGVQQzogbnVtYmVyIHwgdW5kZWZpbmVkO1xuICBwcml2YXRlIG11dGFibGVQcmV2OiBDb2RlUG9pbnQgfCB1bmRlZmluZWQ7XG4gIHByaXZhdGUgbXV0YWJsZU5leHQ6IENvZGVQb2ludCB8IHVuZGVmaW5lZDtcblxuICBwdWJsaWMgY29uc3RydWN0b3IocHVibGljIHJlYWRvbmx5IG5vZGU6IHRzLk5vZGUsIHB1YmxpYyByZWFkb25seSB0YWdzOiBUYWdzKSB7fVxuXG4gIHB1YmxpYyBnZXQgcGMoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5yZXNvbHZlUEMoKTtcbiAgfVxuXG4gIHB1YmxpYyBnZXQgcHJldigpOiBDb2RlUG9pbnQgfCB1bmRlZmluZWQge1xuICAgIHJldHVybiB0aGlzLm11dGFibGVQcmV2O1xuICB9XG5cbiAgcHVibGljIHNldCBwcmV2KHByZXY6IENvZGVQb2ludCB8IHVuZGVmaW5lZCkge1xuICAgIHRoaXMubXV0YWJsZVBDID0gdW5kZWZpbmVkO1xuICAgIHRoaXMubXV0YWJsZVByZXYgPSBwcmV2O1xuICB9XG5cbiAgcHVibGljIGdldCBuZXh0KCk6IENvZGVQb2ludCB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMubXV0YWJsZU5leHQ7XG4gIH1cblxuICBwdWJsaWMgc2V0IG5leHQobmV4dDogQ29kZVBvaW50IHwgdW5kZWZpbmVkKSB7XG4gICAgdGhpcy5tdXRhYmxlTmV4dCA9IG5leHQ7XG4gIH1cblxuICBwdWJsaWMgcmVzb2x2ZUFsbFBDcygpOiB2b2lkIHtcbiAgICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmUgbm8tdGhpcy1hc3NpZ25tZW50XG4gICAgbGV0IGN1cnJlbnQ6IENvZGVQb2ludCB8IHVuZGVmaW5lZCA9IHRoaXM7XG4gICAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lIG5vLWxvb3Atc3RhdGVtZW50XG4gICAgd2hpbGUgKGN1cnJlbnQgIT09IHVuZGVmaW5lZCkge1xuICAgICAgY3VycmVudC5yZXNvbHZlUEModHJ1ZSk7XG4gICAgICBjdXJyZW50ID0gY3VycmVudC5uZXh0O1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgcmVzb2x2ZVBDKGZvcmNlID0gZmFsc2UpOiBudW1iZXIge1xuICAgIGlmIChmb3JjZSB8fCB0aGlzLm11dGFibGVQQyA9PT0gdW5kZWZpbmVkIHx8ICh0aGlzLnByZXYgIT09IHVuZGVmaW5lZCAmJiB0aGlzLnByZXYubXV0YWJsZVBDID09PSB1bmRlZmluZWQpKSB7XG4gICAgICB0aGlzLm11dGFibGVQQyA9IHRoaXMucHJldiA9PT0gdW5kZWZpbmVkID8gMCA6IHRoaXMucHJldi5wYyArIHRoaXMucHJldi5sZW5ndGg7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMubXV0YWJsZVBDO1xuICB9XG59XG5cbmNsYXNzIEp1bXBDb2RlUG9pbnQgZXh0ZW5kcyBDb2RlUG9pbnQge1xuICBwdWJsaWMgcmVhZG9ubHkgbGVuZ3RoID0gMztcbiAgcHJpdmF0ZSBtdXRhYmxlVGFyZ2V0OiBDb2RlUG9pbnQgfCB1bmRlZmluZWQ7XG5cbiAgcHVibGljIGNvbnN0cnVjdG9yKG5vZGU6IHRzLk5vZGUsIHRhZ3M6IFRhZ3MsIHB1YmxpYyByZWFkb25seSB0eXBlOiAnSk1QJyB8ICdKTVBJRicgfCAnSk1QSUZOT1QnIHwgJ0NBTEwnKSB7XG4gICAgc3VwZXIobm9kZSwgdGFncyk7XG4gIH1cblxuICBwdWJsaWMgZ2V0IHRhcmdldCgpOiBDb2RlUG9pbnQge1xuICAgIGlmICh0aGlzLm11dGFibGVUYXJnZXQgPT09IHVuZGVmaW5lZCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdUYXJnZXQgbm90IHNldCcpO1xuICAgIH1cblxuICAgIHJldHVybiB0aGlzLm11dGFibGVUYXJnZXQ7XG4gIH1cblxuICBwdWJsaWMgc2V0IHRhcmdldCh0YXJnZXQ6IENvZGVQb2ludCkge1xuICAgIHRoaXMubXV0YWJsZVRhcmdldCA9IHRhcmdldDtcbiAgfVxuXG4gIHB1YmxpYyBnZXQgaXNGb3J3YXJkSnVtcCgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy50YXJnZXQucGMgPiB0aGlzLnBjO1xuICB9XG5cbiAgcHVibGljIGdldCBpc1JldmVyc2VKdW1wKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLnRhcmdldC5wYyA8IHRoaXMucGM7XG4gIH1cbn1cblxuY2xhc3MgTGluZUNvZGVQb2ludCBleHRlbmRzIENvZGVQb2ludCB7XG4gIHB1YmxpYyByZWFkb25seSBsZW5ndGg6IG51bWJlciA9IDU7XG59XG5cbmNsYXNzIEJ1ZmZlckNvZGVQb2ludCBleHRlbmRzIENvZGVQb2ludCB7XG4gIHB1YmxpYyByZWFkb25seSBsZW5ndGg6IG51bWJlcjtcblxuICBwdWJsaWMgY29uc3RydWN0b3Iobm9kZTogdHMuTm9kZSwgdGFnczogVGFncywgcHVibGljIHJlYWRvbmx5IHZhbHVlOiBCdWZmZXIpIHtcbiAgICBzdXBlcihub2RlLCB0YWdzKTtcbiAgICB0aGlzLmxlbmd0aCA9IHZhbHVlLmxlbmd0aDtcbiAgfVxufVxuXG5jbGFzcyBKdW1wU3RhdGlvbkNvZGVQb2ludCBleHRlbmRzIENvZGVQb2ludCB7XG4gIHB1YmxpYyByZWFkb25seSBsZW5ndGg6IG51bWJlcjtcbiAgcHJpdmF0ZSBtdXRhYmxlVGFyZ2V0OiBDb2RlUG9pbnQgfCB1bmRlZmluZWQ7XG5cbiAgcHVibGljIGNvbnN0cnVjdG9yKG5vZGU6IHRzLk5vZGUsIGhhc0ZvcndhcmQ6IGJvb2xlYW4sIHB1YmxpYyByZWFkb25seSByZXZlcnNlVGFyZ2V0OiBDb2RlUG9pbnQpIHtcbiAgICBzdXBlcihub2RlLCBbJ0p1bXBTdGF0aW9uJ10pO1xuICAgIHRoaXMubGVuZ3RoID0gaGFzRm9yd2FyZCA/IDkgOiA2O1xuICB9XG5cbiAgcHVibGljIGdldCB0YXJnZXQoKTogQ29kZVBvaW50IHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gdGhpcy5tdXRhYmxlVGFyZ2V0O1xuICB9XG5cbiAgcHVibGljIHNldCB0YXJnZXQodGFyZ2V0OiBDb2RlUG9pbnQgfCB1bmRlZmluZWQpIHtcbiAgICB0aGlzLm11dGFibGVUYXJnZXQgPSB0YXJnZXQ7XG4gIH1cbn1cblxuY29uc3QgZ2V0Q29kZVBvaW50ID0gKGJ5dGVjb2RlOiBCeXRlY29kZSk6IENvZGVQb2ludCA9PiB7XG4gIGNvbnN0IG11dGFibGVTb3VyY2VzOiB7IFtwYzogbnVtYmVyXTogQXJyYXk8SnVtcENvZGVQb2ludCB8IEp1bXBTdGF0aW9uQ29kZVBvaW50PiB9ID0ge307XG4gIGNvbnN0IG11dGFibGVDb2RlUG9pbnRzOiB7IFtwYzogbnVtYmVyXTogQ29kZVBvaW50IH0gPSB7fTtcbiAgY29uc3QgW2ZpcnN0Tm9kZSwgZmlyc3RUYWdzLCBmaXJzdEJ5dGVjb2RlXSA9IGJ5dGVjb2RlWzBdO1xuICBpZiAoIShmaXJzdEJ5dGVjb2RlIGluc3RhbmNlb2YgSnVtcCkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ0V4cGVjdGVkIGZpcnN0IGJ5dGVjb2RlIHRvIGJlIGEganVtcC4nKTtcbiAgfVxuICBjb25zdCBmaXJzdCA9IG5ldyBKdW1wQ29kZVBvaW50KGZpcnN0Tm9kZSwgZmlyc3RUYWdzLCBmaXJzdEJ5dGVjb2RlLm9wKTtcbiAgY29uc3QganVtcFRhcmdldFBDID0gZmlyc3RCeXRlY29kZS5wYy5nZXRQQygpO1xuICBtdXRhYmxlU291cmNlc1tqdW1wVGFyZ2V0UENdID0gW2ZpcnN0XTtcbiAgbXV0YWJsZUNvZGVQb2ludHNbMF0gPSBmaXJzdDtcblxuICBsZXQgcGMgPSBmaXJzdC5sZW5ndGg7XG4gIGxldCBtdXRhYmxlUHJldjogQ29kZVBvaW50ID0gZmlyc3Q7XG4gIGJ5dGVjb2RlLnNsaWNlKDEpLmZvckVhY2goKFtub2RlLCB0YWdzLCB2YWx1ZV0pID0+IHtcbiAgICBsZXQgbXV0YWJsZUNvZGVQb2ludDogQ29kZVBvaW50O1xuICAgIGlmICh2YWx1ZSBpbnN0YW5jZW9mIEp1bXApIHtcbiAgICAgIGNvbnN0IHRhcmdldFBDID0gdmFsdWUucGMuZ2V0UEMoKTtcbiAgICAgIGxldCBtdXRhYmxlSnVtcENvZGVQb2ludDtcbiAgICAgIC8vIFdlIG11c3QgaGF2ZSBjcmVhdGVkIHRoZSBDb2RlUG9pbnQgYWxyZWFkeVxuICAgICAgaWYgKHRhcmdldFBDIDwgcGMpIHtcbiAgICAgICAgbXV0YWJsZUp1bXBDb2RlUG9pbnQgPSBuZXcgSnVtcENvZGVQb2ludChub2RlLCB0YWdzLCB2YWx1ZS5vcCk7XG4gICAgICAgIG11dGFibGVKdW1wQ29kZVBvaW50LnRhcmdldCA9IG11dGFibGVDb2RlUG9pbnRzW3RhcmdldFBDXTtcbiAgICAgICAgLy8gV2Ugd2lsbCBjcmVhdGUgaXQgaW4gdGhlIGZ1dHVyZSwgc3RvcmUgZm9yIGxhdGVyXG4gICAgICB9IGVsc2Uge1xuICAgICAgICBtdXRhYmxlSnVtcENvZGVQb2ludCA9IG5ldyBKdW1wQ29kZVBvaW50KG5vZGUsIHRhZ3MsIHZhbHVlLm9wKTtcbiAgICAgICAgaWYgKChtdXRhYmxlU291cmNlc1t0YXJnZXRQQ10gYXMgSnVtcENvZGVQb2ludFtdIHwgdW5kZWZpbmVkKSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgbXV0YWJsZVNvdXJjZXNbdGFyZ2V0UENdID0gW107XG4gICAgICAgIH1cbiAgICAgICAgbXV0YWJsZVNvdXJjZXNbdGFyZ2V0UENdLnB1c2gobXV0YWJsZUp1bXBDb2RlUG9pbnQpO1xuICAgICAgfVxuICAgICAgbXV0YWJsZUNvZGVQb2ludCA9IG11dGFibGVKdW1wQ29kZVBvaW50O1xuICAgIH0gZWxzZSBpZiAodmFsdWUgaW5zdGFuY2VvZiBMaW5lKSB7XG4gICAgICBtdXRhYmxlQ29kZVBvaW50ID0gbmV3IExpbmVDb2RlUG9pbnQobm9kZSwgdGFncyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIG11dGFibGVDb2RlUG9pbnQgPSBuZXcgQnVmZmVyQ29kZVBvaW50KG5vZGUsIHRhZ3MsIHZhbHVlKTtcbiAgICB9XG5cbiAgICAvLyBGaW5kIGFsbCBzb3VyY2VzIHRoYXQgd2UgY3JlYXRlZCB3aGljaCB0YXJnZXQgdGhpcyBjb2RlIHBvaW50IGFuZCBzZXQgdGhlaXIgdGFyZ2V0XG4gICAgY29uc3QgcGNTb3VyY2VzID0gbXV0YWJsZVNvdXJjZXNbcGNdIGFzIEp1bXBDb2RlUG9pbnRbXSB8IHVuZGVmaW5lZDtcbiAgICBpZiAocGNTb3VyY2VzICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHBjU291cmNlcy5mb3JFYWNoKChtdXRhYmxlU291cmNlKSA9PiB7XG4gICAgICAgIG11dGFibGVTb3VyY2UudGFyZ2V0ID0gbXV0YWJsZUNvZGVQb2ludDtcbiAgICAgIH0pO1xuICAgIH1cbiAgICBtdXRhYmxlQ29kZVBvaW50c1twY10gPSBtdXRhYmxlQ29kZVBvaW50O1xuICAgIHBjICs9IG11dGFibGVDb2RlUG9pbnQubGVuZ3RoO1xuXG4gICAgbXV0YWJsZUNvZGVQb2ludC5wcmV2ID0gbXV0YWJsZVByZXY7XG4gICAgbXV0YWJsZVByZXYubmV4dCA9IG11dGFibGVDb2RlUG9pbnQ7XG4gICAgbXV0YWJsZVByZXYgPSBtdXRhYmxlQ29kZVBvaW50O1xuICB9KTtcblxuICByZXR1cm4gZmlyc3Q7XG59O1xuXG5jb25zdCBhZGRKdW1wU3RhdGlvbnMgPSAobm9kZTogdHMuTm9kZSwgY29kZVBvaW50OiBDb2RlUG9pbnQsIG1heE9mZnNldDogbnVtYmVyKTogdm9pZCA9PiB7XG4gIGNvZGVQb2ludC5yZXNvbHZlQWxsUENzKCk7XG5cbiAgY29uc3QgbXV0YWJsZUZpcnN0Q29kZVBvaW50ID0gY29kZVBvaW50O1xuICBpZiAoIShtdXRhYmxlRmlyc3RDb2RlUG9pbnQgaW5zdGFuY2VvZiBKdW1wQ29kZVBvaW50KSkge1xuICAgIHRocm93IG5ldyBFcnJvcignRXhwZWN0ZWQgZmlyc3QgY29kZXBvaW50IHRvIGJlIGEganVtcCcpO1xuICB9XG4gIGNvbnN0IHNlY29uZENvZGVQb2ludCA9IGNvZGVQb2ludC5uZXh0O1xuICBpZiAoc2Vjb25kQ29kZVBvaW50ID09PSB1bmRlZmluZWQpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ0V4cGVjdGVkIGF0IGxlYXN0IHR3byBjb2RlcG9pbnRzJyk7XG4gIH1cblxuICBsZXQgbXV0YWJsZVJldmVyc2VUYXJnZXQgPSBzZWNvbmRDb2RlUG9pbnQ7XG4gIGxldCBmb3J3YXJkRG9uZSA9IGZhbHNlO1xuICBsZXQgbXV0YWJsZUN1cnJlbnQ6IENvZGVQb2ludCB8IHVuZGVmaW5lZCA9IG11dGFibGVGaXJzdENvZGVQb2ludDtcbiAgbGV0IGZpcnN0SnVtcFN0YXRpb246IEp1bXBTdGF0aW9uQ29kZVBvaW50IHwgdW5kZWZpbmVkO1xuICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmUgbm8tbG9vcC1zdGF0ZW1lbnRcbiAgd2hpbGUgKG11dGFibGVDdXJyZW50ICE9PSB1bmRlZmluZWQpIHtcbiAgICBpZiAoXG4gICAgICBtdXRhYmxlQ3VycmVudCBpbnN0YW5jZW9mIEp1bXBDb2RlUG9pbnQgJiZcbiAgICAgIG11dGFibGVDdXJyZW50LmlzUmV2ZXJzZUp1bXAgJiZcbiAgICAgIG11dGFibGVDdXJyZW50LnBjIC0gbXV0YWJsZUN1cnJlbnQudGFyZ2V0LnBjID4gbWF4T2Zmc2V0XG4gICAgKSB7XG4gICAgICBtdXRhYmxlQ3VycmVudC50YXJnZXQgPSBtdXRhYmxlUmV2ZXJzZVRhcmdldDtcbiAgICB9XG5cbiAgICBjb25zdCByZXZlcnNlUEMgPSBtdXRhYmxlUmV2ZXJzZVRhcmdldC5wYyArIChmaXJzdEp1bXBTdGF0aW9uID09PSB1bmRlZmluZWQgPyAwIDogMyk7XG4gICAgY29uc3QgbXV0YWJsZU5leHQgPSBtdXRhYmxlQ3VycmVudC5uZXh0O1xuICAgIGlmIChtdXRhYmxlTmV4dCAhPT0gdW5kZWZpbmVkICYmIG11dGFibGVOZXh0LnBjIC0gcmV2ZXJzZVBDICsgOSA+IG1heE9mZnNldCkge1xuICAgICAgY29uc3QgaGFzRm9yd2FyZCA9ICFmb3J3YXJkRG9uZSAmJiBtdXRhYmxlRmlyc3RDb2RlUG9pbnQudGFyZ2V0LnBjIC0gbWF4T2Zmc2V0ID49IG11dGFibGVOZXh0LnBjO1xuICAgICAgbGV0IG11dGFibGVKdW1wU3RhdGlvbjogSnVtcFN0YXRpb25Db2RlUG9pbnQ7XG4gICAgICBpZiAoIWhhc0ZvcndhcmQgJiYgIWZvcndhcmREb25lKSB7XG4gICAgICAgIG11dGFibGVKdW1wU3RhdGlvbiA9IG5ldyBKdW1wU3RhdGlvbkNvZGVQb2ludChub2RlLCB0cnVlLCBtdXRhYmxlUmV2ZXJzZVRhcmdldCk7XG4gICAgICAgIG11dGFibGVKdW1wU3RhdGlvbi50YXJnZXQgPSBtdXRhYmxlRmlyc3RDb2RlUG9pbnQudGFyZ2V0O1xuICAgICAgICBpZiAobXV0YWJsZVJldmVyc2VUYXJnZXQgaW5zdGFuY2VvZiBKdW1wU3RhdGlvbkNvZGVQb2ludCkge1xuICAgICAgICAgIG11dGFibGVSZXZlcnNlVGFyZ2V0LnRhcmdldCA9IG11dGFibGVKdW1wU3RhdGlvbjtcbiAgICAgICAgfVxuICAgICAgICBmb3J3YXJkRG9uZSA9IHRydWU7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBtdXRhYmxlSnVtcFN0YXRpb24gPSBuZXcgSnVtcFN0YXRpb25Db2RlUG9pbnQobm9kZSwgaGFzRm9yd2FyZCwgbXV0YWJsZVJldmVyc2VUYXJnZXQpO1xuICAgICAgICBpZiAoaGFzRm9yd2FyZCAmJiBtdXRhYmxlUmV2ZXJzZVRhcmdldCBpbnN0YW5jZW9mIEp1bXBTdGF0aW9uQ29kZVBvaW50KSB7XG4gICAgICAgICAgbXV0YWJsZVJldmVyc2VUYXJnZXQudGFyZ2V0ID0gbXV0YWJsZUp1bXBTdGF0aW9uO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmIChmaXJzdEp1bXBTdGF0aW9uID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgZmlyc3RKdW1wU3RhdGlvbiA9IG11dGFibGVKdW1wU3RhdGlvbjtcbiAgICAgIH1cbiAgICAgIG11dGFibGVSZXZlcnNlVGFyZ2V0ID0gbXV0YWJsZUp1bXBTdGF0aW9uO1xuXG4gICAgICBjb25zdCBtdXRhYmxlUHJldiA9IG11dGFibGVDdXJyZW50LnByZXY7XG4gICAgICBpZiAobXV0YWJsZVByZXYgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICBtdXRhYmxlUHJldi5uZXh0ID0gbXV0YWJsZUp1bXBTdGF0aW9uO1xuICAgICAgfVxuICAgICAgbXV0YWJsZUN1cnJlbnQucHJldiA9IG11dGFibGVKdW1wU3RhdGlvbjtcbiAgICAgIG11dGFibGVKdW1wU3RhdGlvbi5uZXh0ID0gbXV0YWJsZUN1cnJlbnQ7XG4gICAgICBtdXRhYmxlSnVtcFN0YXRpb24ucHJldiA9IG11dGFibGVQcmV2O1xuICAgIH1cblxuICAgIG11dGFibGVDdXJyZW50ID0gbXV0YWJsZUN1cnJlbnQubmV4dDtcbiAgfVxuXG4gIGlmIChmaXJzdEp1bXBTdGF0aW9uICE9PSB1bmRlZmluZWQpIHtcbiAgICBtdXRhYmxlRmlyc3RDb2RlUG9pbnQudGFyZ2V0ID0gZmlyc3RKdW1wU3RhdGlvbjtcbiAgfVxufTtcblxuY29uc3QgZ2V0VGFyZ2V0UEMgPSAoY29kZVBvaW50OiBDb2RlUG9pbnQsIHRhcmdldDogQ29kZVBvaW50KTogS25vd25Qcm9ncmFtQ291bnRlciA9PiB7XG4gIGlmICh0YXJnZXQgaW5zdGFuY2VvZiBKdW1wU3RhdGlvbkNvZGVQb2ludCkge1xuICAgIGlmICh0YXJnZXQucGMgPiBjb2RlUG9pbnQucGMpIHtcbiAgICAgIHJldHVybiBuZXcgS25vd25Qcm9ncmFtQ291bnRlcih0YXJnZXQucGMgKyA2KTtcbiAgICB9XG5cbiAgICByZXR1cm4gbmV3IEtub3duUHJvZ3JhbUNvdW50ZXIodGFyZ2V0LnBjICsgMyk7XG4gIH1cblxuICByZXR1cm4gbmV3IEtub3duUHJvZ3JhbUNvdW50ZXIodGFyZ2V0LnBjKTtcbn07XG5cbmNvbnN0IGdldEJ5dGVjb2RlID0gKGZpcnN0OiBDb2RlUG9pbnQpOiBCeXRlY29kZSA9PiB7XG4gIGZpcnN0LnJlc29sdmVBbGxQQ3MoKTtcblxuICBsZXQgY3VycmVudDogQ29kZVBvaW50IHwgdW5kZWZpbmVkID0gZmlyc3Q7XG4gIGNvbnN0IG11dGFibGVPdXQ6IFNpbmdsZUJ5dGVjb2RlW10gPSBbXTtcbiAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lIG5vLWxvb3Atc3RhdGVtZW50XG4gIHdoaWxlIChjdXJyZW50ICE9PSB1bmRlZmluZWQpIHtcbiAgICBpZiAoY3VycmVudCBpbnN0YW5jZW9mIEp1bXBDb2RlUG9pbnQpIHtcbiAgICAgIGNvbnN0IHBjID0gZ2V0VGFyZ2V0UEMoY3VycmVudCwgY3VycmVudC50YXJnZXQpO1xuICAgICAgaWYgKGN1cnJlbnQudHlwZSA9PT0gJ0NBTEwnKSB7XG4gICAgICAgIG11dGFibGVPdXQucHVzaChbY3VycmVudC5ub2RlLCBjdXJyZW50LnRhZ3MsIG5ldyBDYWxsKHBjKV0gYXMgY29uc3QpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgbXV0YWJsZU91dC5wdXNoKFtjdXJyZW50Lm5vZGUsIGN1cnJlbnQudGFncywgbmV3IEptcChjdXJyZW50LnR5cGUsIHBjKV0gYXMgY29uc3QpO1xuICAgICAgfVxuICAgIH0gZWxzZSBpZiAoY3VycmVudCBpbnN0YW5jZW9mIEJ1ZmZlckNvZGVQb2ludCkge1xuICAgICAgbXV0YWJsZU91dC5wdXNoKFtjdXJyZW50Lm5vZGUsIGN1cnJlbnQudGFncywgY3VycmVudC52YWx1ZV0gYXMgY29uc3QpO1xuICAgIH0gZWxzZSBpZiAoY3VycmVudCBpbnN0YW5jZW9mIEp1bXBTdGF0aW9uQ29kZVBvaW50KSB7XG4gICAgICBjb25zdCB0YXJnZXQgPSBjdXJyZW50LnRhcmdldDtcbiAgICAgIGNvbnN0IHJldmVyc2VUYXJnZXQgPSBuZXcgSm1wKCdKTVAnLCBnZXRUYXJnZXRQQyhjdXJyZW50LCBjdXJyZW50LnJldmVyc2VUYXJnZXQpKTtcbiAgICAgIGlmICh0YXJnZXQgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICBtdXRhYmxlT3V0LnB1c2goW1xuICAgICAgICAgIGN1cnJlbnQubm9kZSxcbiAgICAgICAgICBjdXJyZW50LnRhZ3MsXG4gICAgICAgICAgbmV3IEptcCgnSk1QJywgbmV3IEtub3duUHJvZ3JhbUNvdW50ZXIoY3VycmVudC5wYyArIGN1cnJlbnQubGVuZ3RoKSksXG4gICAgICAgIF0gYXMgY29uc3QpO1xuICAgICAgICBtdXRhYmxlT3V0LnB1c2goW2N1cnJlbnQubm9kZSwgY3VycmVudC50YWdzLCByZXZlcnNlVGFyZ2V0XSBhcyBjb25zdCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBtdXRhYmxlT3V0LnB1c2goW1xuICAgICAgICAgIGN1cnJlbnQubm9kZSxcbiAgICAgICAgICBjdXJyZW50LnRhZ3MsXG4gICAgICAgICAgbmV3IEptcCgnSk1QJywgbmV3IEtub3duUHJvZ3JhbUNvdW50ZXIoY3VycmVudC5wYyArIGN1cnJlbnQubGVuZ3RoKSksXG4gICAgICAgIF0gYXMgY29uc3QpO1xuICAgICAgICBtdXRhYmxlT3V0LnB1c2goW2N1cnJlbnQubm9kZSwgY3VycmVudC50YWdzLCByZXZlcnNlVGFyZ2V0XSBhcyBjb25zdCk7XG4gICAgICAgIG11dGFibGVPdXQucHVzaChbY3VycmVudC5ub2RlLCBjdXJyZW50LnRhZ3MsIG5ldyBKbXAoJ0pNUCcsIGdldFRhcmdldFBDKGN1cnJlbnQsIHRhcmdldCkpXSBhcyBjb25zdCk7XG4gICAgICB9XG4gICAgfSBlbHNlIGlmIChjdXJyZW50IGluc3RhbmNlb2YgTGluZUNvZGVQb2ludCkge1xuICAgICAgbXV0YWJsZU91dC5wdXNoKFtjdXJyZW50Lm5vZGUsIGN1cnJlbnQudGFncywgbmV3IExpbmUoKV0gYXMgY29uc3QpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1NvbWV0aGluZyB3ZW50IHdyb25nLicpO1xuICAgIH1cbiAgICBjdXJyZW50ID0gY3VycmVudC5uZXh0O1xuICB9XG5cbiAgcmV0dXJuIG11dGFibGVPdXQ7XG59O1xuXG5leHBvcnQgY29uc3QgcmVzb2x2ZUp1bXBzID0gKGJ5dGVjb2RlOiBCeXRlY29kZSwgbWF4T2Zmc2V0OiBudW1iZXIgPSBNQVhfSlVNUCk6IEJ5dGVjb2RlID0+IHtcbiAgY29uc3QgbGVuZ3RoID0gYnl0ZWNvZGUucmVkdWNlPG51bWJlcj4oXG4gICAgKGFjYywgdmFsdWUpID0+ICh2YWx1ZSBpbnN0YW5jZW9mIEp1bXAgPyBhY2MgKyAzIDogdmFsdWUgaW5zdGFuY2VvZiBMaW5lID8gYWNjICsgNSA6IGFjYyArIHZhbHVlLmxlbmd0aCksXG4gICAgMCxcbiAgKTtcbiAgaWYgKGxlbmd0aCA8IE1BWF9KVU1QKSB7XG4gICAgcmV0dXJuIGJ5dGVjb2RlO1xuICB9XG5cbiAgY29uc3QgY29kZVBvaW50ID0gZ2V0Q29kZVBvaW50KGJ5dGVjb2RlKTtcbiAgYWRkSnVtcFN0YXRpb25zKGJ5dGVjb2RlWzBdWzBdLCBjb2RlUG9pbnQsIG1heE9mZnNldCk7XG5cbiAgcmV0dXJuIGdldEJ5dGVjb2RlKGNvZGVQb2ludCk7XG59O1xuIl19