You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
219 lines
31 KiB
JavaScript
219 lines
31 KiB
JavaScript
var __create = Object.create;
|
|
var __defProp = Object.defineProperty;
|
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
var __getProtoOf = Object.getPrototypeOf;
|
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
var __copyProps = (to, from, except, desc) => {
|
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
for (let key of __getOwnPropNames(from))
|
|
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
}
|
|
return to;
|
|
};
|
|
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod));
|
|
var import_chai = require("chai");
|
|
var sinon = __toESM(require("sinon"));
|
|
var _ = __toESM(require("lodash"));
|
|
var import_utils = require("../../../../session/utils");
|
|
var import_test_utils = require("../../../../test/test-utils");
|
|
var import_PendingMessageCache = require("../../../../session/sending/PendingMessageCache");
|
|
describe("PendingMessageCache", () => {
|
|
const sandbox = sinon.createSandbox();
|
|
let data;
|
|
let pendingMessageCacheStub;
|
|
beforeEach(() => {
|
|
const storageID = "pendingMessages";
|
|
data = {
|
|
id: storageID,
|
|
value: "[]"
|
|
};
|
|
import_test_utils.TestUtils.stubData("getItemById").withArgs("pendingMessages").callsFake(async () => {
|
|
return data;
|
|
});
|
|
import_test_utils.TestUtils.stubData("createOrUpdateItem").callsFake((item) => {
|
|
if (item.id === storageID) {
|
|
data = item;
|
|
}
|
|
});
|
|
pendingMessageCacheStub = new import_PendingMessageCache.PendingMessageCache();
|
|
});
|
|
afterEach(() => {
|
|
sandbox.restore();
|
|
import_test_utils.TestUtils.restoreStubs();
|
|
});
|
|
it("can initialize cache", async () => {
|
|
const cache = await pendingMessageCacheStub.getAllPending();
|
|
(0, import_chai.expect)(cache).to.be.instanceOf(Array);
|
|
(0, import_chai.expect)(cache).to.have.length(0);
|
|
});
|
|
it("can add to cache", async () => {
|
|
const device = import_test_utils.TestUtils.generateFakePubKey();
|
|
const message = import_test_utils.TestUtils.generateVisibleMessage();
|
|
const rawMessage = await import_utils.MessageUtils.toRawMessage(device, message);
|
|
await pendingMessageCacheStub.add(device, message);
|
|
const finalCache = await pendingMessageCacheStub.getAllPending();
|
|
(0, import_chai.expect)(finalCache).to.have.length(1);
|
|
const addedMessage = finalCache[0];
|
|
(0, import_chai.expect)(addedMessage.device).to.deep.equal(rawMessage.device);
|
|
});
|
|
it("can add multiple messages belonging to the same user", async () => {
|
|
const device = import_test_utils.TestUtils.generateFakePubKey();
|
|
await pendingMessageCacheStub.add(device, import_test_utils.TestUtils.generateVisibleMessage());
|
|
await import_test_utils.TestUtils.timeout(5);
|
|
await pendingMessageCacheStub.add(device, import_test_utils.TestUtils.generateVisibleMessage());
|
|
await import_test_utils.TestUtils.timeout(5);
|
|
await pendingMessageCacheStub.add(device, import_test_utils.TestUtils.generateVisibleMessage());
|
|
const finalCache = await pendingMessageCacheStub.getAllPending();
|
|
(0, import_chai.expect)(finalCache).to.have.length(3);
|
|
});
|
|
it("can remove from cache", async () => {
|
|
const device = import_test_utils.TestUtils.generateFakePubKey();
|
|
const message = import_test_utils.TestUtils.generateVisibleMessage();
|
|
const rawMessage = await import_utils.MessageUtils.toRawMessage(device, message);
|
|
await pendingMessageCacheStub.add(device, message);
|
|
const initialCache = await pendingMessageCacheStub.getAllPending();
|
|
(0, import_chai.expect)(initialCache).to.have.length(1);
|
|
await pendingMessageCacheStub.remove(rawMessage);
|
|
const finalCache = await pendingMessageCacheStub.getAllPending();
|
|
(0, import_chai.expect)(finalCache).to.have.length(0);
|
|
});
|
|
it("should only remove messages with different identifier and device", async () => {
|
|
const device = import_test_utils.TestUtils.generateFakePubKey();
|
|
const message = import_test_utils.TestUtils.generateVisibleMessage();
|
|
const rawMessage = await import_utils.MessageUtils.toRawMessage(device, message);
|
|
await pendingMessageCacheStub.add(device, message);
|
|
await import_test_utils.TestUtils.timeout(5);
|
|
const one = await pendingMessageCacheStub.add(device, import_test_utils.TestUtils.generateVisibleMessage());
|
|
const two = await pendingMessageCacheStub.add(import_test_utils.TestUtils.generateFakePubKey(), message);
|
|
const initialCache = await pendingMessageCacheStub.getAllPending();
|
|
(0, import_chai.expect)(initialCache).to.have.length(3);
|
|
await pendingMessageCacheStub.remove(rawMessage);
|
|
const finalCache = await pendingMessageCacheStub.getAllPending();
|
|
(0, import_chai.expect)(finalCache).to.have.length(2);
|
|
(0, import_chai.expect)(finalCache).to.have.deep.members([one, two]);
|
|
});
|
|
it("can get devices", async () => {
|
|
const cacheItems = [
|
|
{
|
|
device: import_test_utils.TestUtils.generateFakePubKey(),
|
|
message: import_test_utils.TestUtils.generateVisibleMessage()
|
|
},
|
|
{
|
|
device: import_test_utils.TestUtils.generateFakePubKey(),
|
|
message: import_test_utils.TestUtils.generateVisibleMessage()
|
|
},
|
|
{
|
|
device: import_test_utils.TestUtils.generateFakePubKey(),
|
|
message: import_test_utils.TestUtils.generateVisibleMessage()
|
|
}
|
|
];
|
|
for (const item of cacheItems) {
|
|
await pendingMessageCacheStub.add(item.device, item.message);
|
|
}
|
|
const cache = await pendingMessageCacheStub.getAllPending();
|
|
(0, import_chai.expect)(cache).to.have.length(cacheItems.length);
|
|
const devicesKeys = cacheItems.map((item) => item.device.key);
|
|
const pulledDevices = await pendingMessageCacheStub.getDevices();
|
|
const pulledDevicesKeys = pulledDevices.map((d) => d.key);
|
|
(0, import_chai.expect)(pulledDevicesKeys).to.have.members(devicesKeys);
|
|
});
|
|
it("can get pending for device", async () => {
|
|
const cacheItems = [
|
|
{
|
|
device: import_test_utils.TestUtils.generateFakePubKey(),
|
|
message: import_test_utils.TestUtils.generateVisibleMessage()
|
|
},
|
|
{
|
|
device: import_test_utils.TestUtils.generateFakePubKey(),
|
|
message: import_test_utils.TestUtils.generateVisibleMessage()
|
|
}
|
|
];
|
|
for (const item of cacheItems) {
|
|
await pendingMessageCacheStub.add(item.device, item.message);
|
|
}
|
|
const initialCache = await pendingMessageCacheStub.getAllPending();
|
|
(0, import_chai.expect)(initialCache).to.have.length(cacheItems.length);
|
|
for (const item of cacheItems) {
|
|
const pendingForDevice = await pendingMessageCacheStub.getForDevice(item.device);
|
|
(0, import_chai.expect)(pendingForDevice).to.have.length(1);
|
|
(0, import_chai.expect)(pendingForDevice[0].device).to.equal(item.device.key);
|
|
}
|
|
});
|
|
it("can find nothing when empty", async () => {
|
|
const device = import_test_utils.TestUtils.generateFakePubKey();
|
|
const message = import_test_utils.TestUtils.generateVisibleMessage();
|
|
const rawMessage = await import_utils.MessageUtils.toRawMessage(device, message);
|
|
const foundMessage = pendingMessageCacheStub.find(rawMessage);
|
|
(0, import_chai.expect)(foundMessage, "a message was found in empty cache").to.be.undefined;
|
|
});
|
|
it("can find message in cache", async () => {
|
|
const device = import_test_utils.TestUtils.generateFakePubKey();
|
|
const message = import_test_utils.TestUtils.generateVisibleMessage();
|
|
const rawMessage = await import_utils.MessageUtils.toRawMessage(device, message);
|
|
await pendingMessageCacheStub.add(device, message);
|
|
const finalCache = await pendingMessageCacheStub.getAllPending();
|
|
(0, import_chai.expect)(finalCache).to.have.length(1);
|
|
const foundMessage = pendingMessageCacheStub.find(rawMessage);
|
|
(0, import_chai.expect)(foundMessage, "message not found in cache").to.be.ok;
|
|
foundMessage && (0, import_chai.expect)(foundMessage.device).to.equal(device.key);
|
|
});
|
|
it("can clear cache", async () => {
|
|
const cacheItems = [
|
|
{
|
|
device: import_test_utils.TestUtils.generateFakePubKey(),
|
|
message: import_test_utils.TestUtils.generateVisibleMessage()
|
|
},
|
|
{
|
|
device: import_test_utils.TestUtils.generateFakePubKey(),
|
|
message: import_test_utils.TestUtils.generateVisibleMessage()
|
|
},
|
|
{
|
|
device: import_test_utils.TestUtils.generateFakePubKey(),
|
|
message: import_test_utils.TestUtils.generateVisibleMessage()
|
|
}
|
|
];
|
|
for (const item of cacheItems) {
|
|
await pendingMessageCacheStub.add(item.device, item.message);
|
|
}
|
|
const initialCache = await pendingMessageCacheStub.getAllPending();
|
|
(0, import_chai.expect)(initialCache).to.have.length(cacheItems.length);
|
|
await pendingMessageCacheStub.clear();
|
|
const finalCache = await pendingMessageCacheStub.getAllPending();
|
|
(0, import_chai.expect)(finalCache).to.have.length(0);
|
|
});
|
|
it("can restore from db", async () => {
|
|
const cacheItems = [
|
|
{
|
|
device: import_test_utils.TestUtils.generateFakePubKey(),
|
|
message: import_test_utils.TestUtils.generateVisibleMessage()
|
|
},
|
|
{
|
|
device: import_test_utils.TestUtils.generateFakePubKey(),
|
|
message: import_test_utils.TestUtils.generateVisibleMessage()
|
|
},
|
|
{
|
|
device: import_test_utils.TestUtils.generateFakePubKey(),
|
|
message: import_test_utils.TestUtils.generateVisibleMessage()
|
|
}
|
|
];
|
|
for (const item of cacheItems) {
|
|
await pendingMessageCacheStub.add(item.device, item.message);
|
|
}
|
|
const addedMessages = await pendingMessageCacheStub.getAllPending();
|
|
(0, import_chai.expect)(addedMessages).to.have.length(cacheItems.length);
|
|
const freshCache = new import_PendingMessageCache.PendingMessageCache();
|
|
const rebuiltMessages = await freshCache.getAllPending();
|
|
for (const [index, message] of rebuiltMessages.entries()) {
|
|
const addedMessage = addedMessages[index];
|
|
const buffersCompare = Buffer.compare(message.plainTextBuffer, addedMessage.plainTextBuffer) === 0;
|
|
(0, import_chai.expect)(buffersCompare).to.equal(true, "buffers were not loaded properly from database");
|
|
const trimmedAdded = _.omit(addedMessage, ["plainTextBuffer"]);
|
|
const trimmedRebuilt = _.omit(message, ["plainTextBuffer"]);
|
|
(0, import_chai.expect)(_.isEqual(trimmedAdded, trimmedRebuilt)).to.equal(true, "cached messages were not rebuilt properly");
|
|
}
|
|
});
|
|
});
|
|
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vLi4vdHMvdGVzdC9zZXNzaW9uL3VuaXQvc2VuZGluZy9QZW5kaW5nTWVzc2FnZUNhY2hlX3Rlc3QudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbIi8vIHRzbGludDpkaXNhYmxlOiBuby1pbXBsaWNpdC1kZXBlbmRlbmNpZXMgbWF4LWZ1bmMtYm9keS1sZW5ndGggbm8tdW51c2VkLWV4cHJlc3Npb25cbmltcG9ydCB7IGV4cGVjdCB9IGZyb20gJ2NoYWknO1xuaW1wb3J0ICogYXMgc2lub24gZnJvbSAnc2lub24nO1xuaW1wb3J0ICogYXMgXyBmcm9tICdsb2Rhc2gnO1xuaW1wb3J0IHsgTWVzc2FnZVV0aWxzIH0gZnJvbSAnLi4vLi4vLi4vLi4vc2Vzc2lvbi91dGlscyc7XG5pbXBvcnQgeyBUZXN0VXRpbHMgfSBmcm9tICcuLi8uLi8uLi8uLi90ZXN0L3Rlc3QtdXRpbHMnO1xuaW1wb3J0IHsgUGVuZGluZ01lc3NhZ2VDYWNoZSB9IGZyb20gJy4uLy4uLy4uLy4uL3Nlc3Npb24vc2VuZGluZy9QZW5kaW5nTWVzc2FnZUNhY2hlJztcblxuLy8gRXF1aXZhbGVudCB0byBEYXRhLlN0b3JhZ2VJdGVtXG5pbnRlcmZhY2UgU3RvcmFnZUl0ZW0ge1xuICBpZDogc3RyaW5nO1xuICB2YWx1ZTogYW55O1xufVxuXG5kZXNjcmliZSgnUGVuZGluZ01lc3NhZ2VDYWNoZScsICgpID0+IHtcbiAgY29uc3Qgc2FuZGJveCA9IHNpbm9uLmNyZWF0ZVNhbmRib3goKTtcbiAgLy8gSW5pdGlhbGl6ZSBuZXcgc3R1YmJlZCBjYWNoZVxuICBsZXQgZGF0YTogU3RvcmFnZUl0ZW07XG4gIGxldCBwZW5kaW5nTWVzc2FnZUNhY2hlU3R1YjogUGVuZGluZ01lc3NhZ2VDYWNoZTtcblxuICBiZWZvcmVFYWNoKCgpID0+IHtcbiAgICAvLyBTdHViIG91dCBtZXRob2RzIHdoaWNoIHRvdWNoIHRoZSBkYXRhYmFzZVxuICAgIGNvbnN0IHN0b3JhZ2VJRCA9ICdwZW5kaW5nTWVzc2FnZXMnO1xuICAgIGRhdGEgPSB7XG4gICAgICBpZDogc3RvcmFnZUlELFxuICAgICAgdmFsdWU6ICdbXScsXG4gICAgfTtcblxuICAgIFRlc3RVdGlscy5zdHViRGF0YSgnZ2V0SXRlbUJ5SWQnKVxuICAgICAgLndpdGhBcmdzKCdwZW5kaW5nTWVzc2FnZXMnKVxuICAgICAgLmNhbGxzRmFrZShhc3luYyAoKSA9PiB7XG4gICAgICAgIHJldHVybiBkYXRhO1xuICAgICAgfSk7XG5cbiAgICBUZXN0VXRpbHMuc3R1YkRhdGEoJ2NyZWF0ZU9yVXBkYXRlSXRlbScpLmNhbGxzRmFrZSgoaXRlbTogU3RvcmFnZUl0ZW0pID0+IHtcbiAgICAgIGlmIChpdGVtLmlkID09PSBzdG9yYWdlSUQpIHtcbiAgICAgICAgZGF0YSA9IGl0ZW07XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICBwZW5kaW5nTWVzc2FnZUNhY2hlU3R1YiA9IG5ldyBQZW5kaW5nTWVzc2FnZUNhY2hlKCk7XG4gIH0pO1xuXG4gIGFmdGVyRWFjaCgoKSA9PiB7XG4gICAgc2FuZGJveC5yZXN0b3JlKCk7XG4gICAgVGVzdFV0aWxzLnJlc3RvcmVTdHVicygpO1xuICB9KTtcblxuICBpdCgnY2FuIGluaXRpYWxpemUgY2FjaGUnLCBhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgY2FjaGUgPSBhd2FpdCBwZW5kaW5nTWVzc2FnZUNhY2hlU3R1Yi5nZXRBbGxQZW5kaW5nKCk7XG5cbiAgICAvLyBXZSBleHBlY3QgdGhlIGNhY2hlIHRvIGluaXRpYWxpc2UgYXMgYW4gZW1wdHkgYXJyYXlcbiAgICBleHBlY3QoY2FjaGUpLnRvLmJlLmluc3RhbmNlT2YoQXJyYXkpO1xuICAgIGV4cGVjdChjYWNoZSkudG8uaGF2ZS5sZW5ndGgoMCk7XG4gIH0pO1xuXG4gIGl0KCdjYW4gYWRkIHRvIGNhY2hlJywgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IGRldmljZSA9IFRlc3RVdGlscy5nZW5lcmF0ZUZha2VQdWJLZXkoKTtcbiAgICBjb25zdCBtZXNzYWdlID0gVGVzdFV0aWxzLmdlbmVyYXRlVmlzaWJsZU1lc3NhZ2UoKTtcbiAgICBjb25zdCByYXdNZXNzYWdlID0gYXdhaXQgTWVzc2FnZVV0aWxzLnRvUmF3TWVzc2FnZShkZXZpY2UsIG1lc3NhZ2UpO1xuXG4gICAgYXdhaXQgcGVuZGluZ01lc3NhZ2VDYWNoZVN0dWIuYWRkKGRldmljZSwgbWVzc2FnZSk7XG5cbiAgICAvLyBWZXJpZnkgdGhhdCB0aGUgbWVzc2FnZSBpcyBpbiB0aGUgY2FjaGVcbiAgICBjb25zdCBmaW5hbENhY2hlID0gYXdhaXQgcGVuZGluZ01lc3NhZ2VDYWNoZVN0dWIuZ2V0QWxsUGVuZGluZygpO1xuXG4gICAgZXhwZWN0KGZpbmFsQ2FjaGUpLnRvLmhhdmUubGVuZ3RoKDEpO1xuXG4gICAgY29uc3QgYWRkZWRNZXNzYWdlID0gZmluYWxDYWNoZVswXTtcbiAgICBleHBlY3QoYWRkZWRNZXNzYWdlLmRldmljZSkudG8uZGVlcC5lcXVhbChyYXdNZXNzYWdlLmRldmljZSk7XG4gIH0pO1xuXG4gIGl0KCdjYW4gYWRkIG11bHRpcGxlIG1lc3NhZ2VzIGJlbG9uZ2luZyB0byB0aGUgc2FtZSB1c2VyJywgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IGRldmljZSA9IFRlc3RVdGlscy5nZW5lcmF0ZUZha2VQdWJLZXkoKTtcblxuICAgIGF3YWl0IHBlbmRpbmdNZXNzYWdlQ2FjaGVTdHViLmFkZChkZXZpY2UsIFRlc3RVdGlscy5nZW5lcmF0ZVZpc2libGVNZXNzYWdlKCkpO1xuICAgIC8vIFdlIGhhdmUgdG8gdGltZW91dCBoZXJlIG90aGVyd2lzZSBpdCdzIHByb2Nlc3NlZCB0b28gZmFzdCBhbmQgbWVzc2FnZXMgc3RhcnQgaGF2aW5nIHRoZSBzYW1lIHRpbWVzdGFtcFxuICAgIGF3YWl0IFRlc3RVdGlscy50aW1lb3V0KDUpO1xuICAgIGF3YWl0IHBlbmRpbmdNZXNzYWdlQ2FjaGVTdHViLmFkZChkZXZpY2UsIFRlc3RVdGlscy5nZW5lcmF0ZVZpc2libGVNZXNzYWdlKCkpO1xuICAgIGF3YWl0IFRlc3RVdGlscy50aW1lb3V0KDUpO1xuICAgIGF3YWl0IHBlbmRpbmdNZXNzYWdlQ2FjaGVTdHViLmFkZChkZXZpY2UsIFRlc3RVdGlscy5nZW5lcmF0ZVZpc2libGVNZXNzYWdlKCkpO1xuXG4gICAgLy8gVmVyaWZ5IHRoYXQgdGhlIG1lc3NhZ2UgaXMgaW4gdGhlIGNhY2hlXG4gICAgY29uc3QgZmluYWxDYWNoZSA9IGF3YWl0IHBlbmRpbmdNZXNzYWdlQ2FjaGVTdHViLmdldEFsbFBlbmRpbmcoKTtcblxuICAgIGV4cGVjdChmaW5hbENhY2hlKS50by5oYXZlLmxlbmd0aCgzKTtcbiAgfSk7XG5cbiAgaXQoJ2NhbiByZW1vdmUgZnJvbSBjYWNoZScsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBkZXZpY2UgPSBUZXN0VXRpbHMuZ2VuZXJhdGVGYWtlUHViS2V5KCk7XG4gICAgY29uc3QgbWVzc2FnZSA9IFRlc3RVdGlscy5nZW5lcmF0ZVZpc2libGVNZXNzYWdlKCk7XG4gICAgY29uc3QgcmF3TWVzc2FnZSA9IGF3YWl0IE1lc3NhZ2VVdGlscy50b1Jhd01lc3NhZ2UoZGV2aWNlLCBtZXNzYWdlKTtcblxuICAgIGF3YWl0IHBlbmRpbmdNZXNzYWdlQ2FjaGVTdHViLmFkZChkZXZpY2UsIG1lc3NhZ2UpO1xuXG4gICAgY29uc3QgaW5pdGlhbENhY2hlID0gYXdhaXQgcGVuZGluZ01lc3NhZ2VDYWNoZVN0dWIuZ2V0QWxsUGVuZGluZygpO1xuICAgIGV4cGVjdChpbml0aWFsQ2FjaGUpLnRvLmhhdmUubGVuZ3RoKDEpO1xuXG4gICAgLy8gUmVtb3ZlIHRoZSBtZXNzYWdlXG4gICAgYXdhaXQgcGVuZGluZ01lc3NhZ2VDYWNoZVN0dWIucmVtb3ZlKHJhd01lc3NhZ2UpO1xuXG4gICAgY29uc3QgZmluYWxDYWNoZSA9IGF3YWl0IHBlbmRpbmdNZXNzYWdlQ2FjaGVTdHViLmdldEFsbFBlbmRpbmcoKTtcblxuICAgIC8vIFZlcmlmeSB0aGF0IHRoZSBtZXNzYWdlIHdhcyByZW1vdmVkXG4gICAgZXhwZWN0KGZpbmFsQ2FjaGUpLnRvLmhhdmUubGVuZ3RoKDApO1xuICB9KTtcblxuICBpdCgnc2hvdWxkIG9ubHkgcmVtb3ZlIG1lc3NhZ2VzIHdpdGggZGlmZmVyZW50IGlkZW50aWZpZXIgYW5kIGRldmljZScsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBkZXZpY2UgPSBUZXN0VXRpbHMuZ2VuZXJhdGVGYWtlUHViS2V5KCk7XG4gICAgY29uc3QgbWVzc2FnZSA9IFRlc3RVdGlscy5nZW5lcmF0ZVZpc2libGVNZXNzYWdlKCk7XG4gICAgY29uc3QgcmF3TWVzc2FnZSA9IGF3YWl0IE1lc3NhZ2VVdGlscy50b1Jhd01lc3NhZ2UoZGV2aWNlLCBtZXNzYWdlKTtcblxuICAgIGF3YWl0IHBlbmRpbmdNZXNzYWdlQ2FjaGVTdHViLmFkZChkZXZpY2UsIG1lc3NhZ2UpO1xuICAgIGF3YWl0IFRlc3RVdGlscy50aW1lb3V0KDUpO1xuICAgIGNvbnN0IG9uZSA9IGF3YWl0IHBlbmRpbmdNZXNzYWdlQ2FjaGVTdHViLmFkZChkZXZpY2UsIFRlc3RVdGlscy5nZW5lcmF0ZVZpc2libGVNZXNzYWdlKCkpO1xuICAgIGNvbnN0IHR3byA9IGF3YWl0IHBlbmRpbmdNZXNzYWdlQ2FjaGVTdHViLmFkZChUZXN0VXRpbHMuZ2VuZXJhdGVGYWtlUHViS2V5KCksIG1lc3NhZ2UpO1xuXG4gICAgY29uc3QgaW5pdGlhbENhY2hlID0gYXdhaXQgcGVuZGluZ01lc3NhZ2VDYWNoZVN0dWIuZ2V0QWxsUGVuZGluZygpO1xuICAgIGV4cGVjdChpbml0aWFsQ2FjaGUpLnRvLmhhdmUubGVuZ3RoKDMpO1xuXG4gICAgLy8gUmVtb3ZlIHRoZSBtZXNzYWdlXG4gICAgYXdhaXQgcGVuZGluZ01lc3NhZ2VDYWNoZVN0dWIucmVtb3ZlKHJhd01lc3NhZ2UpO1xuXG4gICAgY29uc3QgZmluYWxDYWNoZSA9IGF3YWl0IHBlbmRpbmdNZXNzYWdlQ2FjaGVTdHViLmdldEFsbFBlbmRpbmcoKTtcblxuICAgIC8vIFZlcmlmeSB0aGF0IHRoZSBtZXNzYWdlIHdhcyByZW1vdmVkXG4gICAgZXhwZWN0KGZpbmFsQ2FjaGUpLnRvLmhhdmUubGVuZ3RoKDIpO1xuICAgIGV4cGVjdChmaW5hbENhY2hlKS50by5oYXZlLmRlZXAubWVtYmVycyhbb25lLCB0d29dKTtcbiAgfSk7XG5cbiAgaXQoJ2NhbiBnZXQgZGV2aWNlcycsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBjYWNoZUl0ZW1zID0gW1xuICAgICAge1xuICAgICAgICBkZXZpY2U6IFRlc3RVdGlscy5nZW5lcmF0ZUZha2VQdWJLZXkoKSxcbiAgICAgICAgbWVzc2FnZTogVGVzdFV0aWxzLmdlbmVyYXRlVmlzaWJsZU1lc3NhZ2UoKSxcbiAgICAgIH0sXG4gICAgICB7XG4gICAgICAgIGRldmljZTogVGVzdFV0aWxzLmdlbmVyYXRlRmFrZVB1YktleSgpLFxuICAgICAgICBtZXNzYWdlOiBUZXN0VXRpbHMuZ2VuZXJhdGVWaXNpYmxlTWVzc2FnZSgpLFxuICAgICAgfSxcbiAgICAgIHtcbiAgICAgICAgZGV2aWNlOiBUZXN0VXRpbHMuZ2VuZXJhdGVGYWtlUHViS2V5KCksXG4gICAgICAgIG1lc3NhZ2U6IFRlc3RVdGlscy5nZW5lcmF0ZVZpc2libGVNZXNzYWdlKCksXG4gICAgICB9LFxuICAgIF07XG5cbiAgICBmb3IgKGNvbnN0IGl0ZW0gb2YgY2FjaGVJdGVtcykge1xuICAgICAgYXdhaXQgcGVuZGluZ01lc3NhZ2VDYWNoZVN0dWIuYWRkKGl0ZW0uZGV2aWNlLCBpdGVtLm1lc3NhZ2UpO1xuICAgIH1cblxuICAgIGNvbnN0IGNhY2hlID0gYXdhaXQgcGVuZGluZ01lc3NhZ2VDYWNoZVN0dWIuZ2V0QWxsUGVuZGluZygpO1xuICAgIGV4cGVjdChjYWNoZSkudG8uaGF2ZS5sZW5ndGgoY2FjaGVJdGVtcy5sZW5ndGgpO1xuXG4gICAgLy8gR2V0IGxpc3Qgb2YgZGV2aWNlc1xuICAgIGNvbnN0IGRldmljZXNLZXlzID0gY2FjaGVJdGVtcy5tYXAoaXRlbSA9PiBpdGVtLmRldmljZS5rZXkpO1xuICAgIGNvbnN0IHB1bGxlZERldmljZXMgPSBhd2FpdCBwZW5kaW5nTWVzc2FnZUNhY2hlU3R1Yi5nZXREZXZpY2VzKCk7XG4gICAgY29uc3QgcHVsbGVkRGV2aWNlc0tleXMgPSBwdWxsZWREZXZpY2VzLm1hcChkID0+IGQua2V5KTtcblxuICAgIC8vIFZlcmlmeSB0aGF0IGRldmljZSBsaXN0IGZyb20gY2FjaGUgaXMgZXF1aXZhbGVudCB0byBkZXZpY2VzIGFkZGVkXG4gICAgZXhwZWN0KHB1bGxlZERldmljZXNLZXlzKS50by5oYXZlLm1lbWJlcnMoZGV2aWNlc0tleXMpO1xuICB9KTtcblxuICBpdCgnY2FuIGdldCBwZW5kaW5nIGZvciBkZXZpY2UnLCBhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgY2FjaGVJdGVtcyA9IFtcbiAgICAgIHtcbiAgICAgICAgZGV2aWNlOiBUZXN0VXRpbHMuZ2VuZXJhdGVGYWtlUHViS2V5KCksXG4gICAgICAgIG1lc3NhZ2U6IFRlc3RVdGlscy5nZW5lcmF0ZVZpc2libGVNZXNzYWdlKCksXG4gICAgICB9LFxuICAgICAge1xuICAgICAgICBkZXZpY2U6IFRlc3RVdGlscy5nZW5lcmF0ZUZha2VQdWJLZXkoKSxcbiAgICAgICAgbWVzc2FnZTogVGVzdFV0aWxzLmdlbmVyYXRlVmlzaWJsZU1lc3NhZ2UoKSxcbiAgICAgIH0sXG4gICAgXTtcblxuICAgIGZvciAoY29uc3QgaXRlbSBvZiBjYWNoZUl0ZW1zKSB7XG4gICAgICBhd2FpdCBwZW5kaW5nTWVzc2FnZUNhY2hlU3R1Yi5hZGQoaXRlbS5kZXZpY2UsIGl0ZW0ubWVzc2FnZSk7XG4gICAgfVxuXG4gICAgY29uc3QgaW5pdGlhbENhY2hlID0gYXdhaXQgcGVuZGluZ01lc3NhZ2VDYWNoZVN0dWIuZ2V0QWxsUGVuZGluZygpO1xuICAgIGV4cGVjdChpbml0aWFsQ2FjaGUpLnRvLmhhdmUubGVuZ3RoKGNhY2hlSXRlbXMubGVuZ3RoKTtcblxuICAgIC8vIEdldCBwZW5kaW5nIGZvciBlYWNoIHNwZWNpZmljIGRldmljZVxuICAgIGZvciAoY29uc3QgaXRlbSBvZiBjYWNoZUl0ZW1zKSB7XG4gICAgICBjb25zdCBwZW5kaW5nRm9yRGV2aWNlID0gYXdhaXQgcGVuZGluZ01lc3NhZ2VDYWNoZVN0dWIuZ2V0Rm9yRGV2aWNlKGl0ZW0uZGV2aWNlKTtcbiAgICAgIGV4cGVjdChwZW5kaW5nRm9yRGV2aWNlKS50by5oYXZlLmxlbmd0aCgxKTtcbiAgICAgIGV4cGVjdChwZW5kaW5nRm9yRGV2aWNlWzBdLmRldmljZSkudG8uZXF1YWwoaXRlbS5kZXZpY2Uua2V5KTtcbiAgICB9XG4gIH0pO1xuXG4gIGl0KCdjYW4gZmluZCBub3RoaW5nIHdoZW4gZW1wdHknLCBhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgZGV2aWNlID0gVGVzdFV0aWxzLmdlbmVyYXRlRmFrZVB1YktleSgpO1xuICAgIGNvbnN0IG1lc3NhZ2UgPSBUZXN0VXRpbHMuZ2VuZXJhdGVWaXNpYmxlTWVzc2FnZSgpO1xuICAgIGNvbnN0IHJhd01lc3NhZ2UgPSBhd2FpdCBNZXNzYWdlVXRpbHMudG9SYXdNZXNzYWdlKGRldmljZSwgbWVzc2FnZSk7XG5cbiAgICBjb25zdCBmb3VuZE1lc3NhZ2UgPSBwZW5kaW5nTWVzc2FnZUNhY2hlU3R1Yi5maW5kKHJhd01lc3NhZ2UpO1xuICAgIGV4cGVjdChmb3VuZE1lc3NhZ2UsICdhIG1lc3NhZ2Ugd2FzIGZvdW5kIGluIGVtcHR5IGNhY2hlJykudG8uYmUudW5kZWZpbmVkO1xuICB9KTtcblxuICBpdCgnY2FuIGZpbmQgbWVzc2FnZSBpbiBjYWNoZScsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBkZXZpY2UgPSBUZXN0VXRpbHMuZ2VuZXJhdGVGYWtlUHViS2V5KCk7XG4gICAgY29uc3QgbWVzc2FnZSA9IFRlc3RVdGlscy5nZW5lcmF0ZVZpc2libGVNZXNzYWdlKCk7XG4gICAgY29uc3QgcmF3TWVzc2FnZSA9IGF3YWl0IE1lc3NhZ2VVdGlscy50b1Jhd01lc3NhZ2UoZGV2aWNlLCBtZXNzYWdlKTtcblxuICAgIGF3YWl0IHBlbmRpbmdNZXNzYWdlQ2FjaGVTdHViLmFkZChkZXZpY2UsIG1lc3NhZ2UpO1xuXG4gICAgY29uc3QgZmluYWxDYWNoZSA9IGF3YWl0IHBlbmRpbmdNZXNzYWdlQ2FjaGVTdHViLmdldEFsbFBlbmRpbmcoKTtcbiAgICBleHBlY3QoZmluYWxDYWNoZSkudG8uaGF2ZS5sZW5ndGgoMSk7XG5cbiAgICBjb25zdCBmb3VuZE1lc3NhZ2UgPSBwZW5kaW5nTWVzc2FnZUNhY2hlU3R1Yi5maW5kKHJhd01lc3NhZ2UpO1xuICAgIGV4cGVjdChmb3VuZE1lc3NhZ2UsICdtZXNzYWdlIG5vdCBmb3VuZCBpbiBjYWNoZScpLnRvLmJlLm9rO1xuICAgIGZvdW5kTWVzc2FnZSAmJiBleHBlY3QoZm91bmRNZXNzYWdlLmRldmljZSkudG8uZXF1YWwoZGV2aWNlLmtleSk7XG4gIH0pO1xuXG4gIGl0KCdjYW4gY2xlYXIgY2FjaGUnLCBhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgY2FjaGVJdGVtcyA9IFtcbiAgICAgIHtcbiAgICAgICAgZGV2aWNlOiBUZXN0VXRpbHMuZ2VuZXJhdGVGYWtlUHViS2V5KCksXG4gICAgICAgIG1lc3NhZ2U6IFRlc3RVdGlscy5nZW5lcmF0ZVZpc2libGVNZXNzYWdlKCksXG4gICAgICB9LFxuICAgICAge1xuICAgICAgICBkZXZpY2U6IFRlc3RVdGlscy5nZW5lcmF0ZUZha2VQdWJLZXkoKSxcbiAgICAgICAgbWVzc2FnZTogVGVzdFV0aWxzLmdlbmVyYXRlVmlzaWJsZU1lc3NhZ2UoKSxcbiAgICAgIH0sXG4gICAgICB7XG4gICAgICAgIGRldmljZTogVGVzdFV0aWxzLmdlbmVyYXRlRmFrZVB1YktleSgpLFxuICAgICAgICBtZXNzYWdlOiBUZXN0VXRpbHMuZ2VuZXJhdGVWaXNpYmxlTWVzc2FnZSgpLFxuICAgICAgfSxcbiAgICBdO1xuXG4gICAgZm9yIChjb25zdCBpdGVtIG9mIGNhY2hlSXRlbXMpIHtcbiAgICAgIGF3YWl0IHBlbmRpbmdNZXNzYWdlQ2FjaGVTdHViLmFkZChpdGVtLmRldmljZSwgaXRlbS5tZXNzYWdlKTtcbiAgICB9XG5cbiAgICBjb25zdCBpbml0aWFsQ2FjaGUgPSBhd2FpdCBwZW5kaW5nTWVzc2FnZUNhY2hlU3R1Yi5nZXRBbGxQZW5kaW5nKCk7XG4gICAgZXhwZWN0KGluaXRpYWxDYWNoZSkudG8uaGF2ZS5sZW5ndGgoY2FjaGVJdGVtcy5sZW5ndGgpO1xuXG4gICAgLy8gQ2xlYXIgY2FjaGVcbiAgICBhd2FpdCBwZW5kaW5nTWVzc2FnZUNhY2hlU3R1Yi5jbGVhcigpO1xuXG4gICAgY29uc3QgZmluYWxDYWNoZSA9IGF3YWl0IHBlbmRpbmdNZXNzYWdlQ2FjaGVTdHViLmdldEFsbFBlbmRpbmcoKTtcbiAgICBleHBlY3QoZmluYWxDYWNoZSkudG8uaGF2ZS5sZW5ndGgoMCk7XG4gIH0pO1xuXG4gIGl0KCdjYW4gcmVzdG9yZSBmcm9tIGRiJywgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IGNhY2hlSXRlbXMgPSBbXG4gICAgICB7XG4gICAgICAgIGRldmljZTogVGVzdFV0aWxzLmdlbmVyYXRlRmFrZVB1YktleSgpLFxuICAgICAgICBtZXNzYWdlOiBUZXN0VXRpbHMuZ2VuZXJhdGVWaXNpYmxlTWVzc2FnZSgpLFxuICAgICAgfSxcbiAgICAgIHtcbiAgICAgICAgZGV2aWNlOiBUZXN0VXRpbHMuZ2VuZXJhdGVGYWtlUHViS2V5KCksXG4gICAgICAgIG1lc3NhZ2U6IFRlc3RVdGlscy5nZW5lcmF0ZVZpc2libGVNZXNzYWdlKCksXG4gICAgICB9LFxuICAgICAge1xuICAgICAgICBkZXZpY2U6IFRlc3RVdGlscy5nZW5lcmF0ZUZha2VQdWJLZXkoKSxcbiAgICAgICAgbWVzc2FnZTogVGVzdFV0aWxzLmdlbmVyYXRlVmlzaWJsZU1lc3NhZ2UoKSxcbiAgICAgIH0sXG4gICAgXTtcblxuICAgIGZvciAoY29uc3QgaXRlbSBvZiBjYWNoZUl0ZW1zKSB7XG4gICAgICBhd2FpdCBwZW5kaW5nTWVzc2FnZUNhY2hlU3R1Yi5hZGQoaXRlbS5kZXZpY2UsIGl0ZW0ubWVzc2FnZSk7XG4gICAgfVxuXG4gICAgY29uc3QgYWRkZWRNZXNzYWdlcyA9IGF3YWl0IHBlbmRpbmdNZXNzYWdlQ2FjaGVTdHViLmdldEFsbFBlbmRpbmcoKTtcbiAgICBleHBlY3QoYWRkZWRNZXNzYWdlcykudG8uaGF2ZS5sZW5ndGgoY2FjaGVJdGVtcy5sZW5ndGgpO1xuXG4gICAgLy8gUmVidWlsZCBmcm9tIERCXG4gICAgY29uc3QgZnJlc2hDYWNoZSA9IG5ldyBQZW5kaW5nTWVzc2FnZUNhY2hlKCk7XG5cbiAgICAvLyBWZXJpZnkgbWVzc2FnZXNcbiAgICBjb25zdCByZWJ1aWx0TWVzc2FnZXMgPSBhd2FpdCBmcmVzaENhY2hlLmdldEFsbFBlbmRpbmcoKTtcblxuICAgIGZvciAoY29uc3QgW2luZGV4LCBtZXNzYWdlXSBvZiByZWJ1aWx0TWVzc2FnZXMuZW50cmllcygpKSB7XG4gICAgICBjb25zdCBhZGRlZE1lc3NhZ2UgPSBhZGRlZE1lc3NhZ2VzW2luZGV4XTtcblxuICAgICAgLy8gUHVsbCBvdXQgcGxhaW5UZXh0QnVmZmVyIGZvciBhIHNlcGFyYXRlIGNoZWNrXG4gICAgICBjb25zdCBidWZmZXJzQ29tcGFyZSA9XG4gICAgICAgIEJ1ZmZlci5jb21wYXJlKG1lc3NhZ2UucGxhaW5UZXh0QnVmZmVyLCBhZGRlZE1lc3NhZ2UucGxhaW5UZXh0QnVmZmVyKSA9PT0gMDtcbiAgICAgIGV4cGVjdChidWZmZXJzQ29tcGFyZSkudG8uZXF1YWwodHJ1ZSwgJ2J1ZmZlcnMgd2VyZSBub3QgbG9hZGVkIHByb3Blcmx5IGZyb20gZGF0YWJhc2UnKTtcblxuICAgICAgLy8gQ29tcGFyZSBhbGwgb3RoZXIgdmFsdXJlc1xuICAgICAgY29uc3QgdHJpbW1lZEFkZGVkID0gXy5vbWl0KGFkZGVkTWVzc2FnZSwgWydwbGFpblRleHRCdWZmZXInXSk7XG4gICAgICBjb25zdCB0cmltbWVkUmVidWlsdCA9IF8ub21pdChtZXNzYWdlLCBbJ3BsYWluVGV4dEJ1ZmZlciddKTtcblxuICAgICAgZXhwZWN0KF8uaXNFcXVhbCh0cmltbWVkQWRkZWQsIHRyaW1tZWRSZWJ1aWx0KSkudG8uZXF1YWwoXG4gICAgICAgIHRydWUsXG4gICAgICAgICdjYWNoZWQgbWVzc2FnZXMgd2VyZSBub3QgcmVidWlsdCBwcm9wZXJseSdcbiAgICAgICk7XG4gICAgfVxuICB9KTtcbn0pO1xuIl0sCiAgIm1hcHBpbmdzIjogIjs7Ozs7Ozs7Ozs7Ozs7O0FBQ0Esa0JBQXVCO0FBQ3ZCLFlBQXVCO0FBQ3ZCLFFBQW1CO0FBQ25CLG1CQUE2QjtBQUM3Qix3QkFBMEI7QUFDMUIsaUNBQW9DO0FBUXBDLFNBQVMsdUJBQXVCLE1BQU07QUFDcEMsUUFBTSxVQUFVLE1BQU0sY0FBYztBQUVwQyxNQUFJO0FBQ0osTUFBSTtBQUVKLGFBQVcsTUFBTTtBQUVmLFVBQU0sWUFBWTtBQUNsQixXQUFPO0FBQUEsTUFDTCxJQUFJO0FBQUEsTUFDSixPQUFPO0FBQUEsSUFDVDtBQUVBLGdDQUFVLFNBQVMsYUFBYSxFQUM3QixTQUFTLGlCQUFpQixFQUMxQixVQUFVLFlBQVk7QUFDckIsYUFBTztBQUFBLElBQ1QsQ0FBQztBQUVILGdDQUFVLFNBQVMsb0JBQW9CLEVBQUUsVUFBVSxDQUFDLFNBQXNCO0FBQ3hFLFVBQUksS0FBSyxPQUFPLFdBQVc7QUFDekIsZUFBTztBQUFBLE1BQ1Q7QUFBQSxJQUNGLENBQUM7QUFFRCw4QkFBMEIsSUFBSSwrQ0FBb0I7QUFBQSxFQUNwRCxDQUFDO0FBRUQsWUFBVSxNQUFNO0FBQ2QsWUFBUSxRQUFRO0FBQ2hCLGdDQUFVLGFBQWE7QUFBQSxFQUN6QixDQUFDO0FBRUQsS0FBRyx3QkFBd0IsWUFBWTtBQUNyQyxVQUFNLFFBQVEsTUFBTSx3QkFBd0IsY0FBYztBQUcxRCw0QkFBTyxLQUFLLEVBQUUsR0FBRyxHQUFHLFdBQVcsS0FBSztBQUNwQyw0QkFBTyxLQUFLLEVBQUUsR0FBRyxLQUFLLE9BQU8sQ0FBQztBQUFBLEVBQ2hDLENBQUM7QUFFRCxLQUFH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
|