Digested-Tile 2024-09-13

Authors:: Unknown License:: Unspecified Digest Root:: 97d8600101ee #MarkdownTile

Doc Seal 0.9 - Digest & Seal - Current Document.md

<%*
// Doc Seal 0.9 for Obsidian Templater
// Version 0.9.7
 
/* * *Preserve Specs for Tile and Blockchain formats* * *
Tile Spec:
- Structure `###### #Digested-Tile #ds/{deformat-digest}/{YYYY-MM-DD}\nAuthors:: {authors}\nLicense:: {license}\nDigest Root:: {digestRootHash}\n###### #MarkdownTile\n{tile}\n###### #DeformattedTile\n{deformatted-tile}\n###### #EOT\n---\n`
- Location: `x/ds/tiles/{deformat-digest}.md`
- Upsert Logic: Skip (with Notice message) if `#ds/{deformat-digest}/{YYYY-MM-DD}` exists, append otherwise
Blockchain Spec:
- Structure: `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained  to #ds/block/${previousBlockchainEntryDigest} on ${YYYY-MM-DDTHH:mm}\n${digestTags.join(' ')}\n#ds/block/{currentBlockchainEntryDigest}`
- Location: `x/ds/blockchains/wwbc-{YY-MM}.md`
- Blockchain Logic: {previousBlockchainEntryDigest} is a hash of {YY-MM} for initial block or the BlockchainEntryDigest of the previous entry; if there are no "wwbc-....md" files yet, use the hash of the YY-MM, if there are not blocks in this months file yet, use the last #ds/block from the previous month, otherwise, use the last #ds/block in the current month's file
Script Spec:
- use Obsidian Templater scripting language for the script 
- use tp.user.updateFrontMatter to update frontmatter
- 15s Notice messages about updates, 3 messages: status, tiles, and blockchain 
- tp.user scripts: computeSHA256(content, length = 12); splitIntoTiles(content); ensureDirectoryExists(path); upsertToFile(filePath, header, content); updateFrontMatter(file, updates); getPreviousBlockchainEntryDigest(app, computeSHA256);
- inline helper functions: createDigestTag(hash, date); createDigestRootHash(digestTags);  
*/
 
function createDigestTag(hash, date) {
    return `#ds/${hash}/${date}`;
}
 
function createDigestRootHash(digestTags) {
    return tp.user.computeSHA256(digestTags.join(' '), 12);
}
 
