<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/">
  <channel>
    <title>Blog entries :: mwop.net</title>
    <description>Blog entries :: mwop.net</description>
    <pubDate>Fri, 18 Sep 2026 11:30:10 -0500</pubDate>
    <generator>Laminas_Feed_Writer 2 (https://getlaminas.org)</generator>
    <link>https://mwop.net/blog/</link>
    <atom:link rel="self" type="application/rss+xml" href="https://mwop.net/blog/rss.xml"/>
    <item>
      <title>Web&amp;shy;men&amp;shy;tion support</title>
      <pubDate>Fri, 18 Sep 2026 11:30:10 -0500</pubDate>
      <link>https://mwop.net/blog/2026-09-18-webmentions.html</link>
      <guid>https://mwop.net/blog/2026-09-18-webmentions.html</guid>
      <author>contact@mwop.net (Matthew Weier O'Phinney)</author>
      <dc:creator>Matthew Weier O'Phinney</dc:creator>
      <content:encoded><![CDATA[<p>I've known about <a href="https://indieweb.org/Webmention">webmentions</a> for years, as well as <a href="https://microformats.org">microformats</a>; I've even included microformats in my markup for probably close to a decade at this point. But accepting and sending webmentions, while it seemed like a great idea, just never really made it to my priority list.</p>
<p>Until it did.</p>


<p>Inspired by <a href="https://www.jamestitcumb.com/posts/webmentions" class="u-in-reply-to">James Titcumb</a> and <a href="https://godless-internets.org/2026/08/27/critique-of-microformats2" class="in-reply-to">Owls</a>, I started investigating how to implement webmentions, and ended up going down the rabbit hole myself.</p>
<p>There has long been a <a href="https://packagist.org/packages/mf2/mf2">PHP API for Microformats (php-mf2)</a>.  It's not been updated in 4 years — largely because it's complete — and uses PCRE for finding microformats and validating URIs. Here's the thing: the last two releases of PHP (8.4 and 8.5 at the time I write this) have included some amazing features that make things like this both far simpler and  more accurate. These include the new HTML5 parser included in PHP 8.4 — which even provides <code>querySelector()</code> and <code>querySelectorAll()</code> implementations — and the <a href="https://www.php.net/manual/en/book.uri.php">Uri extension</a> included in PHP 8.5, which provides robust, standards-based URL parsing and validation.</p>
<p>Add in things like <a href="https://www.php-fig.org/psr/psr-18/">PSR-18's HTTP Client</a>, and it seemed possible to create a pretty minimal library that gives full-featured support for both microformats and webmentions.</p>
<p>So, I decided to try my hand at it.</p>
<p>I'll likely open source the libraries I created (one for parsing microformats, another for sending and receiving webmentions), but I want to wait until I've ironed out any edge cases. While I've tested against the various resources that <a href="https://webmention.rocks">webmention.rocks</a> provides, as well as the <a href="https://microformats.org">microformats website</a>, I'm sure that I'll be observing some oddities in the wild. But I have webmention receiving in place, with microformats discovery for identifying the type of webmention sent to my site. I have also setup a post-publication process for parsing my own content for links, and performing webmention discovery and sending. I want these all to run for a while to find what is working and what isn't in the real world.</p>
<p>In the meantime, feel free to send webmentions to my <a href="/blog">blog posts</a>, <a href="/art">art gallery images</a>, or <a href="/now">Now pages</a>. Just like my comments, I moderate all webmentions before publishing them (someday I'll blog about how I accomplished that as well).</p>
<h4>Update</h4>
<p>I immediately discovered an error in how I was combing <em>my own content</em> for potential links to which to send webmentions when I first published this! Hopefully I have that corrected now, and folks will get some mentions from this post!</p>


<div class="h-entry">
    <img class="u-photo photo" width="50" src="https://mwop.net/images/favicon/favicon.svg" alt="matthew">
    <a class="u-url u-uid p-name" href="https://mwop.net/blog/2026-09-18-webmentions.html">Web&amp;shy;men&amp;shy;tion support</a> was originally
    published <time class="dt-published" datetime="2026-09-18T10:12:40-05:00">18 September 2026</time>
    on <a href="https://mwop.net">https://mwop.net</a> by
    <a rel="author" class="p-author" href="https://mwop.net">Matthew Weier O&#039;Phinney</a>.
</div>
]]></content:encoded>
      <slash:comments>0</slash:comments>
    </item>
    <item>
      <title>HTML Hyphenation Hints</title>
      <pubDate>Mon, 31 Aug 2026 18:34:29 -0500</pubDate>
      <link>https://mwop.net/blog/2026-08-31-html-shy.html</link>
      <guid>https://mwop.net/blog/2026-08-31-html-shy.html</guid>
      <author>contact@mwop.net (Matthew Weier O'Phinney)</author>
      <dc:creator>Matthew Weier O'Phinney</dc:creator>
      <content:encoded><![CDATA[<p>I recently was troubleshooting how to force the browser to hyphenate a PHP class name, and discovered something new.</p>
<p>The HTML entity <code>&amp;shy;</code> is a &quot;soft hyphen&quot;; it won't display unless the browser decides to introduce a line wrap at that point.</p>
<p>It's shy like that.</p>




<div class="h-entry">
    <img class="u-photo photo" width="50" src="https://mwop.net/images/favicon/favicon.svg" alt="matthew">
    <a class="u-url u-uid p-name" href="https://mwop.net/blog/2026-08-31-html-shy.html">HTML Hyphenation Hints</a> was originally
    published <time class="dt-published" datetime="2026-08-31T18:34:29-05:00">31 August 2026</time>
    on <a href="https://mwop.net">https://mwop.net</a> by
    <a rel="author" class="p-author" href="https://mwop.net">Matthew Weier O&#039;Phinney</a>.
</div>
]]></content:encoded>
      <slash:comments>0</slash:comments>
    </item>
    <item>
      <title>Nextcloud SSRF rules and internal address ranges</title>
      <pubDate>Tue, 07 Jul 2026 10:12:23 -0500</pubDate>
      <link>https://mwop.net/blog/2026-07-07-nextcloud-ssrf-and-internal-address-ranges.html</link>
      <guid>https://mwop.net/blog/2026-07-07-nextcloud-ssrf-and-internal-address-ranges.html</guid>
      <author>contact@mwop.net (Matthew Weier O'Phinney)</author>
      <dc:creator>Matthew Weier O'Phinney</dc:creator>
      <content:encoded><![CDATA[<p>I use <a href="https://nextcloud.com">Nextcloud</a>, and have used the <a href="https://apps.nextcloud.com/apps/news">Nextcloud News</a> app as my feed reader for a number of years.</p>
<p>Since moving all my hosting to a home lab, I noticed that Nextcloud News was unable to retrieve feeds from my own website, which was weird. Looking at the logs, I saw notes about &quot;host violates local access rules&quot;.</p>


<p>This was a DNS issue (it's always DNS), right? Well, kind of.</p>
<p>In order to help prevent <a href="https://owasp.org/www-community/attacks/Server_Side_Request_Forgery">SSRF attacks</a>, Nextcloud, by default, has protections against domains that resolve to internal IP address ranges. When I moved my sites to my homelab, I also setup DNS such that when on the local network, the services resolve to the local address range instead of the public external IP. This was the root of the problem.</p>
<p>Fortunately, there's a configuration setting for that:</p>
<pre><code data-lang="php" class="notranslate hljs"><span class="hljs-comment">// in the Nextcloud config.php:</span>
[ <span class="hljs-string">'allow_local_remote_servers'</span> =&gt; <span class="hljs-keyword">true</span> ]
</code></pre>
<p>After making that change and restarting Nextcloud, I was able to get it to resolve and access my feeds.</p>


<div class="h-entry">
    <img class="u-photo photo" width="50" src="https://mwop.net/images/favicon/favicon.svg" alt="matthew">
    <a class="u-url u-uid p-name" href="https://mwop.net/blog/2026-07-07-nextcloud-ssrf-and-internal-address-ranges.html">Nextcloud SSRF rules and internal address ranges</a> was originally
    published <time class="dt-published" datetime="2026-07-07T10:12:23-05:00">7 July 2026</time>
    on <a href="https://mwop.net">https://mwop.net</a> by
    <a rel="author" class="p-author" href="https://mwop.net">Matthew Weier O&#039;Phinney</a>.
</div>
]]></content:encoded>
      <slash:comments>0</slash:comments>
    </item>
    <item>
      <title>Musings on GenAI</title>
      <pubDate>Mon, 06 Jul 2026 16:00:00 -0500</pubDate>
      <link>https://mwop.net/blog/2026-07-06-musings-on-gen-ai.html</link>
      <guid>https://mwop.net/blog/2026-07-06-musings-on-gen-ai.html</guid>
      <author>contact@mwop.net (Matthew Weier O'Phinney)</author>
      <dc:creator>Matthew Weier O'Phinney</dc:creator>
      <content:encoded><![CDATA[<p><img src="https://mwop.net/images/art/thumbnails/1f177c9e-8c03-6e3e-8080-62f485bac900.png" alt="My AI web weight" title="My intheweights ranking" /></p>
<p>Evidently, the AI models trained on my internet activity, and I have thoughts.</p>


<hr />
<p>I recently saw some folks posting images like the above, linking to <a href="https://intheweights.com">intheweights.com</a>; the site allows you to put in a name, and then it analyzes the various models to see how much they have used that person's work to train them.</p>
<p>I evidently fall in the top 2% of sources on which they trained.</p>
<p>Now, this is not entirely surprising. I have done <em>a lot</em> of open source software development over the past couple decades, and have hundreds of thousands of lines of code up in GitHub that have been downloaded many 10s and 100s of millions of times. I've participated in newsgroups, mailing lists, forums, and standards bodies. I've written a lot of documentation, published a ton of blog articles, and co-authored books.</p>
<p>So, how do I feel about AI companies slurping it all up to train their models?</p>
<blockquote>
<p>There's <em>so much more</em> I could cover in this post. I know I'm not even touching on the environmental impacts, or the inability of AI companies to optimize code and models to consume fewer resources. That doesn't mean those topics are not important; they just weren't the ones top of mind as I wrote this. My apologies if I missed something you find important.</p>
</blockquote>
<h2>The copyright and attribution problem</h2>
<p>Most of my OSS work has used either a BSD, MIT, ASF, or Creative Commons license. The thing about these licenses is that they are permissive; they basically allow anybody to use them in any way, without restriction.</p>
<p>Well, I should say <em>almost</em> no restriction.</p>
<p>Most of these have an <em>attribution</em> clause: the work can be re-used and remixed, so long as <em>attribution</em> is given. This is generally something as simple as including copyright information when you redistribute code.</p>
<p>But here's the thing with generative AI: it doesn't do that. It simply spits out some code. It doesn't tell you where it came from, who wrote it, etc. In fact, it will tell you that the <em>generative AI tool</em> wrote it... and recent court rulings indicate that such code <em>cannot be copyrighted</em>.</p>
<p>This is not great from an ethical or legal point of view. Using generative AI means you're not attributing the work that informed and powered it.</p>
<h2>The reality of work in IT today</h2>
<p>All that said, I work for a software company, and, like basically all software companies today, there's a push to use AI to accelerate outcomes. And like many in the software industry, I have bills to pay, and can't just walk away.</p>
<p>So, I've been learning the ins-and-outs of generative AI, both for managing processes as well for doing development.</p>
<p>Unsurprisingly, I can point generative AI at a code base of mine, and it will generate code that is structurally similar to what I would have done by hand. And it will do it in a fraction of the time. It's fairly uncanny to prompt Claude Code with a change I want to implement, and have it generate tests, code, and templates that look pretty much how I would have written them. And to be honest, a lot of this is stuff I don't have time for: yes, they may be tools I maintain for doing my work or coordinating with my teams, but as a PM for two different brands, I simply don't have time for coding. Being able to write a specification of what I want to do, tell Claude Code to do it, and then go off to do the strategy and planning work that my employer expects of me is huge.</p>
<p>We're also using it as part of our process workflow within the various PM teams. We have MCP servers setup with access to a ton of our internal tools, which gives the agents we use for our PM processes a huge amount of data. And this data turns into signals that were really, really hard to get at before. Developing a business proposal  in the past required that I do weeks and weeks worth of competitive research, pricing research, reporting out of our CRM, scouring support and engineering tickets, and more — oftentimes to ultimately decide to table the idea. Today, I can fire off an agent to do some discovery, and take that work to develop a hypothesis for a product or support feature, and then agents will fire off to do more research, collating the information, raising questions for me to follow-up on with peers, and helping me identify if an idea has value we should follow-up on — often in hours or days.</p>
<p>With web search having gone to shit, and so many enterprise tools being opaque and requiring expert knowledge to use effectively, what AI agents and tools enable for me is tremendous.</p>
<h2>The workforce problem</h2>
<p>When it comes to coding, one thing that sticks out: I have been programming for literal decades. I know how to write a specification. Between that, and the fact that generative AI models trained on my literal code, I'm an ideal target for these tools, as what I write is perfectly tailored for them.</p>
<p>But here's the thing: how do <em>new</em>, <em>junior</em> developers get to that same stage?</p>
<p>In the past, we'd toss those specifications their way, give them tools to help them conform to coding standards guidelines, and do peer review of their work. These activities helped them <em>learn</em>. This was how we got a pipeline from junior to senior developers, by mentoring and training. If we cut out that stage, what will happen to the software industry once the senior developers of today retire?</p>
<h2>GenAI as an accessibility aide</h2>
<p>I mentioned the process changes where we're using GenAI. There's something I didn't talk about though, and it's pretty important.</p>
<p>I'm Autistic and have ADHD. One trait I have is that I see <em>all the steps</em> that need to happen to accomplish something, and quite often, that will overwhelm me. Business plans? One of the worst. I have to do web research, and that often leads into rabbit holes. I have to ask other people to run reports for me, or prepare estimates for me, and that means — ugh!  — waiting on somebody else, and the uncertainty of when I'll get the information I need pushes my anxiety up. Then there's trying to understand what information is relevant to the executive team. It's a lot of work. I can do it, I'm even good at it, but knowing what I have to do can lead me to freeze, until it becomes urgent, and then I'm panicking as I scramble to get it all done.</p>
<p>Even doing the weekly reports — sure, I've developed systems to capture that information in my Obsidian vault, but I still have to collate download statistics and make sense of them, and then locate the Confluence page for this week's report, edit it, and paste my material in. And even with all that, I have to also think about if the information is even useful, and if I'm communicating it correctly, because Autism and masking. And this happens every. Single. Week.</p>
<p>What does this have to do with AI?</p>
<p>Surprisingly, AI has acted as an <em>accessibility tool</em> for me.</p>
<p>I can task GenAI with doing something, and then go off and do <em>other</em> things. It allows me to let go of the plan from my head, because it's already written down, and the agents are doing the squirreling for me. Being able to free up this cognitive space means I'm less tired, and I'm more able to focus on what matters.</p>
<p>Those recurring tasks? As Larry Wall said, one sign of a good programmer is that they're <em>lazy</em>; the counterpoint is we'll spend hours and hours automating something that takes just a few minutes every now and then. But GenAI changes that; I can walk it through a process, and have it capture it as a repeatable skill.</p>
<p>Being able to focus on what matters, and still have energy at the end of the day? This makes a huge difference to my quality of life.</p>
<p>(I've rediscovered the joy of cooking, because I still have the ability to make decisions at the end of the day!)</p>
<h2>The GenAI paywall</h2>
<p>But for all of that, it's also creating an accessibility <em>issue</em>.</p>
<p>I got into open source in part because I did not need to pay for licenses in order to code software. I was able to download runtimes for free, and access manuals for free.</p>
<p>This may not seem like a big deal today, but back in the late 90s and early 00s, it was huge. I didn't need to fork out for ColdFusion, or Frontpage, or Dreamweaver. I didn't need a Microsoft NT license or IIS license. I could spin up Apache with mod_php on my computer, along with MySQL, and just start coding.</p>
<p>Here's the issue: GenAI tools <em>cost money</em>.</p>
<p>Sure, the plans seem cheap, and sure, there's even free thresholds. But the bills are coming in for the data centers used to train LLMs, and investors are starting to wonder when they'll see money back, and this is already leading to pricing changes; just this past month, Microsoft and Github changed from flat pricing plans to usage-based models, and many people discovered that using them was no longer tenable when bills went from $200 to sometimes tens of thousands.</p>
<p>Which leaves me in an interesting spot: GenAI tooling can make my work more accessible to my neurodivergent brain — but I have to <em>pay</em> for that, even though I have no control over how my brain works.</p>
<h2>The new build-vs-buy equation, and the death of OSS</h2>
<p>I mentioned above that I got into OSS in part due to the fact I didn't have to purchase licenses. I stayed because of community, and because I believe strongly that we all build things better when we do them together. You may be the most brilliant coder in your domain, but when you step out of it  —  implementing a message queue, working with encryption, adopting DevOps processes  — you'll benefit from reaching out to somebody with that experience to review.</p>
<p>Open Source Software commoditizes that. We all share our software, and we can all contribute to other people's software. We can stop reinventing the wheel, knowing somebody else, or some group of people, has done it already, and knows the domain better than we do.</p>
<p>For a company that consumes OSS, this can be critical. Your teams do not need to be experts of every technology they touch or implement; they can rely on OSS packages or frameworks or libraries to do the hard work.</p>
<p>The downside is that when a &quot;supply chain&quot; attack occurs on an OSS project, every piece of software in the world that depends on the project, whether or not it's OSS or commercial, now is vulnerable. I put &quot;supply chain&quot; in quotes deliberately: OSS is not a vendor, not a supplier, but <em>businesses treat it as such</em>. And that puts a lot of pressure on OSS developers, who are often unfunded or underfunded, and getting pressure from companies who depend on them, but will never pay them a dime.</p>
<p>But one benefit of OSS is the oft-cited parable of &quot;many eyes makes all bugs shallow.&quot; <em>Because</em> the source is openly available, and because the patching happens within a community, an OSS project is also often uniquely suited to rapid patching of security vulnerabilities.</p>
<p>AI turns all of this on its head.</p>
<p>Because LLMs are trained on OSS, it also means they are very good at generating code to solve the problems that OSS addresses. And because GenAI is currently relatively cheap compared to developers (I expect this to change, and we're already seeing it change!), the &quot;build vs buy&quot; equation has changed.</p>
<p>&quot;Buy&quot; in the &quot;build-vs-buy&quot; equation doesn't need to literally mean &quot;buy&quot;; it can also mean &quot;we're going to add this OSS dependency&quot;. When you add a dependency, you now have to monitor it for security vulnerabilities, and have processes in place to mitigate those. The more dependencies, the larger your security surface area.</p>
<p>And that means a lot of companies do a lot of review before they adopt an upstream dependency.</p>
<p>But now you can tell GenAI, &quot;please develop the functionality <em>X</em>; it should act like OSS project <em>Y</em> and give us the same public API to consume. Provide tests so we can maintain this going forward, and hook it into our static code and security analysis tooling.&quot; And GenAI will happily go and do that, you'll have a one-time token cost, and a small amount of ongoing token costs for periodic maintenance, and have eliminated an upstream dependency for yourself. Sounds like a win, right?</p>
<p>Except it comes at the expense of the OSS ecosystem.</p>
<p>Over time, we'll get more proprietary software that's created using GenAI, and the models won't have a growing corpus of OSS to work against.</p>
<p>And developers will increasingly need to rely on GenAI tooling to do basic programming, because there's nothing in the commons anymore to use. And that will depend on having privilege and money, excluding a whole class of potential upcoming software engineers from ever entering the workforce.</p>
<h2>So, what do you really think?</h2>
<p>I'm incredibly torn on the entire subject.</p>
<p>I hate the hype cycle behind GenAI, and the hand-waving at environmental, ethical, and societal concerns.</p>
<p>At the same time, the tooling has truly freed up time and literal energy for me, and helped me combat some of my worst executive dysfunction, and I see it as being a huge enabler for people.</p>
<p>In other words... it's like everything I've ever observed after decades in technology fields. And I wish it wasn't.</p>


<div class="h-entry">
    <img class="u-photo photo" width="50" src="https://mwop.net/images/favicon/favicon.svg" alt="matthew">
    <a class="u-url u-uid p-name" href="https://mwop.net/blog/2026-07-06-musings-on-gen-ai.html">Musings on GenAI</a> was originally
    published <time class="dt-published" datetime="2026-07-06T16:00:00-05:00">6 July 2026</time>
    on <a href="https://mwop.net">https://mwop.net</a> by
    <a rel="author" class="p-author" href="https://mwop.net">Matthew Weier O&#039;Phinney</a>.
</div>
]]></content:encoded>
      <slash:comments>0</slash:comments>
    </item>
    <item>
      <title>Determining if a reboot is required on Linux</title>
      <pubDate>Mon, 04 May 2026 08:35:08 -0500</pubDate>
      <link>https://mwop.net/blog/2026-05-04-reboot-required.html</link>
      <guid>https://mwop.net/blog/2026-05-04-reboot-required.html</guid>
      <author>contact@mwop.net (Matthew Weier O'Phinney)</author>
      <dc:creator>Matthew Weier O'Phinney</dc:creator>
      <content:encoded><![CDATA[<p>I've been using the construct <code>sudo run-parts /etc/update-motd.d/</code> to determine if recent system updates required a reboot.</p>
<p>Today I learned I can simply check for the existence of the file <code>/var/run/reboot-required</code>.</p>




<div class="h-entry">
    <img class="u-photo photo" width="50" src="https://mwop.net/images/favicon/favicon.svg" alt="matthew">
    <a class="u-url u-uid p-name" href="https://mwop.net/blog/2026-05-04-reboot-required.html">Determining if a reboot is required on Linux</a> was originally
    published <time class="dt-published" datetime="2026-05-04T08:35:08-05:00">4 May 2026</time>
    on <a href="https://mwop.net">https://mwop.net</a> by
    <a rel="author" class="p-author" href="https://mwop.net">Matthew Weier O&#039;Phinney</a>.
</div>
]]></content:encoded>
      <slash:comments>0</slash:comments>
    </item>
    <item>
      <title>PHP DateTime&amp;shy;Im&amp;shy;mut&amp;shy;able::&amp;shy;create&amp;shy;From&amp;shy;Format Reset Character</title>
      <pubDate>Thu, 16 Apr 2026 10:30:00 -0500</pubDate>
      <link>https://mwop.net/blog/2026-04-16-php-create-from-format-reset.html</link>
      <guid>https://mwop.net/blog/2026-04-16-php-create-from-format-reset.html</guid>
      <author>contact@mwop.net (Matthew Weier O'Phinney)</author>
      <dc:creator>Matthew Weier O'Phinney</dc:creator>
      <content:encoded><![CDATA[<p>I was recently building something that was taking date input from an HTML form field, and casting it to a PHP <code>DateTimeImmutable</code>. I was then comparing that to another date, and got thrown off during testing when I compared the resulting instance to <code>new DateTimeImmutable('today')</code>; the instances were not considered equal.</p>


<p>To recreate the conditions, you can try the following:</p>
<pre><code data-lang="php" class="notranslate hljs"><span class="hljs-variable">$date</span>     = <span class="hljs-string">'2016-06-16'</span>;
<span class="hljs-variable">$fromForm</span> = <span class="hljs-type">DateTimeImmutable</span>::<span class="hljs-property">createFromFormat</span>(<span class="hljs-string">'Y-m-d'</span>, <span class="hljs-variable">$date</span>);
<span class="hljs-variable">$today</span>    = <span class="hljs-keyword">new</span> <span class="hljs-type">DateTimeImmutable</span>(<span class="hljs-string">'today'</span>);
<span class="hljs-keyword">echo</span> <span class="hljs-variable">$fromForm</span> == <span class="hljs-variable">$today</span> <span class="hljs-operator">?</span> <span class="hljs-string">'Equal'</span> : <span class="hljs-string">'Not equal'</span>; <span class="hljs-comment">// outputs &quot;Not equal&quot;</span>
</code></pre>
<p>What's happening? Well, if you were to echo the results of each of <code>$fromForm-&gt;format('c')</code> and <code>$today-&gt;format('c')</code>, the difference is clear: the <code>$fromForm</code> value includes the <em>time</em> when the instance was created, while <code>$today</code> has the time set to midnight.</p>
<p>So, how do you zero out the time when using <code>createFromFormat()</code>?</p>
<p>It turns out that one of the format characters you can use is the <code>|</code> operator. When you include this at the end of your format string, any fields not included in the format are zero'ed out:</p>
<pre><code data-lang="php" class="notranslate hljs"><span class="hljs-variable">$fromForm</span> = <span class="hljs-type">DateTimeImmutable</span>::<span class="hljs-property">createFromFormat</span>(<span class="hljs-string">'Y-m-d|'</span>);
</code></pre>
<hr />
<h4>Reference</h4>
<ul>
<li><a href="https://www.php.net/manual/en/datetimeimmutable.createfromformat.php#datetimeimmutable.createfromformat.parameters">DateTime­Im­mut­able::­create­From­Format() Parameters</a></li>
</ul>


<div class="h-entry">
    <img class="u-photo photo" width="50" src="https://mwop.net/images/favicon/favicon.svg" alt="matthew">
    <a class="u-url u-uid p-name" href="https://mwop.net/blog/2026-04-16-php-create-from-format-reset.html">PHP DateTime&amp;shy;Im&amp;shy;mut&amp;shy;able::&amp;shy;create&amp;shy;From&amp;shy;Format Reset Character</a> was originally
    published <time class="dt-published" datetime="2026-04-16T10:30:00-05:00">16 April 2026</time>
    on <a href="https://mwop.net">https://mwop.net</a> by
    <a rel="author" class="p-author" href="https://mwop.net">Matthew Weier O&#039;Phinney</a>.
</div>
]]></content:encoded>
      <slash:comments>0</slash:comments>
    </item>
    <item>
      <title>SQL ENUM Modification</title>
      <pubDate>Wed, 08 Apr 2026 15:34:00 -0500</pubDate>
      <link>https://mwop.net/blog/2026-04-08-sql-enum-modification.html</link>
      <guid>https://mwop.net/blog/2026-04-08-sql-enum-modification.html</guid>
      <author>contact@mwop.net (Matthew Weier O'Phinney)</author>
      <dc:creator>Matthew Weier O'Phinney</dc:creator>
      <content:encoded><![CDATA[<p>I'm doing a little DB work recently, and needing to choose how to represent certain data in the database. For a few fields, ENUM would be the correct choice, but there's a possibility I would need to expand the ENUM later to add values.</p>
<p>My question: is this safe?</p>


<p>The short answer, in my research, is &quot;yes&quot;, but with caveats.</p>
<p>For Postgres, it's trivial; you can easily add values to ENUM types:</p>
<pre><code data-lang="sql" class="notranslate hljs"><span class="hljs-keyword">ALTER</span> TYPE some_previously_defined_enum <span class="hljs-keyword">ADD</span> VALUE '<span class="hljs-string">new-value</span>';
</code></pre>
<p>For MySQL, it's a bit more complex. ENUMs are defined within the table schema, and to change them, you use an <code>ALTER TABLE</code> statement:</p>
<pre><code data-lang="sql" class="notranslate hljs"><span class="hljs-keyword">ALTER TABLE</span> some_table
MODIFY some_previously_defined_enum <span class="hljs-property">ENUM</span>('<span class="hljs-string">value-1</span>','<span class="hljs-string">value-2</span>');
</code></pre>
<p>Essentially, you're <em>replacing</em> the definition. This is fine... so long as you don't change the order, or remove any previously defined value in the ENUM. In other words, <em>append</em> to the existing list if you want to safely change it.</p>


<div class="h-entry">
    <img class="u-photo photo" width="50" src="https://mwop.net/images/favicon/favicon.svg" alt="matthew">
    <a class="u-url u-uid p-name" href="https://mwop.net/blog/2026-04-08-sql-enum-modification.html">SQL ENUM Modification</a> was originally
    published <time class="dt-published" datetime="2026-04-08T15:34:00-05:00">8 April 2026</time>
    on <a href="https://mwop.net">https://mwop.net</a> by
    <a rel="author" class="p-author" href="https://mwop.net">Matthew Weier O&#039;Phinney</a>.
</div>
]]></content:encoded>
      <slash:comments>0</slash:comments>
    </item>
    <item>
      <title>CSS Grid Lanes</title>
      <pubDate>Tue, 07 Apr 2026 10:38:00 -0500</pubDate>
      <link>https://mwop.net/blog/2026-04-07-css-grid-lanes.html</link>
      <guid>https://mwop.net/blog/2026-04-07-css-grid-lanes.html</guid>
      <author>contact@mwop.net (Matthew Weier O'Phinney)</author>
      <dc:creator>Matthew Weier O'Phinney</dc:creator>
      <content:encoded><![CDATA[<p>I've been using the experimental &quot;<code>display: masonry</code>&quot; CSS for my gallery and a few other areas of my website for over a year (with a fallback to standard grid columns). However, I noticed in the last few months that my browser was no longer honoring it, and finally researched what happened.</p>
<p>It turns out it's been renamed to &quot;<code>display: grid-lanes</code>&quot; in the <a href="https://drafts.csswg.org/css-grid-3/#grid-lanes-layout">CSS Grid Level 3 specification</a>. Otherwise, everything else remains the same; continue using <code>grid-template-columns</code> and <code>grid-template-rows</code> as you did with the the masonry display.</p>
<p>Safari has it in preview already, while Firefox and Chrome-based browsers have it behind a flag. (On Chrome-based browsers, visit <code>chrome://flags</code>, and enable the &quot;css-grid-lanes-layout&quot; flag.)</p>




<div class="h-entry">
    <img class="u-photo photo" width="50" src="https://mwop.net/images/favicon/favicon.svg" alt="matthew">
    <a class="u-url u-uid p-name" href="https://mwop.net/blog/2026-04-07-css-grid-lanes.html">CSS Grid Lanes</a> was originally
    published <time class="dt-published" datetime="2026-04-07T10:38:00-05:00">7 April 2026</time>
    on <a href="https://mwop.net">https://mwop.net</a> by
    <a rel="author" class="p-author" href="https://mwop.net">Matthew Weier O&#039;Phinney</a>.
</div>
]]></content:encoded>
      <slash:comments>0</slash:comments>
    </item>
    <item>
      <title>Headless boot for Beelink EQ14</title>
      <pubDate>Mon, 23 Mar 2026 14:06:08 -0500</pubDate>
      <link>https://mwop.net/blog/2026-02-24-headless-boot-beelink-eq14.html</link>
      <guid>https://mwop.net/blog/2026-02-24-headless-boot-beelink-eq14.html</guid>
      <author>contact@mwop.net (Matthew Weier O'Phinney)</author>
      <dc:creator>Matthew Weier O'Phinney</dc:creator>
      <content:encoded><![CDATA[<p>A few months back, I purchased a Beelink EQ14 mini server for my homelab. One thing that has frustrated me has been that rebooting or even powering on... has required I have either my keyboard or my monitor plugged in (I haven't been able to determine exactly which one yet). This has made me reluctant to reboot, as I then have to switch my keyboard from my workstation over to the server, and plug the HDMI from one of my monitors into it. I hate it.</p>
<p>In browsing a number of forums, I saw one recommendation to switch the BIOS to use FastBoot.</p>
<p>~~Can confirm, works!~~</p>
<h4>Update</h4>
<p>While FastBoot helps, it doesn't entirely fix the issues. What I discovered was that the server was requiring my keyboard in order to boot; I tested this by rebooting the machine without cables, and plugging in only the keyboard.</p>
<p>Unfortunately, there are no BIOS settings to override this behavior. I dug up an old USB dongle for a presentation pointer, plugged that in, and voilá — it boots now. I suspect any USB HID dongle will likely work.</p>




<div class="h-entry">
    <img class="u-photo photo" width="50" src="https://mwop.net/images/favicon/favicon.svg" alt="matthew">
    <a class="u-url u-uid p-name" href="https://mwop.net/blog/2026-02-24-headless-boot-beelink-eq14.html">Headless boot for Beelink EQ14</a> was originally
    published <time class="dt-published" datetime="2026-02-24T10:09:08-06:00">24 February 2026</time>
    on <a href="https://mwop.net">https://mwop.net</a> by
    <a rel="author" class="p-author" href="https://mwop.net">Matthew Weier O&#039;Phinney</a>.
</div>
]]></content:encoded>
      <slash:comments>0</slash:comments>
    </item>
    <item>
      <title>Globbing files to pass to CLI command options</title>
      <pubDate>Wed, 18 Feb 2026 13:56:00 -0600</pubDate>
      <link>https://mwop.net/blog/2026-02-18-cli-options-with-globs.html</link>
      <guid>https://mwop.net/blog/2026-02-18-cli-options-with-globs.html</guid>
      <author>contact@mwop.net (Matthew Weier O'Phinney)</author>
      <dc:creator>Matthew Weier O'Phinney</dc:creator>
      <content:encoded><![CDATA[<p>I've been using Helm recently as part of a new product offering, and as a way to deploy my various websites. Helm allows providing <em>values</em> to the templates in a Helm chart via one or more <em>values</em> files, which are provided via the option <code>-f</code>. It's often useful to break these into several files, so you can do things like cover common values, and then environment- or namespace-specific values.</p>
<p>However, the <code>-f</code> option only accepts a single value, and doesn't recognize globs.</p>


<h2>The printf solution</h2>
<p>The solution is to pass the glob to <code>printf</code>, with the format <code>'-f %s '</code>. This will print out an option per file.</p>
<p>When in a terminal, this can be done using <code>printf</code> within a subshell. Now <em>how</em> you do that depends on the shell, because the <code>-f</code> in our format string can be interpreted as an option/flag to <code>printf</code> itself depending on the shell.</p>
<p>For bash, we can do this:</p>
<pre><code data-lang="bash" class="notranslate hljs">helm upgrade <span class="hljs-title">-n</span> qa . $(<span class="hljs-type">printf</span> -- <span class="hljs-string">'-f % '</span> *.values.yaml)
</code></pre>
<p>This is because <code>printf</code> in bash will emit an error for any unknown option/flag it encounters; the <code>--</code> tells the command when the end of all options/flags have been reached, so that it treats the remainder as arguments.</p>
<p>For fish, we don't need the <code>--</code>, as the <code>printf</code> implementation in fish doesn't accept arguments anyways:</p>
<pre><code data-lang="bash" class="notranslate hljs">helm upgrade <span class="hljs-title">-n</span> qa . $(<span class="hljs-type">printf</span> <span class="hljs-string">'-f % '</span> *.values.yaml)
</code></pre>
<h2>Makefile</h2>
<p>Of course, subshells in a <code>Makefile</code> require a little change as well. In a <code>Makefile</code>, I write the above as:</p>
<pre><code data-lang="txt" class="notranslate hljs">helm upgrade -n qa . $(shell printf -- '-f %' *.values.yaml)
</code></pre>
<p>(And since I also declare <code>SHELL=/bin/bash</code> at the top of my <code>Makefile</code>, I have to use the <code>--</code> trick here.)</p>


<div class="h-entry">
    <img class="u-photo photo" width="50" src="https://mwop.net/images/favicon/favicon.svg" alt="matthew">
    <a class="u-url u-uid p-name" href="https://mwop.net/blog/2026-02-18-cli-options-with-globs.html">Globbing files to pass to CLI command options</a> was originally
    published <time class="dt-published" datetime="2026-02-18T13:56:00-06:00">18 February 2026</time>
    on <a href="https://mwop.net">https://mwop.net</a> by
    <a rel="author" class="p-author" href="https://mwop.net">Matthew Weier O&#039;Phinney</a>.
</div>
]]></content:encoded>
      <slash:comments>0</slash:comments>
    </item>
  </channel>
</rss>
