``` javascript const logA = [ { logId: 1, author: "ABC", seqNo: 1, entryHash: "123A", referenceHash: null, message: { action: "create", fields: { text: "Pandas like to eat bamboo." }, }, }, { logId: 1, author: "ABC", seqNo: 2, entryHash: "123B", referenceHash: "123A", message: { id: "123A", action: "update", fields: { text: "Pandas LOVE to eat bamboo." }, }, }, { logId: 1, author: "ABC", seqNo: 3, entryHash: "123C", referenceHash: "123B", message: { id: "123A", action: "update", fields: { text: "Pandas LOVE to eat bamboo!" }, }, }, { logId: 1, author: "ABC", seqNo: 4, entryHash: "123D", referenceHash: "234A", message: { id: "123A", action: "update", fields: { text: "Pandas LOVE to eat bamboo! But they HATE anchovies..." }, }, }, ]; const logB = [ { logId: 1, author: "DEF", seqNo: 1, entryHash: "234A", referenceHash: "123C", message: { id: "123A", action: "update", fields: { text: "Pandas LOVE to eat bamboo! But they hate anchovies..." }, }, }, { logId: 1, author: "DEF", seqNo: 2, entryHash: "234B", referenceHash: "345A", message: { id: "123A", action: "update", fields: { text: "Pandas **LOVE** to eat bamboo! But they **HATE** anchovies and black coffee...", }, }, }, { logId: 1, author: "DEF", seqNo: 3, entryHash: "234C", referenceHash: null, message: { action: "create", fields: { text: "Pandas have big eyes." }, }, }, ]; const logC = [ { logId: 1, author: "GHI", seqNo: 1, entryHash: "345A", referenceHash: "123D", message: { id: "123A", action: "update", fields: { text: "Pandas LOVE to eat bamboo! But they HATE anchovies and black coffee...", }, }, }, { logId: 1, author: "GHI", seqNo: 2, entryHash: "345B", referenceHash: "234C", message: { id: "234C", action: "update", fields: { text: "Pandas have markings on their face which makes their eyes look big.", }, }, }, ]; // Iterator which yields all root "create" entries function* iterateRootEntries(allEntries) { for (entry of allEntries) { if (entry.message.action === "create") { yield entry; } } } // Iterator which plots update path for a root "create" entry function* iterateUpdatePath(currentEntry, allEntries) { while (true) { let nextEntry = allEntries.find( (entry) => entry.referenceHash === currentEntry.entryHash ); if (!nextEntry) break; currentEntry = nextEntry; yield formatLogItem(nextEntry); } } const createDataTree = (allEntries) => { const dataTree = []; const rootEntries = iterateRootEntries(allEntries); let createMessage = rootEntries.next(); while (!createMessage.done) { dataTree.push([ formatLogItem(createMessage.value), ...iterateUpdatePath(createMessage.value, allEntries), ]); createMessage = rootEntries.next(); } return dataTree; }; const createMaterializedView = (dataTree) => { let materializedView = {}; for (path of dataTree) { materializedView[path[path.length - 1].id] = path[path.length - 1].value; } return materializedView; }; const formatLogItem = (entry) => { return { id: entry.message.id ? entry.message.id : entry.entryHash, author: entry.author, value: entry.message.fields.text, }; }; const allEntries = [...logA, ...logB, ...logC]; const dataTree = createDataTree(allEntries); console.log(dataTree); // => change log for each create message let materializedView = createMaterializedView(dataTree); console.log(materializedView); // => final updated message state /* { '123A': 'Pandas **LOVE** to eat bamboo! But they **HATE** anchovies and black coffee...', '234C': 'Pandas have markings on their face which makes their eyes look big.' } */ ```