"I mean." Uberman cleared his throat, adjusted his necktie, and began delivering his morning whine, which is clearly what he'd been intending to do all along. "This is, what? The third network outage this year?""Headcrash" is kind of a no-account cyberpunk-y book from the mid-90s... the technobabble is pretty clumsy, but for some reason this passage has stuck with me for 20 years so I thought I'd post it - from time to time, its reminder that little toy systems can get away with things that projects you want to scale can't is useful.
I stopped. "We're having some problems porting your database to our server, sir." I edged one step closer to the exit.
"I mean," Uberman scowled, "if I can't depend on your network, I'm screwed. Just totally screwed, you know?"
Then how come you're not smiling? is what I thought, but "We'll have it back up as soon as possible," is what I said.
"I mean," Uberman whacked his PC with his newspaper again, "we never had problems like this before MDE acquired us. Dammit, our old Applied Photonics network never crashed! Not once!"
"So I've heard." And heard, and heard, and heard! And if you gave me just sixteen users in a one-floor office, I could make this network look pretty good, too.
Tuesday, April 16, 2024
from "Headcrash"
Thursday, April 4, 2024
easy drag-and-drop sorting/reordering with no build system vanilla js using SortableJS
I've already linked to a defense of making webapps without a build system - it really is great for long term sustainability and updates, and PHP + Vanilla JS are actually really powerful tools these days. You can even build dynamic page parts in a declarative style, using JSX looking string templates:
const list = document.getElementById("myList");
list.innerHTML = items.map((item)=>`<li>${item}</li>`).join("");
It's all right there in the browser these days!
One thing I didn't know how to do is add drag-and-drop reordering - at least not in a way that was mobile-friendly. (The browser's Drag and Drop API is one place where the usual abstraction between computers with mice or touchpads and mobile devices with touch screen breaks down.)
I knew of SortableJS but the README didn't make it clear that it works without a build system. ChatGPT straightened me out - using SortableJS is just a <script> tag away:
<script src="https://cdn.jsdelivr.net/npm/sortablejs@1.14.0/Sortable.min.js"></script>
(Hmm, there's no authentication checksum so you might want to grab the file and move it locally - I mean in general eliminating external dependencies is a good practice, tying into that long term sustainability: linkrot is real and ubiquitous, even well meaning CDNs broke projects depending on them as stuff switched from http to https...)
But back to sortable! Here's about the simplest example:
<script src="Sortable.min.js"></script>
<ol id="items-list">
<!-- List items will be dynamically inserted here -->
</ol>
<script>
document.addEventListener('DOMContentLoaded', () => {
const items = ["Apple", "Banana", "Cherry", "Date"];
const listElement = document.getElementById('items-list');
listElement.innerHTML = items.map(item => `<li>${item}</li>`).join('');
new Sortable(document.getElementById('items-list'), {
animation: 150, // Animation speed (milliseconds)
onEnd: function (evt) {
items.splice(evt.newIndex, 0, items.splice(evt.oldIndex, 1)[0]);
}
});
});
</script>
You can see it in action - everything is right there in the source.
So one slightly wonky aspect is that this kind of reverses the usual flow of declarative programming: Sortable update the DOM and then relies on the onEnd to make your internal state match. Still, a small price to pay for a mobile-friendly reordering solution; so much better than providing little /\ and \/ buttons!
You can go a little further and add some grabbable handles - here's how to make those three lines:
<span class="drag-handle">☰</span>
Add the reference to the Sortable options object:
handle: ".drag-handle",
and then a little CSS:
ul {
list-style-type: none;
padding-left: 0;
}
.drag-handle {
cursor: grab; /* Changes the cursor to indicate movability */
padding-right: 10px; /* Spacing between the handle and the text */
user-select: none; /* Prevents text selection */
}
/* Style the drag handle on hover and active states for better feedback */
.drag-handle:hover, .drag-handle:active {
cursor: grabbing;
}
Here's a working example of that.
Finally, if you DO rerender the list, you should probably hold onto the returned Sortable object and call .destroy() and then reapply. That's obviously more tied into whatever app you're actually making, but here is a basic destroy/rerender example as well, which is a bit closer to my usecase.
Wednesday, April 3, 2024
robohorn
As a kid I wondered if you could make a robot trumpet player. The answer is now yes. I wonder how the cyber-embouchure works... (you can google up a robot sax player as well...)
Related Diesel Sweeties comic 10:
dangerous times
A while back I posted I’m harvesting credit card numbers and passwords from your site. Here’s how. a fake (or was it) description of how the overwhelming amount of npm-ish dependencies can make your webapp vulnerable, if a bad actor makes a helpful looking tiny utility (that the framework you like uses, even if you don't see it as worthwhile) and covers their tracks well.
What we know about the xz Utils backdoor that almost infected the world is along the same lines, except i can't preach the gospel of "use fewer dependencies!"
None of this is new - the seminal Reflections on Trusting Trust - where a trojan could be snuck into a C compiler, covering its tracks all along the way - is 40 years old. But it's scary.
Related: You Are All On The Hobbyists Maintainers' Turf Now. The business world has absolutely embraced the Open Source paradigm - or at least decided to take freely of its fruit, and so the risk of poisoned flowers is there, even as more and more we depend on the good will "doing it for the reputation and to scratch my own itch" work of fewer and fewer - or as XKCD put it:
Monday, April 1, 2024
ObHack: see if I've hit quota
I know I've mentioned Usenet's alt.hackers and "ObHacks" before... the latest is this:
My main VPS is pretty old (I'm migrating to a new one) and it doesn't do a good job of letting me how close to my disk quota I am - but when I start having problems, the clearest telltale is that if I try writing to a file from terminal, the file is made but is zero bytes.
But on that same server I run my personal start page, so many times during the day I'm going back to that site. So now the script that generates that page tries does this:
// QUOTA PROBLEM CHECK
// Get the current Unix timestamp
$timestamp = time();
// Write it to a file named "timetest.txt"
file_put_contents("timetest.txt", $timestamp);
// Initialize $bodyclass with an empty value
$bodyclass = "";
// Open the file and read the timestamp
$readTimestamp = file_get_contents("timetest.txt");
// Check if we can open the file, if it's not empty, and if the contents match
if ($readTimestamp === FALSE
|| $readTimestamp == ""
|| $readTimestamp != $timestamp) {
$bodyclass = "alert";
}
and I made the body.alert CSS to be bright red, so I'll see that something is up.
Heh, that piece of PHP reminds me of a thought I had recently; in general I don't adore TypeScript because while I like having JSON arguments described, there are better ways to do that, I find the syntax makes code a bit harder to read, and also there's more of a chance of a false sense of security, since you don't REALLY know what types are going to come back from a given endpoint at runtime.
My observation with that is that 90% of the typing issues I *do* have in JS would go away if "+" always meant addition and not string concatenation. Which is how PHP does it. But then I realized that PHP only gets away with supporting both $string.$concatenation and $object.key lookup syntax because it prefixes its variables with "$", otherwise you'd have to do object["key"] only since object.key would look like a lookup reference.
Monday, March 25, 2024
baby mock json endpoint server and cloning endpoints
My boss thought it strange that we didn't already have a "mock server" so that we could keep doing UI work in case the endpoints went down.
He suggested using json-server but that wasn't made to emulate a rich set of endpoints, just one level deep, either GETing all the entries or just one at a time by id. Luckily that kind of server is the easy part of the assignment.
The first part was to make a file "urls.txt", with just the relevant part of the endpoint...
then this script load-db.js hits each of those entries and writes the content to a file in mocks/
Then the server.js just looks like this:
package.json is
(Sigh, I suppose if I was feeling ambitious I should make my a little
project out of this and put it on github, but I'm sure someone has, and
better.)
UPDATE: this version now lists the endpoint/files it knows about if you go to the root, and listens to process.env.PORT for instructions on port