@launchmenu/core
Version:
An environment for visual keyboard controlled applets
577 lines • 66.8 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const model_react_1 = require("model-react");
const wait_helper_1 = require("../../../_tests/wait.helper");
const CoreSearchExecuter_1 = require("../CoreSearchExecuter");
const createSimpleResultMap_helper_1 = require("./createSimpleResultMap.helper");
const createSimpleSearch_helper_1 = require("./createSimpleSearch.helper");
const createSimpleResultMap = () => {
const nodes = {};
const listener = new model_react_1.ManualSourceHelper();
return {
onRemove: (ID) => {
const contains = nodes[ID];
delete nodes[ID];
if (contains)
listener.callListeners();
},
onUpdate: (ID, data) => {
nodes[ID] = data;
listener.callListeners();
},
getItems: (hook) => {
listener.addListener(hook);
return createSimpleResultMap_helper_1.s(Object.values(nodes)
.map(({ item }) => item)
.filter(Boolean));
},
getNodes: (hook) => {
listener.addListener(hook);
return Object.values(nodes);
},
nodes,
};
};
const createCoreExecuter = (searchable) => {
const result = createSimpleResultMap();
return [new CoreSearchExecuter_1.CoreSearchExecuter({ searchable, ...result }), result];
};
describe("CoreSearchExecuter", () => {
describe("new CoreSearchExecuter", () => {
it("Can be constructed", () => {
new CoreSearchExecuter_1.CoreSearchExecuter({
searchable: createSimpleSearch_helper_1.createSimpleSearch({ m: () => true }),
onRemove: () => { },
onUpdate: () => { },
});
});
});
describe("CoreSearchExecuter.setQuery", () => {
describe("Correctly obtains the items recursively", () => {
it("Correctly obtains the items recursively", async () => {
const search = createSimpleSearch_helper_1.createSimpleSearch({ m: s => s == "s" });
const [executer, result] = createCoreExecuter(search);
await executer.setQuery("s");
expect(result.getItems()).toEqual([search.ID]);
const [executer2, result2] = createCoreExecuter(search);
await executer2.setQuery("");
expect(result2.getItems()).toEqual([]);
});
it("Works on searchables returning children", async () => {
const search1 = createSimpleSearch_helper_1.createSimpleSearch({ m: s => s.substr(0, 1) == "s" });
const search2 = createSimpleSearch_helper_1.createSimpleSearch({ m: s => s.substr(0, 2) == "s2" });
const search3 = createSimpleSearch_helper_1.createSimpleSearch({ children: [search1, search2] });
const [executer, result] = createCoreExecuter(search3);
await executer.setQuery("s");
expect(result.getItems()).toEqual([search1.ID]);
const [executer2, result2] = createCoreExecuter(search3);
await executer2.setQuery("s2");
expect(createSimpleResultMap_helper_1.s(result2.getItems())).toEqual(createSimpleResultMap_helper_1.s([search1.ID, search2.ID]));
const [executer3, result3] = createCoreExecuter(search3);
await executer3.setQuery("test");
expect(result3.getItems()).toEqual([]);
});
it("Works on searchables returning children and items", async () => {
const search1 = createSimpleSearch_helper_1.createSimpleSearch({ m: s => s.substr(0, 1) == "s" });
const search2 = createSimpleSearch_helper_1.createSimpleSearch({ m: s => s.substr(0, 2) == "s2" });
const search3 = createSimpleSearch_helper_1.createSimpleSearch({
m: s => s.substr(0, 2) == "s3",
children: [search1, search2],
});
const [executer, result] = createCoreExecuter(search3);
await executer.setQuery("s");
expect(result.getItems()).toEqual([search1.ID]);
const [executer2, result2] = createCoreExecuter(search3);
await executer2.setQuery("s2");
expect(result2.getItems()).toEqual(createSimpleResultMap_helper_1.s([search1.ID, search2.ID]));
const [executer3, result3] = createCoreExecuter(search3);
await executer3.setQuery("s3");
expect(result3.getItems()).toEqual(createSimpleResultMap_helper_1.s([search3.ID, search1.ID]));
const [executer4, result4] = createCoreExecuter(search3);
await executer4.setQuery("test");
expect(result4.getItems()).toEqual([]);
});
});
describe("Correctly updates old items", () => {
it("Works correctly when search indicates it no longer matches", async () => {
const search1 = createSimpleSearch_helper_1.createSimpleSearch({
id: "1",
m: s => s.substr(0, 1) == "s",
});
const search2 = createSimpleSearch_helper_1.createSimpleSearch({
id: "2",
m: s => s.substr(0, 2) == "s2",
});
const search3 = createSimpleSearch_helper_1.createSimpleSearch({
id: "3",
m: s => s.substr(0, 2) == "s3",
children: [search1, search2],
});
const [executer, result] = createCoreExecuter(search3);
await executer.setQuery("s");
expect(result.getItems()).toEqual([search1.ID]);
await executer.setQuery("s2");
expect(result.getItems()).toEqual(createSimpleResultMap_helper_1.s([search1.ID, search2.ID]));
await executer.setQuery("s3");
expect(result.getItems()).toEqual(createSimpleResultMap_helper_1.s([search1.ID, search3.ID]));
await executer.setQuery("test");
expect(result.getItems()).toEqual([]);
});
it("Works correctly when search indicates children are no longer there", async () => {
const search1 = createSimpleSearch_helper_1.createSimpleSearch({
id: "1",
m: s => s.substr(s.length - 1) == "s",
});
const search2 = createSimpleSearch_helper_1.createSimpleSearch({
id: "2",
m: s => s.substr(s.length - 1) == "t",
});
const search3 = createSimpleSearch_helper_1.createSimpleSearch({
id: "3",
m: s => s.substr(0, 1) == "s",
children: s => (s.substr(0, 1) == "s" ? [search1, search2] : []),
});
const [executer, result] = createCoreExecuter(search3);
await executer.setQuery("s");
expect(result.getItems()).toEqual(createSimpleResultMap_helper_1.s([search3.ID, search1.ID]));
await executer.setQuery("s2");
expect(result.getItems()).toEqual([search3.ID]);
await executer.setQuery("st");
expect(result.getItems()).toEqual(createSimpleResultMap_helper_1.s([search3.ID, search2.ID]));
await executer.setQuery("t");
expect(result.getItems()).toEqual([]);
await executer.setQuery("st");
expect(result.getItems()).toEqual(createSimpleResultMap_helper_1.s([search3.ID, search2.ID]));
await executer.setQuery("s2");
expect(result.getItems()).toEqual([search3.ID]);
});
describe("Multiple parents", () => {
it("Doesn't duplicate results", async () => {
const search1 = createSimpleSearch_helper_1.createSimpleSearch({
id: "1",
m: s => s.substr(s.length - 1) == "s",
});
const search2 = createSimpleSearch_helper_1.createSimpleSearch({
id: "2",
m: s => s.substr(s.length - 1) == "t",
children: [search1],
});
const search3 = createSimpleSearch_helper_1.createSimpleSearch({
id: "3",
m: s => s.substr(0, 1) == "s",
children: [search1],
});
const search4 = createSimpleSearch_helper_1.createSimpleSearch({
id: "4",
m: s => s.substr(0, 1) == "s",
children: [search2, search3],
});
const updateCallback = jest.fn();
const executer = new CoreSearchExecuter_1.CoreSearchExecuter({
searchable: search4,
onUpdate: updateCallback,
onRemove: () => { },
});
await executer.setQuery("s");
expect(updateCallback.mock.calls.length).toBe(4);
await executer.setQuery("t");
expect(updateCallback.mock.calls.length).toBe(8);
});
it("Doesn't remove child results until all parents removed the child", async () => {
const search1 = createSimpleSearch_helper_1.createSimpleSearch({
id: "1",
m: s => s[0] == "s",
});
const search2 = createSimpleSearch_helper_1.createSimpleSearch({
id: "2",
m: s => s[0] == "t",
children: s => (s.includes("m") ? [] : [search1]),
});
const search3 = createSimpleSearch_helper_1.createSimpleSearch({
id: "3",
m: s => s[0] == "s",
children: s => (s.includes("i") ? [] : [search1]),
});
const search4 = createSimpleSearch_helper_1.createSimpleSearch({
id: "4",
m: s => s[0] == "s",
children: [search2, search3],
});
const [executer, result] = createCoreExecuter(search4);
await executer.setQuery("s");
expect(result.getItems()).toEqual(createSimpleResultMap_helper_1.s([search4.ID, search3.ID, search1.ID]));
await executer.setQuery("sm");
expect(result.getItems()).toEqual(createSimpleResultMap_helper_1.s([search4.ID, search3.ID, search1.ID]));
await executer.setQuery("si");
expect(result.getItems()).toEqual(createSimpleResultMap_helper_1.s([search4.ID, search3.ID, search1.ID]));
await executer.setQuery("sim");
expect(result.getItems()).toEqual(createSimpleResultMap_helper_1.s([search4.ID, search3.ID]));
await executer.setQuery("si");
expect(result.getItems()).toEqual(createSimpleResultMap_helper_1.s([search4.ID, search3.ID, search1.ID]));
});
});
});
describe("Correctly interrupts previous searches", () => {
it("Correctly cancels previous searches", async () => {
const search1 = createSimpleSearch_helper_1.createSimpleSearch({
id: "1",
m: async (s) => {
await wait_helper_1.wait(10);
return s == "s";
},
});
const search2 = createSimpleSearch_helper_1.createSimpleSearch({
id: "2",
m: async (s) => {
await wait_helper_1.wait(10);
return s == "s";
},
});
const search3 = createSimpleSearch_helper_1.createSimpleSearch({
id: "3",
m: async (s) => {
await wait_helper_1.wait(10);
return s == "s";
},
});
const search4 = createSimpleSearch_helper_1.createSimpleSearch({
id: "4",
m: async (s) => {
await wait_helper_1.wait(10);
return s == "s";
},
children: s => [search1, search2, search3],
});
const [executer, result] = createCoreExecuter(search4);
await executer.setQuery("s");
expect(result.getItems()).toEqual(createSimpleResultMap_helper_1.s([search1.ID, search2.ID, search3.ID, search4.ID]));
const [executer2, result2] = createCoreExecuter(search3);
executer2.setQuery("s");
await wait_helper_1.wait(20); // requires 40ms+ to complete
expect(result2.getItems()).not.toEqual(createSimpleResultMap_helper_1.s([search1.ID, search2.ID, search3.ID, search4.ID]));
let resolved = false;
executer.setQuery("st").then(() => (resolved = true));
await wait_helper_1.wait(70); // Requires at most 10 ms to interrupt, + 40ms to complete
expect(result.getItems()).toEqual([]);
expect(resolved).toBe(true);
});
it("Correctly removes items registered to be added", async () => {
const search1 = createSimpleSearch_helper_1.createSimpleSearch({
id: "1",
m: async (s) => {
await wait_helper_1.wait(10);
return s == "s";
},
});
const search2 = createSimpleSearch_helper_1.createSimpleSearch({
id: "2",
m: async (s) => {
await wait_helper_1.wait(10);
return s == "s";
},
});
const search3 = createSimpleSearch_helper_1.createSimpleSearch({
id: "3",
m: async (s) => {
await wait_helper_1.wait(10);
return s == "s" || s == "o";
},
});
const search4 = createSimpleSearch_helper_1.createSimpleSearch({
id: "4",
m: async (s) => {
await wait_helper_1.wait(10);
return s == "s" || s == "o";
},
children: s => (s == "o" ? [] : [search1, search2, search3]),
});
const [executer, result] = createCoreExecuter(search4);
await executer.setQuery("t");
expect(result.getItems()).toEqual([]);
// Update the query which should schedule all searches, but the first search should result in all searches being removed (despite being scheduled already)
await executer.setQuery("o");
expect(result.getItems()).toEqual([search4.ID]);
// Just a normal search to confirm nothing yanky is going on in the test in general
await executer.setQuery("s");
expect(result.getItems()).toEqual(createSimpleResultMap_helper_1.s([search4.ID, search3.ID, search2.ID, search1.ID]));
});
it("Correctly updates previously added items before finding new ones", async () => {
const search1 = createSimpleSearch_helper_1.createSimpleSearch({
id: "1",
m: async (s) => {
await wait_helper_1.wait(50);
return s == "s";
},
});
const search2 = createSimpleSearch_helper_1.createSimpleSearch({
id: "2",
m: async (s) => {
await wait_helper_1.wait(50);
return s == "s";
},
});
const search3 = createSimpleSearch_helper_1.createSimpleSearch({
id: "3",
m: async (s) => {
await wait_helper_1.wait(50);
return s == "o";
},
children: s => [search2, search1],
});
const search4 = createSimpleSearch_helper_1.createSimpleSearch({
id: "4",
m: async (s) => {
await wait_helper_1.wait(50);
return s == "o";
},
children: s => [search3],
});
const sequence = [];
const result = createSimpleResultMap();
let searchUpdated = false;
const executer = new CoreSearchExecuter_1.CoreSearchExecuter({
searchable: search4,
onUpdate: (ID, data) => {
sequence.push({ type: "update", ID });
result.onUpdate(ID, data);
// Update the query when node 3 is reached the first time
if (!searchUpdated && ID == "3") {
searchUpdated = true;
sequence.push(null);
executer.setQuery("s");
}
},
onRemove: (ID, ...rest) => {
sequence.push({ type: "remove", ID });
result.onRemove(ID);
},
});
await executer.setQuery("o");
expect(sequence).toEqual([
{ type: "update", ID: search4.ID },
{ type: "update", ID: search3.ID },
null,
{ type: "update", ID: search3.ID },
{ type: "update", ID: search4.ID },
{ type: "update", ID: search2.ID },
{ type: "update", ID: search1.ID },
]);
});
it("Correctly retains the latest result when results resolve out of order", async () => {
let time = 0;
let resolveOrder = [];
const search1 = createSimpleSearch_helper_1.createSimpleSearch({
id: "1",
m: async (s) => {
const d = ++time;
// Add extra delay such that the first result resolves after the second
if (d == 1)
await wait_helper_1.wait(100);
else
await wait_helper_1.wait(20);
resolveOrder.push(d);
return s == "s";
},
});
const [executer, result] = createCoreExecuter(search1);
executer.setQuery("s");
await wait_helper_1.wait(20);
executer.setQuery("p");
await wait_helper_1.wait(110);
expect(result.getItems()).toEqual([]);
expect(resolveOrder).toEqual([2, 1]);
});
});
describe("Refreshes searches when the searchable changes", () => {
it("Correctly updates the resulting item of a search when requested", async () => {
const field1 = new model_react_1.Field("o");
const search1 = createSimpleSearch_helper_1.createSimpleSearch({
id: "1",
m: (s, h) => s == field1.get(h),
});
const field2 = new model_react_1.Field("s");
const search2 = createSimpleSearch_helper_1.createSimpleSearch({
id: "2",
m: (s, h) => s == field2.get(h),
});
const search3 = createSimpleSearch_helper_1.createSimpleSearch({
id: "3",
m: s => s == "o",
children: s => [search1, search2],
});
const [executer, result] = createCoreExecuter(search3);
await executer.setQuery("s");
expect(result.getItems()).toEqual(createSimpleResultMap_helper_1.s([search2.ID]));
await executer.setQuery("o");
expect(result.getItems()).toEqual(createSimpleResultMap_helper_1.s([search1.ID, search3.ID]));
field2.set("o");
await wait_helper_1.wait(1);
expect(result.getItems()).toEqual(createSimpleResultMap_helper_1.s([search1.ID, search2.ID, search3.ID]));
field1.set("s");
await wait_helper_1.wait(1);
expect(result.getItems()).toEqual(createSimpleResultMap_helper_1.s([search2.ID, search3.ID]));
await executer.setQuery("s");
expect(result.getItems()).toEqual(createSimpleResultMap_helper_1.s([search1.ID]));
});
it("Correctly updates the children of a search when requested", async () => {
const search1 = createSimpleSearch_helper_1.createSimpleSearch({
id: "1",
m: s => s == "s" || s == "p",
});
const search2 = createSimpleSearch_helper_1.createSimpleSearch({
id: "2",
m: s => s == "o" || s == "p",
});
const field = new model_react_1.Field("m");
const search3 = createSimpleSearch_helper_1.createSimpleSearch({
id: "3",
m: s => s == "o" || s == "p",
children: (s, h) => (s == field.get(h) ? [] : [search1, search2]),
});
const [executer, result] = createCoreExecuter(search3);
await executer.setQuery("s");
expect(result.getItems()).toEqual(createSimpleResultMap_helper_1.s([search1.ID]));
await executer.setQuery("o");
expect(result.getItems()).toEqual(createSimpleResultMap_helper_1.s([search2.ID, search3.ID]));
await executer.setQuery("p");
expect(result.getItems()).toEqual(createSimpleResultMap_helper_1.s([search1.ID, search2.ID, search3.ID]));
field.set("p");
await wait_helper_1.wait(1);
expect(result.getItems()).toEqual(createSimpleResultMap_helper_1.s([search3.ID]));
});
it("Doesn't update unaffected items", async () => {
const field1 = new model_react_1.Field("o");
const search1 = createSimpleSearch_helper_1.createSimpleSearch({
id: "1",
m: (s, h) => s == field1.get(h),
});
const field2 = new model_react_1.Field("s");
const search2 = createSimpleSearch_helper_1.createSimpleSearch({
id: "2",
m: (s, h) => s == field2.get(h),
});
let request = false;
const search3 = createSimpleSearch_helper_1.createSimpleSearch({
id: "3",
m: s => {
request = true;
return s == "o";
},
children: s => [search1, search2],
});
const [executer, result] = createCoreExecuter(search3);
await executer.setQuery("s");
expect(result.getItems()).toEqual(createSimpleResultMap_helper_1.s([search2.ID]));
request = false;
await executer.setQuery("o");
expect(result.getItems()).toEqual(createSimpleResultMap_helper_1.s([search1.ID, search3.ID]));
expect(request).toBe(true);
request = false;
field2.set("o");
await wait_helper_1.wait(1);
expect(result.getItems()).toEqual(createSimpleResultMap_helper_1.s([search1.ID, search2.ID, search3.ID]));
expect(request).toBe(false);
field1.set("s");
await wait_helper_1.wait(1);
expect(result.getItems()).toEqual(createSimpleResultMap_helper_1.s([search2.ID, search3.ID]));
expect(request).toBe(false);
await executer.setQuery("s");
expect(result.getItems()).toEqual(createSimpleResultMap_helper_1.s([search1.ID]));
expect(request).toBe(true);
});
});
describe("Correctly executes searches in parallel", () => {
it("Doesn't make one search block an other", async () => {
const search1 = createSimpleSearch_helper_1.createSimpleSearch({
id: "1",
m: async (s) => {
await wait_helper_1.wait(10);
return s == "s";
},
});
const search2 = createSimpleSearch_helper_1.createSimpleSearch({
id: "2",
m: async (s) => {
await wait_helper_1.wait(150);
return s == "s";
},
});
const search3 = createSimpleSearch_helper_1.createSimpleSearch({
id: "3",
m: async (s) => {
await wait_helper_1.wait(10);
return s == "s";
},
children: s => [search1],
});
const search4 = createSimpleSearch_helper_1.createSimpleSearch({
id: "4",
m: async (s) => {
await wait_helper_1.wait(70);
return s == "s";
},
});
const search5 = createSimpleSearch_helper_1.createSimpleSearch({
id: "5",
m: async (s) => {
await wait_helper_1.wait(10);
return s == "s";
},
children: s => [search2, search3, search4],
});
const [executer, result] = createCoreExecuter(search5);
const searchPromise = executer.setQuery("s");
await wait_helper_1.wait(50);
expect(result.getItems()).toEqual(createSimpleResultMap_helper_1.s([search5.ID, search1.ID, search3.ID]));
await wait_helper_1.wait(50);
expect(result.getItems()).toEqual(createSimpleResultMap_helper_1.s([search5.ID, search1.ID, search3.ID, search4.ID]));
await searchPromise;
expect(result.getItems()).toEqual(createSimpleResultMap_helper_1.s([search5.ID, search1.ID, search3.ID, search4.ID, search2.ID]));
});
});
});
describe("CoreSearchExecuter.getQuery", () => {
it("Correctly reflects the latest query", () => {
const search = createSimpleSearch_helper_1.createSimpleSearch({ m: s => s == "s" });
const [executer] = createCoreExecuter(search);
executer.setQuery("hoi");
expect(executer.getQuery()).toEqual("hoi");
});
it("Can be subscribed to", async () => {
const search = createSimpleSearch_helper_1.createSimpleSearch({ m: s => s == "s" });
const [executer] = createCoreExecuter(search);
const listener = jest.fn();
new model_react_1.Observer(h => executer.getQuery(h)).listen(listener);
executer.setQuery("hoi");
await wait_helper_1.wait(1);
executer.setQuery("stuff");
await wait_helper_1.wait(1);
expect(listener.mock.calls[0][0]).toEqual("hoi");
expect(listener.mock.calls[1][0]).toEqual("stuff");
});
});
describe("CoreSearchExecuter.isSearching", () => {
it("Correctly reflects the search status", async () => {
const search = createSimpleSearch_helper_1.createSimpleSearch({ m: async (s) => wait_helper_1.wait(20, s == "s") });
const [executer] = createCoreExecuter(search);
expect(executer.isSearching()).toEqual(false);
const promise = executer.setQuery("hoi");
await wait_helper_1.wait(1);
expect(executer.isSearching()).toEqual(true);
await promise;
expect(executer.isSearching()).toEqual(false);
});
it("Can be subscribed to", async () => {
const search = createSimpleSearch_helper_1.createSimpleSearch({ m: async (s) => wait_helper_1.wait(20, s == "s") });
const [executer] = createCoreExecuter(search);
const listener = jest.fn();
new model_react_1.Observer(h => executer.isSearching(h)).listen(listener);
await executer.setQuery("hoi");
await wait_helper_1.wait();
expect(listener.mock.calls.length).toBe(2);
expect(listener.mock.calls[0][0]).toEqual(true);
expect(listener.mock.calls[1][0]).toEqual(false);
});
});
});
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ29yZVNlYXJjaEV4ZWN1dGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3V0aWxzL3NlYXJjaEV4ZWN1dGVyL190ZXN0cy9Db3JlU2VhcmNoRXhlY3V0ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSw2Q0FBMkU7QUFDM0UsNkRBQWlEO0FBRWpELDhEQUF5RDtBQUd6RCxpRkFBaUQ7QUFDakQsMkVBQStEO0FBRS9ELE1BQU0scUJBQXFCLEdBQUcsR0FBTSxFQUFFO0lBQ2xDLE1BQU0sS0FBSyxHQUFHLEVBQXdELENBQUM7SUFDdkUsTUFBTSxRQUFRLEdBQUcsSUFBSSxnQ0FBa0IsRUFBRSxDQUFDO0lBQzFDLE9BQU87UUFDSCxRQUFRLEVBQUUsQ0FBQyxFQUFTLEVBQUUsRUFBRTtZQUNwQixNQUFNLFFBQVEsR0FBRyxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUM7WUFDM0IsT0FBTyxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUM7WUFDakIsSUFBSSxRQUFRO2dCQUFFLFFBQVEsQ0FBQyxhQUFhLEVBQUUsQ0FBQztRQUMzQyxDQUFDO1FBQ0QsUUFBUSxFQUFFLENBQUMsRUFBUyxFQUFFLElBQXdDLEVBQUUsRUFBRTtZQUM5RCxLQUFLLENBQUMsRUFBRSxDQUFDLEdBQUcsSUFBSSxDQUFDO1lBQ2pCLFFBQVEsQ0FBQyxhQUFhLEVBQUUsQ0FBQztRQUM3QixDQUFDO1FBQ0QsUUFBUSxFQUFFLENBQUMsSUFBZ0IsRUFBRSxFQUFFO1lBQzNCLFFBQVEsQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDM0IsT0FBTyxnQ0FBQyxDQUNKLE1BQU0sQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDO2lCQUNmLEdBQUcsQ0FBQyxDQUFDLEVBQUMsSUFBSSxFQUFDLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQztpQkFDckIsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUNoQixDQUFDO1FBQ2IsQ0FBQztRQUNELFFBQVEs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