// Main function
async function dsTaggerChain() {
    const version = "0.9.7";
    const startTime = Date.now();
    const currentDate = new Date().toISOString().split('T')[0];
    const currentTimestamp = new Date().toISOString();
    console.log(`[${currentDate}] DS Tagger Chain v${version} started`);
 
    // Configuration
    const tileDirectoryPath = "x/ds/tiles";
    const blockchainDirectoryPath = "x/ds/blockchains";
 
    try {
        // Ensure directories exist
        await tp.user.ensureDirectoryExists(tileDirectoryPath);
        await tp.user.ensureDirectoryExists(blockchainDirectoryPath);
 
        let content = tp.file.content;
        const fileName = tp.file.title;
        const currentFile = tp.file.find_tfile(fileName);
 
        if (typeof content !== 'string') {
            throw new Error('Received non-string content');
        }
 
        const authors = tp.frontmatter.authors || 'Unknown';
        const license = tp.frontmatter.license || 'Unspecified';
        console.log(`[${currentDate}] Authors extracted: ${authors}`);
        console.log(`[${currentDate}] License extracted: ${license}`);
 
        console.log(`[${currentDate}] File content length: ${content.length} characters`);
 
        const { frontmatter, tiles } = tp.user.splitIntoTiles(content);
        console.log(`[${currentDate}] Number of tiles: ${tiles.length}`);
 
        let processedTiles = [];
        let digestedTiles = 0;
        let nonDigestedTiles = 0;
        let updatedTiles = 0;
        let digestTags = [];
        let tileFilesUpdated = {};
 
        for (let i = 0; i < tiles.length; i++) {
            let tile = tiles[i];
            const tileHash = tp.user.computeSHA256(tile);
            console.log(`\n[${currentDate}] Processing tile ${i + 1} (${tileHash})`);
 
            let existingDigestMatch = tile.match(/\s*(#ds\/[a-f0-9]+\/\d{4}-\d{2}-\d{2})/);
            let existingDigest = existingDigestMatch ? existingDigestMatch[1] : null;
 
            console.log(`Existing Digest Tag: ${existingDigest || 'None'}`);
 
            let cleanTile = tile.replace(/\s*#ds\/[a-f0-9]+\/\d{4}-\d{2}-\d{2}/, '').trim();
 
            let { deformattedContent, charactersRemoved } = tp.user.deformatTile(cleanTile);
            let digest = tp.user.computeSHA256(deformattedContent);
            let digestTag = createDigestTag(digest, currentDate);
 
            console.log(`New Digest Tag: ${digestTag}`);
 
            if (existingDigest && existingDigest.includes(digest)) {
                console.log(`Content unchanged for tile ${tileHash}. Keeping existing Digest Tag.`);
                digestTag = existingDigest;
                nonDigestedTiles++;
               // new Notice(`Skipping unchanged tile: ${digestTag}`, 15000);
            } else {
                console.log(`Content changed or new for tile ${tileHash}. Updating Digest Tag.`);
                if (existingDigest) {
                    updatedTiles++;
                } else {
                    digestedTiles++;
                }
            }
 
            let processedTile = `${cleanTile} ${digestTag}`;
            processedTiles.push(processedTile);
            digestTags.push(digestTag);
 
            console.log(`Tile ${tileHash} stats: Characters removed: ${charactersRemoved}`);
 
            const tileFilePath = `${tileDirectoryPath}/${digest}.md`;
            const digestRootHash = createDigestRootHash(digestTags);
            const tileFileContent = `###### #Digested-Tile ${digestTag}
Authors:: ${authors}
License:: ${license}
Digest Root:: ${digestRootHash}
###### #MarkdownTile
${cleanTile}
###### #DeformattedTile
${deformattedContent}
###### #EOT
---`;
            const { status: tileUpdateStatus, file: tileFile } = await tp.user.upsertToFile(tileFilePath, `###### #Digested-Tile ${digestTag}`, tileFileContent);
            tileFilesUpdated[tileFilePath] = tileUpdateStatus;
 
            // Update tile file frontmatter
            if (tileFile) {
                await tp.user.updateFrontMatter(tileFile, {
                    aliases: [digestTag],
                    authors: authors,
                    license: license,
                    'digest-root': digestRootHash
                });
            }
        }
 
        let result = frontmatter + '\n' + processedTiles.join('\n\n');
        const yearMonth = currentDate.slice(2, 7);
 
        let digestRootHash = createDigestRootHash(digestTags);
        console.log(`\n[${currentDate}] Digest Root hash created: ${digestRootHash}`);
 
        // Modify the current file content
        await app.vault.modify(currentFile, result);
 
        // Update current file frontmatter using tp.user.updateFrontMatter after modifying content
        await tp.user.updateFrontMatter(currentFile, {
			aliases: [`#ds/root/${digestRootHash}`],
			'blockchain_last_digest_root': `#ds/root/${digestRootHash}`,
            'blockchain_digest_timestamp': currentTimestamp,
            'blockchain_file': `[[wwbc-${yearMonth}]]`
        });
 
        // Update blockchain file
        const blockchainFilePath = `${blockchainDirectoryPath}/wwbc-${yearMonth}.md`;
        const previousBlockchainEntryDigest = await tp.user.getPreviousBlockchainEntryDigest(app, blockchainDirectoryPath, tp.user.computeSHA256);
        console.log(`Previous blockchain entry digest: ${previousBlockchainEntryDigest}`);
 
        // Create the blockchain content without the final hash
        const blockchainContentWithoutHash = `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}
${digestTags.join(' ')}`.trim();
 
        // Generate the hash for the blockchain entry
        const blockchainEntryHash = tp.user.computeSHA256(blockchainContentWithoutHash);
 
        // Create the final blockchain content
        const blockchainFileContent = `${blockchainContentWithoutHash}
#ds/block/${blockchainEntryHash}`;
 
        const { status: blockchainUpdateStatus, file: blockchainFile  } = await tp.user.upsertToFile(blockchainFilePath, `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}`, blockchainFileContent);
		if (blockchainFile) {
			await tp.user.updateFrontMatter(blockchainFile, {
				cssclasses: [`locked`]
			});
		}
        if (blockchainUpdateStatus === 'updated') {
            console.log(`Updated blockchain file: ${blockchainFilePath}`);
        } else {
            console.log(`Blockchain file already up to date: ${blockchainFilePath}`);
        }
 
        const endTime = Date.now();
        const runtime = ((endTime - startTime) / 1000).toFixed(2);
        console.log(`\n[${currentDate}] DS Tagger Chain process completed successfully`);
        
        const statusMessage = `DS Tagger Chain v${version} completed:
Runtime: ${runtime}s
#ds/root/${digestRootHash}
Tiles processed: ${tiles.length}
Tiles digested: ${digestedTiles}
Tiles not digested: ${nonDigestedTiles}
Tiles updated: ${updatedTiles}
Date: ${currentDate}`;
 
        const tileFilesMessage = `Tile files updated (BUGY):
${Object.entries(tileFilesUpdated).map(([file, status]) => `${file}: ${status}`).join('\n')}`;
 
        const blockchainEntryMessage = `Blockchain entry (${blockchainUpdateStatus}):
${blockchainFileContent}`;
 
        console.log(statusMessage);
        console.log(tileFilesMessage);
        console.log(blockchainEntryMessage);
 
        new Notice(statusMessage, 15000);
        new Notice(tileFilesMessage, 15000);
        new Notice(blockchainEntryMessage, 15000);
 
    } catch (error) {
        console.error(`[${currentDate}] An error occurred:`, error);
        new Notice(`Error in DS Tagger Chain v${version}: ${error.message}. Check console for details.`, 15000);
    }
}
 
// Run the script and output the result
await dsTaggerChain();
%>
DeformattedTile

Doc Seal 0.9 - Digest & Seal - Current Document.md

<%*
// Doc Seal 0.9 for Obsidian Templater
// Version 0.9.7
/* * *Preserve Specs for Tile and Blockchain formats* * *
Tile Spec:
- Structure `###### #Digested-Tile #ds/{deformat-digest}/{YYYY-MM-DD}\nAuthors:: {authors}\nLicense:: {license}\nDigest Root:: {digestRootHash}\n###### #MarkdownTile\n{tile}\n###### #DeformattedTile\n{deformatted-tile}\n###### #EOT\n---\n`
- Location: `x/ds/tiles/{deformat-digest}.md`
- Upsert Logic: Skip (with Notice message) if `#ds/{deformat-digest}/{YYYY-MM-DD}` exists, append otherwise
Blockchain Spec:
- Structure: `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained  to #ds/block/${previousBlockchainEntryDigest} on ${YYYY-MM-DDTHH:mm}\n${digestTags.join(' ')}\n#ds/block/{currentBlockchainEntryDigest}`
- Location: `x/ds/blockchains/wwbc-{YY-MM}.md`
- Blockchain Logic: {previousBlockchainEntryDigest} is a hash of {YY-MM} for initial block or the BlockchainEntryDigest of the previous entry; if there are no "wwbc-....md" files yet, use the hash of the YY-MM, if there are not blocks in this months file yet, use the last #ds/block from the previous month, otherwise, use the last #ds/block in the current month's file
Script Spec:
- use Obsidian Templater scripting language for the script 
- use tp.user.updateFrontMatter to update frontmatter
- 15s Notice messages about updates, 3 messages: status, tiles, and blockchain 
- tp.user scripts: computeSHA256(content, length = 12); splitIntoTiles(content); ensureDirectoryExists(path); upsertToFile(filePath, header, content); updateFrontMatter(file, updates); getPreviousBlockchainEntryDigest(app, computeSHA256);
- inline helper functions: createDigestTag(hash, date); createDigestRootHash(digestTags);  
*/
function createDigestTag(hash, date) {
    return `#ds/${hash}/${date}`;
}
function createDigestRootHash(digestTags) {
    return tp.user.computeSHA256(digestTags.join(' '), 12);
}
// Main function
async function dsTaggerChain() {
    const version = "0.9.7";
    const startTime = Date.now();
    const currentDate = new Date().toISOString().split('T')[0];
    const currentTimestamp = new Date().toISOString();
    console.log(`[${currentDate}] DS Tagger Chain v${version} started`);
    // Configuration
    const tileDirectoryPath = "x/ds/tiles";
    const blockchainDirectoryPath = "x/ds/blockchains";
    try {
        // Ensure directories exist
        await tp.user.ensureDirectoryExists(tileDirectoryPath);
        await tp.user.ensureDirectoryExists(blockchainDirectoryPath);
        let content = tp.file.content;
        const fileName = tp.file.title;
        const currentFile = tp.file.find_tfile(fileName);
        if (typeof content !== 'string') {
            throw new Error('Received non-string content');
        }
        const authors = tp.frontmatter.authors || 'Unknown';
        const license = tp.frontmatter.license || 'Unspecified';
        console.log(`[${currentDate}] Authors extracted: ${authors}`);
        console.log(`[${currentDate}] License extracted: ${license}`);
        console.log(`[${currentDate}] File content length: ${content.length} characters`);
        const { frontmatter, tiles } = tp.user.splitIntoTiles(content);
        console.log(`[${currentDate}] Number of tiles: ${tiles.length}`);
        let processedTiles = [];
        let digestedTiles = 0;
        let nonDigestedTiles = 0;
        let updatedTiles = 0;
        let digestTags = [];
        let tileFilesUpdated = {};
        for (let i = 0; i < tiles.length; i++) {
            let tile = tiles[i];
            const tileHash = tp.user.computeSHA256(tile);
            console.log(`\n[${currentDate}] Processing tile ${i + 1} (${tileHash})`);
            let existingDigestMatch = tile.match(/\s*(#ds\/[a-f0-9]+\/\d{4}-\d{2}-\d{2})/);
            let existingDigest = existingDigestMatch ? existingDigestMatch[1] : null;
            console.log(`Existing Digest Tag: ${existingDigest || 'None'}`);
            let cleanTile = tile.replace(/\s*#ds\/[a-f0-9]+\/\d{4}-\d{2}-\d{2}/, '').trim();
            let { deformattedContent, charactersRemoved } = tp.user.deformatTile(cleanTile);
            let digest = tp.user.computeSHA256(deformattedContent);
            let digestTag = createDigestTag(digest, currentDate);
            console.log(`New Digest Tag: ${digestTag}`);
            if (existingDigest && existingDigest.includes(digest)) {
                console.log(`Content unchanged for tile ${tileHash}. Keeping existing Digest Tag.`);
                digestTag = existingDigest;
                nonDigestedTiles++;
               // new Notice(`Skipping unchanged tile: ${digestTag}`, 15000);
            } else {
                console.log(`Content changed or new for tile ${tileHash}. Updating Digest Tag.`);
                if (existingDigest) {
                    updatedTiles++;
                } else {
                    digestedTiles++;
                }
            }
            let processedTile = `${cleanTile} ${digestTag}`;
            processedTiles.push(processedTile);
            digestTags.push(digestTag);
            console.log(`Tile ${tileHash} stats: Characters removed: ${charactersRemoved}`);
            const tileFilePath = `${tileDirectoryPath}/${digest}.md`;
            const digestRootHash = createDigestRootHash(digestTags);
            const tileFileContent = `###### #Digested-Tile ${digestTag}
Authors:: ${authors}
License:: ${license}
Digest Root:: ${digestRootHash}
#MarkdownTile
${cleanTile}
#DeformattedTile
${deformattedContent}
#EOT
---`;
            const { status: tileUpdateStatus, file: tileFile } = await tp.user.upsertToFile(tileFilePath, `###### #Digested-Tile ${digestTag}`, tileFileContent);
            tileFilesUpdated[tileFilePath] = tileUpdateStatus;
            // Update tile file frontmatter
            if (tileFile) {
                await tp.user.updateFrontMatter(tileFile, {
                    aliases: [digestTag],
                    authors: authors,
                    license: license,
                    'digest-root': digestRootHash
                });
            }
        }
        let result = frontmatter + '\n' + processedTiles.join('\n\n');
        const yearMonth = currentDate.slice(2, 7);
        let digestRootHash = createDigestRootHash(digestTags);
        console.log(`\n[${currentDate}] Digest Root hash created: ${digestRootHash}`);
        // Modify the current file content
        await app.vault.modify(currentFile, result);
        // Update current file frontmatter using tp.user.updateFrontMatter after modifying content
        await tp.user.updateFrontMatter(currentFile, {
			aliases: [`#ds/root/${digestRootHash}`],
			'blockchain_last_digest_root': `#ds/root/${digestRootHash}`,
            'blockchain_digest_timestamp': currentTimestamp,
            'blockchain_file': `[[wwbc-${yearMonth}]]`
        });
        // Update blockchain file
        const blockchainFilePath = `${blockchainDirectoryPath}/wwbc-${yearMonth}.md`;
        const previousBlockchainEntryDigest = await tp.user.getPreviousBlockchainEntryDigest(app, blockchainDirectoryPath, tp.user.computeSHA256);
        console.log(`Previous blockchain entry digest: ${previousBlockchainEntryDigest}`);
        // Create the blockchain content without the final hash
        const blockchainContentWithoutHash = `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}
${digestTags.join(' ')}`.trim();
        // Generate the hash for the blockchain entry
        const blockchainEntryHash = tp.user.computeSHA256(blockchainContentWithoutHash);
        // Create the final blockchain content
        const blockchainFileContent = `${blockchainContentWithoutHash}
#ds/block/${blockchainEntryHash}`;
        const { status: blockchainUpdateStatus, file: blockchainFile  } = await tp.user.upsertToFile(blockchainFilePath, `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}`, blockchainFileContent);
		if (blockchainFile) {
			await tp.user.updateFrontMatter(blockchainFile, {
				cssclasses: [`locked`]
			});
		}
        if (blockchainUpdateStatus === 'updated') {
            console.log(`Updated blockchain file: ${blockchainFilePath}`);
        } else {
            console.log(`Blockchain file already up to date: ${blockchainFilePath}`);
        }
        const endTime = Date.now();
        const runtime = ((endTime - startTime) / 1000).toFixed(2);
        console.log(`\n[${currentDate}] DS Tagger Chain process completed successfully`);
        
        const statusMessage = `DS Tagger Chain v${version} completed:
Runtime: ${runtime}s
#ds/root/${digestRootHash}
Tiles processed: ${tiles.length}
Tiles digested: ${digestedTiles}
Tiles not digested: ${nonDigestedTiles}
Tiles updated: ${updatedTiles}
Date: ${currentDate}`;
        const tileFilesMessage = `Tile files updated (BUGY):
${Object.entries(tileFilesUpdated).map(([file, status]) => `${file}: ${status}`).join('\n')}`;
        const blockchainEntryMessage = `Blockchain entry (${blockchainUpdateStatus}):
${blockchainFileContent}`;
        console.log(statusMessage);
        console.log(tileFilesMessage);
        console.log(blockchainEntryMessage);
        new Notice(statusMessage, 15000);
        new Notice(tileFilesMessage, 15000);
        new Notice(blockchainEntryMessage, 15000);
    } catch (error) {
        console.error(`[${currentDate}] An error occurred:`, error);
        new Notice(`Error in DS Tagger Chain v${version}: ${error.message}. Check console for details.`, 15000);
    }
}
// Run the script and output the result
await dsTaggerChain();
%>
EOT

DeformattedTile Doc Seal 0.9 - Digest & Seal - Current Document.md

<%*
// Doc Seal 0.9 for Obsidian Templater
// Version 0.9.7
/* * *Preserve Specs for Tile and Blockchain formats* * *
Tile Spec:
- Structure `###### #Digested-Tile #ds/{deformat-digest}/{YYYY-MM-DD}\nAuthors:: {authors}\nLicense:: {license}\nDigest Root:: {digestRootHash}\n###### #MarkdownTile\n{tile}\n###### #DeformattedTile\n{deformatted-tile}\n###### #EOT\n---\n`
- Location: `x/ds/tiles/{deformat-digest}.md`
- Upsert Logic: Skip (with Notice message) if `#ds/{deformat-digest}/{YYYY-MM-DD}` exists, append otherwise
Blockchain Spec:
- Structure: `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained  to #ds/block/${previousBlockchainEntryDigest} on ${YYYY-MM-DDTHH:mm}\n${digestTags.join(' ')}\n#ds/block/{currentBlockchainEntryDigest}`
- Location: `x/ds/blockchains/wwbc-{YY-MM}.md`
- Blockchain Logic: {previousBlockchainEntryDigest} is a hash of {YY-MM} for initial block or the BlockchainEntryDigest of the previous entry; if there are no "wwbc-....md" files yet, use the hash of the YY-MM, if there are not blocks in this months file yet, use the last #ds/block from the previous month, otherwise, use the last #ds/block in the current month's file
Script Spec:
- use Obsidian Templater scripting language for the script 
- use tp.user.updateFrontMatter to update frontmatter
- 15s Notice messages about updates, 3 messages: status, tiles, and blockchain 
- tp.user scripts: computeSHA256(content, length = 12); splitIntoTiles(content); ensureDirectoryExists(path); upsertToFile(filePath, header, content); updateFrontMatter(file, updates); getPreviousBlockchainEntryDigest(app, computeSHA256);
- inline helper functions: createDigestTag(hash, date); createDigestRootHash(digestTags);  
*/
function createDigestTag(hash, date) {
    return `#ds/${hash}/${date}`;
}
function createDigestRootHash(digestTags) {
    return tp.user.computeSHA256(digestTags.join(' '), 12);
}
// Main function
async function dsTaggerChain() {
    const version = "0.9.7";
    const startTime = Date.now();
    const currentDate = new Date().toISOString().split('T')[0];
    const currentTimestamp = new Date().toISOString();
    console.log(`[${currentDate}] DS Tagger Chain v${version} started`);
    // Configuration
    const tileDirectoryPath = "x/ds/tiles";
    const blockchainDirectoryPath = "x/ds/blockchains";
    try {
        // Ensure directories exist
        await tp.user.ensureDirectoryExists(tileDirectoryPath);
        await tp.user.ensureDirectoryExists(blockchainDirectoryPath);
        let content = tp.file.content;
        const fileName = tp.file.title;
        const currentFile = tp.file.find_tfile(fileName);
        if (typeof content !== 'string') {
            throw new Error('Received non-string content');
        }
        const authors = tp.frontmatter.authors || 'Unknown';
        const license = tp.frontmatter.license || 'Unspecified';
        console.log(`[${currentDate}] Authors extracted: ${authors}`);
        console.log(`[${currentDate}] License extracted: ${license}`);
        console.log(`[${currentDate}] File content length: ${content.length} characters`);
        const { frontmatter, tiles } = tp.user.splitIntoTiles(content);
        console.log(`[${currentDate}] Number of tiles: ${tiles.length}`);
        let processedTiles = [];
        let digestedTiles = 0;
        let nonDigestedTiles = 0;
        let updatedTiles = 0;
        let digestTags = [];
        let tileFilesUpdated = {};
        for (let i = 0; i < tiles.length; i++) {
            let tile = tiles[i];
            const tileHash = tp.user.computeSHA256(tile);
            console.log(`\n[${currentDate}] Processing tile ${i + 1} (${tileHash})`);
            let existingDigestMatch = tile.match(/\s*(#ds\/[a-f0-9]+\/\d{4}-\d{2}-\d{2})/);
            let existingDigest = existingDigestMatch ? existingDigestMatch[1] : null;
            console.log(`Existing Digest Tag: ${existingDigest || 'None'}`);
            let cleanTile = tile.replace(/\s*#ds\/[a-f0-9]+\/\d{4}-\d{2}-\d{2}/, '').trim();
            let { deformattedContent, charactersRemoved } = tp.user.deformatTile(cleanTile);
            let digest = tp.user.computeSHA256(deformattedContent);
            let digestTag = createDigestTag(digest, currentDate);
            console.log(`New Digest Tag: ${digestTag}`);
            if (existingDigest && existingDigest.includes(digest)) {
                console.log(`Content unchanged for tile ${tileHash}. Keeping existing Digest Tag.`);
                digestTag = existingDigest;
                nonDigestedTiles++;
               // new Notice(`Skipping unchanged tile: ${digestTag}`, 15000);
            } else {
                console.log(`Content changed or new for tile ${tileHash}. Updating Digest Tag.`);
                if (existingDigest) {
                    updatedTiles++;
                } else {
                    digestedTiles++;
                }
            }
            let processedTile = `${cleanTile} ${digestTag}`;
            processedTiles.push(processedTile);
            digestTags.push(digestTag);
            console.log(`Tile ${tileHash} stats: Characters removed: ${charactersRemoved}`);
            const tileFilePath = `${tileDirectoryPath}/${digest}.md`;
            const digestRootHash = createDigestRootHash(digestTags);
            const tileFileContent = `###### #Digested-Tile ${digestTag}
Authors:: ${authors}
License:: ${license}
Digest Root:: ${digestRootHash}
#MarkdownTile
${cleanTile}
#DeformattedTile
${deformattedContent}
#EOT
---`;
            const { status: tileUpdateStatus, file: tileFile } = await tp.user.upsertToFile(tileFilePath, `###### #Digested-Tile ${digestTag}`, tileFileContent);
            tileFilesUpdated[tileFilePath] = tileUpdateStatus;
            // Update tile file frontmatter
            if (tileFile) {
                await tp.user.updateFrontMatter(tileFile, {
                    aliases: [digestTag],
                    authors: authors,
                    license: license,
                    'digest-root': digestRootHash
                });
            }
        }
        let result = frontmatter + '\n' + processedTiles.join('\n\n');
        const yearMonth = currentDate.slice(2, 7);
        let digestRootHash = createDigestRootHash(digestTags);
        console.log(`\n[${currentDate}] Digest Root hash created: ${digestRootHash}`);
        // Modify the current file content
        await app.vault.modify(currentFile, result);
        // Update current file frontmatter using tp.user.updateFrontMatter after modifying content
        await tp.user.updateFrontMatter(currentFile, {
			aliases: [`#ds/root/${digestRootHash}`],
			'blockchain_last_digest_root': `#ds/root/${digestRootHash}`,
            'blockchain_digest_timestamp': currentTimestamp,
            'blockchain_file': `[[wwbc-${yearMonth}]]`
        });
        // Update blockchain file
        const blockchainFilePath = `${blockchainDirectoryPath}/wwbc-${yearMonth}.md`;
        const previousBlockchainEntryDigest = await tp.user.getPreviousBlockchainEntryDigest(app, blockchainDirectoryPath, tp.user.computeSHA256);
        console.log(`Previous blockchain entry digest: ${previousBlockchainEntryDigest}`);
        // Create the blockchain content without the final hash
        const blockchainContentWithoutHash = `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}
${digestTags.join(' ')}`.trim();
        // Generate the hash for the blockchain entry
        const blockchainEntryHash = tp.user.computeSHA256(blockchainContentWithoutHash);
        // Create the final blockchain content
        const blockchainFileContent = `${blockchainContentWithoutHash}
#ds/block/${blockchainEntryHash}`;
        const { status: blockchainUpdateStatus, file: blockchainFile  } = await tp.user.upsertToFile(blockchainFilePath, `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}`, blockchainFileContent);
		if (blockchainFile) {
			await tp.user.updateFrontMatter(blockchainFile, {
				cssclasses: [`locked`]
			});
		}
        if (blockchainUpdateStatus === 'updated') {
            console.log(`Updated blockchain file: ${blockchainFilePath}`);
        } else {
            console.log(`Blockchain file already up to date: ${blockchainFilePath}`);
        }
        const endTime = Date.now();
        const runtime = ((endTime - startTime) / 1000).toFixed(2);
        console.log(`\n[${currentDate}] DS Tagger Chain process completed successfully`);
        
        const statusMessage = `DS Tagger Chain v${version} completed:
Runtime: ${runtime}s
#ds/root/${digestRootHash}
Tiles processed: ${tiles.length}
Tiles digested: ${digestedTiles}
Tiles not digested: ${nonDigestedTiles}
Tiles updated: ${updatedTiles}
Date: ${currentDate}`;
        const tileFilesMessage = `Tile files updated (BUGY):
${Object.entries(tileFilesUpdated).map(([file, status]) => `${file}: ${status}`).join('\n')}`;
        const blockchainEntryMessage = `Blockchain entry (${blockchainUpdateStatus}):
${blockchainFileContent}`;
        console.log(statusMessage);
        console.log(tileFilesMessage);
        console.log(blockchainEntryMessage);
        new Notice(statusMessage, 15000);
        new Notice(tileFilesMessage, 15000);
        new Notice(blockchainEntryMessage, 15000);
    } catch (error) {
        console.error(`[${currentDate}] An error occurred:`, error);
        new Notice(`Error in DS Tagger Chain v${version}: ${error.message}. Check console for details.`, 15000);
    }
}
// Run the script and output the result
await dsTaggerChain();
%>

DeformattedTile Doc Seal 0.9 - Digest & Seal - Current Document.md

<%*
// Doc Seal 0.9 for Obsidian Templater
// Version 0.9.7
/* * *Preserve Specs for Tile and Blockchain formats* * *
Tile Spec:
- Structure `###### #Digested-Tile #ds/{deformat-digest}/{YYYY-MM-DD}\nAuthors:: {authors}\nLicense:: {license}\nDigest Root:: {digestRootHash}\n###### #MarkdownTile\n{tile}\n###### #DeformattedTile\n{deformatted-tile}\n###### #EOT\n---\n`
- Location: `x/ds/tiles/{deformat-digest}.md`
- Upsert Logic: Skip (with Notice message) if `#ds/{deformat-digest}/{YYYY-MM-DD}` exists, append otherwise
Blockchain Spec:
- Structure: `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained  to #ds/block/${previousBlockchainEntryDigest} on ${YYYY-MM-DDTHH:mm}\n${digestTags.join(' ')}\n#ds/block/{currentBlockchainEntryDigest}`
- Location: `x/ds/blockchains/wwbc-{YY-MM}.md`
- Blockchain Logic: {previousBlockchainEntryDigest} is a hash of {YY-MM} for initial block or the BlockchainEntryDigest of the previous entry; if there are no "wwbc-....md" files yet, use the hash of the YY-MM, if there are not blocks in this months file yet, use the last #ds/block from the previous month, otherwise, use the last #ds/block in the current month's file
Script Spec:
- use Obsidian Templater scripting language for the script 
- use tp.user.updateFrontMatter to update frontmatter
- 15s Notice messages about updates, 3 messages: status, tiles, and blockchain 
- tp.user scripts: computeSHA256(content, length = 12); splitIntoTiles(content); ensureDirectoryExists(path); upsertToFile(filePath, header, content); updateFrontMatter(file, updates); getPreviousBlockchainEntryDigest(app, computeSHA256);
- inline helper functions: createDigestTag(hash, date); createDigestRootHash(digestTags);  
*/
function createDigestTag(hash, date) {
    return `#ds/${hash}/${date}`;
}
function createDigestRootHash(digestTags) {
    return tp.user.computeSHA256(digestTags.join(' '), 12);
}
// Main function
async function dsTaggerChain() {
    const version = "0.9.7";
    const startTime = Date.now();
    const currentDate = new Date().toISOString().split('T')[0];
    const currentTimestamp = new Date().toISOString();
    console.log(`[${currentDate}] DS Tagger Chain v${version} started`);
    // Configuration
    const tileDirectoryPath = "x/ds/tiles";
    const blockchainDirectoryPath = "x/ds/blockchains";
    try {
        // Ensure directories exist
        await tp.user.ensureDirectoryExists(tileDirectoryPath);
        await tp.user.ensureDirectoryExists(blockchainDirectoryPath);
        let content = tp.file.content;
        const fileName = tp.file.title;
        const currentFile = tp.file.find_tfile(fileName);
        if (typeof content !== 'string') {
            throw new Error('Received non-string content');
        }
        const authors = tp.frontmatter.authors || 'Unknown';
        const license = tp.frontmatter.license || 'Unspecified';
        console.log(`[${currentDate}] Authors extracted: ${authors}`);
        console.log(`[${currentDate}] License extracted: ${license}`);
        console.log(`[${currentDate}] File content length: ${content.length} characters`);
        const { frontmatter, tiles } = tp.user.splitIntoTiles(content);
        console.log(`[${currentDate}] Number of tiles: ${tiles.length}`);
        let processedTiles = [];
        let digestedTiles = 0;
        let nonDigestedTiles = 0;
        let updatedTiles = 0;
        let digestTags = [];
        let tileFilesUpdated = {};
        for (let i = 0; i < tiles.length; i++) {
            let tile = tiles[i];
            const tileHash = tp.user.computeSHA256(tile);
            console.log(`\n[${currentDate}] Processing tile ${i + 1} (${tileHash})`);
            let existingDigestMatch = tile.match(/\s*(#ds\/[a-f0-9]+\/\d{4}-\d{2}-\d{2})/);
            let existingDigest = existingDigestMatch ? existingDigestMatch[1] : null;
            console.log(`Existing Digest Tag: ${existingDigest || 'None'}`);
            let cleanTile = tile.replace(/\s*#ds\/[a-f0-9]+\/\d{4}-\d{2}-\d{2}/, '').trim();
            let { deformattedContent, charactersRemoved } = tp.user.deformatTile(cleanTile);
            let digest = tp.user.computeSHA256(deformattedContent);
            let digestTag = createDigestTag(digest, currentDate);
            console.log(`New Digest Tag: ${digestTag}`);
            if (existingDigest && existingDigest.includes(digest)) {
                console.log(`Content unchanged for tile ${tileHash}. Keeping existing Digest Tag.`);
                digestTag = existingDigest;
                nonDigestedTiles++;
               // new Notice(`Skipping unchanged tile: ${digestTag}`, 15000);
            } else {
                console.log(`Content changed or new for tile ${tileHash}. Updating Digest Tag.`);
                if (existingDigest) {
                    updatedTiles++;
                } else {
                    digestedTiles++;
                }
            }
            let processedTile = `${cleanTile} ${digestTag}`;
            processedTiles.push(processedTile);
            digestTags.push(digestTag);
            console.log(`Tile ${tileHash} stats: Characters removed: ${charactersRemoved}`);
            const tileFilePath = `${tileDirectoryPath}/${digest}.md`;
            const digestRootHash = createDigestRootHash(digestTags);
            const tileFileContent = `###### #Digested-Tile ${digestTag}
Authors:: ${authors}
License:: ${license}
Digest Root:: ${digestRootHash}
#MarkdownTile
${cleanTile}
#DeformattedTile
${deformattedContent}
#EOT
---`;
            const { status: tileUpdateStatus, file: tileFile } = await tp.user.upsertToFile(tileFilePath, `###### #Digested-Tile ${digestTag}`, tileFileContent);
            tileFilesUpdated[tileFilePath] = tileUpdateStatus;
            // Update tile file frontmatter
            if (tileFile) {
                await tp.user.updateFrontMatter(tileFile, {
                    aliases: [digestTag],
                    authors: authors,
                    license: license,
                    'digest-root': digestRootHash
                });
            }
        }
        let result = frontmatter + '\n' + processedTiles.join('\n\n');
        const yearMonth = currentDate.slice(2, 7);
        let digestRootHash = createDigestRootHash(digestTags);
        console.log(`\n[${currentDate}] Digest Root hash created: ${digestRootHash}`);
        // Modify the current file content
        await app.vault.modify(currentFile, result);
        // Update current file frontmatter using tp.user.updateFrontMatter after modifying content
        await tp.user.updateFrontMatter(currentFile, {
			aliases: [`#ds/root/${digestRootHash}`],
			'blockchain_last_digest_root': `#ds/root/${digestRootHash}`,
            'blockchain_digest_timestamp': currentTimestamp,
            'blockchain_file': `[[wwbc-${yearMonth}]]`
        });
        // Update blockchain file
        const blockchainFilePath = `${blockchainDirectoryPath}/wwbc-${yearMonth}.md`;
        const previousBlockchainEntryDigest = await tp.user.getPreviousBlockchainEntryDigest(app, blockchainDirectoryPath, tp.user.computeSHA256);
        console.log(`Previous blockchain entry digest: ${previousBlockchainEntryDigest}`);
        // Create the blockchain content without the final hash
        const blockchainContentWithoutHash = `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}
${digestTags.join(' ')}`.trim();
        // Generate the hash for the blockchain entry
        const blockchainEntryHash = tp.user.computeSHA256(blockchainContentWithoutHash);
        // Create the final blockchain content
        const blockchainFileContent = `${blockchainContentWithoutHash}
#ds/block/${blockchainEntryHash}`;
        const { status: blockchainUpdateStatus, file: blockchainFile  } = await tp.user.upsertToFile(blockchainFilePath, `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}`, blockchainFileContent);
		if (blockchainFile) {
			await tp.user.updateFrontMatter(blockchainFile, {
				cssclasses: [`locked`]
			});
		}
        if (blockchainUpdateStatus === 'updated') {
            console.log(`Updated blockchain file: ${blockchainFilePath}`);
        } else {
            console.log(`Blockchain file already up to date: ${blockchainFilePath}`);
        }
        const endTime = Date.now();
        const runtime = ((endTime - startTime) / 1000).toFixed(2);
        console.log(`\n[${currentDate}] DS Tagger Chain process completed successfully`);
        
        const statusMessage = `DS Tagger Chain v${version} completed:
Runtime: ${runtime}s
#ds/root/${digestRootHash}
Tiles processed: ${tiles.length}
Tiles digested: ${digestedTiles}
Tiles not digested: ${nonDigestedTiles}
Tiles updated: ${updatedTiles}
Date: ${currentDate}`;
        const tileFilesMessage = `Tile files updated (BUGY):
${Object.entries(tileFilesUpdated).map(([file, status]) => `${file}: ${status}`).join('\n')}`;
        const blockchainEntryMessage = `Blockchain entry (${blockchainUpdateStatus}):
${blockchainFileContent}`;
        console.log(statusMessage);
        console.log(tileFilesMessage);
        console.log(blockchainEntryMessage);
        new Notice(statusMessage, 15000);
        new Notice(tileFilesMessage, 15000);
        new Notice(blockchainEntryMessage, 15000);
    } catch (error) {
        console.error(`[${currentDate}] An error occurred:`, error);
        new Notice(`Error in DS Tagger Chain v${version}: ${error.message}. Check console for details.`, 15000);
    }
}
// Run the script and output the result
await dsTaggerChain();
%>

EOT

EOT

DeformattedTile Doc Seal 0.9 - Digest & Seal - Current Document.md

<%*
// Doc Seal 0.9 for Obsidian Templater
// Version 0.9.7
/* * *Preserve Specs for Tile and Blockchain formats* * *
Tile Spec:
- Structure `###### #Digested-Tile #ds/{deformat-digest}/{YYYY-MM-DD}\nAuthors:: {authors}\nLicense:: {license}\nDigest Root:: {digestRootHash}\n###### #MarkdownTile\n{tile}\n###### #DeformattedTile\n{deformatted-tile}\n###### #EOT\n---\n`
- Location: `x/ds/tiles/{deformat-digest}.md`
- Upsert Logic: Skip (with Notice message) if `#ds/{deformat-digest}/{YYYY-MM-DD}` exists, append otherwise
Blockchain Spec:
- Structure: `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained  to #ds/block/${previousBlockchainEntryDigest} on ${YYYY-MM-DDTHH:mm}\n${digestTags.join(' ')}\n#ds/block/{currentBlockchainEntryDigest}`
- Location: `x/ds/blockchains/wwbc-{YY-MM}.md`
- Blockchain Logic: {previousBlockchainEntryDigest} is a hash of {YY-MM} for initial block or the BlockchainEntryDigest of the previous entry; if there are no "wwbc-....md" files yet, use the hash of the YY-MM, if there are not blocks in this months file yet, use the last #ds/block from the previous month, otherwise, use the last #ds/block in the current month's file
Script Spec:
- use Obsidian Templater scripting language for the script 
- use tp.user.updateFrontMatter to update frontmatter
- 15s Notice messages about updates, 3 messages: status, tiles, and blockchain 
- tp.user scripts: computeSHA256(content, length = 12); splitIntoTiles(content); ensureDirectoryExists(path); upsertToFile(filePath, header, content); updateFrontMatter(file, updates); getPreviousBlockchainEntryDigest(app, computeSHA256);
- inline helper functions: createDigestTag(hash, date); createDigestRootHash(digestTags);  
*/
function createDigestTag(hash, date) {
    return `#ds/${hash}/${date}`;
}
function createDigestRootHash(digestTags) {
    return tp.user.computeSHA256(digestTags.join(' '), 12);
}
// Main function
async function dsTaggerChain() {
    const version = "0.9.7";
    const startTime = Date.now();
    const currentDate = new Date().toISOString().split('T')[0];
    const currentTimestamp = new Date().toISOString();
    console.log(`[${currentDate}] DS Tagger Chain v${version} started`);
    // Configuration
    const tileDirectoryPath = "x/ds/tiles";
    const blockchainDirectoryPath = "x/ds/blockchains";
    try {
        // Ensure directories exist
        await tp.user.ensureDirectoryExists(tileDirectoryPath);
        await tp.user.ensureDirectoryExists(blockchainDirectoryPath);
        let content = tp.file.content;
        const fileName = tp.file.title;
        const currentFile = tp.file.find_tfile(fileName);
        if (typeof content !== 'string') {
            throw new Error('Received non-string content');
        }
        const authors = tp.frontmatter.authors || 'Unknown';
        const license = tp.frontmatter.license || 'Unspecified';
        console.log(`[${currentDate}] Authors extracted: ${authors}`);
        console.log(`[${currentDate}] License extracted: ${license}`);
        console.log(`[${currentDate}] File content length: ${content.length} characters`);
        const { frontmatter, tiles } = tp.user.splitIntoTiles(content);
        console.log(`[${currentDate}] Number of tiles: ${tiles.length}`);
        let processedTiles = [];
        let digestedTiles = 0;
        let nonDigestedTiles = 0;
        let updatedTiles = 0;
        let digestTags = [];
        let tileFilesUpdated = {};
        for (let i = 0; i < tiles.length; i++) {
            let tile = tiles[i];
            const tileHash = tp.user.computeSHA256(tile);
            console.log(`\n[${currentDate}] Processing tile ${i + 1} (${tileHash})`);
            let existingDigestMatch = tile.match(/\s*(#ds\/[a-f0-9]+\/\d{4}-\d{2}-\d{2})/);
            let existingDigest = existingDigestMatch ? existingDigestMatch[1] : null;
            console.log(`Existing Digest Tag: ${existingDigest || 'None'}`);
            let cleanTile = tile.replace(/\s*#ds\/[a-f0-9]+\/\d{4}-\d{2}-\d{2}/, '').trim();
            let { deformattedContent, charactersRemoved } = tp.user.deformatTile(cleanTile);
            let digest = tp.user.computeSHA256(deformattedContent);
            let digestTag = createDigestTag(digest, currentDate);
            console.log(`New Digest Tag: ${digestTag}`);
            if (existingDigest && existingDigest.includes(digest)) {
                console.log(`Content unchanged for tile ${tileHash}. Keeping existing Digest Tag.`);
                digestTag = existingDigest;
                nonDigestedTiles++;
               // new Notice(`Skipping unchanged tile: ${digestTag}`, 15000);
            } else {
                console.log(`Content changed or new for tile ${tileHash}. Updating Digest Tag.`);
                if (existingDigest) {
                    updatedTiles++;
                } else {
                    digestedTiles++;
                }
            }
            let processedTile = `${cleanTile} ${digestTag}`;
            processedTiles.push(processedTile);
            digestTags.push(digestTag);
            console.log(`Tile ${tileHash} stats: Characters removed: ${charactersRemoved}`);
            const tileFilePath = `${tileDirectoryPath}/${digest}.md`;
            const digestRootHash = createDigestRootHash(digestTags);
            const tileFileContent = `###### #Digested-Tile ${digestTag}
Authors:: ${authors}
License:: ${license}
Digest Root:: ${digestRootHash}
#MarkdownTile
${cleanTile}
#DeformattedTile
${deformattedContent}
#EOT
---`;
            const { status: tileUpdateStatus, file: tileFile } = await tp.user.upsertToFile(tileFilePath, `###### #Digested-Tile ${digestTag}`, tileFileContent);
            tileFilesUpdated[tileFilePath] = tileUpdateStatus;
            // Update tile file frontmatter
            if (tileFile) {
                await tp.user.updateFrontMatter(tileFile, {
                    aliases: [digestTag],
                    authors: authors,
                    license: license,
                    'digest-root': digestRootHash
                });
            }
        }
        let result = frontmatter + '\n' + processedTiles.join('\n\n');
        const yearMonth = currentDate.slice(2, 7);
        let digestRootHash = createDigestRootHash(digestTags);
        console.log(`\n[${currentDate}] Digest Root hash created: ${digestRootHash}`);
        // Modify the current file content
        await app.vault.modify(currentFile, result);
        // Update current file frontmatter using tp.user.updateFrontMatter after modifying content
        await tp.user.updateFrontMatter(currentFile, {
			aliases: [`#ds/root/${digestRootHash}`],
			'blockchain_last_digest_root': `#ds/root/${digestRootHash}`,
            'blockchain_digest_timestamp': currentTimestamp,
            'blockchain_file': `[[wwbc-${yearMonth}]]`
        });
        // Update blockchain file
        const blockchainFilePath = `${blockchainDirectoryPath}/wwbc-${yearMonth}.md`;
        const previousBlockchainEntryDigest = await tp.user.getPreviousBlockchainEntryDigest(app, blockchainDirectoryPath, tp.user.computeSHA256);
        console.log(`Previous blockchain entry digest: ${previousBlockchainEntryDigest}`);
        // Create the blockchain content without the final hash
        const blockchainContentWithoutHash = `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}
${digestTags.join(' ')}`.trim();
        // Generate the hash for the blockchain entry
        const blockchainEntryHash = tp.user.computeSHA256(blockchainContentWithoutHash);
        // Create the final blockchain content
        const blockchainFileContent = `${blockchainContentWithoutHash}
#ds/block/${blockchainEntryHash}`;
        const { status: blockchainUpdateStatus, file: blockchainFile  } = await tp.user.upsertToFile(blockchainFilePath, `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}`, blockchainFileContent);
		if (blockchainFile) {
			await tp.user.updateFrontMatter(blockchainFile, {
				cssclasses: [`locked`]
			});
		}
        if (blockchainUpdateStatus === 'updated') {
            console.log(`Updated blockchain file: ${blockchainFilePath}`);
        } else {
            console.log(`Blockchain file already up to date: ${blockchainFilePath}`);
        }
        const endTime = Date.now();
        const runtime = ((endTime - startTime) / 1000).toFixed(2);
        console.log(`\n[${currentDate}] DS Tagger Chain process completed successfully`);
        
        const statusMessage = `DS Tagger Chain v${version} completed:
Runtime: ${runtime}s
#ds/root/${digestRootHash}
Tiles processed: ${tiles.length}
Tiles digested: ${digestedTiles}
Tiles not digested: ${nonDigestedTiles}
Tiles updated: ${updatedTiles}
Date: ${currentDate}`;
        const tileFilesMessage = `Tile files updated (BUGY):
${Object.entries(tileFilesUpdated).map(([file, status]) => `${file}: ${status}`).join('\n')}`;
        const blockchainEntryMessage = `Blockchain entry (${blockchainUpdateStatus}):
${blockchainFileContent}`;
        console.log(statusMessage);
        console.log(tileFilesMessage);
        console.log(blockchainEntryMessage);
        new Notice(statusMessage, 15000);
        new Notice(tileFilesMessage, 15000);
        new Notice(blockchainEntryMessage, 15000);
    } catch (error) {
        console.error(`[${currentDate}] An error occurred:`, error);
        new Notice(`Error in DS Tagger Chain v${version}: ${error.message}. Check console for details.`, 15000);
    }
}
// Run the script and output the result
await dsTaggerChain();
%>

DeformattedTile Doc Seal 0.9 - Digest & Seal - Current Document.md

<%*
// Doc Seal 0.9 for Obsidian Templater
// Version 0.9.7
/* * *Preserve Specs for Tile and Blockchain formats* * *
Tile Spec:
- Structure `###### #Digested-Tile #ds/{deformat-digest}/{YYYY-MM-DD}\nAuthors:: {authors}\nLicense:: {license}\nDigest Root:: {digestRootHash}\n###### #MarkdownTile\n{tile}\n###### #DeformattedTile\n{deformatted-tile}\n###### #EOT\n---\n`
- Location: `x/ds/tiles/{deformat-digest}.md`
- Upsert Logic: Skip (with Notice message) if `#ds/{deformat-digest}/{YYYY-MM-DD}` exists, append otherwise
Blockchain Spec:
- Structure: `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained  to #ds/block/${previousBlockchainEntryDigest} on ${YYYY-MM-DDTHH:mm}\n${digestTags.join(' ')}\n#ds/block/{currentBlockchainEntryDigest}`
- Location: `x/ds/blockchains/wwbc-{YY-MM}.md`
- Blockchain Logic: {previousBlockchainEntryDigest} is a hash of {YY-MM} for initial block or the BlockchainEntryDigest of the previous entry; if there are no "wwbc-....md" files yet, use the hash of the YY-MM, if there are not blocks in this months file yet, use the last #ds/block from the previous month, otherwise, use the last #ds/block in the current month's file
Script Spec:
- use Obsidian Templater scripting language for the script 
- use tp.user.updateFrontMatter to update frontmatter
- 15s Notice messages about updates, 3 messages: status, tiles, and blockchain 
- tp.user scripts: computeSHA256(content, length = 12); splitIntoTiles(content); ensureDirectoryExists(path); upsertToFile(filePath, header, content); updateFrontMatter(file, updates); getPreviousBlockchainEntryDigest(app, computeSHA256);
- inline helper functions: createDigestTag(hash, date); createDigestRootHash(digestTags);  
*/
function createDigestTag(hash, date) {
    return `#ds/${hash}/${date}`;
}
function createDigestRootHash(digestTags) {
    return tp.user.computeSHA256(digestTags.join(' '), 12);
}
// Main function
async function dsTaggerChain() {
    const version = "0.9.7";
    const startTime = Date.now();
    const currentDate = new Date().toISOString().split('T')[0];
    const currentTimestamp = new Date().toISOString();
    console.log(`[${currentDate}] DS Tagger Chain v${version} started`);
    // Configuration
    const tileDirectoryPath = "x/ds/tiles";
    const blockchainDirectoryPath = "x/ds/blockchains";
    try {
        // Ensure directories exist
        await tp.user.ensureDirectoryExists(tileDirectoryPath);
        await tp.user.ensureDirectoryExists(blockchainDirectoryPath);
        let content = tp.file.content;
        const fileName = tp.file.title;
        const currentFile = tp.file.find_tfile(fileName);
        if (typeof content !== 'string') {
            throw new Error('Received non-string content');
        }
        const authors = tp.frontmatter.authors || 'Unknown';
        const license = tp.frontmatter.license || 'Unspecified';
        console.log(`[${currentDate}] Authors extracted: ${authors}`);
        console.log(`[${currentDate}] License extracted: ${license}`);
        console.log(`[${currentDate}] File content length: ${content.length} characters`);
        const { frontmatter, tiles } = tp.user.splitIntoTiles(content);
        console.log(`[${currentDate}] Number of tiles: ${tiles.length}`);
        let processedTiles = [];
        let digestedTiles = 0;
        let nonDigestedTiles = 0;
        let updatedTiles = 0;
        let digestTags = [];
        let tileFilesUpdated = {};
        for (let i = 0; i < tiles.length; i++) {
            let tile = tiles[i];
            const tileHash = tp.user.computeSHA256(tile);
            console.log(`\n[${currentDate}] Processing tile ${i + 1} (${tileHash})`);
            let existingDigestMatch = tile.match(/\s*(#ds\/[a-f0-9]+\/\d{4}-\d{2}-\d{2})/);
            let existingDigest = existingDigestMatch ? existingDigestMatch[1] : null;
            console.log(`Existing Digest Tag: ${existingDigest || 'None'}`);
            let cleanTile = tile.replace(/\s*#ds\/[a-f0-9]+\/\d{4}-\d{2}-\d{2}/, '').trim();
            let { deformattedContent, charactersRemoved } = tp.user.deformatTile(cleanTile);
            let digest = tp.user.computeSHA256(deformattedContent);
            let digestTag = createDigestTag(digest, currentDate);
            console.log(`New Digest Tag: ${digestTag}`);
            if (existingDigest && existingDigest.includes(digest)) {
                console.log(`Content unchanged for tile ${tileHash}. Keeping existing Digest Tag.`);
                digestTag = existingDigest;
                nonDigestedTiles++;
               // new Notice(`Skipping unchanged tile: ${digestTag}`, 15000);
            } else {
                console.log(`Content changed or new for tile ${tileHash}. Updating Digest Tag.`);
                if (existingDigest) {
                    updatedTiles++;
                } else {
                    digestedTiles++;
                }
            }
            let processedTile = `${cleanTile} ${digestTag}`;
            processedTiles.push(processedTile);
            digestTags.push(digestTag);
            console.log(`Tile ${tileHash} stats: Characters removed: ${charactersRemoved}`);
            const tileFilePath = `${tileDirectoryPath}/${digest}.md`;
            const digestRootHash = createDigestRootHash(digestTags);
            const tileFileContent = `###### #Digested-Tile ${digestTag}
Authors:: ${authors}
License:: ${license}
Digest Root:: ${digestRootHash}
#MarkdownTile
${cleanTile}
#DeformattedTile
${deformattedContent}
#EOT
---`;
            const { status: tileUpdateStatus, file: tileFile } = await tp.user.upsertToFile(tileFilePath, `###### #Digested-Tile ${digestTag}`, tileFileContent);
            tileFilesUpdated[tileFilePath] = tileUpdateStatus;
            // Update tile file frontmatter
            if (tileFile) {
                await tp.user.updateFrontMatter(tileFile, {
                    aliases: [digestTag],
                    authors: authors,
                    license: license,
                    'digest-root': digestRootHash
                });
            }
        }
        let result = frontmatter + '\n' + processedTiles.join('\n\n');
        const yearMonth = currentDate.slice(2, 7);
        let digestRootHash = createDigestRootHash(digestTags);
        console.log(`\n[${currentDate}] Digest Root hash created: ${digestRootHash}`);
        // Modify the current file content
        await app.vault.modify(currentFile, result);
        // Update current file frontmatter using tp.user.updateFrontMatter after modifying content
        await tp.user.updateFrontMatter(currentFile, {
			aliases: [`#ds/root/${digestRootHash}`],
			'blockchain_last_digest_root': `#ds/root/${digestRootHash}`,
            'blockchain_digest_timestamp': currentTimestamp,
            'blockchain_file': `[[wwbc-${yearMonth}]]`
        });
        // Update blockchain file
        const blockchainFilePath = `${blockchainDirectoryPath}/wwbc-${yearMonth}.md`;
        const previousBlockchainEntryDigest = await tp.user.getPreviousBlockchainEntryDigest(app, blockchainDirectoryPath, tp.user.computeSHA256);
        console.log(`Previous blockchain entry digest: ${previousBlockchainEntryDigest}`);
        // Create the blockchain content without the final hash
        const blockchainContentWithoutHash = `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}
${digestTags.join(' ')}`.trim();
        // Generate the hash for the blockchain entry
        const blockchainEntryHash = tp.user.computeSHA256(blockchainContentWithoutHash);
        // Create the final blockchain content
        const blockchainFileContent = `${blockchainContentWithoutHash}
#ds/block/${blockchainEntryHash}`;
        const { status: blockchainUpdateStatus, file: blockchainFile  } = await tp.user.upsertToFile(blockchainFilePath, `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}`, blockchainFileContent);
		if (blockchainFile) {
			await tp.user.updateFrontMatter(blockchainFile, {
				cssclasses: [`locked`]
			});
		}
        if (blockchainUpdateStatus === 'updated') {
            console.log(`Updated blockchain file: ${blockchainFilePath}`);
        } else {
            console.log(`Blockchain file already up to date: ${blockchainFilePath}`);
        }
        const endTime = Date.now();
        const runtime = ((endTime - startTime) / 1000).toFixed(2);
        console.log(`\n[${currentDate}] DS Tagger Chain process completed successfully`);
        
        const statusMessage = `DS Tagger Chain v${version} completed:
Runtime: ${runtime}s
#ds/root/${digestRootHash}
Tiles processed: ${tiles.length}
Tiles digested: ${digestedTiles}
Tiles not digested: ${nonDigestedTiles}
Tiles updated: ${updatedTiles}
Date: ${currentDate}`;
        const tileFilesMessage = `Tile files updated (BUGY):
${Object.entries(tileFilesUpdated).map(([file, status]) => `${file}: ${status}`).join('\n')}`;
        const blockchainEntryMessage = `Blockchain entry (${blockchainUpdateStatus}):
${blockchainFileContent}`;
        console.log(statusMessage);
        console.log(tileFilesMessage);
        console.log(blockchainEntryMessage);
        new Notice(statusMessage, 15000);
        new Notice(tileFilesMessage, 15000);
        new Notice(blockchainEntryMessage, 15000);
    } catch (error) {
        console.error(`[${currentDate}] An error occurred:`, error);
        new Notice(`Error in DS Tagger Chain v${version}: ${error.message}. Check console for details.`, 15000);
    }
}
// Run the script and output the result
await dsTaggerChain();
%>

EOT

DeformattedTile Doc Seal 0.9 - Digest & Seal - Current Document.md

<%*
// Doc Seal 0.9 for Obsidian Templater
// Version 0.9.7
/* * *Preserve Specs for Tile and Blockchain formats* * *
Tile Spec:
- Structure `###### #Digested-Tile #ds/{deformat-digest}/{YYYY-MM-DD}\nAuthors:: {authors}\nLicense:: {license}\nDigest Root:: {digestRootHash}\n###### #MarkdownTile\n{tile}\n###### #DeformattedTile\n{deformatted-tile}\n###### #EOT\n---\n`
- Location: `x/ds/tiles/{deformat-digest}.md`
- Upsert Logic: Skip (with Notice message) if `#ds/{deformat-digest}/{YYYY-MM-DD}` exists, append otherwise
Blockchain Spec:
- Structure: `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained  to #ds/block/${previousBlockchainEntryDigest} on ${YYYY-MM-DDTHH:mm}\n${digestTags.join(' ')}\n#ds/block/{currentBlockchainEntryDigest}`
- Location: `x/ds/blockchains/wwbc-{YY-MM}.md`
- Blockchain Logic: {previousBlockchainEntryDigest} is a hash of {YY-MM} for initial block or the BlockchainEntryDigest of the previous entry; if there are no "wwbc-....md" files yet, use the hash of the YY-MM, if there are not blocks in this months file yet, use the last #ds/block from the previous month, otherwise, use the last #ds/block in the current month's file
Script Spec:
- use Obsidian Templater scripting language for the script 
- use tp.user.updateFrontMatter to update frontmatter
- 15s Notice messages about updates, 3 messages: status, tiles, and blockchain 
- tp.user scripts: computeSHA256(content, length = 12); splitIntoTiles(content); ensureDirectoryExists(path); upsertToFile(filePath, header, content); updateFrontMatter(file, updates); getPreviousBlockchainEntryDigest(app, computeSHA256);
- inline helper functions: createDigestTag(hash, date); createDigestRootHash(digestTags);  
*/
function createDigestTag(hash, date) {
    return `#ds/${hash}/${date}`;
}
function createDigestRootHash(digestTags) {
    return tp.user.computeSHA256(digestTags.join(' '), 12);
}
// Main function
async function dsTaggerChain() {
    const version = "0.9.7";
    const startTime = Date.now();
    const currentDate = new Date().toISOString().split('T')[0];
    const currentTimestamp = new Date().toISOString();
    console.log(`[${currentDate}] DS Tagger Chain v${version} started`);
    // Configuration
    const tileDirectoryPath = "x/ds/tiles";
    const blockchainDirectoryPath = "x/ds/blockchains";
    try {
        // Ensure directories exist
        await tp.user.ensureDirectoryExists(tileDirectoryPath);
        await tp.user.ensureDirectoryExists(blockchainDirectoryPath);
        let content = tp.file.content;
        const fileName = tp.file.title;
        const currentFile = tp.file.find_tfile(fileName);
        if (typeof content !== 'string') {
            throw new Error('Received non-string content');
        }
        const authors = tp.frontmatter.authors || 'Unknown';
        const license = tp.frontmatter.license || 'Unspecified';
        console.log(`[${currentDate}] Authors extracted: ${authors}`);
        console.log(`[${currentDate}] License extracted: ${license}`);
        console.log(`[${currentDate}] File content length: ${content.length} characters`);
        const { frontmatter, tiles } = tp.user.splitIntoTiles(content);
        console.log(`[${currentDate}] Number of tiles: ${tiles.length}`);
        let processedTiles = [];
        let digestedTiles = 0;
        let nonDigestedTiles = 0;
        let updatedTiles = 0;
        let digestTags = [];
        let tileFilesUpdated = {};
        for (let i = 0; i < tiles.length; i++) {
            let tile = tiles[i];
            const tileHash = tp.user.computeSHA256(tile);
            console.log(`\n[${currentDate}] Processing tile ${i + 1} (${tileHash})`);
            let existingDigestMatch = tile.match(/\s*(#ds\/[a-f0-9]+\/\d{4}-\d{2}-\d{2})/);
            let existingDigest = existingDigestMatch ? existingDigestMatch[1] : null;
            console.log(`Existing Digest Tag: ${existingDigest || 'None'}`);
            let cleanTile = tile.replace(/\s*#ds\/[a-f0-9]+\/\d{4}-\d{2}-\d{2}/, '').trim();
            let { deformattedContent, charactersRemoved } = tp.user.deformatTile(cleanTile);
            let digest = tp.user.computeSHA256(deformattedContent);
            let digestTag = createDigestTag(digest, currentDate);
            console.log(`New Digest Tag: ${digestTag}`);
            if (existingDigest && existingDigest.includes(digest)) {
                console.log(`Content unchanged for tile ${tileHash}. Keeping existing Digest Tag.`);
                digestTag = existingDigest;
                nonDigestedTiles++;
               // new Notice(`Skipping unchanged tile: ${digestTag}`, 15000);
            } else {
                console.log(`Content changed or new for tile ${tileHash}. Updating Digest Tag.`);
                if (existingDigest) {
                    updatedTiles++;
                } else {
                    digestedTiles++;
                }
            }
            let processedTile = `${cleanTile} ${digestTag}`;
            processedTiles.push(processedTile);
            digestTags.push(digestTag);
            console.log(`Tile ${tileHash} stats: Characters removed: ${charactersRemoved}`);
            const tileFilePath = `${tileDirectoryPath}/${digest}.md`;
            const digestRootHash = createDigestRootHash(digestTags);
            const tileFileContent = `###### #Digested-Tile ${digestTag}
Authors:: ${authors}
License:: ${license}
Digest Root:: ${digestRootHash}
#MarkdownTile
${cleanTile}
#DeformattedTile
${deformattedContent}
#EOT
---`;
            const { status: tileUpdateStatus, file: tileFile } = await tp.user.upsertToFile(tileFilePath, `###### #Digested-Tile ${digestTag}`, tileFileContent);
            tileFilesUpdated[tileFilePath] = tileUpdateStatus;
            // Update tile file frontmatter
            if (tileFile) {
                await tp.user.updateFrontMatter(tileFile, {
                    aliases: [digestTag],
                    authors: authors,
                    license: license,
                    'digest-root': digestRootHash
                });
            }
        }
        let result = frontmatter + '\n' + processedTiles.join('\n\n');
        const yearMonth = currentDate.slice(2, 7);
        let digestRootHash = createDigestRootHash(digestTags);
        console.log(`\n[${currentDate}] Digest Root hash created: ${digestRootHash}`);
        // Modify the current file content
        await app.vault.modify(currentFile, result);
        // Update current file frontmatter using tp.user.updateFrontMatter after modifying content
        await tp.user.updateFrontMatter(currentFile, {
			aliases: [`#ds/root/${digestRootHash}`],
			'blockchain_last_digest_root': `#ds/root/${digestRootHash}`,
            'blockchain_digest_timestamp': currentTimestamp,
            'blockchain_file': `[[wwbc-${yearMonth}]]`
        });
        // Update blockchain file
        const blockchainFilePath = `${blockchainDirectoryPath}/wwbc-${yearMonth}.md`;
        const previousBlockchainEntryDigest = await tp.user.getPreviousBlockchainEntryDigest(app, blockchainDirectoryPath, tp.user.computeSHA256);
        console.log(`Previous blockchain entry digest: ${previousBlockchainEntryDigest}`);
        // Create the blockchain content without the final hash
        const blockchainContentWithoutHash = `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}
${digestTags.join(' ')}`.trim();
        // Generate the hash for the blockchain entry
        const blockchainEntryHash = tp.user.computeSHA256(blockchainContentWithoutHash);
        // Create the final blockchain content
        const blockchainFileContent = `${blockchainContentWithoutHash}
#ds/block/${blockchainEntryHash}`;
        const { status: blockchainUpdateStatus, file: blockchainFile  } = await tp.user.upsertToFile(blockchainFilePath, `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}`, blockchainFileContent);
		if (blockchainFile) {
			await tp.user.updateFrontMatter(blockchainFile, {
				cssclasses: [`locked`]
			});
		}
        if (blockchainUpdateStatus === 'updated') {
            console.log(`Updated blockchain file: ${blockchainFilePath}`);
        } else {
            console.log(`Blockchain file already up to date: ${blockchainFilePath}`);
        }
        const endTime = Date.now();
        const runtime = ((endTime - startTime) / 1000).toFixed(2);
        console.log(`\n[${currentDate}] DS Tagger Chain process completed successfully`);
        
        const statusMessage = `DS Tagger Chain v${version} completed:
Runtime: ${runtime}s
#ds/root/${digestRootHash}
Tiles processed: ${tiles.length}
Tiles digested: ${digestedTiles}
Tiles not digested: ${nonDigestedTiles}
Tiles updated: ${updatedTiles}
Date: ${currentDate}`;
        const tileFilesMessage = `Tile files updated (BUGY):
${Object.entries(tileFilesUpdated).map(([file, status]) => `${file}: ${status}`).join('\n')}`;
        const blockchainEntryMessage = `Blockchain entry (${blockchainUpdateStatus}):
${blockchainFileContent}`;
        console.log(statusMessage);
        console.log(tileFilesMessage);
        console.log(blockchainEntryMessage);
        new Notice(statusMessage, 15000);
        new Notice(tileFilesMessage, 15000);
        new Notice(blockchainEntryMessage, 15000);
    } catch (error) {
        console.error(`[${currentDate}] An error occurred:`, error);
        new Notice(`Error in DS Tagger Chain v${version}: ${error.message}. Check console for details.`, 15000);
    }
}
// Run the script and output the result
await dsTaggerChain();
%>

DeformattedTile Doc Seal 0.9 - Digest & Seal - Current Document.md

<%*
// Doc Seal 0.9 for Obsidian Templater
// Version 0.9.7
/* * *Preserve Specs for Tile and Blockchain formats* * *
Tile Spec:
- Structure `###### #Digested-Tile #ds/{deformat-digest}/{YYYY-MM-DD}\nAuthors:: {authors}\nLicense:: {license}\nDigest Root:: {digestRootHash}\n###### #MarkdownTile\n{tile}\n###### #DeformattedTile\n{deformatted-tile}\n###### #EOT\n---\n`
- Location: `x/ds/tiles/{deformat-digest}.md`
- Upsert Logic: Skip (with Notice message) if `#ds/{deformat-digest}/{YYYY-MM-DD}` exists, append otherwise
Blockchain Spec:
- Structure: `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained  to #ds/block/${previousBlockchainEntryDigest} on ${YYYY-MM-DDTHH:mm}\n${digestTags.join(' ')}\n#ds/block/{currentBlockchainEntryDigest}`
- Location: `x/ds/blockchains/wwbc-{YY-MM}.md`
- Blockchain Logic: {previousBlockchainEntryDigest} is a hash of {YY-MM} for initial block or the BlockchainEntryDigest of the previous entry; if there are no "wwbc-....md" files yet, use the hash of the YY-MM, if there are not blocks in this months file yet, use the last #ds/block from the previous month, otherwise, use the last #ds/block in the current month's file
Script Spec:
- use Obsidian Templater scripting language for the script 
- use tp.user.updateFrontMatter to update frontmatter
- 15s Notice messages about updates, 3 messages: status, tiles, and blockchain 
- tp.user scripts: computeSHA256(content, length = 12); splitIntoTiles(content); ensureDirectoryExists(path); upsertToFile(filePath, header, content); updateFrontMatter(file, updates); getPreviousBlockchainEntryDigest(app, computeSHA256);
- inline helper functions: createDigestTag(hash, date); createDigestRootHash(digestTags);  
*/
function createDigestTag(hash, date) {
    return `#ds/${hash}/${date}`;
}
function createDigestRootHash(digestTags) {
    return tp.user.computeSHA256(digestTags.join(' '), 12);
}
// Main function
async function dsTaggerChain() {
    const version = "0.9.7";
    const startTime = Date.now();
    const currentDate = new Date().toISOString().split('T')[0];
    const currentTimestamp = new Date().toISOString();
    console.log(`[${currentDate}] DS Tagger Chain v${version} started`);
    // Configuration
    const tileDirectoryPath = "x/ds/tiles";
    const blockchainDirectoryPath = "x/ds/blockchains";
    try {
        // Ensure directories exist
        await tp.user.ensureDirectoryExists(tileDirectoryPath);
        await tp.user.ensureDirectoryExists(blockchainDirectoryPath);
        let content = tp.file.content;
        const fileName = tp.file.title;
        const currentFile = tp.file.find_tfile(fileName);
        if (typeof content !== 'string') {
            throw new Error('Received non-string content');
        }
        const authors = tp.frontmatter.authors || 'Unknown';
        const license = tp.frontmatter.license || 'Unspecified';
        console.log(`[${currentDate}] Authors extracted: ${authors}`);
        console.log(`[${currentDate}] License extracted: ${license}`);
        console.log(`[${currentDate}] File content length: ${content.length} characters`);
        const { frontmatter, tiles } = tp.user.splitIntoTiles(content);
        console.log(`[${currentDate}] Number of tiles: ${tiles.length}`);
        let processedTiles = [];
        let digestedTiles = 0;
        let nonDigestedTiles = 0;
        let updatedTiles = 0;
        let digestTags = [];
        let tileFilesUpdated = {};
        for (let i = 0; i < tiles.length; i++) {
            let tile = tiles[i];
            const tileHash = tp.user.computeSHA256(tile);
            console.log(`\n[${currentDate}] Processing tile ${i + 1} (${tileHash})`);
            let existingDigestMatch = tile.match(/\s*(#ds\/[a-f0-9]+\/\d{4}-\d{2}-\d{2})/);
            let existingDigest = existingDigestMatch ? existingDigestMatch[1] : null;
            console.log(`Existing Digest Tag: ${existingDigest || 'None'}`);
            let cleanTile = tile.replace(/\s*#ds\/[a-f0-9]+\/\d{4}-\d{2}-\d{2}/, '').trim();
            let { deformattedContent, charactersRemoved } = tp.user.deformatTile(cleanTile);
            let digest = tp.user.computeSHA256(deformattedContent);
            let digestTag = createDigestTag(digest, currentDate);
            console.log(`New Digest Tag: ${digestTag}`);
            if (existingDigest && existingDigest.includes(digest)) {
                console.log(`Content unchanged for tile ${tileHash}. Keeping existing Digest Tag.`);
                digestTag = existingDigest;
                nonDigestedTiles++;
               // new Notice(`Skipping unchanged tile: ${digestTag}`, 15000);
            } else {
                console.log(`Content changed or new for tile ${tileHash}. Updating Digest Tag.`);
                if (existingDigest) {
                    updatedTiles++;
                } else {
                    digestedTiles++;
                }
            }
            let processedTile = `${cleanTile} ${digestTag}`;
            processedTiles.push(processedTile);
            digestTags.push(digestTag);
            console.log(`Tile ${tileHash} stats: Characters removed: ${charactersRemoved}`);
            const tileFilePath = `${tileDirectoryPath}/${digest}.md`;
            const digestRootHash = createDigestRootHash(digestTags);
            const tileFileContent = `###### #Digested-Tile ${digestTag}
Authors:: ${authors}
License:: ${license}
Digest Root:: ${digestRootHash}
#MarkdownTile
${cleanTile}
#DeformattedTile
${deformattedContent}
#EOT
---`;
            const { status: tileUpdateStatus, file: tileFile } = await tp.user.upsertToFile(tileFilePath, `###### #Digested-Tile ${digestTag}`, tileFileContent);
            tileFilesUpdated[tileFilePath] = tileUpdateStatus;
            // Update tile file frontmatter
            if (tileFile) {
                await tp.user.updateFrontMatter(tileFile, {
                    aliases: [digestTag],
                    authors: authors,
                    license: license,
                    'digest-root': digestRootHash
                });
            }
        }
        let result = frontmatter + '\n' + processedTiles.join('\n\n');
        const yearMonth = currentDate.slice(2, 7);
        let digestRootHash = createDigestRootHash(digestTags);
        console.log(`\n[${currentDate}] Digest Root hash created: ${digestRootHash}`);
        // Modify the current file content
        await app.vault.modify(currentFile, result);
        // Update current file frontmatter using tp.user.updateFrontMatter after modifying content
        await tp.user.updateFrontMatter(currentFile, {
			aliases: [`#ds/root/${digestRootHash}`],
			'blockchain_last_digest_root': `#ds/root/${digestRootHash}`,
            'blockchain_digest_timestamp': currentTimestamp,
            'blockchain_file': `[[wwbc-${yearMonth}]]`
        });
        // Update blockchain file
        const blockchainFilePath = `${blockchainDirectoryPath}/wwbc-${yearMonth}.md`;
        const previousBlockchainEntryDigest = await tp.user.getPreviousBlockchainEntryDigest(app, blockchainDirectoryPath, tp.user.computeSHA256);
        console.log(`Previous blockchain entry digest: ${previousBlockchainEntryDigest}`);
        // Create the blockchain content without the final hash
        const blockchainContentWithoutHash = `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}
${digestTags.join(' ')}`.trim();
        // Generate the hash for the blockchain entry
        const blockchainEntryHash = tp.user.computeSHA256(blockchainContentWithoutHash);
        // Create the final blockchain content
        const blockchainFileContent = `${blockchainContentWithoutHash}
#ds/block/${blockchainEntryHash}`;
        const { status: blockchainUpdateStatus, file: blockchainFile  } = await tp.user.upsertToFile(blockchainFilePath, `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}`, blockchainFileContent);
		if (blockchainFile) {
			await tp.user.updateFrontMatter(blockchainFile, {
				cssclasses: [`locked`]
			});
		}
        if (blockchainUpdateStatus === 'updated') {
            console.log(`Updated blockchain file: ${blockchainFilePath}`);
        } else {
            console.log(`Blockchain file already up to date: ${blockchainFilePath}`);
        }
        const endTime = Date.now();
        const runtime = ((endTime - startTime) / 1000).toFixed(2);
        console.log(`\n[${currentDate}] DS Tagger Chain process completed successfully`);
        
        const statusMessage = `DS Tagger Chain v${version} completed:
Runtime: ${runtime}s
#ds/root/${digestRootHash}
Tiles processed: ${tiles.length}
Tiles digested: ${digestedTiles}
Tiles not digested: ${nonDigestedTiles}
Tiles updated: ${updatedTiles}
Date: ${currentDate}`;
        const tileFilesMessage = `Tile files updated (BUGY):
${Object.entries(tileFilesUpdated).map(([file, status]) => `${file}: ${status}`).join('\n')}`;
        const blockchainEntryMessage = `Blockchain entry (${blockchainUpdateStatus}):
${blockchainFileContent}`;
        console.log(statusMessage);
        console.log(tileFilesMessage);
        console.log(blockchainEntryMessage);
        new Notice(statusMessage, 15000);
        new Notice(tileFilesMessage, 15000);
        new Notice(blockchainEntryMessage, 15000);
    } catch (error) {
        console.error(`[${currentDate}] An error occurred:`, error);
        new Notice(`Error in DS Tagger Chain v${version}: ${error.message}. Check console for details.`, 15000);
    }
}
// Run the script and output the result
await dsTaggerChain();
%>

EOT

EOT

EOT

DeformattedTile Doc Seal 0.9 - Digest & Seal - Current Document.md

<%*
// Doc Seal 0.9 for Obsidian Templater
// Version 0.9.7
/* * *Preserve Specs for Tile and Blockchain formats* * *
Tile Spec:
- Structure `###### #Digested-Tile #ds/{deformat-digest}/{YYYY-MM-DD}\nAuthors:: {authors}\nLicense:: {license}\nDigest Root:: {digestRootHash}\n###### #MarkdownTile\n{tile}\n###### #DeformattedTile\n{deformatted-tile}\n###### #EOT\n---\n`
- Location: `x/ds/tiles/{deformat-digest}.md`
- Upsert Logic: Skip (with Notice message) if `#ds/{deformat-digest}/{YYYY-MM-DD}` exists, append otherwise
Blockchain Spec:
- Structure: `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained  to #ds/block/${previousBlockchainEntryDigest} on ${YYYY-MM-DDTHH:mm}\n${digestTags.join(' ')}\n#ds/block/{currentBlockchainEntryDigest}`
- Location: `x/ds/blockchains/wwbc-{YY-MM}.md`
- Blockchain Logic: {previousBlockchainEntryDigest} is a hash of {YY-MM} for initial block or the BlockchainEntryDigest of the previous entry; if there are no "wwbc-....md" files yet, use the hash of the YY-MM, if there are not blocks in this months file yet, use the last #ds/block from the previous month, otherwise, use the last #ds/block in the current month's file
Script Spec:
- use Obsidian Templater scripting language for the script 
- use tp.user.updateFrontMatter to update frontmatter
- 15s Notice messages about updates, 3 messages: status, tiles, and blockchain 
- tp.user scripts: computeSHA256(content, length = 12); splitIntoTiles(content); ensureDirectoryExists(path); upsertToFile(filePath, header, content); updateFrontMatter(file, updates); getPreviousBlockchainEntryDigest(app, computeSHA256);
- inline helper functions: createDigestTag(hash, date); createDigestRootHash(digestTags);  
*/
function createDigestTag(hash, date) {
    return `#ds/${hash}/${date}`;
}
function createDigestRootHash(digestTags) {
    return tp.user.computeSHA256(digestTags.join(' '), 12);
}
// Main function
async function dsTaggerChain() {
    const version = "0.9.7";
    const startTime = Date.now();
    const currentDate = new Date().toISOString().split('T')[0];
    const currentTimestamp = new Date().toISOString();
    console.log(`[${currentDate}] DS Tagger Chain v${version} started`);
    // Configuration
    const tileDirectoryPath = "x/ds/tiles";
    const blockchainDirectoryPath = "x/ds/blockchains";
    try {
        // Ensure directories exist
        await tp.user.ensureDirectoryExists(tileDirectoryPath);
        await tp.user.ensureDirectoryExists(blockchainDirectoryPath);
        let content = tp.file.content;
        const fileName = tp.file.title;
        const currentFile = tp.file.find_tfile(fileName);
        if (typeof content !== 'string') {
            throw new Error('Received non-string content');
        }
        const authors = tp.frontmatter.authors || 'Unknown';
        const license = tp.frontmatter.license || 'Unspecified';
        console.log(`[${currentDate}] Authors extracted: ${authors}`);
        console.log(`[${currentDate}] License extracted: ${license}`);
        console.log(`[${currentDate}] File content length: ${content.length} characters`);
        const { frontmatter, tiles } = tp.user.splitIntoTiles(content);
        console.log(`[${currentDate}] Number of tiles: ${tiles.length}`);
        let processedTiles = [];
        let digestedTiles = 0;
        let nonDigestedTiles = 0;
        let updatedTiles = 0;
        let digestTags = [];
        let tileFilesUpdated = {};
        for (let i = 0; i < tiles.length; i++) {
            let tile = tiles[i];
            const tileHash = tp.user.computeSHA256(tile);
            console.log(`\n[${currentDate}] Processing tile ${i + 1} (${tileHash})`);
            let existingDigestMatch = tile.match(/\s*(#ds\/[a-f0-9]+\/\d{4}-\d{2}-\d{2})/);
            let existingDigest = existingDigestMatch ? existingDigestMatch[1] : null;
            console.log(`Existing Digest Tag: ${existingDigest || 'None'}`);
            let cleanTile = tile.replace(/\s*#ds\/[a-f0-9]+\/\d{4}-\d{2}-\d{2}/, '').trim();
            let { deformattedContent, charactersRemoved } = tp.user.deformatTile(cleanTile);
            let digest = tp.user.computeSHA256(deformattedContent);
            let digestTag = createDigestTag(digest, currentDate);
            console.log(`New Digest Tag: ${digestTag}`);
            if (existingDigest && existingDigest.includes(digest)) {
                console.log(`Content unchanged for tile ${tileHash}. Keeping existing Digest Tag.`);
                digestTag = existingDigest;
                nonDigestedTiles++;
               // new Notice(`Skipping unchanged tile: ${digestTag}`, 15000);
            } else {
                console.log(`Content changed or new for tile ${tileHash}. Updating Digest Tag.`);
                if (existingDigest) {
                    updatedTiles++;
                } else {
                    digestedTiles++;
                }
            }
            let processedTile = `${cleanTile} ${digestTag}`;
            processedTiles.push(processedTile);
            digestTags.push(digestTag);
            console.log(`Tile ${tileHash} stats: Characters removed: ${charactersRemoved}`);
            const tileFilePath = `${tileDirectoryPath}/${digest}.md`;
            const digestRootHash = createDigestRootHash(digestTags);
            const tileFileContent = `###### #Digested-Tile ${digestTag}
Authors:: ${authors}
License:: ${license}
Digest Root:: ${digestRootHash}
#MarkdownTile
${cleanTile}
#DeformattedTile
${deformattedContent}
#EOT
---`;
            const { status: tileUpdateStatus, file: tileFile } = await tp.user.upsertToFile(tileFilePath, `###### #Digested-Tile ${digestTag}`, tileFileContent);
            tileFilesUpdated[tileFilePath] = tileUpdateStatus;
            // Update tile file frontmatter
            if (tileFile) {
                await tp.user.updateFrontMatter(tileFile, {
                    aliases: [digestTag],
                    authors: authors,
                    license: license,
                    'digest-root': digestRootHash
                });
            }
        }
        let result = frontmatter + '\n' + processedTiles.join('\n\n');
        const yearMonth = currentDate.slice(2, 7);
        let digestRootHash = createDigestRootHash(digestTags);
        console.log(`\n[${currentDate}] Digest Root hash created: ${digestRootHash}`);
        // Modify the current file content
        await app.vault.modify(currentFile, result);
        // Update current file frontmatter using tp.user.updateFrontMatter after modifying content
        await tp.user.updateFrontMatter(currentFile, {
			aliases: [`#ds/root/${digestRootHash}`],
			'blockchain_last_digest_root': `#ds/root/${digestRootHash}`,
            'blockchain_digest_timestamp': currentTimestamp,
            'blockchain_file': `[[wwbc-${yearMonth}]]`
        });
        // Update blockchain file
        const blockchainFilePath = `${blockchainDirectoryPath}/wwbc-${yearMonth}.md`;
        const previousBlockchainEntryDigest = await tp.user.getPreviousBlockchainEntryDigest(app, blockchainDirectoryPath, tp.user.computeSHA256);
        console.log(`Previous blockchain entry digest: ${previousBlockchainEntryDigest}`);
        // Create the blockchain content without the final hash
        const blockchainContentWithoutHash = `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}
${digestTags.join(' ')}`.trim();
        // Generate the hash for the blockchain entry
        const blockchainEntryHash = tp.user.computeSHA256(blockchainContentWithoutHash);
        // Create the final blockchain content
        const blockchainFileContent = `${blockchainContentWithoutHash}
#ds/block/${blockchainEntryHash}`;
        const { status: blockchainUpdateStatus, file: blockchainFile  } = await tp.user.upsertToFile(blockchainFilePath, `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}`, blockchainFileContent);
		if (blockchainFile) {
			await tp.user.updateFrontMatter(blockchainFile, {
				cssclasses: [`locked`]
			});
		}
        if (blockchainUpdateStatus === 'updated') {
            console.log(`Updated blockchain file: ${blockchainFilePath}`);
        } else {
            console.log(`Blockchain file already up to date: ${blockchainFilePath}`);
        }
        const endTime = Date.now();
        const runtime = ((endTime - startTime) / 1000).toFixed(2);
        console.log(`\n[${currentDate}] DS Tagger Chain process completed successfully`);
        
        const statusMessage = `DS Tagger Chain v${version} completed:
Runtime: ${runtime}s
#ds/root/${digestRootHash}
Tiles processed: ${tiles.length}
Tiles digested: ${digestedTiles}
Tiles not digested: ${nonDigestedTiles}
Tiles updated: ${updatedTiles}
Date: ${currentDate}`;
        const tileFilesMessage = `Tile files updated (BUGY):
${Object.entries(tileFilesUpdated).map(([file, status]) => `${file}: ${status}`).join('\n')}`;
        const blockchainEntryMessage = `Blockchain entry (${blockchainUpdateStatus}):
${blockchainFileContent}`;
        console.log(statusMessage);
        console.log(tileFilesMessage);
        console.log(blockchainEntryMessage);
        new Notice(statusMessage, 15000);
        new Notice(tileFilesMessage, 15000);
        new Notice(blockchainEntryMessage, 15000);
    } catch (error) {
        console.error(`[${currentDate}] An error occurred:`, error);
        new Notice(`Error in DS Tagger Chain v${version}: ${error.message}. Check console for details.`, 15000);
    }
}
// Run the script and output the result
await dsTaggerChain();
%>

DeformattedTile Doc Seal 0.9 - Digest & Seal - Current Document.md

<%*
// Doc Seal 0.9 for Obsidian Templater
// Version 0.9.7
/* * *Preserve Specs for Tile and Blockchain formats* * *
Tile Spec:
- Structure `###### #Digested-Tile #ds/{deformat-digest}/{YYYY-MM-DD}\nAuthors:: {authors}\nLicense:: {license}\nDigest Root:: {digestRootHash}\n###### #MarkdownTile\n{tile}\n###### #DeformattedTile\n{deformatted-tile}\n###### #EOT\n---\n`
- Location: `x/ds/tiles/{deformat-digest}.md`
- Upsert Logic: Skip (with Notice message) if `#ds/{deformat-digest}/{YYYY-MM-DD}` exists, append otherwise
Blockchain Spec:
- Structure: `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained  to #ds/block/${previousBlockchainEntryDigest} on ${YYYY-MM-DDTHH:mm}\n${digestTags.join(' ')}\n#ds/block/{currentBlockchainEntryDigest}`
- Location: `x/ds/blockchains/wwbc-{YY-MM}.md`
- Blockchain Logic: {previousBlockchainEntryDigest} is a hash of {YY-MM} for initial block or the BlockchainEntryDigest of the previous entry; if there are no "wwbc-....md" files yet, use the hash of the YY-MM, if there are not blocks in this months file yet, use the last #ds/block from the previous month, otherwise, use the last #ds/block in the current month's file
Script Spec:
- use Obsidian Templater scripting language for the script 
- use tp.user.updateFrontMatter to update frontmatter
- 15s Notice messages about updates, 3 messages: status, tiles, and blockchain 
- tp.user scripts: computeSHA256(content, length = 12); splitIntoTiles(content); ensureDirectoryExists(path); upsertToFile(filePath, header, content); updateFrontMatter(file, updates); getPreviousBlockchainEntryDigest(app, computeSHA256);
- inline helper functions: createDigestTag(hash, date); createDigestRootHash(digestTags);  
*/
function createDigestTag(hash, date) {
    return `#ds/${hash}/${date}`;
}
function createDigestRootHash(digestTags) {
    return tp.user.computeSHA256(digestTags.join(' '), 12);
}
// Main function
async function dsTaggerChain() {
    const version = "0.9.7";
    const startTime = Date.now();
    const currentDate = new Date().toISOString().split('T')[0];
    const currentTimestamp = new Date().toISOString();
    console.log(`[${currentDate}] DS Tagger Chain v${version} started`);
    // Configuration
    const tileDirectoryPath = "x/ds/tiles";
    const blockchainDirectoryPath = "x/ds/blockchains";
    try {
        // Ensure directories exist
        await tp.user.ensureDirectoryExists(tileDirectoryPath);
        await tp.user.ensureDirectoryExists(blockchainDirectoryPath);
        let content = tp.file.content;
        const fileName = tp.file.title;
        const currentFile = tp.file.find_tfile(fileName);
        if (typeof content !== 'string') {
            throw new Error('Received non-string content');
        }
        const authors = tp.frontmatter.authors || 'Unknown';
        const license = tp.frontmatter.license || 'Unspecified';
        console.log(`[${currentDate}] Authors extracted: ${authors}`);
        console.log(`[${currentDate}] License extracted: ${license}`);
        console.log(`[${currentDate}] File content length: ${content.length} characters`);
        const { frontmatter, tiles } = tp.user.splitIntoTiles(content);
        console.log(`[${currentDate}] Number of tiles: ${tiles.length}`);
        let processedTiles = [];
        let digestedTiles = 0;
        let nonDigestedTiles = 0;
        let updatedTiles = 0;
        let digestTags = [];
        let tileFilesUpdated = {};
        for (let i = 0; i < tiles.length; i++) {
            let tile = tiles[i];
            const tileHash = tp.user.computeSHA256(tile);
            console.log(`\n[${currentDate}] Processing tile ${i + 1} (${tileHash})`);
            let existingDigestMatch = tile.match(/\s*(#ds\/[a-f0-9]+\/\d{4}-\d{2}-\d{2})/);
            let existingDigest = existingDigestMatch ? existingDigestMatch[1] : null;
            console.log(`Existing Digest Tag: ${existingDigest || 'None'}`);
            let cleanTile = tile.replace(/\s*#ds\/[a-f0-9]+\/\d{4}-\d{2}-\d{2}/, '').trim();
            let { deformattedContent, charactersRemoved } = tp.user.deformatTile(cleanTile);
            let digest = tp.user.computeSHA256(deformattedContent);
            let digestTag = createDigestTag(digest, currentDate);
            console.log(`New Digest Tag: ${digestTag}`);
            if (existingDigest && existingDigest.includes(digest)) {
                console.log(`Content unchanged for tile ${tileHash}. Keeping existing Digest Tag.`);
                digestTag = existingDigest;
                nonDigestedTiles++;
               // new Notice(`Skipping unchanged tile: ${digestTag}`, 15000);
            } else {
                console.log(`Content changed or new for tile ${tileHash}. Updating Digest Tag.`);
                if (existingDigest) {
                    updatedTiles++;
                } else {
                    digestedTiles++;
                }
            }
            let processedTile = `${cleanTile} ${digestTag}`;
            processedTiles.push(processedTile);
            digestTags.push(digestTag);
            console.log(`Tile ${tileHash} stats: Characters removed: ${charactersRemoved}`);
            const tileFilePath = `${tileDirectoryPath}/${digest}.md`;
            const digestRootHash = createDigestRootHash(digestTags);
            const tileFileContent = `###### #Digested-Tile ${digestTag}
Authors:: ${authors}
License:: ${license}
Digest Root:: ${digestRootHash}
#MarkdownTile
${cleanTile}
#DeformattedTile
${deformattedContent}
#EOT
---`;
            const { status: tileUpdateStatus, file: tileFile } = await tp.user.upsertToFile(tileFilePath, `###### #Digested-Tile ${digestTag}`, tileFileContent);
            tileFilesUpdated[tileFilePath] = tileUpdateStatus;
            // Update tile file frontmatter
            if (tileFile) {
                await tp.user.updateFrontMatter(tileFile, {
                    aliases: [digestTag],
                    authors: authors,
                    license: license,
                    'digest-root': digestRootHash
                });
            }
        }
        let result = frontmatter + '\n' + processedTiles.join('\n\n');
        const yearMonth = currentDate.slice(2, 7);
        let digestRootHash = createDigestRootHash(digestTags);
        console.log(`\n[${currentDate}] Digest Root hash created: ${digestRootHash}`);
        // Modify the current file content
        await app.vault.modify(currentFile, result);
        // Update current file frontmatter using tp.user.updateFrontMatter after modifying content
        await tp.user.updateFrontMatter(currentFile, {
			aliases: [`#ds/root/${digestRootHash}`],
			'blockchain_last_digest_root': `#ds/root/${digestRootHash}`,
            'blockchain_digest_timestamp': currentTimestamp,
            'blockchain_file': `[[wwbc-${yearMonth}]]`
        });
        // Update blockchain file
        const blockchainFilePath = `${blockchainDirectoryPath}/wwbc-${yearMonth}.md`;
        const previousBlockchainEntryDigest = await tp.user.getPreviousBlockchainEntryDigest(app, blockchainDirectoryPath, tp.user.computeSHA256);
        console.log(`Previous blockchain entry digest: ${previousBlockchainEntryDigest}`);
        // Create the blockchain content without the final hash
        const blockchainContentWithoutHash = `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}
${digestTags.join(' ')}`.trim();
        // Generate the hash for the blockchain entry
        const blockchainEntryHash = tp.user.computeSHA256(blockchainContentWithoutHash);
        // Create the final blockchain content
        const blockchainFileContent = `${blockchainContentWithoutHash}
#ds/block/${blockchainEntryHash}`;
        const { status: blockchainUpdateStatus, file: blockchainFile  } = await tp.user.upsertToFile(blockchainFilePath, `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}`, blockchainFileContent);
		if (blockchainFile) {
			await tp.user.updateFrontMatter(blockchainFile, {
				cssclasses: [`locked`]
			});
		}
        if (blockchainUpdateStatus === 'updated') {
            console.log(`Updated blockchain file: ${blockchainFilePath}`);
        } else {
            console.log(`Blockchain file already up to date: ${blockchainFilePath}`);
        }
        const endTime = Date.now();
        const runtime = ((endTime - startTime) / 1000).toFixed(2);
        console.log(`\n[${currentDate}] DS Tagger Chain process completed successfully`);
        
        const statusMessage = `DS Tagger Chain v${version} completed:
Runtime: ${runtime}s
#ds/root/${digestRootHash}
Tiles processed: ${tiles.length}
Tiles digested: ${digestedTiles}
Tiles not digested: ${nonDigestedTiles}
Tiles updated: ${updatedTiles}
Date: ${currentDate}`;
        const tileFilesMessage = `Tile files updated (BUGY):
${Object.entries(tileFilesUpdated).map(([file, status]) => `${file}: ${status}`).join('\n')}`;
        const blockchainEntryMessage = `Blockchain entry (${blockchainUpdateStatus}):
${blockchainFileContent}`;
        console.log(statusMessage);
        console.log(tileFilesMessage);
        console.log(blockchainEntryMessage);
        new Notice(statusMessage, 15000);
        new Notice(tileFilesMessage, 15000);
        new Notice(blockchainEntryMessage, 15000);
    } catch (error) {
        console.error(`[${currentDate}] An error occurred:`, error);
        new Notice(`Error in DS Tagger Chain v${version}: ${error.message}. Check console for details.`, 15000);
    }
}
// Run the script and output the result
await dsTaggerChain();
%>

EOT

DeformattedTile Doc Seal 0.9 - Digest & Seal - Current Document.md

<%*
// Doc Seal 0.9 for Obsidian Templater
// Version 0.9.7
/* * *Preserve Specs for Tile and Blockchain formats* * *
Tile Spec:
- Structure `###### #Digested-Tile #ds/{deformat-digest}/{YYYY-MM-DD}\nAuthors:: {authors}\nLicense:: {license}\nDigest Root:: {digestRootHash}\n###### #MarkdownTile\n{tile}\n###### #DeformattedTile\n{deformatted-tile}\n###### #EOT\n---\n`
- Location: `x/ds/tiles/{deformat-digest}.md`
- Upsert Logic: Skip (with Notice message) if `#ds/{deformat-digest}/{YYYY-MM-DD}` exists, append otherwise
Blockchain Spec:
- Structure: `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained  to #ds/block/${previousBlockchainEntryDigest} on ${YYYY-MM-DDTHH:mm}\n${digestTags.join(' ')}\n#ds/block/{currentBlockchainEntryDigest}`
- Location: `x/ds/blockchains/wwbc-{YY-MM}.md`
- Blockchain Logic: {previousBlockchainEntryDigest} is a hash of {YY-MM} for initial block or the BlockchainEntryDigest of the previous entry; if there are no "wwbc-....md" files yet, use the hash of the YY-MM, if there are not blocks in this months file yet, use the last #ds/block from the previous month, otherwise, use the last #ds/block in the current month's file
Script Spec:
- use Obsidian Templater scripting language for the script 
- use tp.user.updateFrontMatter to update frontmatter
- 15s Notice messages about updates, 3 messages: status, tiles, and blockchain 
- tp.user scripts: computeSHA256(content, length = 12); splitIntoTiles(content); ensureDirectoryExists(path); upsertToFile(filePath, header, content); updateFrontMatter(file, updates); getPreviousBlockchainEntryDigest(app, computeSHA256);
- inline helper functions: createDigestTag(hash, date); createDigestRootHash(digestTags);  
*/
function createDigestTag(hash, date) {
    return `#ds/${hash}/${date}`;
}
function createDigestRootHash(digestTags) {
    return tp.user.computeSHA256(digestTags.join(' '), 12);
}
// Main function
async function dsTaggerChain() {
    const version = "0.9.7";
    const startTime = Date.now();
    const currentDate = new Date().toISOString().split('T')[0];
    const currentTimestamp = new Date().toISOString();
    console.log(`[${currentDate}] DS Tagger Chain v${version} started`);
    // Configuration
    const tileDirectoryPath = "x/ds/tiles";
    const blockchainDirectoryPath = "x/ds/blockchains";
    try {
        // Ensure directories exist
        await tp.user.ensureDirectoryExists(tileDirectoryPath);
        await tp.user.ensureDirectoryExists(blockchainDirectoryPath);
        let content = tp.file.content;
        const fileName = tp.file.title;
        const currentFile = tp.file.find_tfile(fileName);
        if (typeof content !== 'string') {
            throw new Error('Received non-string content');
        }
        const authors = tp.frontmatter.authors || 'Unknown';
        const license = tp.frontmatter.license || 'Unspecified';
        console.log(`[${currentDate}] Authors extracted: ${authors}`);
        console.log(`[${currentDate}] License extracted: ${license}`);
        console.log(`[${currentDate}] File content length: ${content.length} characters`);
        const { frontmatter, tiles } = tp.user.splitIntoTiles(content);
        console.log(`[${currentDate}] Number of tiles: ${tiles.length}`);
        let processedTiles = [];
        let digestedTiles = 0;
        let nonDigestedTiles = 0;
        let updatedTiles = 0;
        let digestTags = [];
        let tileFilesUpdated = {};
        for (let i = 0; i < tiles.length; i++) {
            let tile = tiles[i];
            const tileHash = tp.user.computeSHA256(tile);
            console.log(`\n[${currentDate}] Processing tile ${i + 1} (${tileHash})`);
            let existingDigestMatch = tile.match(/\s*(#ds\/[a-f0-9]+\/\d{4}-\d{2}-\d{2})/);
            let existingDigest = existingDigestMatch ? existingDigestMatch[1] : null;
            console.log(`Existing Digest Tag: ${existingDigest || 'None'}`);
            let cleanTile = tile.replace(/\s*#ds\/[a-f0-9]+\/\d{4}-\d{2}-\d{2}/, '').trim();
            let { deformattedContent, charactersRemoved } = tp.user.deformatTile(cleanTile);
            let digest = tp.user.computeSHA256(deformattedContent);
            let digestTag = createDigestTag(digest, currentDate);
            console.log(`New Digest Tag: ${digestTag}`);
            if (existingDigest && existingDigest.includes(digest)) {
                console.log(`Content unchanged for tile ${tileHash}. Keeping existing Digest Tag.`);
                digestTag = existingDigest;
                nonDigestedTiles++;
               // new Notice(`Skipping unchanged tile: ${digestTag}`, 15000);
            } else {
                console.log(`Content changed or new for tile ${tileHash}. Updating Digest Tag.`);
                if (existingDigest) {
                    updatedTiles++;
                } else {
                    digestedTiles++;
                }
            }
            let processedTile = `${cleanTile} ${digestTag}`;
            processedTiles.push(processedTile);
            digestTags.push(digestTag);
            console.log(`Tile ${tileHash} stats: Characters removed: ${charactersRemoved}`);
            const tileFilePath = `${tileDirectoryPath}/${digest}.md`;
            const digestRootHash = createDigestRootHash(digestTags);
            const tileFileContent = `###### #Digested-Tile ${digestTag}
Authors:: ${authors}
License:: ${license}
Digest Root:: ${digestRootHash}
#MarkdownTile
${cleanTile}
#DeformattedTile
${deformattedContent}
#EOT
---`;
            const { status: tileUpdateStatus, file: tileFile } = await tp.user.upsertToFile(tileFilePath, `###### #Digested-Tile ${digestTag}`, tileFileContent);
            tileFilesUpdated[tileFilePath] = tileUpdateStatus;
            // Update tile file frontmatter
            if (tileFile) {
                await tp.user.updateFrontMatter(tileFile, {
                    aliases: [digestTag],
                    authors: authors,
                    license: license,
                    'digest-root': digestRootHash
                });
            }
        }
        let result = frontmatter + '\n' + processedTiles.join('\n\n');
        const yearMonth = currentDate.slice(2, 7);
        let digestRootHash = createDigestRootHash(digestTags);
        console.log(`\n[${currentDate}] Digest Root hash created: ${digestRootHash}`);
        // Modify the current file content
        await app.vault.modify(currentFile, result);
        // Update current file frontmatter using tp.user.updateFrontMatter after modifying content
        await tp.user.updateFrontMatter(currentFile, {
			aliases: [`#ds/root/${digestRootHash}`],
			'blockchain_last_digest_root': `#ds/root/${digestRootHash}`,
            'blockchain_digest_timestamp': currentTimestamp,
            'blockchain_file': `[[wwbc-${yearMonth}]]`
        });
        // Update blockchain file
        const blockchainFilePath = `${blockchainDirectoryPath}/wwbc-${yearMonth}.md`;
        const previousBlockchainEntryDigest = await tp.user.getPreviousBlockchainEntryDigest(app, blockchainDirectoryPath, tp.user.computeSHA256);
        console.log(`Previous blockchain entry digest: ${previousBlockchainEntryDigest}`);
        // Create the blockchain content without the final hash
        const blockchainContentWithoutHash = `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}
${digestTags.join(' ')}`.trim();
        // Generate the hash for the blockchain entry
        const blockchainEntryHash = tp.user.computeSHA256(blockchainContentWithoutHash);
        // Create the final blockchain content
        const blockchainFileContent = `${blockchainContentWithoutHash}
#ds/block/${blockchainEntryHash}`;
        const { status: blockchainUpdateStatus, file: blockchainFile  } = await tp.user.upsertToFile(blockchainFilePath, `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}`, blockchainFileContent);
		if (blockchainFile) {
			await tp.user.updateFrontMatter(blockchainFile, {
				cssclasses: [`locked`]
			});
		}
        if (blockchainUpdateStatus === 'updated') {
            console.log(`Updated blockchain file: ${blockchainFilePath}`);
        } else {
            console.log(`Blockchain file already up to date: ${blockchainFilePath}`);
        }
        const endTime = Date.now();
        const runtime = ((endTime - startTime) / 1000).toFixed(2);
        console.log(`\n[${currentDate}] DS Tagger Chain process completed successfully`);
        
        const statusMessage = `DS Tagger Chain v${version} completed:
Runtime: ${runtime}s
#ds/root/${digestRootHash}
Tiles processed: ${tiles.length}
Tiles digested: ${digestedTiles}
Tiles not digested: ${nonDigestedTiles}
Tiles updated: ${updatedTiles}
Date: ${currentDate}`;
        const tileFilesMessage = `Tile files updated (BUGY):
${Object.entries(tileFilesUpdated).map(([file, status]) => `${file}: ${status}`).join('\n')}`;
        const blockchainEntryMessage = `Blockchain entry (${blockchainUpdateStatus}):
${blockchainFileContent}`;
        console.log(statusMessage);
        console.log(tileFilesMessage);
        console.log(blockchainEntryMessage);
        new Notice(statusMessage, 15000);
        new Notice(tileFilesMessage, 15000);
        new Notice(blockchainEntryMessage, 15000);
    } catch (error) {
        console.error(`[${currentDate}] An error occurred:`, error);
        new Notice(`Error in DS Tagger Chain v${version}: ${error.message}. Check console for details.`, 15000);
    }
}
// Run the script and output the result
await dsTaggerChain();
%>

DeformattedTile Doc Seal 0.9 - Digest & Seal - Current Document.md

<%*
// Doc Seal 0.9 for Obsidian Templater
// Version 0.9.7
/* * *Preserve Specs for Tile and Blockchain formats* * *
Tile Spec:
- Structure `###### #Digested-Tile #ds/{deformat-digest}/{YYYY-MM-DD}\nAuthors:: {authors}\nLicense:: {license}\nDigest Root:: {digestRootHash}\n###### #MarkdownTile\n{tile}\n###### #DeformattedTile\n{deformatted-tile}\n###### #EOT\n---\n`
- Location: `x/ds/tiles/{deformat-digest}.md`
- Upsert Logic: Skip (with Notice message) if `#ds/{deformat-digest}/{YYYY-MM-DD}` exists, append otherwise
Blockchain Spec:
- Structure: `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained  to #ds/block/${previousBlockchainEntryDigest} on ${YYYY-MM-DDTHH:mm}\n${digestTags.join(' ')}\n#ds/block/{currentBlockchainEntryDigest}`
- Location: `x/ds/blockchains/wwbc-{YY-MM}.md`
- Blockchain Logic: {previousBlockchainEntryDigest} is a hash of {YY-MM} for initial block or the BlockchainEntryDigest of the previous entry; if there are no "wwbc-....md" files yet, use the hash of the YY-MM, if there are not blocks in this months file yet, use the last #ds/block from the previous month, otherwise, use the last #ds/block in the current month's file
Script Spec:
- use Obsidian Templater scripting language for the script 
- use tp.user.updateFrontMatter to update frontmatter
- 15s Notice messages about updates, 3 messages: status, tiles, and blockchain 
- tp.user scripts: computeSHA256(content, length = 12); splitIntoTiles(content); ensureDirectoryExists(path); upsertToFile(filePath, header, content); updateFrontMatter(file, updates); getPreviousBlockchainEntryDigest(app, computeSHA256);
- inline helper functions: createDigestTag(hash, date); createDigestRootHash(digestTags);  
*/
function createDigestTag(hash, date) {
    return `#ds/${hash}/${date}`;
}
function createDigestRootHash(digestTags) {
    return tp.user.computeSHA256(digestTags.join(' '), 12);
}
// Main function
async function dsTaggerChain() {
    const version = "0.9.7";
    const startTime = Date.now();
    const currentDate = new Date().toISOString().split('T')[0];
    const currentTimestamp = new Date().toISOString();
    console.log(`[${currentDate}] DS Tagger Chain v${version} started`);
    // Configuration
    const tileDirectoryPath = "x/ds/tiles";
    const blockchainDirectoryPath = "x/ds/blockchains";
    try {
        // Ensure directories exist
        await tp.user.ensureDirectoryExists(tileDirectoryPath);
        await tp.user.ensureDirectoryExists(blockchainDirectoryPath);
        let content = tp.file.content;
        const fileName = tp.file.title;
        const currentFile = tp.file.find_tfile(fileName);
        if (typeof content !== 'string') {
            throw new Error('Received non-string content');
        }
        const authors = tp.frontmatter.authors || 'Unknown';
        const license = tp.frontmatter.license || 'Unspecified';
        console.log(`[${currentDate}] Authors extracted: ${authors}`);
        console.log(`[${currentDate}] License extracted: ${license}`);
        console.log(`[${currentDate}] File content length: ${content.length} characters`);
        const { frontmatter, tiles } = tp.user.splitIntoTiles(content);
        console.log(`[${currentDate}] Number of tiles: ${tiles.length}`);
        let processedTiles = [];
        let digestedTiles = 0;
        let nonDigestedTiles = 0;
        let updatedTiles = 0;
        let digestTags = [];
        let tileFilesUpdated = {};
        for (let i = 0; i < tiles.length; i++) {
            let tile = tiles[i];
            const tileHash = tp.user.computeSHA256(tile);
            console.log(`\n[${currentDate}] Processing tile ${i + 1} (${tileHash})`);
            let existingDigestMatch = tile.match(/\s*(#ds\/[a-f0-9]+\/\d{4}-\d{2}-\d{2})/);
            let existingDigest = existingDigestMatch ? existingDigestMatch[1] : null;
            console.log(`Existing Digest Tag: ${existingDigest || 'None'}`);
            let cleanTile = tile.replace(/\s*#ds\/[a-f0-9]+\/\d{4}-\d{2}-\d{2}/, '').trim();
            let { deformattedContent, charactersRemoved } = tp.user.deformatTile(cleanTile);
            let digest = tp.user.computeSHA256(deformattedContent);
            let digestTag = createDigestTag(digest, currentDate);
            console.log(`New Digest Tag: ${digestTag}`);
            if (existingDigest && existingDigest.includes(digest)) {
                console.log(`Content unchanged for tile ${tileHash}. Keeping existing Digest Tag.`);
                digestTag = existingDigest;
                nonDigestedTiles++;
               // new Notice(`Skipping unchanged tile: ${digestTag}`, 15000);
            } else {
                console.log(`Content changed or new for tile ${tileHash}. Updating Digest Tag.`);
                if (existingDigest) {
                    updatedTiles++;
                } else {
                    digestedTiles++;
                }
            }
            let processedTile = `${cleanTile} ${digestTag}`;
            processedTiles.push(processedTile);
            digestTags.push(digestTag);
            console.log(`Tile ${tileHash} stats: Characters removed: ${charactersRemoved}`);
            const tileFilePath = `${tileDirectoryPath}/${digest}.md`;
            const digestRootHash = createDigestRootHash(digestTags);
            const tileFileContent = `###### #Digested-Tile ${digestTag}
Authors:: ${authors}
License:: ${license}
Digest Root:: ${digestRootHash}
#MarkdownTile
${cleanTile}
#DeformattedTile
${deformattedContent}
#EOT
---`;
            const { status: tileUpdateStatus, file: tileFile } = await tp.user.upsertToFile(tileFilePath, `###### #Digested-Tile ${digestTag}`, tileFileContent);
            tileFilesUpdated[tileFilePath] = tileUpdateStatus;
            // Update tile file frontmatter
            if (tileFile) {
                await tp.user.updateFrontMatter(tileFile, {
                    aliases: [digestTag],
                    authors: authors,
                    license: license,
                    'digest-root': digestRootHash
                });
            }
        }
        let result = frontmatter + '\n' + processedTiles.join('\n\n');
        const yearMonth = currentDate.slice(2, 7);
        let digestRootHash = createDigestRootHash(digestTags);
        console.log(`\n[${currentDate}] Digest Root hash created: ${digestRootHash}`);
        // Modify the current file content
        await app.vault.modify(currentFile, result);
        // Update current file frontmatter using tp.user.updateFrontMatter after modifying content
        await tp.user.updateFrontMatter(currentFile, {
			aliases: [`#ds/root/${digestRootHash}`],
			'blockchain_last_digest_root': `#ds/root/${digestRootHash}`,
            'blockchain_digest_timestamp': currentTimestamp,
            'blockchain_file': `[[wwbc-${yearMonth}]]`
        });
        // Update blockchain file
        const blockchainFilePath = `${blockchainDirectoryPath}/wwbc-${yearMonth}.md`;
        const previousBlockchainEntryDigest = await tp.user.getPreviousBlockchainEntryDigest(app, blockchainDirectoryPath, tp.user.computeSHA256);
        console.log(`Previous blockchain entry digest: ${previousBlockchainEntryDigest}`);
        // Create the blockchain content without the final hash
        const blockchainContentWithoutHash = `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}
${digestTags.join(' ')}`.trim();
        // Generate the hash for the blockchain entry
        const blockchainEntryHash = tp.user.computeSHA256(blockchainContentWithoutHash);
        // Create the final blockchain content
        const blockchainFileContent = `${blockchainContentWithoutHash}
#ds/block/${blockchainEntryHash}`;
        const { status: blockchainUpdateStatus, file: blockchainFile  } = await tp.user.upsertToFile(blockchainFilePath, `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}`, blockchainFileContent);
		if (blockchainFile) {
			await tp.user.updateFrontMatter(blockchainFile, {
				cssclasses: [`locked`]
			});
		}
        if (blockchainUpdateStatus === 'updated') {
            console.log(`Updated blockchain file: ${blockchainFilePath}`);
        } else {
            console.log(`Blockchain file already up to date: ${blockchainFilePath}`);
        }
        const endTime = Date.now();
        const runtime = ((endTime - startTime) / 1000).toFixed(2);
        console.log(`\n[${currentDate}] DS Tagger Chain process completed successfully`);
        
        const statusMessage = `DS Tagger Chain v${version} completed:
Runtime: ${runtime}s
#ds/root/${digestRootHash}
Tiles processed: ${tiles.length}
Tiles digested: ${digestedTiles}
Tiles not digested: ${nonDigestedTiles}
Tiles updated: ${updatedTiles}
Date: ${currentDate}`;
        const tileFilesMessage = `Tile files updated (BUGY):
${Object.entries(tileFilesUpdated).map(([file, status]) => `${file}: ${status}`).join('\n')}`;
        const blockchainEntryMessage = `Blockchain entry (${blockchainUpdateStatus}):
${blockchainFileContent}`;
        console.log(statusMessage);
        console.log(tileFilesMessage);
        console.log(blockchainEntryMessage);
        new Notice(statusMessage, 15000);
        new Notice(tileFilesMessage, 15000);
        new Notice(blockchainEntryMessage, 15000);
    } catch (error) {
        console.error(`[${currentDate}] An error occurred:`, error);
        new Notice(`Error in DS Tagger Chain v${version}: ${error.message}. Check console for details.`, 15000);
    }
}
// Run the script and output the result
await dsTaggerChain();
%>

EOT

EOT

DeformattedTile Doc Seal 0.9 - Digest & Seal - Current Document.md

<%*
// Doc Seal 0.9 for Obsidian Templater
// Version 0.9.7
/* * *Preserve Specs for Tile and Blockchain formats* * *
Tile Spec:
- Structure `###### #Digested-Tile #ds/{deformat-digest}/{YYYY-MM-DD}\nAuthors:: {authors}\nLicense:: {license}\nDigest Root:: {digestRootHash}\n###### #MarkdownTile\n{tile}\n###### #DeformattedTile\n{deformatted-tile}\n###### #EOT\n---\n`
- Location: `x/ds/tiles/{deformat-digest}.md`
- Upsert Logic: Skip (with Notice message) if `#ds/{deformat-digest}/{YYYY-MM-DD}` exists, append otherwise
Blockchain Spec:
- Structure: `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained  to #ds/block/${previousBlockchainEntryDigest} on ${YYYY-MM-DDTHH:mm}\n${digestTags.join(' ')}\n#ds/block/{currentBlockchainEntryDigest}`
- Location: `x/ds/blockchains/wwbc-{YY-MM}.md`
- Blockchain Logic: {previousBlockchainEntryDigest} is a hash of {YY-MM} for initial block or the BlockchainEntryDigest of the previous entry; if there are no "wwbc-....md" files yet, use the hash of the YY-MM, if there are not blocks in this months file yet, use the last #ds/block from the previous month, otherwise, use the last #ds/block in the current month's file
Script Spec:
- use Obsidian Templater scripting language for the script 
- use tp.user.updateFrontMatter to update frontmatter
- 15s Notice messages about updates, 3 messages: status, tiles, and blockchain 
- tp.user scripts: computeSHA256(content, length = 12); splitIntoTiles(content); ensureDirectoryExists(path); upsertToFile(filePath, header, content); updateFrontMatter(file, updates); getPreviousBlockchainEntryDigest(app, computeSHA256);
- inline helper functions: createDigestTag(hash, date); createDigestRootHash(digestTags);  
*/
function createDigestTag(hash, date) {
    return `#ds/${hash}/${date}`;
}
function createDigestRootHash(digestTags) {
    return tp.user.computeSHA256(digestTags.join(' '), 12);
}
// Main function
async function dsTaggerChain() {
    const version = "0.9.7";
    const startTime = Date.now();
    const currentDate = new Date().toISOString().split('T')[0];
    const currentTimestamp = new Date().toISOString();
    console.log(`[${currentDate}] DS Tagger Chain v${version} started`);
    // Configuration
    const tileDirectoryPath = "x/ds/tiles";
    const blockchainDirectoryPath = "x/ds/blockchains";
    try {
        // Ensure directories exist
        await tp.user.ensureDirectoryExists(tileDirectoryPath);
        await tp.user.ensureDirectoryExists(blockchainDirectoryPath);
        let content = tp.file.content;
        const fileName = tp.file.title;
        const currentFile = tp.file.find_tfile(fileName);
        if (typeof content !== 'string') {
            throw new Error('Received non-string content');
        }
        const authors = tp.frontmatter.authors || 'Unknown';
        const license = tp.frontmatter.license || 'Unspecified';
        console.log(`[${currentDate}] Authors extracted: ${authors}`);
        console.log(`[${currentDate}] License extracted: ${license}`);
        console.log(`[${currentDate}] File content length: ${content.length} characters`);
        const { frontmatter, tiles } = tp.user.splitIntoTiles(content);
        console.log(`[${currentDate}] Number of tiles: ${tiles.length}`);
        let processedTiles = [];
        let digestedTiles = 0;
        let nonDigestedTiles = 0;
        let updatedTiles = 0;
        let digestTags = [];
        let tileFilesUpdated = {};
        for (let i = 0; i < tiles.length; i++) {
            let tile = tiles[i];
            const tileHash = tp.user.computeSHA256(tile);
            console.log(`\n[${currentDate}] Processing tile ${i + 1} (${tileHash})`);
            let existingDigestMatch = tile.match(/\s*(#ds\/[a-f0-9]+\/\d{4}-\d{2}-\d{2})/);
            let existingDigest = existingDigestMatch ? existingDigestMatch[1] : null;
            console.log(`Existing Digest Tag: ${existingDigest || 'None'}`);
            let cleanTile = tile.replace(/\s*#ds\/[a-f0-9]+\/\d{4}-\d{2}-\d{2}/, '').trim();
            let { deformattedContent, charactersRemoved } = tp.user.deformatTile(cleanTile);
            let digest = tp.user.computeSHA256(deformattedContent);
            let digestTag = createDigestTag(digest, currentDate);
            console.log(`New Digest Tag: ${digestTag}`);
            if (existingDigest && existingDigest.includes(digest)) {
                console.log(`Content unchanged for tile ${tileHash}. Keeping existing Digest Tag.`);
                digestTag = existingDigest;
                nonDigestedTiles++;
               // new Notice(`Skipping unchanged tile: ${digestTag}`, 15000);
            } else {
                console.log(`Content changed or new for tile ${tileHash}. Updating Digest Tag.`);
                if (existingDigest) {
                    updatedTiles++;
                } else {
                    digestedTiles++;
                }
            }
            let processedTile = `${cleanTile} ${digestTag}`;
            processedTiles.push(processedTile);
            digestTags.push(digestTag);
            console.log(`Tile ${tileHash} stats: Characters removed: ${charactersRemoved}`);
            const tileFilePath = `${tileDirectoryPath}/${digest}.md`;
            const digestRootHash = createDigestRootHash(digestTags);
            const tileFileContent = `###### #Digested-Tile ${digestTag}
Authors:: ${authors}
License:: ${license}
Digest Root:: ${digestRootHash}
#MarkdownTile
${cleanTile}
#DeformattedTile
${deformattedContent}
#EOT
---`;
            const { status: tileUpdateStatus, file: tileFile } = await tp.user.upsertToFile(tileFilePath, `###### #Digested-Tile ${digestTag}`, tileFileContent);
            tileFilesUpdated[tileFilePath] = tileUpdateStatus;
            // Update tile file frontmatter
            if (tileFile) {
                await tp.user.updateFrontMatter(tileFile, {
                    aliases: [digestTag],
                    authors: authors,
                    license: license,
                    'digest-root': digestRootHash
                });
            }
        }
        let result = frontmatter + '\n' + processedTiles.join('\n\n');
        const yearMonth = currentDate.slice(2, 7);
        let digestRootHash = createDigestRootHash(digestTags);
        console.log(`\n[${currentDate}] Digest Root hash created: ${digestRootHash}`);
        // Modify the current file content
        await app.vault.modify(currentFile, result);
        // Update current file frontmatter using tp.user.updateFrontMatter after modifying content
        await tp.user.updateFrontMatter(currentFile, {
			aliases: [`#ds/root/${digestRootHash}`],
			'blockchain_last_digest_root': `#ds/root/${digestRootHash}`,
            'blockchain_digest_timestamp': currentTimestamp,
            'blockchain_file': `[[wwbc-${yearMonth}]]`
        });
        // Update blockchain file
        const blockchainFilePath = `${blockchainDirectoryPath}/wwbc-${yearMonth}.md`;
        const previousBlockchainEntryDigest = await tp.user.getPreviousBlockchainEntryDigest(app, blockchainDirectoryPath, tp.user.computeSHA256);
        console.log(`Previous blockchain entry digest: ${previousBlockchainEntryDigest}`);
        // Create the blockchain content without the final hash
        const blockchainContentWithoutHash = `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}
${digestTags.join(' ')}`.trim();
        // Generate the hash for the blockchain entry
        const blockchainEntryHash = tp.user.computeSHA256(blockchainContentWithoutHash);
        // Create the final blockchain content
        const blockchainFileContent = `${blockchainContentWithoutHash}
#ds/block/${blockchainEntryHash}`;
        const { status: blockchainUpdateStatus, file: blockchainFile  } = await tp.user.upsertToFile(blockchainFilePath, `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}`, blockchainFileContent);
		if (blockchainFile) {
			await tp.user.updateFrontMatter(blockchainFile, {
				cssclasses: [`locked`]
			});
		}
        if (blockchainUpdateStatus === 'updated') {
            console.log(`Updated blockchain file: ${blockchainFilePath}`);
        } else {
            console.log(`Blockchain file already up to date: ${blockchainFilePath}`);
        }
        const endTime = Date.now();
        const runtime = ((endTime - startTime) / 1000).toFixed(2);
        console.log(`\n[${currentDate}] DS Tagger Chain process completed successfully`);
        
        const statusMessage = `DS Tagger Chain v${version} completed:
Runtime: ${runtime}s
#ds/root/${digestRootHash}
Tiles processed: ${tiles.length}
Tiles digested: ${digestedTiles}
Tiles not digested: ${nonDigestedTiles}
Tiles updated: ${updatedTiles}
Date: ${currentDate}`;
        const tileFilesMessage = `Tile files updated (BUGY):
${Object.entries(tileFilesUpdated).map(([file, status]) => `${file}: ${status}`).join('\n')}`;
        const blockchainEntryMessage = `Blockchain entry (${blockchainUpdateStatus}):
${blockchainFileContent}`;
        console.log(statusMessage);
        console.log(tileFilesMessage);
        console.log(blockchainEntryMessage);
        new Notice(statusMessage, 15000);
        new Notice(tileFilesMessage, 15000);
        new Notice(blockchainEntryMessage, 15000);
    } catch (error) {
        console.error(`[${currentDate}] An error occurred:`, error);
        new Notice(`Error in DS Tagger Chain v${version}: ${error.message}. Check console for details.`, 15000);
    }
}
// Run the script and output the result
await dsTaggerChain();
%>

DeformattedTile Doc Seal 0.9 - Digest & Seal - Current Document.md

<%*
// Doc Seal 0.9 for Obsidian Templater
// Version 0.9.7
/* * *Preserve Specs for Tile and Blockchain formats* * *
Tile Spec:
- Structure `###### #Digested-Tile #ds/{deformat-digest}/{YYYY-MM-DD}\nAuthors:: {authors}\nLicense:: {license}\nDigest Root:: {digestRootHash}\n###### #MarkdownTile\n{tile}\n###### #DeformattedTile\n{deformatted-tile}\n###### #EOT\n---\n`
- Location: `x/ds/tiles/{deformat-digest}.md`
- Upsert Logic: Skip (with Notice message) if `#ds/{deformat-digest}/{YYYY-MM-DD}` exists, append otherwise
Blockchain Spec:
- Structure: `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained  to #ds/block/${previousBlockchainEntryDigest} on ${YYYY-MM-DDTHH:mm}\n${digestTags.join(' ')}\n#ds/block/{currentBlockchainEntryDigest}`
- Location: `x/ds/blockchains/wwbc-{YY-MM}.md`
- Blockchain Logic: {previousBlockchainEntryDigest} is a hash of {YY-MM} for initial block or the BlockchainEntryDigest of the previous entry; if there are no "wwbc-....md" files yet, use the hash of the YY-MM, if there are not blocks in this months file yet, use the last #ds/block from the previous month, otherwise, use the last #ds/block in the current month's file
Script Spec:
- use Obsidian Templater scripting language for the script 
- use tp.user.updateFrontMatter to update frontmatter
- 15s Notice messages about updates, 3 messages: status, tiles, and blockchain 
- tp.user scripts: computeSHA256(content, length = 12); splitIntoTiles(content); ensureDirectoryExists(path); upsertToFile(filePath, header, content); updateFrontMatter(file, updates); getPreviousBlockchainEntryDigest(app, computeSHA256);
- inline helper functions: createDigestTag(hash, date); createDigestRootHash(digestTags);  
*/
function createDigestTag(hash, date) {
    return `#ds/${hash}/${date}`;
}
function createDigestRootHash(digestTags) {
    return tp.user.computeSHA256(digestTags.join(' '), 12);
}
// Main function
async function dsTaggerChain() {
    const version = "0.9.7";
    const startTime = Date.now();
    const currentDate = new Date().toISOString().split('T')[0];
    const currentTimestamp = new Date().toISOString();
    console.log(`[${currentDate}] DS Tagger Chain v${version} started`);
    // Configuration
    const tileDirectoryPath = "x/ds/tiles";
    const blockchainDirectoryPath = "x/ds/blockchains";
    try {
        // Ensure directories exist
        await tp.user.ensureDirectoryExists(tileDirectoryPath);
        await tp.user.ensureDirectoryExists(blockchainDirectoryPath);
        let content = tp.file.content;
        const fileName = tp.file.title;
        const currentFile = tp.file.find_tfile(fileName);
        if (typeof content !== 'string') {
            throw new Error('Received non-string content');
        }
        const authors = tp.frontmatter.authors || 'Unknown';
        const license = tp.frontmatter.license || 'Unspecified';
        console.log(`[${currentDate}] Authors extracted: ${authors}`);
        console.log(`[${currentDate}] License extracted: ${license}`);
        console.log(`[${currentDate}] File content length: ${content.length} characters`);
        const { frontmatter, tiles } = tp.user.splitIntoTiles(content);
        console.log(`[${currentDate}] Number of tiles: ${tiles.length}`);
        let processedTiles = [];
        let digestedTiles = 0;
        let nonDigestedTiles = 0;
        let updatedTiles = 0;
        let digestTags = [];
        let tileFilesUpdated = {};
        for (let i = 0; i < tiles.length; i++) {
            let tile = tiles[i];
            const tileHash = tp.user.computeSHA256(tile);
            console.log(`\n[${currentDate}] Processing tile ${i + 1} (${tileHash})`);
            let existingDigestMatch = tile.match(/\s*(#ds\/[a-f0-9]+\/\d{4}-\d{2}-\d{2})/);
            let existingDigest = existingDigestMatch ? existingDigestMatch[1] : null;
            console.log(`Existing Digest Tag: ${existingDigest || 'None'}`);
            let cleanTile = tile.replace(/\s*#ds\/[a-f0-9]+\/\d{4}-\d{2}-\d{2}/, '').trim();
            let { deformattedContent, charactersRemoved } = tp.user.deformatTile(cleanTile);
            let digest = tp.user.computeSHA256(deformattedContent);
            let digestTag = createDigestTag(digest, currentDate);
            console.log(`New Digest Tag: ${digestTag}`);
            if (existingDigest && existingDigest.includes(digest)) {
                console.log(`Content unchanged for tile ${tileHash}. Keeping existing Digest Tag.`);
                digestTag = existingDigest;
                nonDigestedTiles++;
               // new Notice(`Skipping unchanged tile: ${digestTag}`, 15000);
            } else {
                console.log(`Content changed or new for tile ${tileHash}. Updating Digest Tag.`);
                if (existingDigest) {
                    updatedTiles++;
                } else {
                    digestedTiles++;
                }
            }
            let processedTile = `${cleanTile} ${digestTag}`;
            processedTiles.push(processedTile);
            digestTags.push(digestTag);
            console.log(`Tile ${tileHash} stats: Characters removed: ${charactersRemoved}`);
            const tileFilePath = `${tileDirectoryPath}/${digest}.md`;
            const digestRootHash = createDigestRootHash(digestTags);
            const tileFileContent = `###### #Digested-Tile ${digestTag}
Authors:: ${authors}
License:: ${license}
Digest Root:: ${digestRootHash}
#MarkdownTile
${cleanTile}
#DeformattedTile
${deformattedContent}
#EOT
---`;
            const { status: tileUpdateStatus, file: tileFile } = await tp.user.upsertToFile(tileFilePath, `###### #Digested-Tile ${digestTag}`, tileFileContent);
            tileFilesUpdated[tileFilePath] = tileUpdateStatus;
            // Update tile file frontmatter
            if (tileFile) {
                await tp.user.updateFrontMatter(tileFile, {
                    aliases: [digestTag],
                    authors: authors,
                    license: license,
                    'digest-root': digestRootHash
                });
            }
        }
        let result = frontmatter + '\n' + processedTiles.join('\n\n');
        const yearMonth = currentDate.slice(2, 7);
        let digestRootHash = createDigestRootHash(digestTags);
        console.log(`\n[${currentDate}] Digest Root hash created: ${digestRootHash}`);
        // Modify the current file content
        await app.vault.modify(currentFile, result);
        // Update current file frontmatter using tp.user.updateFrontMatter after modifying content
        await tp.user.updateFrontMatter(currentFile, {
			aliases: [`#ds/root/${digestRootHash}`],
			'blockchain_last_digest_root': `#ds/root/${digestRootHash}`,
            'blockchain_digest_timestamp': currentTimestamp,
            'blockchain_file': `[[wwbc-${yearMonth}]]`
        });
        // Update blockchain file
        const blockchainFilePath = `${blockchainDirectoryPath}/wwbc-${yearMonth}.md`;
        const previousBlockchainEntryDigest = await tp.user.getPreviousBlockchainEntryDigest(app, blockchainDirectoryPath, tp.user.computeSHA256);
        console.log(`Previous blockchain entry digest: ${previousBlockchainEntryDigest}`);
        // Create the blockchain content without the final hash
        const blockchainContentWithoutHash = `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}
${digestTags.join(' ')}`.trim();
        // Generate the hash for the blockchain entry
        const blockchainEntryHash = tp.user.computeSHA256(blockchainContentWithoutHash);
        // Create the final blockchain content
        const blockchainFileContent = `${blockchainContentWithoutHash}
#ds/block/${blockchainEntryHash}`;
        const { status: blockchainUpdateStatus, file: blockchainFile  } = await tp.user.upsertToFile(blockchainFilePath, `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}`, blockchainFileContent);
		if (blockchainFile) {
			await tp.user.updateFrontMatter(blockchainFile, {
				cssclasses: [`locked`]
			});
		}
        if (blockchainUpdateStatus === 'updated') {
            console.log(`Updated blockchain file: ${blockchainFilePath}`);
        } else {
            console.log(`Blockchain file already up to date: ${blockchainFilePath}`);
        }
        const endTime = Date.now();
        const runtime = ((endTime - startTime) / 1000).toFixed(2);
        console.log(`\n[${currentDate}] DS Tagger Chain process completed successfully`);
        
        const statusMessage = `DS Tagger Chain v${version} completed:
Runtime: ${runtime}s
#ds/root/${digestRootHash}
Tiles processed: ${tiles.length}
Tiles digested: ${digestedTiles}
Tiles not digested: ${nonDigestedTiles}
Tiles updated: ${updatedTiles}
Date: ${currentDate}`;
        const tileFilesMessage = `Tile files updated (BUGY):
${Object.entries(tileFilesUpdated).map(([file, status]) => `${file}: ${status}`).join('\n')}`;
        const blockchainEntryMessage = `Blockchain entry (${blockchainUpdateStatus}):
${blockchainFileContent}`;
        console.log(statusMessage);
        console.log(tileFilesMessage);
        console.log(blockchainEntryMessage);
        new Notice(statusMessage, 15000);
        new Notice(tileFilesMessage, 15000);
        new Notice(blockchainEntryMessage, 15000);
    } catch (error) {
        console.error(`[${currentDate}] An error occurred:`, error);
        new Notice(`Error in DS Tagger Chain v${version}: ${error.message}. Check console for details.`, 15000);
    }
}
// Run the script and output the result
await dsTaggerChain();
%>

EOT

DeformattedTile Doc Seal 0.9 - Digest & Seal - Current Document.md

<%*
// Doc Seal 0.9 for Obsidian Templater
// Version 0.9.7
/* * *Preserve Specs for Tile and Blockchain formats* * *
Tile Spec:
- Structure `###### #Digested-Tile #ds/{deformat-digest}/{YYYY-MM-DD}\nAuthors:: {authors}\nLicense:: {license}\nDigest Root:: {digestRootHash}\n###### #MarkdownTile\n{tile}\n###### #DeformattedTile\n{deformatted-tile}\n###### #EOT\n---\n`
- Location: `x/ds/tiles/{deformat-digest}.md`
- Upsert Logic: Skip (with Notice message) if `#ds/{deformat-digest}/{YYYY-MM-DD}` exists, append otherwise
Blockchain Spec:
- Structure: `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained  to #ds/block/${previousBlockchainEntryDigest} on ${YYYY-MM-DDTHH:mm}\n${digestTags.join(' ')}\n#ds/block/{currentBlockchainEntryDigest}`
- Location: `x/ds/blockchains/wwbc-{YY-MM}.md`
- Blockchain Logic: {previousBlockchainEntryDigest} is a hash of {YY-MM} for initial block or the BlockchainEntryDigest of the previous entry; if there are no "wwbc-....md" files yet, use the hash of the YY-MM, if there are not blocks in this months file yet, use the last #ds/block from the previous month, otherwise, use the last #ds/block in the current month's file
Script Spec:
- use Obsidian Templater scripting language for the script 
- use tp.user.updateFrontMatter to update frontmatter
- 15s Notice messages about updates, 3 messages: status, tiles, and blockchain 
- tp.user scripts: computeSHA256(content, length = 12); splitIntoTiles(content); ensureDirectoryExists(path); upsertToFile(filePath, header, content); updateFrontMatter(file, updates); getPreviousBlockchainEntryDigest(app, computeSHA256);
- inline helper functions: createDigestTag(hash, date); createDigestRootHash(digestTags);  
*/
function createDigestTag(hash, date) {
    return `#ds/${hash}/${date}`;
}
function createDigestRootHash(digestTags) {
    return tp.user.computeSHA256(digestTags.join(' '), 12);
}
// Main function
async function dsTaggerChain() {
    const version = "0.9.7";
    const startTime = Date.now();
    const currentDate = new Date().toISOString().split('T')[0];
    const currentTimestamp = new Date().toISOString();
    console.log(`[${currentDate}] DS Tagger Chain v${version} started`);
    // Configuration
    const tileDirectoryPath = "x/ds/tiles";
    const blockchainDirectoryPath = "x/ds/blockchains";
    try {
        // Ensure directories exist
        await tp.user.ensureDirectoryExists(tileDirectoryPath);
        await tp.user.ensureDirectoryExists(blockchainDirectoryPath);
        let content = tp.file.content;
        const fileName = tp.file.title;
        const currentFile = tp.file.find_tfile(fileName);
        if (typeof content !== 'string') {
            throw new Error('Received non-string content');
        }
        const authors = tp.frontmatter.authors || 'Unknown';
        const license = tp.frontmatter.license || 'Unspecified';
        console.log(`[${currentDate}] Authors extracted: ${authors}`);
        console.log(`[${currentDate}] License extracted: ${license}`);
        console.log(`[${currentDate}] File content length: ${content.length} characters`);
        const { frontmatter, tiles } = tp.user.splitIntoTiles(content);
        console.log(`[${currentDate}] Number of tiles: ${tiles.length}`);
        let processedTiles = [];
        let digestedTiles = 0;
        let nonDigestedTiles = 0;
        let updatedTiles = 0;
        let digestTags = [];
        let tileFilesUpdated = {};
        for (let i = 0; i < tiles.length; i++) {
            let tile = tiles[i];
            const tileHash = tp.user.computeSHA256(tile);
            console.log(`\n[${currentDate}] Processing tile ${i + 1} (${tileHash})`);
            let existingDigestMatch = tile.match(/\s*(#ds\/[a-f0-9]+\/\d{4}-\d{2}-\d{2})/);
            let existingDigest = existingDigestMatch ? existingDigestMatch[1] : null;
            console.log(`Existing Digest Tag: ${existingDigest || 'None'}`);
            let cleanTile = tile.replace(/\s*#ds\/[a-f0-9]+\/\d{4}-\d{2}-\d{2}/, '').trim();
            let { deformattedContent, charactersRemoved } = tp.user.deformatTile(cleanTile);
            let digest = tp.user.computeSHA256(deformattedContent);
            let digestTag = createDigestTag(digest, currentDate);
            console.log(`New Digest Tag: ${digestTag}`);
            if (existingDigest && existingDigest.includes(digest)) {
                console.log(`Content unchanged for tile ${tileHash}. Keeping existing Digest Tag.`);
                digestTag = existingDigest;
                nonDigestedTiles++;
               // new Notice(`Skipping unchanged tile: ${digestTag}`, 15000);
            } else {
                console.log(`Content changed or new for tile ${tileHash}. Updating Digest Tag.`);
                if (existingDigest) {
                    updatedTiles++;
                } else {
                    digestedTiles++;
                }
            }
            let processedTile = `${cleanTile} ${digestTag}`;
            processedTiles.push(processedTile);
            digestTags.push(digestTag);
            console.log(`Tile ${tileHash} stats: Characters removed: ${charactersRemoved}`);
            const tileFilePath = `${tileDirectoryPath}/${digest}.md`;
            const digestRootHash = createDigestRootHash(digestTags);
            const tileFileContent = `###### #Digested-Tile ${digestTag}
Authors:: ${authors}
License:: ${license}
Digest Root:: ${digestRootHash}
#MarkdownTile
${cleanTile}
#DeformattedTile
${deformattedContent}
#EOT
---`;
            const { status: tileUpdateStatus, file: tileFile } = await tp.user.upsertToFile(tileFilePath, `###### #Digested-Tile ${digestTag}`, tileFileContent);
            tileFilesUpdated[tileFilePath] = tileUpdateStatus;
            // Update tile file frontmatter
            if (tileFile) {
                await tp.user.updateFrontMatter(tileFile, {
                    aliases: [digestTag],
                    authors: authors,
                    license: license,
                    'digest-root': digestRootHash
                });
            }
        }
        let result = frontmatter + '\n' + processedTiles.join('\n\n');
        const yearMonth = currentDate.slice(2, 7);
        let digestRootHash = createDigestRootHash(digestTags);
        console.log(`\n[${currentDate}] Digest Root hash created: ${digestRootHash}`);
        // Modify the current file content
        await app.vault.modify(currentFile, result);
        // Update current file frontmatter using tp.user.updateFrontMatter after modifying content
        await tp.user.updateFrontMatter(currentFile, {
			aliases: [`#ds/root/${digestRootHash}`],
			'blockchain_last_digest_root': `#ds/root/${digestRootHash}`,
            'blockchain_digest_timestamp': currentTimestamp,
            'blockchain_file': `[[wwbc-${yearMonth}]]`
        });
        // Update blockchain file
        const blockchainFilePath = `${blockchainDirectoryPath}/wwbc-${yearMonth}.md`;
        const previousBlockchainEntryDigest = await tp.user.getPreviousBlockchainEntryDigest(app, blockchainDirectoryPath, tp.user.computeSHA256);
        console.log(`Previous blockchain entry digest: ${previousBlockchainEntryDigest}`);
        // Create the blockchain content without the final hash
        const blockchainContentWithoutHash = `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}
${digestTags.join(' ')}`.trim();
        // Generate the hash for the blockchain entry
        const blockchainEntryHash = tp.user.computeSHA256(blockchainContentWithoutHash);
        // Create the final blockchain content
        const blockchainFileContent = `${blockchainContentWithoutHash}
#ds/block/${blockchainEntryHash}`;
        const { status: blockchainUpdateStatus, file: blockchainFile  } = await tp.user.upsertToFile(blockchainFilePath, `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}`, blockchainFileContent);
		if (blockchainFile) {
			await tp.user.updateFrontMatter(blockchainFile, {
				cssclasses: [`locked`]
			});
		}
        if (blockchainUpdateStatus === 'updated') {
            console.log(`Updated blockchain file: ${blockchainFilePath}`);
        } else {
            console.log(`Blockchain file already up to date: ${blockchainFilePath}`);
        }
        const endTime = Date.now();
        const runtime = ((endTime - startTime) / 1000).toFixed(2);
        console.log(`\n[${currentDate}] DS Tagger Chain process completed successfully`);
        
        const statusMessage = `DS Tagger Chain v${version} completed:
Runtime: ${runtime}s
#ds/root/${digestRootHash}
Tiles processed: ${tiles.length}
Tiles digested: ${digestedTiles}
Tiles not digested: ${nonDigestedTiles}
Tiles updated: ${updatedTiles}
Date: ${currentDate}`;
        const tileFilesMessage = `Tile files updated (BUGY):
${Object.entries(tileFilesUpdated).map(([file, status]) => `${file}: ${status}`).join('\n')}`;
        const blockchainEntryMessage = `Blockchain entry (${blockchainUpdateStatus}):
${blockchainFileContent}`;
        console.log(statusMessage);
        console.log(tileFilesMessage);
        console.log(blockchainEntryMessage);
        new Notice(statusMessage, 15000);
        new Notice(tileFilesMessage, 15000);
        new Notice(blockchainEntryMessage, 15000);
    } catch (error) {
        console.error(`[${currentDate}] An error occurred:`, error);
        new Notice(`Error in DS Tagger Chain v${version}: ${error.message}. Check console for details.`, 15000);
    }
}
// Run the script and output the result
await dsTaggerChain();
%>

DeformattedTile Doc Seal 0.9 - Digest & Seal - Current Document.md

<%*
// Doc Seal 0.9 for Obsidian Templater
// Version 0.9.7
/* * *Preserve Specs for Tile and Blockchain formats* * *
Tile Spec:
- Structure `###### #Digested-Tile #ds/{deformat-digest}/{YYYY-MM-DD}\nAuthors:: {authors}\nLicense:: {license}\nDigest Root:: {digestRootHash}\n###### #MarkdownTile\n{tile}\n###### #DeformattedTile\n{deformatted-tile}\n###### #EOT\n---\n`
- Location: `x/ds/tiles/{deformat-digest}.md`
- Upsert Logic: Skip (with Notice message) if `#ds/{deformat-digest}/{YYYY-MM-DD}` exists, append otherwise
Blockchain Spec:
- Structure: `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained  to #ds/block/${previousBlockchainEntryDigest} on ${YYYY-MM-DDTHH:mm}\n${digestTags.join(' ')}\n#ds/block/{currentBlockchainEntryDigest}`
- Location: `x/ds/blockchains/wwbc-{YY-MM}.md`
- Blockchain Logic: {previousBlockchainEntryDigest} is a hash of {YY-MM} for initial block or the BlockchainEntryDigest of the previous entry; if there are no "wwbc-....md" files yet, use the hash of the YY-MM, if there are not blocks in this months file yet, use the last #ds/block from the previous month, otherwise, use the last #ds/block in the current month's file
Script Spec:
- use Obsidian Templater scripting language for the script 
- use tp.user.updateFrontMatter to update frontmatter
- 15s Notice messages about updates, 3 messages: status, tiles, and blockchain 
- tp.user scripts: computeSHA256(content, length = 12); splitIntoTiles(content); ensureDirectoryExists(path); upsertToFile(filePath, header, content); updateFrontMatter(file, updates); getPreviousBlockchainEntryDigest(app, computeSHA256);
- inline helper functions: createDigestTag(hash, date); createDigestRootHash(digestTags);  
*/
function createDigestTag(hash, date) {
    return `#ds/${hash}/${date}`;
}
function createDigestRootHash(digestTags) {
    return tp.user.computeSHA256(digestTags.join(' '), 12);
}
// Main function
async function dsTaggerChain() {
    const version = "0.9.7";
    const startTime = Date.now();
    const currentDate = new Date().toISOString().split('T')[0];
    const currentTimestamp = new Date().toISOString();
    console.log(`[${currentDate}] DS Tagger Chain v${version} started`);
    // Configuration
    const tileDirectoryPath = "x/ds/tiles";
    const blockchainDirectoryPath = "x/ds/blockchains";
    try {
        // Ensure directories exist
        await tp.user.ensureDirectoryExists(tileDirectoryPath);
        await tp.user.ensureDirectoryExists(blockchainDirectoryPath);
        let content = tp.file.content;
        const fileName = tp.file.title;
        const currentFile = tp.file.find_tfile(fileName);
        if (typeof content !== 'string') {
            throw new Error('Received non-string content');
        }
        const authors = tp.frontmatter.authors || 'Unknown';
        const license = tp.frontmatter.license || 'Unspecified';
        console.log(`[${currentDate}] Authors extracted: ${authors}`);
        console.log(`[${currentDate}] License extracted: ${license}`);
        console.log(`[${currentDate}] File content length: ${content.length} characters`);
        const { frontmatter, tiles } = tp.user.splitIntoTiles(content);
        console.log(`[${currentDate}] Number of tiles: ${tiles.length}`);
        let processedTiles = [];
        let digestedTiles = 0;
        let nonDigestedTiles = 0;
        let updatedTiles = 0;
        let digestTags = [];
        let tileFilesUpdated = {};
        for (let i = 0; i < tiles.length; i++) {
            let tile = tiles[i];
            const tileHash = tp.user.computeSHA256(tile);
            console.log(`\n[${currentDate}] Processing tile ${i + 1} (${tileHash})`);
            let existingDigestMatch = tile.match(/\s*(#ds\/[a-f0-9]+\/\d{4}-\d{2}-\d{2})/);
            let existingDigest = existingDigestMatch ? existingDigestMatch[1] : null;
            console.log(`Existing Digest Tag: ${existingDigest || 'None'}`);
            let cleanTile = tile.replace(/\s*#ds\/[a-f0-9]+\/\d{4}-\d{2}-\d{2}/, '').trim();
            let { deformattedContent, charactersRemoved } = tp.user.deformatTile(cleanTile);
            let digest = tp.user.computeSHA256(deformattedContent);
            let digestTag = createDigestTag(digest, currentDate);
            console.log(`New Digest Tag: ${digestTag}`);
            if (existingDigest && existingDigest.includes(digest)) {
                console.log(`Content unchanged for tile ${tileHash}. Keeping existing Digest Tag.`);
                digestTag = existingDigest;
                nonDigestedTiles++;
               // new Notice(`Skipping unchanged tile: ${digestTag}`, 15000);
            } else {
                console.log(`Content changed or new for tile ${tileHash}. Updating Digest Tag.`);
                if (existingDigest) {
                    updatedTiles++;
                } else {
                    digestedTiles++;
                }
            }
            let processedTile = `${cleanTile} ${digestTag}`;
            processedTiles.push(processedTile);
            digestTags.push(digestTag);
            console.log(`Tile ${tileHash} stats: Characters removed: ${charactersRemoved}`);
            const tileFilePath = `${tileDirectoryPath}/${digest}.md`;
            const digestRootHash = createDigestRootHash(digestTags);
            const tileFileContent = `###### #Digested-Tile ${digestTag}
Authors:: ${authors}
License:: ${license}
Digest Root:: ${digestRootHash}
#MarkdownTile
${cleanTile}
#DeformattedTile
${deformattedContent}
#EOT
---`;
            const { status: tileUpdateStatus, file: tileFile } = await tp.user.upsertToFile(tileFilePath, `###### #Digested-Tile ${digestTag}`, tileFileContent);
            tileFilesUpdated[tileFilePath] = tileUpdateStatus;
            // Update tile file frontmatter
            if (tileFile) {
                await tp.user.updateFrontMatter(tileFile, {
                    aliases: [digestTag],
                    authors: authors,
                    license: license,
                    'digest-root': digestRootHash
                });
            }
        }
        let result = frontmatter + '\n' + processedTiles.join('\n\n');
        const yearMonth = currentDate.slice(2, 7);
        let digestRootHash = createDigestRootHash(digestTags);
        console.log(`\n[${currentDate}] Digest Root hash created: ${digestRootHash}`);
        // Modify the current file content
        await app.vault.modify(currentFile, result);
        // Update current file frontmatter using tp.user.updateFrontMatter after modifying content
        await tp.user.updateFrontMatter(currentFile, {
			aliases: [`#ds/root/${digestRootHash}`],
			'blockchain_last_digest_root': `#ds/root/${digestRootHash}`,
            'blockchain_digest_timestamp': currentTimestamp,
            'blockchain_file': `[[wwbc-${yearMonth}]]`
        });
        // Update blockchain file
        const blockchainFilePath = `${blockchainDirectoryPath}/wwbc-${yearMonth}.md`;
        const previousBlockchainEntryDigest = await tp.user.getPreviousBlockchainEntryDigest(app, blockchainDirectoryPath, tp.user.computeSHA256);
        console.log(`Previous blockchain entry digest: ${previousBlockchainEntryDigest}`);
        // Create the blockchain content without the final hash
        const blockchainContentWithoutHash = `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}
${digestTags.join(' ')}`.trim();
        // Generate the hash for the blockchain entry
        const blockchainEntryHash = tp.user.computeSHA256(blockchainContentWithoutHash);
        // Create the final blockchain content
        const blockchainFileContent = `${blockchainContentWithoutHash}
#ds/block/${blockchainEntryHash}`;
        const { status: blockchainUpdateStatus, file: blockchainFile  } = await tp.user.upsertToFile(blockchainFilePath, `### [[${fileName}]] 🔒 #ds/root/${digestRootHash} chained to #ds/block/${previousBlockchainEntryDigest} on ${currentTimestamp}`, blockchainFileContent);
		if (blockchainFile) {
			await tp.user.updateFrontMatter(blockchainFile, {
				cssclasses: [`locked`]
			});
		}
        if (blockchainUpdateStatus === 'updated') {
            console.log(`Updated blockchain file: ${blockchainFilePath}`);
        } else {
            console.log(`Blockchain file already up to date: ${blockchainFilePath}`);
        }
        const endTime = Date.now();
        const runtime = ((endTime - startTime) / 1000).toFixed(2);
        console.log(`\n[${currentDate}] DS Tagger Chain process completed successfully`);
        
        const statusMessage = `DS Tagger Chain v${version} completed:
Runtime: ${runtime}s
#ds/root/${digestRootHash}
Tiles processed: ${tiles.length}
Tiles digested: ${digestedTiles}
Tiles not digested: ${nonDigestedTiles}
Tiles updated: ${updatedTiles}
Date: ${currentDate}`;
        const tileFilesMessage = `Tile files updated (BUGY):
${Object.entries(tileFilesUpdated).map(([file, status]) => `${file}: ${status}`).join('\n')}`;
        const blockchainEntryMessage = `Blockchain entry (${blockchainUpdateStatus}):
${blockchainFileContent}`;
        console.log(statusMessage);
        console.log(tileFilesMessage);
        console.log(blockchainEntryMessage);
        new Notice(statusMessage, 15000);
        new Notice(tileFilesMessage, 15000);
        new Notice(blockchainEntryMessage, 15000);
    } catch (error) {
        console.error(`[${currentDate}] An error occurred:`, error);
        new Notice(`Error in DS Tagger Chain v${version}: ${error.message}. Check console for details.`, 15000);
    }
}
// Run the script and output the result
await dsTaggerChain();
%>

EOT

EOT

EOT

EOT