hachyderm.io is one of the many independent Mastodon servers you can use to participate in the fediverse.
Hachyderm is a safe space, LGBTQIA+ and BLM, primarily comprised of tech industry professionals world wide. Note that many non-user account types have restrictions - please see our About page.

Administered by:

Server stats:

9.6K
active users

#howto

12 posts12 participants1 post today
Terence Eden’s Blog<p><strong>Pretty Print HTML using PHP 8.4's new HTML DOM</strong></p><p><a href="https://shkspr.mobi/blog/2025/03/pretty-print-html-using-php-8-4s-new-html-dom/" rel="nofollow noopener noreferrer" translate="no" target="_blank"><span class="invisible">https://</span><span class="ellipsis">shkspr.mobi/blog/2025/03/prett</span><span class="invisible">y-print-html-using-php-8-4s-new-html-dom/</span></a></p><p>Those whom the gods would send mad, they first teach recursion.</p><p>PHP 8.4 introduces a new <a href="https://www.php.net/manual/en/class.dom-htmldocument.php" rel="nofollow noopener noreferrer" target="_blank">Dom\HTMLDocument class</a> it is a modern HTML5 replacement for the ageing XHTML based DOMDocument. You can <a href="https://wiki.php.net/rfc/domdocument_html5_parser" rel="nofollow noopener noreferrer" target="_blank">read more about how it works</a> - the short version is that it reads and correctly sanitises HTML and turns it into a nested object. Hurrah!</p><p>The one thing it <em>doesn't</em> do is pretty-printing. When you call <code>$dom-&gt;saveHTML()</code> it will output something like:</p><pre><code>&lt;html lang="en-GB"&gt;&lt;head&gt;&lt;title&gt;Test&lt;/title&gt;&lt;/head&gt;&lt;body&gt;&lt;h1&gt;Testing&lt;/h1&gt;&lt;main&gt;&lt;p&gt;Some &lt;em&gt;HTML&lt;/em&gt; and an &lt;img src="example.png"&gt;&lt;/p&gt;&lt;ol&gt;&lt;li&gt;List&lt;/li&gt;&lt;li&gt;Another list&lt;/li&gt;&lt;/ol&gt;&lt;/main&gt;&lt;/body&gt;&lt;/html&gt;</code></pre><p>Perfect for a computer to read, but slightly tricky for humans.</p><p>As was <a href="https://libraries.mit.edu/150books/2011/05/11/1985/" rel="nofollow noopener noreferrer" target="_blank">written by the sages</a>:</p><blockquote><p>A computer language is not just a way of getting a computer to perform operations but rather … it is a novel formal medium for expressing ideas about methodology. Thus, programs must be written for people to read, and only incidentally for machines to execute.</p></blockquote><p>HTML <em>is</em> a programming language. Making markup easy to read for humans is a fine and noble goal. The aim is to turn the single line above into something like:</p><pre><code>&lt;html lang="en-GB"&gt; &lt;head&gt; &lt;title&gt;Test&lt;/title&gt; &lt;/head&gt; &lt;body&gt; &lt;h1&gt;Testing&lt;/h1&gt; &lt;main&gt; &lt;p&gt;Some &lt;em&gt;HTML&lt;/em&gt; and an &lt;img src="example.png"&gt;&lt;/p&gt; &lt;ol&gt; &lt;li&gt;List&lt;/li&gt; &lt;li&gt;Another list&lt;/li&gt; &lt;/ol&gt; &lt;/main&gt; &lt;/body&gt;&lt;/html&gt;</code></pre><p>Cor! That's much better!</p><p>I've cobbled together a script which is <em>broadly</em> accurate. There are a million-and-one edge cases and about twice as many personal preferences. This aims to be quick, simple, and basically fine. I am indebted to <a href="https://topic.alibabacloud.com/a/php-domdocument-recursive-formatting-of-indented-html-documents_4_86_30953142.html" rel="nofollow noopener noreferrer" target="_blank">this random Chinese script</a> and to <a href="https://github.com/wasinger/html-pretty-min" rel="nofollow noopener noreferrer" target="_blank">html-pretty-min</a>.</p><p><strong>Step By Step</strong></p><p>I'm going to walk through how everything works. This is as much for my benefit as for yours! This is beta code. It sorta-kinda-works for me. Think of it as a first pass at an attempt to prove that something can be done. Please don't use it in production!</p><p><strong>Setting up the DOM</strong></p><p>The new HTMLDocument should be broadly familiar to anyone who has used the previous one.</p><pre><code>$html = '&lt;html lang="en-GB"&gt;&lt;head&gt;&lt;title&gt;Test&lt;/title&gt;&lt;/head&gt;&lt;body&gt;&lt;h1&gt;Testing&lt;/h1&gt;&lt;main&gt;&lt;p&gt;Some &lt;em&gt;HTML&lt;/em&gt; and an &lt;img src="example.png"&gt;&lt;/p&gt;&lt;ol&gt;&lt;li&gt;List&lt;li&gt;Another list&lt;/body&gt;&lt;/html&gt;'$dom = Dom\HTMLDocument::createFromString( $html, LIBXML_NOERROR, "UTF-8" );</code></pre><p>This automatically adds <code>&lt;head&gt;</code> and <code>&lt;body&gt;</code> elements. If you don't want that, use the <a href="https://www.php.net/manual/en/libxml.constants.php#constant.libxml-html-noimplied" rel="nofollow noopener noreferrer" target="_blank"><code>LIBXML_HTML_NOIMPLIED</code> flag</a>:</p><pre><code>$dom = Dom\HTMLDocument::createFromString( $html, LIBXML_NOERROR | LIBXML_HTML_NOIMPLIED, "UTF-8" );</code></pre><p><strong>Where not to indent</strong></p><p>There are certain elements whose contents shouldn't be pretty-printed because it might change the meaning or layout of the text. For example, in a paragraph:</p><pre><code>&lt;p&gt; Some &lt;em&gt; HT &lt;strong&gt;M&lt;/strong&gt; L &lt;/em&gt;&lt;/p&gt;</code></pre><p>I've picked these elements from <a href="https://html.spec.whatwg.org/multipage/text-level-semantics.html#text-level-semantics" rel="nofollow noopener noreferrer" target="_blank">text-level semantics</a> and a few others which I consider sensible. Feel free to edit this list if you want.</p><pre><code>$preserve_internal_whitespace = [ "a", "em", "strong", "small", "s", "cite", "q", "dfn", "abbr", "ruby", "rt", "rp", "data", "time", "pre", "code", "var", "samp", "kbd", "sub", "sup", "b", "i", "mark", "u", "bdi", "bdo", "span", "h1", "h2", "h3", "h4", "h5", "h6", "p", "li", "button", "form", "input", "label", "select", "textarea",];</code></pre><p>The function has an option to <em>force</em> indenting every time it encounters an element.</p><p><strong>Tabs 🆚 Space</strong></p><p>Tabs, obviously. Users can set their tab width to their personal preference and it won't get confused with semantically significant whitespace.</p><pre><code>$indent_character = "\t";</code></pre><p><strong>Recursive Function</strong></p><p>This function reads through each node in the HTML tree. If the node should be indented, the function inserts a new node with the requisite number of tabs before the existing node. It also adds a suffix node to indent the next line appropriately. It then goes through the node's children and recursively repeats the process.</p><p><strong>This modifies the existing Document</strong>.</p><pre><code>function prettyPrintHTML( $node, $treeIndex = 0, $forceWhitespace = false ){ global $indent_character, $preserve_internal_whitespace; // If this node contains content which shouldn't be separately indented // And if whitespace is not forced if ( property_exists( $node, "localName" ) &amp;&amp; in_array( $node-&gt;localName, $preserve_internal_whitespace ) &amp;&amp; !$forceWhitespace ) { return; } // Does this node have children? if( property_exists( $node, "childElementCount" ) &amp;&amp; $node-&gt;childElementCount &gt; 0 ) { // Move in a step $treeIndex++; $tabStart = "\n" . str_repeat( $indent_character, $treeIndex ); $tabEnd = "\n" . str_repeat( $indent_character, $treeIndex - 1); // Remove any existing indenting at the start of the line $node-&gt;innerHTML = trim($node-&gt;innerHTML); // Loop through the children $i=0; while( $childNode = $node-&gt;childNodes-&gt;item( $i++ ) ) { // Was the *previous* sibling a text-only node? // If so, don't add a previous newline if ( $i &gt; 0 ) { $olderSibling = $node-&gt;childNodes-&gt;item( $i-1 ); if ( $olderSibling-&gt;nodeType == XML_TEXT_NODE &amp;&amp; !$forceWhitespace ) { $i++; continue; } $node-&gt;insertBefore( $node-&gt;ownerDocument-&gt;createTextNode( $tabStart ), $childNode ); } $i++; // Recursively indent all children prettyPrintHTML( $childNode, $treeIndex, $forceWhitespace ); }; // Suffix with a node which has "\n" and a suitable number of "\t" $node-&gt;appendChild( $node-&gt;ownerDocument-&gt;createTextNode( $tabEnd ) ); }}</code></pre><p><strong>Printing it out</strong></p><p>First, call the function. <strong>This modifies the existing Document</strong>.</p><pre><code>prettyPrintHTML( $dom-&gt;documentElement );</code></pre><p>Then call <a href="https://www.php.net/manual/en/dom-htmldocument.savehtml.php" rel="nofollow noopener noreferrer" target="_blank">the normal <code>saveHtml()</code> serialiser</a>:</p><pre><code>echo $dom-&gt;saveHTML();</code></pre><p>Note - this does not print a <code>&lt;!doctype html&gt;</code> - you'll need to include that manually if you're intending to use the entire document.</p><p><strong>Licence</strong></p><p>I consider the above too trivial to licence - but you may treat it as MIT if that makes you happy.</p><p><strong>Thoughts? Comments? Next steps?</strong></p><p>I've not written any formal tests, nor have I measured its speed, there may be subtle-bugs, and catastrophic errors. I know it doesn't work well if the HTML is already indented. It mysteriously prints double newlines for some unfathomable reason.</p><p>I'd love to know if you find this useful. Please <a href="https://gitlab.com/edent/pretty-print-html-using-php/" rel="nofollow noopener noreferrer" target="_blank">get involved on GitLab</a> or drop a comment here.</p><p><a rel="nofollow noopener noreferrer" class="hashtag u-tag u-category" href="https://shkspr.mobi/blog/tag/howto/" target="_blank">#HowTo</a> <a rel="nofollow noopener noreferrer" class="hashtag u-tag u-category" href="https://shkspr.mobi/blog/tag/html/" target="_blank">#HTML</a> <a rel="nofollow noopener noreferrer" class="hashtag u-tag u-category" href="https://shkspr.mobi/blog/tag/php/" target="_blank">#php</a></p>
Vikarti Anatra<p><strong>Get Started with Cursor - The AI Code Editor</strong></p> <p><a href="https://videos.viorsan.com/videos/watch/3ae37aa5-c860-4d8b-9302-f51d67f9774a" rel="nofollow noopener noreferrer" translate="no" target="_blank"><span class="invisible">https://</span><span class="ellipsis">videos.viorsan.com/videos/watc</span><span class="invisible">h/3ae37aa5-c860-4d8b-9302-f51d67f9774a</span></a></p>
windowsCult<p>If your <a href="https://techhub.social/tags/scanner" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>scanner</span></a> isn't working, first check the connections, ensure the printer is on and ready, and try restarting both the scanner and your computer. Read more <a href="https://www.windowscult.com/scanner-not-working/" rel="nofollow noopener noreferrer" translate="no" target="_blank"><span class="invisible">https://www.</span><span class="ellipsis">windowscult.com/scanner-not-wo</span><span class="invisible">rking/</span></a> </p><p><a href="https://techhub.social/tags/printer" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>printer</span></a> <a href="https://techhub.social/tags/Windows" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>Windows</span></a> <a href="https://techhub.social/tags/Windows11" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>Windows11</span></a> <a href="https://techhub.social/tags/howto" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>howto</span></a> <a href="https://techhub.social/tags/troubleshooting" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>troubleshooting</span></a> <a href="https://techhub.social/tags/Tech" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>Tech</span></a> <a href="https://techhub.social/tags/Technology" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>Technology</span></a></p>
windowsCult<p>If your <a href="https://flipboard.social/tags/scanner" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>scanner</span></a> isn't working, first check the connections, ensure the printer is on and ready, and try restarting both the scanner and your computer. Read more <a href="https://www.windowscult.com/scanner-not-working/" rel="nofollow noopener noreferrer" translate="no" target="_blank"><span class="invisible">https://www.</span><span class="ellipsis">windowscult.com/scanner-not-wo</span><span class="invisible">rking/</span></a> </p><p><a href="https://flipboard.social/tags/printer" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>printer</span></a> <a href="https://flipboard.social/tags/Windows" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>Windows</span></a> <a href="https://flipboard.social/tags/Windows11" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>Windows11</span></a> <a href="https://flipboard.social/tags/howto" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>howto</span></a> <a href="https://flipboard.social/tags/troubleshooting" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>troubleshooting</span></a> <a href="https://flipboard.social/tags/Tech" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>Tech</span></a> <a href="https://flipboard.social/tags/Technology" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>Technology</span></a></p>
Crow<p>Is there a way to NOT be notified when a boosted/liked post is edited?</p><p><a href="https://cville.online/tags/howto" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>howto</span></a> <a href="https://cville.online/tags/fediverse" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>fediverse</span></a> <a href="https://cville.online/tags/mastodontips" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>mastodontips</span></a></p>
ResearchBuzz: Firehose<p>Elena Rossini: PeerTube: the Fediverse’s decentralized video platform (part 2: creator edition). “In the previous article in this series I covered what it’s like to use PeerTube from the point of view of a casual user… Today’s post will discuss: how to use the software as a video creator – and its advantages over video hosting platforms by Big Tech companies.”</p><p><a href="https://rbfirehose.com/2025/03/29/peertube-the-fediverses-decentralized-video-platform-part-2-creator-edition-elena-rossini/" class="" rel="nofollow noopener noreferrer" target="_blank">https://rbfirehose.com/2025/03/29/peertube-the-fediverses-decentralized-video-platform-part-2-creator-edition-elena-rossini/</a></p>
Petra van Cronenburg<p>I manually review accounts who want to follow me (too many bot and scam waves). I automatically reject empty accounts!</p><p>If you don't want to be mistaken for a fake account, fill out your profile, post something that shows you as a human, only then follow people. How to: <a href="https://fedi.tips/how-do-i-customise-my-profile-how-do-i-upload-a-profile-banner-how-do-i-verify-my-account/" rel="nofollow noopener noreferrer" translate="no" target="_blank"><span class="invisible">https://</span><span class="ellipsis">fedi.tips/how-do-i-customise-m</span><span class="invisible">y-profile-how-do-i-upload-a-profile-banner-how-do-i-verify-my-account/</span></a></p><p><a href="https://mastodon.online/tags/profile" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>profile</span></a> <a href="https://mastodon.online/tags/follow" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>follow</span></a> <a href="https://mastodon.online/tags/following" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>following</span></a> <a href="https://mastodon.online/tags/accounts" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>accounts</span></a> <a href="https://mastodon.online/tags/fakeAccounts" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>fakeAccounts</span></a> <a href="https://mastodon.online/tags/spam" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>spam</span></a> <a href="https://mastodon.online/tags/bots" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>bots</span></a> <a href="https://mastodon.online/tags/Mastodon" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>Mastodon</span></a> <a href="https://mastodon.online/tags/HowTo" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>HowTo</span></a> <a href="https://mastodon.online/tags/feditips" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>feditips</span></a></p>
Linknation<p><a href="https://infosec.exchange/tags/AIConversation" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>AIConversation</span></a>: a <a href="https://infosec.exchange/tags/conversationwithdeepseek" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>conversationwithdeepseek</span></a> 70b:</p><p>Q: what would you say, why did the <a href="https://infosec.exchange/tags/Ukraine" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>Ukraine</span></a> <a href="https://infosec.exchange/tags/conflict" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>conflict</span></a> escalate and what to do to <a href="https://infosec.exchange/tags/deescalate" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>deescalate</span></a> it?<br>&lt;think&gt;<br>Okay, so I need to figure out why the Ukraine conflict escalated and how to deescalate it. Hmm, where do I start?</p><p>I remember that the conflict has been going on for a while. It started in 2014 with some protests, right? That's when <a href="https://infosec.exchange/tags/Crimea" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>Crimea</span></a> was annexed by <a href="https://infosec.exchange/tags/Russia" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>Russia</span></a>. But now it's gotten much worse since <br>February 2022 because Russia invaded Ukraine more aggressively.</p><p>Why did it escalate so much this time? Maybe there are deeper reasons. I think it has to do with historical ties between Russia and Ukraine. They were part of the Soviet Union <br>together, so there's a lot of shared history, but also some tensions, especially over Ukrainian independence.</p><p>Another thing is <a href="https://infosec.exchange/tags/NATOexpansion" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>NATOexpansion</span></a>. After the <a href="https://infosec.exchange/tags/ColdWar" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>ColdWar</span></a>, <a href="https://infosec.exchange/tags/NATO" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>NATO</span></a> started including more Eastern <a href="https://infosec.exchange/tags/European" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>European</span></a> countries. <a href="https://infosec.exchange/tags/Russia" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>Russia</span></a> didn't like that because it felt threatened by <a href="https://infosec.exchange/tags/military" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>military</span></a> <a href="https://infosec.exchange/tags/alliances" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>alliances</span></a> <br>getting closer to its <a href="https://infosec.exchange/tags/borders" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>borders</span></a>. So when <a href="https://infosec.exchange/tags/Ukraine" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>Ukraine</span></a> considered joining <a href="https://infosec.exchange/tags/NATO" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>NATO</span></a>, maybe <a href="https://infosec.exchange/tags/Russia" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>Russia</span></a> saw that as a direct threat and decided to act.</p><p>There's also the issue of pro-Russian <a href="https://infosec.exchange/tags/separatists" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>separatists</span></a> in eastern <a href="https://infosec.exchange/tags/Ukraine" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>Ukraine</span></a>. Since 2014, they've been fighting against the Ukrainian government, and Russia has supported them. That ongoing <br><a href="https://infosec.exchange/tags/conflict" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>conflict</span></a> probably kept tensions high and made things worse over time.</p><p>In terms of deescalating, I'm not sure what can be done. Maybe a <a href="https://infosec.exchange/tags/ceasefire" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>ceasefire</span></a> would help stop the immediate <a href="https://infosec.exchange/tags/violence" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>violence</span></a> <br>But how do you get both sides to agree? </p><p>They might need some kind of <br><a href="https://infosec.exchange/tags/mediator" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>mediator</span></a> or <a href="https://infosec.exchange/tags/peacetalks" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>peacetalks</span></a> facilitated by other countries or organizations like the <a href="https://infosec.exchange/tags/UN" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>UN</span></a>.</p><p><a href="https://infosec.exchange/tags/Economic" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>Economic</span></a> <a href="https://infosec.exchange/tags/sanctions" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>sanctions</span></a> were imposed on Russia because of their actions, but maybe easing those could be an incentive for deescalation.</p><p>Though I'm not sure if that would work without other measures in place.</p><p><a href="https://infosec.exchange/tags/Ukraine" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>Ukraine</span></a>'s <a href="https://infosec.exchange/tags/sovereignty" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>sovereignty</span></a> is really important here.</p><p>They should have the right to make their own decisions about alliances and security without interference from bigger powers like Russia <br>or NATO.</p><p>I think a long-term solution needs to address those underlying issues, maybe through <a href="https://infosec.exchange/tags/negotiations" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>negotiations</span></a> where both sides can express their concerns. But it's complicated because there are so <br>many historical and political factors at play. Plus, you have external actors involved, which might make it harder to reach an agreement.</p><p>Overall, it seems like the conflict escalated due to a mix of historical tensions, security concerns, and internal Ukrainian politics.</p><p><a href="https://infosec.exchange/tags/Deescalating" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>Deescalating</span></a> would require careful diplomacy, possibly involving third parties, to find a compromise that respects Ukraine's sovereignty while addressing <a href="https://infosec.exchange/tags/Russia" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>Russia</span></a>'s <a href="https://infosec.exchange/tags/fear" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>fear</span></a> about <a href="https://infosec.exchange/tags/NATOexpansion" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>NATOexpansion</span></a>.</p><p>&lt;/think&gt;</p><p>The Ukraine conflict has deepened due to a complex interplay of historical, political, and security factors. To deescalate, a multifaceted approach is necessary:</p><p>1. **Immediate Measures**: Implementing a <a href="https://infosec.exchange/tags/ceasefire" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>ceasefire</span></a> under international mediation can halt the violence. Organizations like the <a href="https://infosec.exchange/tags/UN" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>UN</span></a> could facilitate this process.</p><p>2. **Diplomatic Engagement**: <a href="https://infosec.exchange/tags/Peace" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>Peace</span></a> talks involving Ukraine, Russia, and mediators are crucial. These should address security concerns, including NATO's expansion and regional <br>stability.</p><p>3. **Economic Incentives**: Easing sanctions on Russia might provide an incentive for deescalation, contingent upon reciprocal actions from Russia.</p><p>4. **<a href="https://infosec.exchange/tags/Sovereignty" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>Sovereignty</span></a> <a href="https://infosec.exchange/tags/Respect" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>Respect</span></a>**: Upholding Ukraine's right to <a href="https://infosec.exchange/tags/selfdetermination" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>selfdetermination</span></a> and international relations is essential.</p><p>5. **Long-term Solutions**: Negotiations should consider historical ties and political tensions, ensuring a balance between Ukraine's autonomy and regional <a href="https://infosec.exchange/tags/security" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>security</span></a> dynamics.</p><p>In summary, <a href="https://infosec.exchange/tags/deescalation" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>deescalation</span></a> requires careful <a href="https://infosec.exchange/tags/diplomacy" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>diplomacy</span></a>, addressing both immediate concerns and underlying issues through mediated talks and mutual incentives.</p><p><a href="https://infosec.exchange/tags/howto" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>howto</span></a> <a href="https://infosec.exchange/tags/AI" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>AI</span></a> <a href="https://infosec.exchange/tags/LLM" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>LLM</span></a> model <a href="https://infosec.exchange/tags/deepseek" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>deepseek</span></a> 70GByte in size have a lot of RAM and fast CPU or GPU:</p><p>curl -fsSL <a href="https://ollama.com/install.sh" rel="nofollow noopener noreferrer" translate="no" target="_blank"><span class="invisible">https://</span><span class="">ollama.com/install.sh</span><span class="invisible"></span></a> | sh<br># then<br>ollama run deepseek-r1:70b</p><p>hashtags: <a href="https://infosec.exchange/tags/politics" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>politics</span></a> <a href="https://infosec.exchange/tags/politic" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>politic</span></a> <a href="https://infosec.exchange/tags/economy" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>economy</span></a> <a href="https://infosec.exchange/tags/war" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>war</span></a> <a href="https://infosec.exchange/tags/worldorder" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>worldorder</span></a></p>
Hugh's Views & News  <p><strong>Harnessing AI in Blogging: Benefits, Challenges, and Personal&nbsp;Insights</strong></p><p>In today’s digital landscape, artificial intelligence (AI) is emerging as a progressively popular tool across various domains, including blogging.</p><p>WordPress integrated AI into its platform a few years ago, joining numerous other sites that now offer AI as an option.</p><p>I have witnessed many bloggers who are afraid of what AI can do, but I have also seen many bloggers embrace AI and utilise it for the benefits it can offer.</p><p>However, like any tool, there are pros and cons to consider. </p><p>What are your thoughts about using AI to blog?</p><p>This post examines the advantages and disadvantages of integrating AI into your blogging process.</p><p><strong>Pros of Using AI in Blogging</strong></p><p><strong>1. Improved Efficiency</strong></p><p>AI tools can streamline the writing process. From generating topic ideas to creating content drafts, AI can save bloggers considerable time, allowing them to focus on refining their unique voice and style.</p><p>This may prove beneficial to bloggers who publish daily, but those bloggers who publish less often may not see any benefit. </p><p><strong>2. Enhanced Creativity</strong></p><p>AI can assist in brainstorming and generating creative content ideas. With access to vast databases and algorithms that identify trends, AI can offer fresh perspectives and innovative suggestions.</p><p>However, some consider this to be plagiarism, a term that specifically refers to taking another person’s work—words, ideas, and so forth—and presenting it as one’s own without proper attribution.</p><p>Did you know that WordPress users can choose to stop their blog’s content from being shared with a WordPress-licensed network of content and research partners, including those that train AI models? To achieve this, navigate to your blog’s dashboard, select <strong>Settings—Reading</strong>, and tick the box next to ‘<strong>Prevent third-party sharing.</strong>..’.</p> <a href="https://hughsviewsandnews.com/wp-content/uploads/2025/03/screenshot-4.png" rel="nofollow noopener noreferrer" target="_blank"></a>Tick this box to stop AI from using your blog content. <p><strong>3. SEO Optimization</strong></p><p>Numerous AI-based tools can analyse keywords and optimise content for search engines. They offer insights into the types of content that rank well, assisting bloggers in enhancing their visibility and reach.</p><p>I utilise AI to generate titles for blog posts when I struggle to think of a captivating title that will entice readers to read and engage further. Consequently, I have observed a significant increase in engagement and visitors to my blog.</p><p><strong>4. Data-Driven Decisions</strong></p><p>AI can analyse reader behaviour and feedback to inform content strategy. By understanding what resonates with the audience, bloggers can create more targeted and engaging content.</p><p>However, your WordPress statistics can also provide this information by analysing the stats of posts that receive higher engagement. Typically, you’ll observe a correlation between those posts that engage readers more and those that attract less engagement.</p><p><strong>5. Consistency</strong></p><p>AI can assist in maintaining a consistent posting schedule by automating aspects of the content creation process. This guarantees that the blog stays active and engaging for readers.</p><p>It is widely known that blogs which publish on a schedule tend to retain readers; however, it is unwise to publish content merely for the sake of it. There is nothing wrong with occasionally missing the publication of a blog post or taking a break from blogging. Nevertheless, if you choose to take the latter route, ensure that you inform your readers.</p><p><strong>Cons of Using AI in Blogging</strong></p><p><strong>1. Lack of Personal Touch</strong></p><p>AI-generated content often lacks the emotional depth and personal touch that human writers naturally provide. Readers tend to connect more readily with personal stories and unique experiences that AI is unable to replicate.</p><p>If you let AI compose all your posts, you’ll soon notice a decline in visitors and engagement.</p><p><strong>2. Quality Control</strong></p><p>While AI can generate content rapidly, the quality does not always meet high standards. Bloggers must review and edit AI-generated content to ensure it aligns with their voice and is factually accurate. Remember, it is your blog, not that of AI. Your voice matters.</p><p><strong>3. Dependence on Technology</strong></p><p>Over-reliance on AI can hinder writing skills. Bloggers may grow overly dependent on tools, stifling creative development and originality. This is particularly evident in the fiction world, where I have observed AI produce stories that lack emotion or feeling, thus making them dull and unappealing. </p><p>My advice is that if you are going to AI, mix it with your written content. </p><p><strong>4. Ethical Concerns</strong></p><p>The use of AI raises ethical questions, such as plagiarism (which I discussed earlier) and authenticity. Bloggers must ensure that their use of AI does not compromise their integrity or mislead their audience. Always check (and check again) what AI produces.</p><p><strong>5. Costs</strong></p><p>Although some AI tools are free, many come with a cost. For bloggers on a tight budget, investing in AI technology might not be practical. However, this won’t affect those who choose not to use AI.</p><p><strong>Do I use AI in blogging?</strong></p><p>Yes, I utilise AI to assist with spelling and grammar corrections. I have also used AI to verify if I have omitted anything essential from a post, as well as for generating titles for blog posts.</p><p>The featured images I use in my blog posts (including this one) are primarily created using the WordPress AI image tool. However, I have found that the tool is not always particularly effective at generating images, especially when more than a few words are included. More work is needed to improve it. </p><p><strong>Conclusion</strong></p><p>Utilising AI in blogging offers both exciting opportunities and significant challenges. While it can enhance efficiency, creativity, and data-driven decisions, it is crucial to maintain a balance and preserve the unique voice that attracts readers. By carefully weighing the pros and cons, bloggers can make informed choices about incorporating AI into their writing process.</p><p>If you wish to utilise AI, do so with your own writing rather than generating posts entirely composed by AI.</p><p>Finally, we must never forget that we all have a choice regarding AI. We can either use it or leave it be. What we must never do is persuade other users to use it or not. It’s a personal decision. Never criticise those who choose to use AI if you are against any use of AI in writing. Likewise, don’t criticise anyone who refuses to use AI if you use it. </p><p><strong>Recommended reading about AI in blogging from other bloggers. </strong></p><p>If you want a guide on AI on WordPress, check out this excellent article from Fedora, ‘<a href="https://fedorapancakes.com/2025/03/06/a-guide-to-wordpress-coms-ai-assistant/" rel="nofollow noopener noreferrer" target="_blank">A Guide To WordPress.Com’s AI Assistant</a>.’ </p><p>This post from Debbie at Deb’s World, “<a href="https://debs-world.com/2025/03/13/reinventing-blogging-a-look-into-2125/" rel="nofollow noopener noreferrer" target="_blank">Reinventing Blogging: A Look into the Future</a>,” dives into the controversial realm of AI in blogging, and trust me, it’s a must-read that has ignited plenty of debate. Are you ready to jump into the fray and add your voice to the discussion?</p><p>Are you hopping on the AI train in your blogging adventure? If so, what tools are you using, and what benefits has AI brought you and your blog? Does the use of AI in the blogging world concern you? Are you against using AI in Blogging? If so, what are your reasons? We want to hear your thoughts if you’re for or against AI. Drop your thoughts in the comments, and let’s chat!</p><p>I’m getting tough with non-engaging comments. Any non-engaging comments such as ‘Nice post’ are marked as spam.</p><p>Follow Hugh on social media. Click the buttons below.</p><ul><li><a href="https://hughsviewsandnews.com/" class="" rel="nofollow noopener noreferrer" target="_blank"><span class="">WordPress</span></a></li><li><a href="https://www.amazon.co.uk/stores/Hugh-W.-Roberts/author/B01N40ZABP?ref=ap_rdr&amp;isDramIntegrated=true&amp;shoppingPortalEnabled=true" class="" rel="nofollow noopener noreferrer" target="_blank"><span class="">Amazon</span></a></li><li><a href="https://www.goodreads.com/author/show/16123684.Hugh_W_Roberts" class="" rel="nofollow noopener noreferrer" target="_blank"><span class="">Goodreads</span></a></li><li><a href="https://toot.wales/@HughWRoberts" class="" rel="nofollow noopener noreferrer" target="_blank"><span class="">Mastodon</span></a></li><li><a href="https://flipboard.com/@HughWRoberts?from=share&amp;utm_source=flipboard&amp;utm_medium=curator_share" class="" rel="nofollow noopener noreferrer" target="_blank"><span class="">Link</span></a></li><li><a href="https://bsky.app/profile/hughsviewsandnews.com" class="" rel="nofollow noopener noreferrer" target="_blank"><span class="">Bluesky</span></a></li></ul><p><strong>Copyright @ 2025 hughsviewsandnews.com – All rights reserved.</strong></p><p></p><p><a rel="nofollow noopener noreferrer" class="hashtag u-tag u-category" href="https://hughsviewsandnews.com/tag/ai/" target="_blank">#AI</a> <a rel="nofollow noopener noreferrer" class="hashtag u-tag u-category" href="https://hughsviewsandnews.com/tag/ai-in-blogging/" target="_blank">#AIInBlogging</a> <a rel="nofollow noopener noreferrer" class="hashtag u-tag u-category" href="https://hughsviewsandnews.com/tag/artificial-intelligence/" target="_blank">#ArtificialIntelligence</a> <a rel="nofollow noopener noreferrer" class="hashtag u-tag u-category" href="https://hughsviewsandnews.com/tag/blogging-advice/" target="_blank">#BloggingAdvice</a> <a rel="nofollow noopener noreferrer" class="hashtag u-tag u-category" href="https://hughsviewsandnews.com/tag/blogging-help/" target="_blank">#BloggingHelp</a> <a rel="nofollow noopener noreferrer" class="hashtag u-tag u-category" href="https://hughsviewsandnews.com/tag/blogging-questions/" target="_blank">#BloggingQuestions</a> <a rel="nofollow noopener noreferrer" class="hashtag u-tag u-category" href="https://hughsviewsandnews.com/tag/blogging-tips/" target="_blank">#BloggingTips</a> <a rel="nofollow noopener noreferrer" class="hashtag u-tag u-category" href="https://hughsviewsandnews.com/tag/blogging-tools/" target="_blank">#BloggingTools</a> <a rel="nofollow noopener noreferrer" class="hashtag u-tag u-category" href="https://hughsviewsandnews.com/tag/how-to/" target="_blank">#HowTo</a> <a rel="nofollow noopener noreferrer" class="hashtag u-tag u-category" href="https://hughsviewsandnews.com/tag/wordpress/" target="_blank">#WordPress</a></p>
Geeker's Digest<p>When starting a Docker <a href="https://techhub.social/tags/container" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>container</span></a>, this uses a so-called "<a href="https://techhub.social/tags/Docker" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>Docker</span></a> Image" in the background. These images can be built on top of each other (called layers). </p><p>An image can be created from yet another image, potentially resulting in many many layers. </p><p>To extract files and directories from all these layers, there's some patience and wizardry needed. </p><p>Or you use our <a href="https://techhub.social/tags/HowTo" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>HowTo</span></a> which shows a really nice helper script doing all the work for you. 👇 </p><p><a href="https://www.geekersdigest.com/how-to-unpack-a-docker-container-image-and-extract-files/" rel="nofollow noopener noreferrer" translate="no" target="_blank"><span class="invisible">https://www.</span><span class="ellipsis">geekersdigest.com/how-to-unpac</span><span class="invisible">k-a-docker-container-image-and-extract-files/</span></a></p>
Terence Eden’s Blog<p><strong>Create a Table of Contents based on HTML Heading Elements</strong></p><p><a href="https://shkspr.mobi/blog/2025/03/create-a-table-of-contents-based-on-html-heading-elements/" rel="nofollow noopener noreferrer" translate="no" target="_blank"><span class="invisible">https://</span><span class="ellipsis">shkspr.mobi/blog/2025/03/creat</span><span class="invisible">e-a-table-of-contents-based-on-html-heading-elements/</span></a></p><p>Some of my blog posts are long0. They have lots of HTML headings like <code>&lt;h2&gt;</code> and <code>&lt;h3&gt;</code>. Say, wouldn't it be super-awesome to have something magically generate a Table of Contents? I've built a utility which runs server-side using PHP. Give it some HTML and it will construct a Table of Contents.</p><p>Let's dive in!</p> <li><p><strong>Table of Contents</strong></p><li>Background<br><li>Heading Example</li><li>What is the purpose of a table of contents?</li></li><li>Code<br><li>Load the HTML<br><li>Using PHP 8.4</li></li><li>Parse the HTML<br><li>PHP 8.4 querySelectorAll</li></li><li>Recursive looping<br><li><br><li><br><li>Missing content</li></li></li></li><li>Converting to HTML</li></li><li>Semantic Correctness<br><li>ePub Example</li><li>Split the difference with a menu</li><li>Where should the heading go?</li></li><li>Conclusion</li></li> <p><strong>Background</strong></p><p>HTML has <a href="https://html.spec.whatwg.org/multipage/sections.html#the-h1,-h2,-h3,-h4,-h5,-and-h6-elements" rel="nofollow noopener noreferrer" target="_blank">six levels of headings</a>1 - <code>&lt;h1&gt;</code> is the main heading for content, <code>&lt;h2&gt;</code> is a sub-heading, <code>&lt;h3&gt;</code> is a sub-sub-heading, and so on.</p><p>Together, they form a hierarchy.</p><p><strong>Heading Example</strong></p><p>HTML headings are expected to be used a bit like this (I've nested this example so you can see the hierarchy):</p><pre><code>&lt;h1&gt;The Theory of Everything&lt;/h1&gt; &lt;h2&gt;Experiments&lt;/h2&gt; &lt;h3&gt;First attempt&lt;/h3&gt; &lt;h3&gt;Second attempt&lt;/h3&gt; &lt;h2&gt;Equipment&lt;/h2&gt; &lt;h3&gt;Broken equipment&lt;/h3&gt; &lt;h4&gt;Repaired equipment&lt;/h4&gt; &lt;h3&gt;Working Equipment&lt;/h3&gt;…</code></pre><p><strong>What is the purpose of a table of contents?</strong></p><p>Wayfinding. On a long document, it is useful to be able to see an overview of the contents and then immediately navigate to the desired location.</p><p>The ToC has to provide a hierarchical view of all the headings and then link to them.</p><p><strong>Code</strong></p><p>I'm running this as part of a WordPress plugin. You may need to adapt it for your own use.</p><p><strong>Load the HTML</strong></p><p>This uses <a href="https://www.php.net/manual/en/class.domdocument.php" rel="nofollow noopener noreferrer" target="_blank">PHP's DOMdocument</a>. I've manually added a <code>UTF-8</code> header so that Unicode is preserved. If your HTML already has that, you can remove the addition from the code.</p><pre><code>// Load it into a DOM for manipulation$dom = new DOMDocument();// Suppress warnings about HTML errorslibxml_use_internal_errors( true );// Force UTF-8 support$dom-&gt;loadHTML( "&lt;!DOCTYPE html&gt;&lt;html&gt;&lt;head&gt;&lt;meta charset=UTF-8&gt;&lt;/head&gt;&lt;body&gt;" . $content, LIBXML_NOERROR | LIBXML_NOWARNING );libxml_clear_errors();</code></pre><p><strong>Using PHP 8.4</strong></p><p>The latest version of PHP contains <a href="https://www.php.net/manual/en/class.dom-htmldocument.php" rel="nofollow noopener noreferrer" target="_blank">a better HTML-aware DOM</a>. It can be used like this:</p><pre><code>$dom = Dom\HTMLDocument::createFromString( $content, LIBXML_NOERROR , "UTF-8" );</code></pre><p><strong>Parse the HTML</strong></p><p>It is not a good idea to use Regular Expressions to parse HTML - no matter how well-formed you think it is. Instead, use <a href="https://www.php.net/manual/en/class.domxpath.php" rel="nofollow noopener noreferrer" target="_blank">XPath</a> to extract data from the DOM.</p><pre><code>// Parse with XPath$xpath = new DOMXPath( $dom );// Look for all h* elements$headings = $xpath-&gt;query( "//h1 | //h2 | //h3 | //h4 | //h5 | //h6" );</code></pre><p>This produces an array with all the heading elements in the order they appear in the document.</p><p><strong>PHP 8.4 querySelectorAll</strong></p><p>Rather than using XPath, modern versions of PHP can use <a href="https://www.php.net/manual/en/dom-parentnode.queryselectorall.php" rel="nofollow noopener noreferrer" target="_blank">querySelectorAll</a>:</p><pre><code>$headings = $dom-&gt;querySelectorAll( "h1, h2, h3, h4, h5, h6" );</code></pre><p><strong>Recursive looping</strong></p><p>This is a bit knotty. It produces a nested array of the elements, their <code>id</code> attributes, and text. The end result should be something like:</p><pre><code>array ( array ( 'text' =&gt; '&lt;h2&gt;Table of Contents&lt;/h2&gt;', 'raw' =&gt; true, ), array ( 'text' =&gt; 'The Theory of Everything', 'id' =&gt; 'the-theory-of-everything', 'children' =&gt; array ( array ( 'text' =&gt; 'Experiments', 'id' =&gt; 'experiments', 'children' =&gt; array ( array ( 'text' =&gt; 'First attempt', 'id' =&gt; 'first-attempt', ), array ( 'text' =&gt; 'Second attempt', 'id' =&gt; 'second-attempt',</code></pre><p>The code is moderately complex, but I've commented it as best as I can.</p><pre><code>// Start an array to hold all the headings in a hierarchy$root = [];// Add an h2 with the title$root[] = [ "text" =&gt; "&lt;h2&gt;Table of Contents&lt;/h2&gt;", "raw" =&gt; true, "children" =&gt; []];// Stack to track current hierarchy level$stack = [&amp;$root]; // Loop through the headingsforeach ($headings as $heading) { // Get the information // Expecting &lt;h2 id="something"&gt;Text&lt;/h2&gt; $element = $heading-&gt;nodeName; // e.g. h2, h3, h4, etc $text = trim( $heading-&gt;textContent ); $id = $heading-&gt;getAttribute( "id" ); // h2 becomes 2, h3 becomes 3 etc $level = (int) substr($element, 1); // Get data from element $node = array( "text" =&gt; $text, "id" =&gt; $id , "children" =&gt; [] ); // Ensure there are no gaps in the heading hierarchy while ( count( $stack ) &gt; $level ) { array_pop( $stack ); } // If a gap exists (e.g., h4 without an immediately preceding h3), create placeholders while ( count( $stack ) &lt; $level ) { // What's the last element in the stack? $stackSize = count( $stack ); $lastIndex = count( $stack[ $stackSize - 1] ) - 1; if ($lastIndex &lt; 0) { // If there is no previous sibling, create a placeholder parent $stack[$stackSize - 1][] = [ "text" =&gt; "", // This could have some placeholder text to warn the user? "children" =&gt; [] ]; $stack[] = &amp;$stack[count($stack) - 1][0]['children']; } else { $stack[] = &amp;$stack[count($stack) - 1][$lastIndex]['children']; } } // Add the node to the current level $stack[count($stack) - 1][] = $node; $stack[] = &amp;$stack[count($stack) - 1][count($stack[count($stack) - 1]) - 1]['children'];}</code></pre><p><strong>Missing content</strong></p><p>The trickiest part of the above is dealing with missing elements in the hierarchy. If you're <em>sure</em> you don't ever skip from an <code>&lt;h3&gt;</code> to an <code>&lt;h6&gt;</code>, you can get rid of some of the code dealing with that edge case.</p><p><strong>Converting to HTML</strong></p><p>OK, there's a hierarchical array, how does it become HTML?</p><p>Again, a little bit of recursion:</p><pre><code>function arrayToHTMLList( $array, $style = "ul" ){ $html = ""; // Loop through the array foreach( $array as $element ) { // Get the data of this element $text = $element["text"]; $id = $element["id"]; $children = $element["children"]; $raw = $element["raw"] ?? false; if ( $raw ) { // Add it to the HTML without adding an internal link $html .= "&lt;li&gt;{$text}"; } else { // Add it to the HTML $html .= "&lt;li&gt;&lt;a href=#{$id}&gt;{$text}&lt;/a&gt;"; } // If the element has children if ( sizeof( $children ) &gt; 0 ) { // Recursively add it to the HTML $html .= "&lt;{$style}&gt;" . arrayToHTMLList( $children, $style ) . "&lt;/{$style}&gt;"; } } return $html;}</code></pre><p><strong>Semantic Correctness</strong></p><p>Finally, what should a table of contents look like in HTML? There is no <code>&lt;toc&gt;</code> element, so what is most appropriate?</p><p><strong>ePub Example</strong></p><p>Modern eBooks use the ePub standard which is based on HTML. Here's how <a href="https://kb.daisy.org/publishing/docs/navigation/toc.html" rel="nofollow noopener noreferrer" target="_blank">an ePub creates a ToC</a>.</p><pre><code>&lt;nav role="doc-toc" epub:type="toc" id="toc"&gt;&lt;h2&gt;Table of Contents&lt;/h2&gt;&lt;ol&gt; &lt;li&gt; &lt;a href="s01.xhtml"&gt;A simple link&lt;/a&gt; &lt;/li&gt; …&lt;/ol&gt;&lt;/nav&gt;</code></pre><p>The modern(ish) <code>&lt;nav&gt;</code> element!</p><blockquote><p>The nav element represents a section of a page that links to other pages or to parts within the page: a section with navigation links. <a href="https://html.spec.whatwg.org/multipage/sections.html#the-nav-element" rel="nofollow noopener noreferrer" target="_blank">HTML Specification</a></p></blockquote><p>But there's a slight wrinkle. The ePub example above use <code>&lt;ol&gt;</code> an ordered list. The HTML example in the spec uses <code>&lt;ul&gt;</code> an <em>un</em>ordered list.</p><p>Which is right? Well, that depends on whether you think the contents on your page should be referred to in order or not. There is, however, a secret third way.</p><p><strong>Split the difference with a menu</strong></p><p>I decided to use <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/menu" rel="nofollow noopener noreferrer" target="_blank">the <code>&lt;menu&gt;</code> element</a> for my navigation. It is semantically the same as <code>&lt;ul&gt;</code> but just feels a bit closer to what I expect from navigation. Feel free to argue with me in the comments.</p><p><strong>Where should the heading go?</strong></p><p>I've put the title of the list into the list itself. That's valid HTML and, if my understanding is correct, should announce itself as the title of the navigation element to screen-readers and the like.</p><p><strong>Conclusion</strong></p><p>I've used <em>slightly</em> more heading in this post than I would usually, but hopefully the Table of Contents at the top demonstrates how this works.</p><p>If you want to reuse this code, I consider it too trivial to licence. But, if it makes you happy, you can treat it as MIT.</p><p>Thoughts? Comments? Feedback? Drop a note in the box.</p> <ol start="0"><li><p>Too long really, but who can be bothered to edit?&nbsp;↩︎</p></li><li><p>Although <a href="https://www.nme.com/news/music/paul-mccartney-12-1188735" rel="nofollow noopener noreferrer" target="_blank">Paul McCartney disagrees</a>.&nbsp;↩︎</p></li></ol> <p><a rel="nofollow noopener noreferrer" class="hashtag u-tag u-category" href="https://shkspr.mobi/blog/tag/howto/" target="_blank">#HowTo</a> <a rel="nofollow noopener noreferrer" class="hashtag u-tag u-category" href="https://shkspr.mobi/blog/tag/html/" target="_blank">#HTML</a> <a rel="nofollow noopener noreferrer" class="hashtag u-tag u-category" href="https://shkspr.mobi/blog/tag/php/" target="_blank">#php</a></p>
ResearchBuzz: Firehose<p>Hongkiat: Running Large Language Models (LLMs) Locally with LM Studio. “Running large language models (LLMs) locally with tools like LM Studio or Ollama has many advantages, including privacy, lower costs, and offline availability. However, these models can be resource-intensive and require proper optimization to run efficiently. In this article, we will walk you through optimizing your […]</p><p><a href="https://rbfirehose.com/2025/03/25/hongkiat-running-large-language-models-llms-locally-with-lm-studio/" class="" rel="nofollow noopener noreferrer" target="_blank">https://rbfirehose.com/2025/03/25/hongkiat-running-large-language-models-llms-locally-with-lm-studio/</a></p>
Kevin Darty<p>How GitHub engineers learn new codebases</p><p><a href="https://hachyderm.io/tags/Code" class="mention hashtag" rel="tag">#<span>Code</span></a> <a href="https://hachyderm.io/tags/Learning" class="mention hashtag" rel="tag">#<span>Learning</span></a> <a href="https://hachyderm.io/tags/HowTo" class="mention hashtag" rel="tag">#<span>HowTo</span></a> <a href="https://hachyderm.io/tags/Coding" class="mention hashtag" rel="tag">#<span>Coding</span></a> <a href="https://hachyderm.io/tags/Programming" class="mention hashtag" rel="tag">#<span>Programming</span></a> <a href="https://hachyderm.io/tags/SoftwareDevelopment" class="mention hashtag" rel="tag">#<span>SoftwareDevelopment</span></a> <a href="https://hachyderm.io/tags/AI" class="mention hashtag" rel="tag">#<span>AI</span></a> <a href="https://hachyderm.io/tags/GitHubCopilot" class="mention hashtag" rel="tag">#<span>GitHubCopilot</span></a></p><p><a href="https://github.blog/developer-skills/application-development/how-github-engineers-learn-new-codebases/" target="_blank" rel="nofollow noopener noreferrer" translate="no"><span class="invisible">https://</span><span class="ellipsis">github.blog/developer-skills/a</span><span class="invisible">pplication-development/how-github-engineers-learn-new-codebases/</span></a></p>
windowsCult<p>To keep your Mac running smoothly, using a reliable cleaner app can help free up storage, improve performance, and maintain system health. Here are some of the best free Mac cleaner apps to optimize your Mac. <a href="https://www.techaipost.com/free-mac-cleaner-apps/" rel="nofollow noopener noreferrer" translate="no" target="_blank"><span class="invisible">https://www.</span><span class="ellipsis">techaipost.com/free-mac-cleane</span><span class="invisible">r-apps/</span></a> <a href="https://flipboard.social/tags/mac" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>mac</span></a> <a href="https://flipboard.social/tags/optimize" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>optimize</span></a> <a href="https://flipboard.social/tags/apple" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>apple</span></a> <a href="https://flipboard.social/tags/MacBookPro" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>MacBookPro</span></a> <a href="https://flipboard.social/tags/howto" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>howto</span></a> <a href="https://flipboard.social/tags/Tech" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>Tech</span></a> <a href="https://flipboard.social/tags/technology" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>technology</span></a> <a href="https://flipboard.social/tags/techterms" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>techterms</span></a></p>
Datenwolke 🛡️<p>Wie zur Hoelle bekomme ich das Qt SDK geladen? Ich wollte fuer <a href="https://social.tchncs.de/tags/KDE" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>KDE</span></a> etwas programmieren, bekommen aber nur die kostenpflichtige Version "Free Evaluation" zum Download angeboten. Ein Konto habe ich auch schon erstellt, aber wo zum Henker ist Download??? Oder gibt es keine freie SDK mehr...<br>Ich verstehe es nicht, bitte um Hilfe.</p><p><a href="https://social.tchncs.de/tags/qt" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>qt</span></a> <a href="https://social.tchncs.de/tags/sdk" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>sdk</span></a> <a href="https://social.tchncs.de/tags/download" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>download</span></a> <a href="https://social.tchncs.de/tags/howto" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>howto</span></a> <a href="https://social.tchncs.de/tags/help" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>help</span></a></p>
Jools [Friendica]<p>Nachdem ich nun eine PeerTube-Instanz gefunden habe, dachte ich mir, ich nehme doch mal schnell ein kurzes Video auf für die neuen User, die sich das erste Mal <b>bei einer bestehenden Friendica-Instanz</b> registrieren und dann vor einer leeren Timeline stehen...</p><p><br>Das Video gibt es bei clip.place, einer PeerTube-Instanz und darf gerne geteilt werden.</p><p><br><b>Link:</b> <a href="https://clip.place/w/9mH7RduEWaBhZBYxzycstG" rel="nofollow noopener noreferrer" target="_blank">Friendica - Timeline mit Inhalten füllen</a></p><p><br><a href="https://missocial.de/search?tag=Fediverse" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>Fediverse</span></a>, <a href="https://missocial.de/search?tag=Friendica" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>Friendica</span></a>, <a href="https://missocial.de/search?tag=Anleitung" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>Anleitung</span></a>, <a href="https://missocial.de/search?tag=Tutorial" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>Tutorial</span></a>, <a href="https://missocial.de/search?tag=Timeline" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>Timeline</span></a>, <a href="https://missocial.de/search?tag=Video" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>Video</span></a>, <a href="https://missocial.de/search?tag=HowTo" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>HowTo</span></a>, <a href="https://missocial.de/search?tag=NeuHier" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>NeuHier</span></a></p>
ResearchBuzz: Firehose<p>Lifehacker: How to Take Photos on iOS Without All the Post-Processing Junk. “It’s worth noting that it’s difficult to get absolutely zero processing on any smartphone camera. There’s always some amount of interpretation of raw data in order to display it. What we want to minimize here is how much your phone makes decisions about the ‘right’ way your photos should look—decisions like […]</p><p><a href="https://rbfirehose.com/2025/03/22/lifehacker-how-to-take-photos-on-ios-without-all-the-post-processing-junk/" class="" rel="nofollow noopener noreferrer" target="_blank">https://rbfirehose.com/2025/03/22/lifehacker-how-to-take-photos-on-ios-without-all-the-post-processing-junk/</a></p>
Kevin Karhan :verified:<p><span class="h-card" translate="no"><a href="https://jorts.horse/@kobilacroix" class="u-url mention" rel="nofollow noopener noreferrer" target="_blank">@<span>kobilacroix</span></a></span> Maybe I should do that.</p><ul><li>Problem is it's basically impossible to get a filming permit in most supermarkets, but worst case I guess <a href="https://infosec.space/tags/Pinta" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>Pinta</span></a>, a <a href="https://infosec.space/tags/Screenrecorder" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>Screenrecorder</span></a> and my <a href="https://infosec.space/tags/Headset" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>Headset</span></a> will do...</li></ul><p>It's actually simple but yeah, someone should do a quick <a href="https://infosec.space/tags/HowTo" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>HowTo</span></a> and write some <a href="https://infosec.space/tags/docs" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#<span>docs</span></a>...</p><p>Q: You'd be interested in a collab on that?</p>
Interesting Links<p><strong><a href="https://blog.zgp.org/turning-off-browser-ad-features-from-the-command-line/" rel="nofollow noopener noreferrer" target="_blank">turning off browser ad features from the command line</a></strong></p><p><a href="https://bookmarks.kvibber.com/tagged/HowTo" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#HowTo</a> <a href="https://bookmarks.kvibber.com/tagged/privacy" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#privacy</a> <a href="https://bookmarks.kvibber.com/tagged/Firefox" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#Firefox</a> <a href="https://bookmarks.kvibber.com/tagged/Chrome" class="mention hashtag" rel="nofollow noopener noreferrer" target="_blank">#Chrome</a></p>
The IT Blog<p><strong>How to set up Navidrome for MP3 Streaming on a RaspberryPi</strong></p><p>Recently I noticed that I hardly ever listen my MP3 music collection – mainly because I don’t like my music players (both on mobile and on the desktop). So, let’s look for a nicer player!</p><p>I had only two constraints: 1) it should be able to use the files from OneDrive and 2) it should be able to cache them (in case of no connectivity). And as I went through the candidates, I stumbled across <a href="https://www.navidrome.org/" rel="nofollow noopener noreferrer" target="_blank">Navidrome</a>:</p><blockquote><p>Navidrome allows you to enjoy your music collection from anywhere, by making it available through a modern Web UI and through a wide range of third-party compatible mobile apps, for both iOS and Android devices.</p></blockquote><p>Navidrome also supports Playlists and Internet-Radio! Nice. So why not let it run on a RaspberryPi at home and make it available through my VPN? But would I have enough RAM left? I just tried!</p><p></p><p><strong>TL;DR:</strong> RAM / Memory requirements: ~40 MB</p><p><strong>Installing</strong></p><p>Don’t forget to simply <a href="https://www.navidrome.org/docs/installation/docker/" rel="nofollow noopener noreferrer" target="_blank">checkout the documentation about Installation</a> at the Navidrome site!</p><p><strong>Install Samba and mount Music</strong></p><p>Navidrome can only stream from a local file source. So, let’s mount the music from the NAS.</p> <pre>sudo apt-get install samba-common smbclient samba-common-bin smbclient cifs-utilssudo mkdir /mnt/music</pre> <p>Mount the NAS directory on startup:</p> <pre>sudo nano /etc/fstab//diskstation/music /mnt/music cifs user=...,pass=...,iocharset=utf8,rw,uid=1000,gid=1000 0 0</pre> <p><em>uid </em>and <em>gid </em>should be the same as your pi user’s uid/gid. Well <a href="https://www.navidrome.org/docs/usage/security" rel="nofollow noopener noreferrer" target="_blank">according to the documentation</a>, it would be better to run Navidrome as its own user, just ensure that the user has read permissions on the music folder:</p> <pre>$ iduid=1000(pi) gid=1000(pi) groups=1000(pi),4(adm), .....</pre> <p>Then just mount:</p> <pre>sudo mount -a</pre> <p>If you want to put the credentials into a separate file:</p> <pre>nano ~/.smbcredentialsusername=...password=...chmod 600 ~/.smbcredentials</pre> <p>And change the entry in <code>/etc/fstab</code> to:</p> <pre>//diskstation/music /mnt/music cifs credentials=/home/pi/.smbcredentials,...</pre> <p>I find it quite handy to reboot the RaspberryPi at this stage to ensure that mounting on startup REALLY works.</p><p><strong>Install Docker</strong></p> <pre>curl -sSL https://get.docker.com | shsudo usermod -aG docker $USER</pre> <p>Log out and back in after installing docker.</p><p><strong>Install Navidrome</strong></p><p>I install Navidrome in my home directory. This may not be the best choice, feel free to change it to suit your needs.</p> <pre>mkdir -p ~/navidrome/datamkdir -p ~/navidrome/backup</pre> <p>Create a <code>~/navidrome/compose.yaml</code>:</p> <pre># check the options in the Docs: https://www.navidrome.org/docs/usage/configuration-options/#available-optionsservices: navidrome: image: deluan/navidrome:latest user: 1000:1000 ports: - "4533:4533" restart: unless-stopped environment: ND_SCANNER_ENABLED: true ND_SCANNER_SCHEDULE: "0 19 * * *" ND_SCANNER_SCANONSTARTUP: true ND_LOGLEVEL: info ND_BASEURL: "" ND_LASTFM_APIKEY: ... ND_LASTFM_SECRET: ... ND_SPOTIFY_ID: ... ND_SPOTIFY_SECRET: ... ND_BACKUP_PATH: /backup ND_BACKUP_SCHEDULE: "0 20 * * *" ND_BACKUP_COUNT: 7 volumes: - "/home/pi/navidrome/data:/data" - "/home/pi/navidrome/backup:/backup" - "/mnt/music:/music:ro"</pre> <p>Instead of putting the configuration into the <code>compose.yaml</code>, you could also use a config file. Checkout <a href="https://www.navidrome.org/docs/usage/configuration-options/" rel="nofollow noopener noreferrer" target="_blank">the documentation</a> for it (I somehow just put it into the <code>compose.yaml</code> without special reason). Also refer to the <a href="https://www.navidrome.org/docs/usage/external-integrations/" rel="nofollow noopener noreferrer" target="_blank">excellent documentation</a> for how to get the <strong>API credentials</strong> for LastFM and Spotify.</p><p><strong>(Re)Start Navidrome</strong></p> <pre>cd ~/navidromedocker compose downdocker compose up -d --remove-orphans</pre> <p>And after a successfull start, Navidrome should be available under <code>&lt;hostname&gt;:4533</code>.</p><p><strong>Logs</strong></p><p>If you need to check the logs (because something is going wrong):</p> <pre>docker compose logs</pre> <p><strong>Client</strong></p><p>As mobile client I currently favour <a href="https://www.symfonium.app/" rel="nofollow noopener noreferrer" target="_blank"><strong>Symfonium</strong></a>. It looks pretty nice and the caching mechanism looks good so far. Nothing overly fancy – just simple enough for me. Other apps are <a href="https://www.navidrome.org/docs/overview/#apps" rel="nofollow noopener noreferrer" target="_blank">listed on the Navidrome page</a> and as Navidrome supports the <a href="https://airsonic.github.io" rel="nofollow noopener noreferrer" target="_blank">Airsonic API</a>, you can use <a href="https://airsonic.github.io/docs/apps/" rel="nofollow noopener noreferrer" target="_blank">any Airsonic compatible player</a> as well.</p><p>Have fun!</p><p><a href="https://www.locked.de/how-to-set-up-navidrome-for-mp3-streaming/" rel="nofollow noopener noreferrer" translate="no" target="_blank"><span class="invisible">https://www.</span><span class="ellipsis">locked.de/how-to-set-up-navidr</span><span class="invisible">ome-for-mp3-streaming/</span></a><br><a rel="nofollow noopener noreferrer" class="hashtag u-tag u-category" href="https://www.locked.de/tag/howto/" target="_blank">#HowTo</a> <a rel="nofollow noopener noreferrer" class="hashtag u-tag u-category" href="https://www.locked.de/tag/mp3/" target="_blank">#MP3</a> <a rel="nofollow noopener noreferrer" class="hashtag u-tag u-category" href="https://www.locked.de/tag/music/" target="_blank">#music</a> <a rel="nofollow noopener noreferrer" class="hashtag u-tag u-category" href="https://www.locked.de/tag/musicstreaming/" target="_blank">#MusicStreaming</a> <a rel="nofollow noopener noreferrer" class="hashtag u-tag u-category" href="https://www.locked.de/tag/navidrome/" target="_blank">#Navidrome</a> <a rel="nofollow noopener noreferrer" class="hashtag u-tag u-category" href="https://www.locked.de/tag/raspberrypi/" target="_blank">#RaspberryPi</a> <a rel="nofollow noopener noreferrer" class="hashtag u-tag u-category" href="https://www.locked.de/tag/selfhosting/" target="_blank">#selfhosting</a></p>