<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="/styles/rss-style.xsl"?>

<rss version="2.0"
 xmlns:blogChannel="http://backend.userland.com/blogChannelModule"
>

<channel>
<title>troglodyne.net</title>
<link>http://troglodyne.net//programming?format=xml</link>
<description>troglodyne.net : /programming</description>
<language>en</language>
<pubDate>2026-04-20T00:14:28</pubDate>
<lastBuildDate>2026-04-20T00:14:28</lastBuildDate>

<image>
<title>troglodyne.net</title>
<url>/favicon.ico</url>
<link>http://troglodyne.net</link>
<width>32</width>
<height>32</height>
<description>troglodyne.net favicon</description>
</image>
<item>
<title>Performance Engineering for the Layman</title>
<link>http://troglodyne.net/posts/396ae7fc-8098-11ec-9660-ba87b245d611</link>
<description><![CDATA[<p>
As my nephews are coming of age, I'm considering taking an apprentice.
This has resulted in me thinking more of how I might explain programming best practices to the layman.
Today I'd like to focus on performance.
</p>
<p>
Suppose you had to till, plant and water an arbitrary number of acres.
Would you propose ploughing a foot, planting a seed and watering ad nauseum?
I suspect not.
This is because context switching costs a great deal.
Indeed, the context switches involved between planting, seeding and watering will end up being the costliest action when scaling this (highly inefficient) process to many acres.
</p>
<p>
This is why batching of work is the solution everyone reaches for instinctively.
It is from this fact that economic specialization developed.
I can only hold so much in my own two hands and can't be in two places at once.
It follows that I can produce far more washed dishes or orders being a cook or dish-washer all day than I can switching between the tasks repeatedly.
</p>
<p>
That said, doing so only makes sense at a particular scale of activity.
If your operational scale can't afford specialized people or equipment you will be forced to "wear all the hats" yourself.
Naturally this means that operating at a larger scale will be more efficient, as it can avoid those context switching costs.
</p>
<p>
Unfortunately, the practices adopted at small scale prove difficult to overcome.
When these are embodied in programs, they are like concreting in a plumbing mistake (and thus quite costly to remedy).
I have found this to be incredibly common in the systems I have worked with.
The only way to avoid such problems is to insist your developers not test against trivial data-sets, but worst-case data sets.
</p>
<h2>Optimizing your search pattern</h2>
<p>
When ploughing you can choose a pattern of furroughing that ends up right where you started to minimize the cost of the eventual context switch to seeding or watering.
Almost every young man has mowed a lawn and has come to this understanding naturally.
Why is it then that I repeatedly see simple performance mistakes which a manual laborer would consider obvious?
</p>
<p>
For example, consider a file you are parsing to be a field, and lines to be the furroughs.
If we need to make multiple passes, it will behoove us to avoid a seek to the beginning, much like we try to arrive close to the point of origin in real life.
We would instead iterate in reverse over the lines.
Many performance issues are essentially a failure to understand this problem.
Which is to say, a <a href="https://en.wikipedia.org/wiki/Cache_(computing)#CACHE-MISS">cache miss</a>.
Where we need to be is not within immediate sequential reach of our working set.
Now a costly context switch must be made.
</p>
<p>
<em>All</em> important software currently in use is precisely because it understood this, and it's competitors <em>did not</em>.
The reason preforking webservers and then PSGI/WSGI + reverse proxies took over the world is because of this -- program startup is an important context switch.
Indeed, the rise of <a href="https://en.wikipedia.org/wiki/Event-driven_programming">Event-Driven programming</a> is entirely due to this reality.
It encourages the programmer to keep as much as possible in the working set, where we can get acceptable performance.
Unfortunately, this is also behind the extreme bloat in working sets of programs, as proper cache loading and eviction is a hard problem.
</p>
<p>
If we wish to avoid bloat <em>and</em> context switches, both our data and the implements we wish to apply to it must be sequentially available to each other.
Computers are in fact built to exploit this; "Deep pipelining" is essentially this concept.
Unfortunately, a common abstraction which has made programming understandable to many hinders this.
</p>
<h2>Journey to flatland</h2>
<p>
Object-Orientation encourages programmers to <a href="http://catb.org/jargon/html/B/bag-on-the-side.html">hang a bag on the side</a> of their data as a means of managing the complexity involved with "what should transform this" and "what state do we need to keep track of doing so".
The trouble with this is that it encourages one-dimensional thinking.
My plow object is calling the aerateSoil() method of the land object, which is instantiated per square foot, which calls back to the seedFurroughedSoil() method...
You might laugh at this example (given the problem is so obvious with it), but nearly every "DataTable" component has this problem to some degree.
Much of the slowness of the modern web is indeed tied up in this simple failure to realize they are context switching far too often.
</p>
<p>
This is not to say that object orientation is bad, but that one-dimensional thinking (as is common with those of lesser mental faculties) is bad for performance.
Sometimes one-dimensional thinking is great -- every project is filled with one-dimensional problems which do not require creative thinkers to solve.
We will need dishes washed until the end of time.
That said, letting the dish washers design the business is probably not the smartest of moves.
I wouldn't have trusted myself to design and run a restaurant back when I washed dishes for a living.
</p>
<p>
You have to consider multiple dimensions.  In 2D, your data will need to be consumed in large batches.
In practice, this means <a href="https://en.wikipedia.org/wiki/Memoization">memoization</a> and tight loops rather than function composition or method chaining.
Problems scale beyond this -- into the third and fourth dimension, and the techniques used there are even more interesting.
Almost every problem in 3 dimensions can be seen as a matrix translation, and in 4 dimensions as a series of <em>relative</em> shape rotations (rather than as quaternion matrix translation).
</p>
<h2>The outside view</h2>
<p>
Thankfully, this discussion of viewing things from multiple dimensions hits upon the practical approach to fixing performance problems.
Running many iterations of a program with a large dataset under a profiling framework (hopefully producing <a href="https://www.brendangregg.com/flamegraphs.html">flame-graphs</a>) is the change of perspective most developers need.
Considering the call stack forces you into the 2-dimensional mindset you need to be in (data over time).
</p>
<p>
This should make sense intuitively, as the example of the ploughman.
He calls furrough(), seed() and water() upon the dataset consisting of many hectares of soil.
Which is taking the majority of time should be made immediately obvious simply by observing how long it takes per foot of soil acted upon per call, and context switch costs.
</p>]]></description>
<author>george</author>
<guid isPermaLink="true">http://troglodyne.net/posts/396ae7fc-8098-11ec-9660-ba87b245d611</guid>
<pubDate>2022-01-29T00:13:02</pubDate>
<enclosure url="http://troglodyne.net/posts/396ae7fc-8098-11ec-9660-ba87b245d611" type="text/html" />
</item>
<item>
<title>Idiot-Proofing Software: Me worry?</title>
<link>http://troglodyne.net/posts/6d4662dc-ca68-11ec-8a87-d4d968700238</link>
<description><![CDATA[<p>
I read a Warren Buffet quote the other day that sort of underlines the philosophy I try to take with my programs given the option:
<blockquote>
"We try to find businesses that an idiot can run, because eventually an idiot will run it."
</blockquote>
This applies inevitably to your programs too.
I'm not saying that you should treat your customers like idiots.
Idiots don't have much money and treating customers like they are upsets the smart ones that actually do have money.
You must understand that they <em>can</em> cost you a lot of money without much effort on their part.
This is the thrust of a seminal article: <a href="http://harmful.cat-v.org/people/basic-laws-of-human-stupidity/">The fundamental laws of human stupidity</a>.
</p>
<p>
This is why many good programs focus on having sane defaults, because that catches 80% of the stupid mistakes people make.
That said, the 20% of people who are part of the "I know just enough to be dangerous" cohort (see illustration) cause 80% of the damage.
Aside from the discipline that comes with age (George, why do you charge so much?), there are a few things you can do to whittle down 80% of that dangerous 20%.
This usually involves erecting a Chesterton's Fence of some kind, like a --force or --dryrun option.
Beyond that lies the realm of disaster recovery, as some people will just drop the table because a query failed.
</p>
<p>
This also applies to the architecture of software stacks and the business in general (as mentioned by Buffet).
I see a lot of approaches advocated to the independent software vendor because "google uses it" and similar nonsense.
They've got a huge blind spot they admit freely as "I can't count that low".
What has resulted from this desire to "ape our betters" is an epidemic of swatting flies with elephant guns, and vault doors on crack houses.
This time could have been spent building win-wins with smart customers or limiting the attack surface exploited by the dumb or malicious.
</p>
<p>
So long as you take a fairly arms-length approach with regard to the components critical to your stack,
swapping one out for another more capable one is the kind of problem you like to have.
This means you are scaling to the point you can afford to solve it.
</p>]]></description>
<author>george</author>
<guid isPermaLink="true">http://troglodyne.net/posts/6d4662dc-ca68-11ec-8a87-d4d968700238</guid>
<pubDate>2022-05-02T22:37:20</pubDate>
<enclosure url="http://troglodyne.net/posts/6d4662dc-ca68-11ec-8a87-d4d968700238" type="text/html" />
</item>
<item>
<title>How computer science captured the hearts and minds of generations of scientists</title>
<link>http://troglodyne.net/posts/72ca7893-97df-11ec-9eb9-a330e32c2df2</link>
<description><![CDATA[<p>
The scientific method is well understood by schoolchildren in theory, but thanks to the realities of schooling systems they are rarely if ever exposed to its actual practice.
This is because the business of science can be quite expensive.
Every experiment takes time and nontrivial amounts of capital, much of which may be irreversibly lost in each experiment.
As such, academia is far behind modern development organizations.
In most cases they are not even aware to the extent that we have made great strides towards actually doing experimentation.
</p>
<p>
Some of this is due to everyone capable of making a difference toward that problem being able to achieve more gainful employment in the private sector.
Most of it is due to the other hard sciences not catching up to our way of experimentation either.
This is why SpaceX has been able to succeed where NASA has failed -- by applying our way to a hard science.
There's also a lack of understanding at a policy level as to why it is the scientifically inclined are overwhelmingly preferring computers to concrete sciences.
The Chinese government has made waves of late claiming they wish to address this, but I see no signs as of yet that they are aware how this trend occurred in the first place.
</p>
<p>
Even if it were not the case that programming is a far quicker path to life-changing income for most than the other sciences, I suspect most would still prefer it.
Why this income potential exists in the first place is actually the reason for such preference.
It is far, far quicker and cheaper to iterate (and thus learn from) your experiments.
Our tools for peer review are also far superior to the legacy systems that still dominate in the other sciences.
</p>
<p>
Our process also systematically embraces the building of experiments (control-groups, etc) to the point we've got entire automated orchestration systems.
The Dev, Staging/Testing and Production environments model works quite well when applied to the other sciences.
Your development environment is little more than a crude simulator that allows you to do controlled, ceteris-paribus experiments quickly.
As changes percolate upward and mix they hit the much more mutis mutandis environment of staging/testing.
When you get to production your likelihood of failure is much reduced versus the alternative.
When failures do happen, we "eat the dog food" and do our best to fix the problems in our simulated environments.
</p>
<p>
Where applied in the other sciences, our approach has resurrected forward momentum.
Firms which do not adopt them in the coming years will be outcompeted by those that do.
Similarly, countries which do not re-orient their educational systems away from rote memorization and towards guided experimental rediscovery from first principles using tools very much like ours will also fall behind.
</p>]]></description>
<author>george</author>
<guid isPermaLink="true">http://troglodyne.net/posts/72ca7893-97df-11ec-9eb9-a330e32c2df2</guid>
<pubDate>2022-02-27T15:10:50</pubDate>
<enclosure url="http://troglodyne.net/posts/72ca7893-97df-11ec-9eb9-a330e32c2df2" type="text/html" />
</item>
<item>
<title>Audit::Log released to CPAN</title>
<link>http://troglodyne.net/posts/a49ed777-7801-11ec-a570-927ac1c30435</link>
<description><![CDATA[For those of you interested in parsing audit logs with perl.<br /><br />

Looks like I need to make some more business expenses if I want to be able to stream 4k video!]]></description>
<author>george</author>
<guid isPermaLink="true">http://troglodyne.net/posts/a49ed777-7801-11ec-a570-927ac1c30435</guid>
<pubDate>2022-01-18T01:54:59</pubDate>
<enclosure url="http://troglodyne.net/posts/a49ed777-7801-11ec-a570-927ac1c30435" type="text/html" />
</item>
<item>
<title>Async/Await? Real men prefer Promise.all()</title>
<link>http://troglodyne.net/posts/6fc05049-13de-11ec-84d9-e3b1a9d1a692</link>
<description><![CDATA[<p>
I've been writing a bunch of TypeScript lately, and figured out why most of the "Async" modules out there are actually fakin' the funk with coroutines.
</p>
<p>
Turns out even pedants like programmers aren't immune to meaning drift!  I guess I'm an old man now lol.
</p>
<p>
Article mentioned:
<a href="https://troglodyne.net/posts/1615831259">Troglodyne Q3 Open Source goals</a>
</p>]]></description>
<author>george</author>
<guid isPermaLink="true">http://troglodyne.net/posts/6fc05049-13de-11ec-84d9-e3b1a9d1a692</guid>
<pubDate>2021-03-16T00:04:13</pubDate>
<enclosure url="http://troglodyne.net/posts/6fc05049-13de-11ec-84d9-e3b1a9d1a692" type="text/html" />
</item>
<item>
<title>Async/Await? Real men prefer Promise.all()</title>
<link>http://troglodyne.net/posts/1615853053</link>
<description><![CDATA[<p>
I've been writing a bunch of TypeScript lately, and figured out why most of the "Async" modules out there are actually fakin' the funk with coroutines.
</p>
<p>
Turns out even pedants like programmers aren't immune to meaning drift!  I guess I'm an old man now lol.
</p>
<p>
Article mentioned:
<a href="https://troglodyne.net/posts/1615831259">Troglodyne Q3 Open Source goals</a>
</p>]]></description>
<author>george</author>
<guid isPermaLink="true">http://troglodyne.net/posts/1615853053</guid>
<pubDate>2021-03-16T00:04:13</pubDate>
<enclosure url="http://troglodyne.net/posts/1615853053" type="text/html" />
</item>
<item>
<title>Link Unfurling with HTML::SocialMeta</title>
<link>http://troglodyne.net/posts/6e9cf9d3-13de-11ec-84d9-ae6cc12fba6d</link>
<description><![CDATA[I did a deep dive into how pasted links turn into previews in chat and social media applications and was pleasantly surprised to find CPAN had the solution for me.  I found a couple of gotchas you might want to know about if you don't want to figure this out the hard way.]]></description>
<author>andy</author>
<guid isPermaLink="true">http://troglodyne.net/posts/6e9cf9d3-13de-11ec-84d9-ae6cc12fba6d</guid>
<pubDate>2021-01-06T17:27:34</pubDate>
<enclosure type="text/html" url="http://troglodyne.net/posts/6e9cf9d3-13de-11ec-84d9-ae6cc12fba6d" />
</item>
<item>
<title>Link Unfurling with HTML::SocialMeta</title>
<link>http://troglodyne.net/posts/1609954054</link>
<description><![CDATA[I did a deep dive into how pasted links turn into previews in chat and social media applications and was pleasantly surprised to find CPAN had the solution for me.  I found a couple of gotchas you might want to know about if you don't want to figure this out the hard way.]]></description>
<author>andy</author>
<guid isPermaLink="true">http://troglodyne.net/posts/1609954054</guid>
<pubDate>2021-01-06T17:27:34</pubDate>
<enclosure url="http://troglodyne.net/posts/1609954054" type="text/html" />
</item>
<item>
<title>tCMS Hacking VII: Mixed Content Warnings</title>
<link>http://troglodyne.net/posts/6e233ae9-13de-11ec-84d9-8d980500e7cb</link>
<description><![CDATA[A common problem in websites is the "Mixed Content Warning" on SSL virtualHosts.  In the end it becomes yet another "I should (and do) know better" stream, lol]]></description>
<author>george</author>
<guid isPermaLink="true">http://troglodyne.net/posts/6e233ae9-13de-11ec-84d9-8d980500e7cb</guid>
<pubDate>2020-12-31T23:02:33</pubDate>
<enclosure type="text/html" url="http://troglodyne.net/posts/6e233ae9-13de-11ec-84d9-8d980500e7cb" />
</item>
<item>
<title>tCMS Hacking VII: Mixed Content Warnings</title>
<link>http://troglodyne.net/posts/1609455753</link>
<description><![CDATA[A common problem in websites is the "Mixed Content Warning" on SSL virtualHosts.  In the end it becomes yet another "I should (and do) know better" stream, lol]]></description>
<author>george</author>
<guid isPermaLink="true">http://troglodyne.net/posts/1609455753</guid>
<pubDate>2020-12-31T23:02:33</pubDate>
<enclosure url="http://troglodyne.net/posts/1609455753" type="text/html" />
</item>
<item>
<title>tCMS Hacking VI: How programming usually goes</title>
<link>http://troglodyne.net/posts/6e2f1b89-13de-11ec-84d9-a5be85d148a9</link>
<description><![CDATA[I tried to fix a bug, but had to fix other things first.  This is how most days go when you are programming.]]></description>
<author>george</author>
<guid isPermaLink="true">http://troglodyne.net/posts/6e2f1b89-13de-11ec-84d9-a5be85d148a9</guid>
<pubDate>2020-12-31T22:46:26</pubDate>
<enclosure type="text/html" url="http://troglodyne.net/posts/6e2f1b89-13de-11ec-84d9-a5be85d148a9" />
</item>
<item>
<title>tCMS Hacking VI: How programming usually goes</title>
<link>http://troglodyne.net/posts/1609454786</link>
<description><![CDATA[I tried to fix a bug, but had to fix other things first.  This is how most days go when you are programming.]]></description>
<author>george</author>
<guid isPermaLink="true">http://troglodyne.net/posts/1609454786</guid>
<pubDate>2020-12-31T22:46:26</pubDate>
<enclosure type="text/html" url="http://troglodyne.net/posts/1609454786" />
</item>
<item>
<title>tCMS Deploys using Buildah and Podman</title>
<link>http://troglodyne.net/posts/6f08e0cc-13de-11ec-84d9-a9668552b912</link>
<description><![CDATA[Branching out thanks to our friends over at the <a href="http://houstonlinux.org">Houston Linux User's Group</a>.]]></description>
<author>george</author>
<guid isPermaLink="true">http://troglodyne.net/posts/6f08e0cc-13de-11ec-84d9-a9668552b912</guid>
<pubDate>2020-12-31T19:18:54</pubDate>
<enclosure type="text/html" url="http://troglodyne.net/posts/6f08e0cc-13de-11ec-84d9-a9668552b912" />
</item>
<item>
<title>tCMS Deploys using Buildah and Podman</title>
<link>http://troglodyne.net/posts/1609442334</link>
<description><![CDATA[Branching out thanks to our friends over at the <a href="http://houstonlinux.org">Houston Linux User's Group</a>.]]></description>
<author>george</author>
<guid isPermaLink="true">http://troglodyne.net/posts/1609442334</guid>
<pubDate>2020-12-31T19:18:54</pubDate>
<enclosure url="http://troglodyne.net/posts/1609442334" type="text/html" />
</item>
<item>
<title>tCMS Hacking V: Speeding up Docker deployment with overlays</title>
<link>http://troglodyne.net/posts/6e27720d-13de-11ec-84d9-a81468cf9752</link>
<description><![CDATA[The fundamental motivation for all programmers -- "this is taking to long!"
<br /><br />
Speaking of, this stream took way too long because the docu I was looking at was solving a different problem (smaller disk size than less time).
<br /><br />
Feed my greedy algos!!!1]]></description>
<author>george</author>
<guid isPermaLink="true">http://troglodyne.net/posts/6e27720d-13de-11ec-84d9-a81468cf9752</guid>
<pubDate>2020-12-30T01:48:33</pubDate>
<enclosure url="http://troglodyne.net/posts/6e27720d-13de-11ec-84d9-a81468cf9752" type="text/html" />
</item>
<item>
<title>tCMS Hacking V: Speeding up Docker deployment with overlays</title>
<link>http://troglodyne.net/posts/1609292913</link>
<description><![CDATA[The fundamental motivation for all programmers -- "this is taking to long!"
<br /><br />
Speaking of, this stream took way too long because the docu I was looking at was solving a different problem (smaller disk size than less time).
<br /><br />
Feed my greedy algos!!!1]]></description>
<author>george</author>
<guid isPermaLink="true">http://troglodyne.net/posts/1609292913</guid>
<pubDate>2020-12-30T01:48:33</pubDate>
<enclosure type="text/html" url="http://troglodyne.net/posts/1609292913" />
</item>
<item>
<title>tCMS Hacking IV: Practical concerns when doing docker deploys</title>
<link>http://troglodyne.net/posts/6df1fa6e-13de-11ec-84d9-ae58771f3014</link>
<description><![CDATA[Try not to stick your hands in the guts of your containers unless you want jungle diseases.  Here's a practical example of doing the targeted surgery required to keep sane.]]></description>
<author>george</author>
<guid isPermaLink="true">http://troglodyne.net/posts/6df1fa6e-13de-11ec-84d9-ae58771f3014</guid>
<pubDate>2020-12-29T20:18:58</pubDate>
<enclosure url="http://troglodyne.net/posts/6df1fa6e-13de-11ec-84d9-ae58771f3014" type="text/html" />
</item>
<item>
<title>tCMS Hacking IV: Practical concerns when doing docker deploys</title>
<link>http://troglodyne.net/posts/1609273138</link>
<description><![CDATA[Try not to stick your hands in the guts of your containers unless you want jungle diseases.  Here's a practical example of doing the targeted surgery required to keep sane.]]></description>
<author>george</author>
<guid isPermaLink="true">http://troglodyne.net/posts/1609273138</guid>
<pubDate>2020-12-29T20:18:58</pubDate>
<enclosure type="text/html" url="http://troglodyne.net/posts/1609273138" />
</item>
<item>
<title>tCMS Hacking III: Filter your REQUEST_URI or you&#x27;ll die</title>
<link>http://troglodyne.net/posts/6f3b0f20-13de-11ec-84d9-a8485fa9deb9</link>
<description><![CDATA[Yet another from the "I should know better" (and do) files.  A little dab of regex will do.]]></description>
<author>george</author>
<guid isPermaLink="true">http://troglodyne.net/posts/6f3b0f20-13de-11ec-84d9-a8485fa9deb9</guid>
<pubDate>2020-12-29T17:57:50</pubDate>
<enclosure url="http://troglodyne.net/posts/6f3b0f20-13de-11ec-84d9-a8485fa9deb9" type="text/html" />
</item>
<item>
<title>tCMS Hacking III: Filter your REQUEST_URI or you&#x27;ll die</title>
<link>http://troglodyne.net/posts/1609264670</link>
<description><![CDATA[Yet another from the "I should know better" (and do) files.  A little dab of regex will do.]]></description>
<author>george</author>
<guid isPermaLink="true">http://troglodyne.net/posts/1609264670</guid>
<pubDate>2020-12-29T17:57:50</pubDate>
<enclosure type="text/html" url="http://troglodyne.net/posts/1609264670" />
</item>
<item>
<title>tCMS Hacking II: Making schema updates</title>
<link>http://troglodyne.net/posts/6e80f6e4-13de-11ec-84d9-b22b8f3d806b</link>
<description><![CDATA[Cleaning up after your SQL mistakes is important.  Here's how to do it in a way that minimizes downtime.]]></description>
<author>andy</author>
<guid isPermaLink="true">http://troglodyne.net/posts/6e80f6e4-13de-11ec-84d9-b22b8f3d806b</guid>
<pubDate>2020-12-16T03:38:01</pubDate>
<enclosure url="http://troglodyne.net/posts/6e80f6e4-13de-11ec-84d9-b22b8f3d806b" type="text/html" />
</item>
<item>
<title>tCMS Hacking II: Making schema updates</title>
<link>http://troglodyne.net/posts/1608089881</link>
<description><![CDATA[Cleaning up after your SQL mistakes is important.  Here's how to do it in a way that minimizes downtime.]]></description>
<author>andy</author>
<guid isPermaLink="true">http://troglodyne.net/posts/1608089881</guid>
<pubDate>2020-12-16T03:38:01</pubDate>
<enclosure type="text/html" url="http://troglodyne.net/posts/1608089881" />
</item>
<item>
<title>tCMS Hacking: Removing unneeded schema</title>
<link>http://troglodyne.net/posts/6f40e056-13de-11ec-84d9-8a25e0e1eaa2</link>
<description><![CDATA[From the "I should know better" files.  Having predictable user identifiers which are also superfluous is pretty bad, and something I already knew not to do, but hey, worse is better!]]></description>
<author>andy</author>
<guid isPermaLink="true">http://troglodyne.net/posts/6f40e056-13de-11ec-84d9-8a25e0e1eaa2</guid>
<pubDate>2020-12-16T03:35:48</pubDate>
<enclosure type="text/html" url="http://troglodyne.net/posts/6f40e056-13de-11ec-84d9-8a25e0e1eaa2" />
</item>
<item>
<title>tCMS Hacking: Removing unneeded schema</title>
<link>http://troglodyne.net/posts/1608089748</link>
<description><![CDATA[From the "I should know better" files.  Having predictable user identifiers which are also superfluous is pretty bad, and something I already knew not to do, but hey, worse is better!]]></description>
<author>andy</author>
<guid isPermaLink="true">http://troglodyne.net/posts/1608089748</guid>
<pubDate>2020-12-16T03:35:48</pubDate>
<enclosure type="text/html" url="http://troglodyne.net/posts/1608089748" />
</item>
<item>
<title>Playwright for Perl: Update 2</title>
<link>http://troglodyne.net/posts/6f0eca9f-13de-11ec-84d9-b622d3e1498f</link>
<description><![CDATA[Wherein big progress is made.]]></description>
<author>george</author>
<guid isPermaLink="true">http://troglodyne.net/posts/6f0eca9f-13de-11ec-84d9-b622d3e1498f</guid>
<pubDate>2020-12-12T20:48:24</pubDate>
<enclosure type="text/html" url="http://troglodyne.net/posts/6f0eca9f-13de-11ec-84d9-b622d3e1498f" />
</item>
<item>
<title>Playwright for Perl: Update 2</title>
<link>http://troglodyne.net/posts/1607806104</link>
<description><![CDATA[Wherein big progress is made.]]></description>
<author>george</author>
<guid isPermaLink="true">http://troglodyne.net/posts/1607806104</guid>
<pubDate>2020-12-12T20:48:24</pubDate>
<enclosure url="http://troglodyne.net/posts/1607806104" type="text/html" />
</item>
<item>
<title>Playwright for Perl!</title>
<link>http://troglodyne.net/posts/707ad51c-13de-11ec-84d9-b921b9a01225</link>
<description><![CDATA[Selenium is dead. Long live Playwright! Though just at the start of things today, surprisingly good progress has been made already.<br />
<a href="https://github.com/teodesian/playwright-perl">https://github.com/teodesian/playwright-perl</a>]]></description>
<author>george</author>
<guid isPermaLink="true">http://troglodyne.net/posts/707ad51c-13de-11ec-84d9-b921b9a01225</guid>
<pubDate>2020-12-12T20:20:50</pubDate>
<enclosure type="text/html" url="http://troglodyne.net/posts/707ad51c-13de-11ec-84d9-b921b9a01225" />
</item>
<item>
<title>Playwright for Perl!</title>
<link>http://troglodyne.net/posts/1607804450</link>
<description><![CDATA[Selenium is dead. Long live Playwright! Though just at the start of things today, surprisingly good progress has been made already.<br />
<a href="https://github.com/teodesian/playwright-perl">https://github.com/teodesian/playwright-perl</a>]]></description>
<author>george</author>
<guid isPermaLink="true">http://troglodyne.net/posts/1607804450</guid>
<pubDate>2020-12-12T20:20:50</pubDate>
<enclosure type="text/html" url="http://troglodyne.net/posts/1607804450" />
</item>
<item>
<title>Add an Emoji Picker to your Website!</title>
<link>http://troglodyne.net/posts/6f53a9a4-13de-11ec-84d9-cbbc3280b2b0</link>
<description><![CDATA[Had a desire to add some emojis earlier to a news posting I was doing for <a href="https://teodesian.net" title="OOOOH YEAAAA I'M SHITPOOOSTIN'">teodesian.net</a>.  Decided to do a few seconds of googlin' and found a pretty decent looking library for doing this here:
<br /><br />
<a href="https://github.com/woody180/vanilla-javascript-emoji-picker">https://github.com/woody180/vanilla-javascript-emoji-picker</a>
<br /><br />
Figured I may as well let y'all ride shotgun with me as I added this sucker to my posting UI as such. Hopefully it helps someone out there on the interwebs!]]></description>
<author>andy</author>
<guid isPermaLink="true">http://troglodyne.net/posts/6f53a9a4-13de-11ec-84d9-cbbc3280b2b0</guid>
<pubDate>2020-12-10T03:36:15</pubDate>
<enclosure url="http://troglodyne.net/posts/6f53a9a4-13de-11ec-84d9-cbbc3280b2b0" type="text/html" />
</item>
<item>
<title>Add an Emoji Picker to your Website!</title>
<link>http://troglodyne.net/posts/1607568309</link>
<description><![CDATA[Had a desire to add some emojis earlier to a news posting I was doing for <a href="https://teodesian.net" title="OOOOH YEAAAA I'M SHITPOOOSTIN'">teodesian.net</a>.  Decided to do a few seconds of googlin' and found a pretty decent looking library for doing this here:
<br /><br />
<a href="https://github.com/woody180/vanilla-javascript-emoji-picker">https://github.com/woody180/vanilla-javascript-emoji-picker</a>
<br /><br />
Figured I may as well let y'all ride shotgun with me as I added this sucker to my posting UI as such. Hopefully it helps someone out there on the interwebs!]]></description>
<author>andy</author>
<guid isPermaLink="true">http://troglodyne.net/posts/1607568309</guid>
<pubDate>2020-12-10T03:36:15</pubDate>
<enclosure url="http://troglodyne.net/posts/1607568309" type="text/html" />
</item>
<item>
<title>Programming Videos</title>
<link>http://troglodyne.net/programming</link>
<description><![CDATA[Random videos involving actual code slinging]]></description>
<author>andy</author>
<guid isPermaLink="true">http://troglodyne.net/programming</guid>
<pubDate>2020-12-10T02:29:22</pubDate>
<enclosure url="http://troglodyne.net/programming" type="text/html" />
</item>
<item>
<title>Programming Videos</title>
<link>http://troglodyne.net/posts/1607567362</link>
<description><![CDATA[Random videos involving actual code slinging]]></description>
<author>andy</author>
<guid isPermaLink="true">http://troglodyne.net/posts/1607567362</guid>
<pubDate>2020-12-10T02:29:22</pubDate>
<enclosure type="text/html" url="http://troglodyne.net/posts/1607567362" />
</item>
<item>
<title>Programming Videos</title>
<link>http://troglodyne.net/series/1607567362</link>
<description><![CDATA[Random videos involving actual code slinging]]></description>
<author>andy</author>
<guid isPermaLink="true">http://troglodyne.net/series/1607567362</guid>
<pubDate>2020-12-10T02:29:22</pubDate>
<enclosure url="http://troglodyne.net/series/1607567362" type="text/html" />
</item>
<item>
<title>Programming Videos</title>
<link>http://troglodyne.net/posts/6dd7cbda-13de-11ec-84d9-dbde6d93afd7</link>
<description><![CDATA[Random videos involving actual code slinging]]></description>
<author>andy</author>
<guid isPermaLink="true">http://troglodyne.net/posts/6dd7cbda-13de-11ec-84d9-dbde6d93afd7</guid>
<pubDate>2020-12-10T02:29:22</pubDate>
<enclosure url="http://troglodyne.net/posts/6dd7cbda-13de-11ec-84d9-dbde6d93afd7" type="text/html" />
</item>
<item>
<title>Programming Videos</title>
<link>http://troglodyne.net/series/6dd7cbda-13de-11ec-84d9-dbde6d93afd7</link>
<description><![CDATA[Random videos involving actual code slinging]]></description>
<author>andy</author>
<guid isPermaLink="true">http://troglodyne.net/series/6dd7cbda-13de-11ec-84d9-dbde6d93afd7</guid>
<pubDate>2020-12-10T02:29:22</pubDate>
<enclosure url="http://troglodyne.net/series/6dd7cbda-13de-11ec-84d9-dbde6d93afd7" type="text/html" />
</item>
</channel>
</rss>
