Digested-Tile 2024-09-13

Authors:: Unknown License:: Unspecified Digest Root:: 77a0af761954 #MarkdownTile

Digested-Tile

Authors:: Unknown License:: Unspecified Digest Root:: 7762842fd202 #MarkdownTile

Digested-Tile

Authors:: Unknown License:: Unspecified Digest Root:: d1cb7f7e6f2d #MarkdownTile

Digested-Tile

Authors:: Unknown License:: Unspecified Digest Root:: 62f36b314bb7

MarkdownTile

<%* // 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 block from the previous month, otherwise, use the last 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:: {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}

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: {digestedTiles} Tiles not digested: {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 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 block from the previous month, otherwise, use the last 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: {digestedTiles} Tiles not digested: {updatedTiles} Date: {Object.entries(tileFilesUpdated).map(([file, status]) ${file}: ${status}).join(‘\n’)}; const blockchainEntryMessage = Blockchain entry ({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([{version}: ${error.message}. Check console for details.`, 15000); } } // Run the script and output the result await dsTaggerChain(); %>

EOT

DeformattedTile #Digested-Tile Authors:: Unknown License:: Unspecified Digest Root:: 62f36b314bb7 #MarkdownTile <%* // 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 block from the previous month, otherwise, use the last 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: {digestedTiles} Tiles not digested: {updatedTiles} Date: {Object.entries(tileFilesUpdated).map(([file, status]) ${file}: ${status}).join(‘\n’)}; const blockchainEntryMessage = Blockchain entry ({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([{version}: ${error.message}. Check console for details.`, 15000); } } // Run the script and output the result await dsTaggerChain(); %> #DeformattedTile <%* // 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 block from the previous month, otherwise, use the last 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: {digestedTiles} Tiles not digested: {updatedTiles} Date: {Object.entries(tileFilesUpdated).map(([file, status]) ${file}: ${status}).join(‘\n’)}; const blockchainEntryMessage = Blockchain entry ({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([{version}: ${error.message}. Check console for details.`, 15000); } } // Run the script and output the result await dsTaggerChain(); %> #EOT

EOT

DeformattedTile #Digested-Tile Authors:: Unknown License:: Unspecified Digest Root:: d1cb7f7e6f2d #MarkdownTile #Digested-Tile Authors:: Unknown License:: Unspecified Digest Root:: 62f36b314bb7 #MarkdownTile <%* // 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 block from the previous month, otherwise, use the last 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: {digestedTiles} Tiles not digested: {updatedTiles} Date: {Object.entries(tileFilesUpdated).map(([file, status]) ${file}: ${status}).join(‘\n’)}; const blockchainEntryMessage = Blockchain entry ({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([{version}: ${error.message}. Check console for details.`, 15000); } } // Run the script and output the result await dsTaggerChain(); %> #DeformattedTile <%* // 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 block from the previous month, otherwise, use the last 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: {digestedTiles} Tiles not digested: {updatedTiles} Date: {Object.entries(tileFilesUpdated).map(([file, status]) ${file}: ${status}).join(‘\n’)}; const blockchainEntryMessage = Blockchain entry ({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([{version}: ${error.message}. Check console for details.`, 15000); } } // Run the script and output the result await dsTaggerChain(); %> #EOT

DeformattedTile #Digested-Tile Authors:: Unknown License:: Unspecified Digest Root:: 62f36b314bb7 #MarkdownTile <%* // 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 block from the previous month, otherwise, use the last 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: {digestedTiles} Tiles not digested: {updatedTiles} Date: {Object.entries(tileFilesUpdated).map(([file, status]) ${file}: ${status}).join(‘\n’)}; const blockchainEntryMessage = Blockchain entry ({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([{version}: ${error.message}. Check console for details.`, 15000); } } // Run the script and output the result await dsTaggerChain(); %> #DeformattedTile <%* // 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 block from the previous month, otherwise, use the last 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: {digestedTiles} Tiles not digested: {updatedTiles} Date: {Object.entries(tileFilesUpdated).map(([file, status]) ${file}: ${status}).join(‘\n’)}; const blockchainEntryMessage = Blockchain entry ({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([{version}: ${error.message}. Check console for details.`, 15000); } } // Run the script and output the result await dsTaggerChain(); %> #EOT

EOT

EOT

DeformattedTile #Digested-Tile Authors:: Unknown License:: Unspecified Digest Root:: 7762842fd202 #MarkdownTile #Digested-Tile Authors:: Unknown License:: Unspecified Digest Root:: d1cb7f7e6f2d #MarkdownTile #Digested-Tile Authors:: Unknown License:: Unspecified Digest Root:: 62f36b314bb7 #MarkdownTile <%* // 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 block from the previous month, otherwise, use the last 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: {digestedTiles} Tiles not digested: {updatedTiles} Date: {Object.entries(tileFilesUpdated).map(([file, status]) ${file}: ${status}).join(‘\n’)}; const blockchainEntryMessage = Blockchain entry ({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([{version}: ${error.message}. Check console for details.`, 15000); } } // Run the script and output the result await dsTaggerChain(); %> #DeformattedTile <%* // 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 block from the previous month, otherwise, use the last 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: {digestedTiles} Tiles not digested: {updatedTiles} Date: {Object.entries(tileFilesUpdated).map(([file, status]) ${file}: ${status}).join(‘\n’)}; const blockchainEntryMessage = Blockchain entry ({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([{version}: ${error.message}. Check console for details.`, 15000); } } // Run the script and output the result await dsTaggerChain(); %> #EOT

DeformattedTile #Digested-Tile Authors:: Unknown License:: Unspecified Digest Root:: 62f36b314bb7 #MarkdownTile <%* // 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 block from the previous month, otherwise, use the last 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: {digestedTiles} Tiles not digested: {updatedTiles} Date: {Object.entries(tileFilesUpdated).map(([file, status]) ${file}: ${status}).join(‘\n’)}; const blockchainEntryMessage = Blockchain entry ({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([{version}: ${error.message}. Check console for details.`, 15000); } } // Run the script and output the result await dsTaggerChain(); %> #DeformattedTile <%* // 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 block from the previous month, otherwise, use the last 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: {digestedTiles} Tiles not digested: {updatedTiles} Date: {Object.entries(tileFilesUpdated).map(([file, status]) ${file}: ${status}).join(‘\n’)}; const blockchainEntryMessage = Blockchain entry ({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([{version}: ${error.message}. Check console for details.`, 15000); } } // Run the script and output the result await dsTaggerChain(); %> #EOT

EOT

DeformattedTile #Digested-Tile Authors:: Unknown License:: Unspecified Digest Root:: d1cb7f7e6f2d #MarkdownTile #Digested-Tile Authors:: Unknown License:: Unspecified Digest Root:: 62f36b314bb7 #MarkdownTile <%* // 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 block from the previous month, otherwise, use the last 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: {digestedTiles} Tiles not digested: {updatedTiles} Date: {Object.entries(tileFilesUpdated).map(([file, status]) ${file}: ${status}).join(‘\n’)}; const blockchainEntryMessage = Blockchain entry ({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([{version}: ${error.message}. Check console for details.`, 15000); } } // Run the script and output the result await dsTaggerChain(); %> #DeformattedTile <%* // 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 block from the previous month, otherwise, use the last 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: {digestedTiles} Tiles not digested: {updatedTiles} Date: {Object.entries(tileFilesUpdated).map(([file, status]) ${file}: ${status}).join(‘\n’)}; const blockchainEntryMessage = Blockchain entry ({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([{version}: ${error.message}. Check console for details.`, 15000); } } // Run the script and output the result await dsTaggerChain(); %> #EOT

DeformattedTile #Digested-Tile Authors:: Unknown License:: Unspecified Digest Root:: 62f36b314bb7 #MarkdownTile <%* // 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 block from the previous month, otherwise, use the last 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: {digestedTiles} Tiles not digested: {updatedTiles} Date: {Object.entries(tileFilesUpdated).map(([file, status]) ${file}: ${status}).join(‘\n’)}; const blockchainEntryMessage = Blockchain entry ({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([{version}: ${error.message}. Check console for details.`, 15000); } } // Run the script and output the result await dsTaggerChain(); %> #DeformattedTile <%* // 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 block from the previous month, otherwise, use the last 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: {digestedTiles} Tiles not digested: {updatedTiles} Date: {Object.entries(tileFilesUpdated).map(([file, status]) ${file}: ${status}).join(‘\n’)}; const blockchainEntryMessage = Blockchain entry ({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([{version}: ${error.message}. Check console for details.`, 15000); } } // Run the script and output the result await dsTaggerChain(); %> #EOT

EOT

EOT

EOT