Full Width [alt+shift+f] Shortcuts [alt+shift+k]
Sign Up [alt+shift+s] Log In [alt+shift+l]
39
Today is a good day. Joseph Robinette Biden Jr. has been inaugurated as our 46th president. And Kamala Devi Harris as our 49th vice president. While they cannot immediately undo the American carnage inflicted upon us by the previous administration, at least the vindictive malevolence has stopped now. Finally, and ironically, fulfilling the promise made four years ago by Donald Trump, deposed tyrant and career criminal. So let’s take a moment to unload that uncomfortable weight off our chests and shout in celebration. Fuck yeah! ‘Murica!
over a year ago

Improve your reading experience

Logged in users get linked directly to articles resulting in a better reading experience. Please login for free, it takes less than 1 minute.

More from Don Melton

Sorry, we’re closed

For reasons that will soon become obvious, I’m shutting the doors on this website. Everything will remain online for now, but I don’t plan on returning to write anything new here. Not that I’ve added any content in almost two years anyway. I still have a passion for making observations, telling stories and recording my thoughts as they happen. I’ll just be doing it elsewhere. Thank you for reading.

a year ago 84 votes
Happy twentieth to Safari and WebKit

Safari and WebKit aren’t teenagers anymore. I just want to make note of that. To quote a previous post: On June 25, 2001, I arrived at Apple Computer to lead the effort in building a new Web browser. It was also Ken Kocienda’s first day on the job, both at Apple and on that same project with me. For that reason, Ken and I have always considered our start date to be when Safari and WebKit were born. Not any other position on the calendar. Only June 25, 2001. We were there. We should know. That was 20 years ago today. Twenty years! Of course, it’s been over nine years since I retired from Apple. Obviously, I’m not a teenager anymore either. But I still remember that first day clearly. So, happy birthday to Safari and WebKit and the team now tasked with their adult supervision.

over a year ago 37 votes
Cranking up the blogging machine again

For whatever reason I started blogging again last week. Not knowing why isn’t due to a lack of introspection on my part. Maybe the nauseating weight of the Trump administration was suppressing my desire to write for the previous three-and-a-half years? Or maybe I’m just arbitrary and lazy? It’s also unclear how long I can keep this up. Inspiration and a willingness to type are not something which you can purchase online or install with a package manager. I suppose we’ll find out. However, the mechanics of blogging again are simpler to understand. For one thing, as I write here: … this website is only free-range, handcrafted, artisanal HTML. With a little CSS, of course. No JavaScript—that’s just crazy talk. Technically, it’s all created using software. I don’t actually type all that markup manually, like some filthy animal. And since the site remained unchanged from the time I generated it during June of 2017, it was still working fine as of last week. Keep that in mind when you consider the architecture for your own blog. Once you’ve created it, static HTML is pretty much maintenance free. However, there’s that whole problem of generating it again. With new content. Yeah. I had all the publishing software, content, configuration, etc. installed on my Mac originally. But since we all know I’m using a Windows PC now, I had to migrate everything. That meant just copying my blog posts since they’re simply Markdown documents with YAML frontmatter. Easy. But my content management system is Nanoc, a Ruby-based generator. And while it’s reasonably cross-platform and mostly runs on Windows, it’s not officially supported there. More importantly, the scripts and other tools I built on top of Nanoc were kinda Unix-adjacent, if you know what I mean. This is where the Windows Subsystem for Linux (WSL) came to the rescue. Normally, I use the Windows-specific version of ruby.exe for my other projects. But with WSL, you really need to apt-get ruby and shove that baby into Ubuntu as well. After that it was just a gem install of nanoc and kramdown, my Markdown parser of choice. At least, I thought that’s all I needed. Turns out the kramdown-parser-gfm Gem is required too since I depend on GitHub-flavored Markdown and the kramdown developers removed support for it from the main project back in 2019. Surprise, surprise. But that’s what I get for not parsing any Markdown for so damn long. By the way, for any of you also installing Ruby Gems in WSL or other Unix-like environments, don’t preface gem install with sudo. This is both unnecessary and unwise. It’s unnecessary because you can simply append --user-install to those installation commands. This will place them in ~/.gem, your local Gem directory. And it’s unwise because you don’t want them placed in your system-wide Gem directory. Doing so will delete, overwrite or otherwise fuck them up whenever you update ruby itself. Of course, you’ll need to add that local Gem directory to your $PATH variable in ~/.bash_profile or whatever the equivalent is for your shell. Otherwise the shell can’t find those Gems. Duh. Here’s an example ~/.bash_profile showing how to do just that: if [ -f ~/.bashrc ]; then . ~/.bashrc fi PATH=$HOME/.gem/ruby/2.7.0/bin:$PATH Obviously the version of ruby in that path will need to be adjusted if yours if different. So after getting the correct Gems installed in the correct places, I then had to make a few changes to my Nanoc configuration files and various homebuilt Unix-y scripts. These were mostly just converting some hard-coded macOS-specific directory names to their Windows-specific equivalents. And then… it all worked. Flawlessly. Which means migration was not really much of a problem at all. Sure, thinking ahead on what I needed to do took awhile, but that actual typing necessary to make it happen was just a matter of minutes. Kind of anticlimactic, really. Of course, now I have to figure out what to write. Dammit.

over a year ago 36 votes
Our long national nightmare is not over

I have faith in Joe Biden. And Kamala Harris. They’re good people. They and the team they’ve selected know what they’re doing. It’s obvious just listening to them. So I can barely wait for them to take over the White House tomorrow. Because real governance will be back in residence. And we need all of that to make it through this pandemic. Along with a crushing number of other crises. But even after Trump slithers back to Florida—with a few of his favorite swamp creatures in tow—his enablers in federal, state and local government aren’t going anywhere. And they don’t believe in accountability for him or themselves. Then there’s 75% of Republican voters out there who still think the election was stolen and that Biden is an illegitimate president. Which means The Big Lie isn’t going anywhere either. Don’t ever assume it’s just a small minority that suddenly developed a taste for bullshit. Worse, Trump might be without a platform but he’ll continue to incite his army of insurrectionists with more grievance and more lies. Not all of these people are silly cosplayers. There are enough with military training and weapons to cause significant damage. God only knows what they’ll do the next time. Possibly pose as real troops or law enforcement. If we’re lucky, Trump will just blow up the Republican Party instead of the whole country. But let’s not bet on being lucky. We need to be vigilant. This isn’t over yet.

over a year ago 39 votes

More in programming

Notes from Andreas Fredriksson’s “Context is Everything”

I quite enjoyed this talk. Some of the technical details went over my head (I don’t know what “split 16-bit mask into two 8-bit LTUs” means) but I could still follow the underlying point. First off, Andreas has a great story at the beginning about how he has a friend with a browser bookmarklet that replaces every occurrence of the word “dependency” with the word “liability”. Can you imagine npm working that way? Inside package.json: { "liabilities": { "react": "^19.0.0", "typescript": "^5.0.0" }, "devLiabilities": {...} } But I digress, back to Andreas. He points out that the context of your problems and the context of someone else’s problems do not overlap as often as we might think. It’s so unlikely that someone else tried to solve exactly our same problem with exactly our same constraints that [their solution or abstraction] will be the most economical or the best choice for us. It might be ok, but it won’t be the best thing. So while we immediately jump to tools built by others, the reality is that their tools were built for their problems and therefore won’t overlap with our problems as much or as often as we’re led to believe. In Andreas’ example, rather than using a third-party library to parse JSON and turn it into something, he writes his own bespoke parser for the problem at hand. His parser ignores a whole swath of abstractions a more generalized parser solves for, and guess what? His is an order of magnitude faster! Solving problems in the wrong domain and then glueing things together is always much, much worse [in terms of performance] than solving for what you actually need to solve. It’s fun watching him step through the performance gains as he goes from a generalized solution to one more tailored to his own specific context. What really resonates in his step-by-step process is how, as problems present themselves, you see how much easier it is to deal with performance issues for stuff you wrote vs. stuff others wrote. Not only that, but you can debug way faster! (Just think of the last time you tried to debug a file 1) you wrote, vs. 2) one you vendored vs. 3) one you installed deep down in node_modules somewhere.) Andreas goes from 41MB/s throughput to 1.25GB/s throughput without changing the behavior of the program. He merely removed a bunch of generalized abstractions he wasn’t using and didn’t need. Surprise, surprise: not doing unnecessary things is faster! You should always consider the unique context of your situation and weigh trade-offs. A “generic” solution means a solution “not tuned for your use case”. Email · Mastodon · Bluesky

15 hours ago 2 votes
Adding graphics support to DandeGUI

<![CDATA[DandeGUI now does graphics and this is what it looks like. Some text and graphics output windows created with DandeGUI on Medley Interlisp. In addition to the square root table text output demo, I created the other graphics windows with the newly implemented functionality. For example, this code draws the random circles of the top window: (DEFUN RANDOM-CIRCLES (&KEY (N 200) (MAX-R 50) (WIDTH 640) (HEIGHT 480)) (LET ((RANGE-X (- WIDTH ( 2 MAX-R))) (RANGE-Y (- HEIGHT ( 2 MAX-R))) (SHADES (LIST IL:BLACKSHADE IL:GRAYSHADE (RANDOM 65536)))) (DANDEGUI:WITH-GRAPHICS-WINDOW (STREAM :TITLE "Random Circles") (DOTIMES (I N) (DECLARE (IGNORE I)) (IL:FILLCIRCLE (+ MAX-R (RANDOM RANGE-X)) (+ MAX-R (RANDOM RANGE-Y)) (RANDOM MAX-R) (ELT SHADES (RANDOM 3)) STREAM))))) GUI:WITH-GRAPHICS-WINDOW, GUI:OPEN-GRAPHICS-STREAM, and GUI:WITH-GRAPHICS-STREAM are the main additions. These functions and macros are the equivalent for graphics of what GUI:WITH-OUTPUT-TO-WINDOW, GUI:OPEN-WINDOW-STREAM, and GUI:WITH-WINDOW-STREAM, respectively, do for text. The difference is the text facilities send output to TEXTSTREAM streams whereas the graphics facilities to IMAGESTREAM, a type of device-independent graphics streams. Under the hood DandeGUI text windows are customized TEdit windows with an associated TEXTSTREAM. TEdit is the rich text editor of Medley Interlisp. Similarly, the graphics windows of DandeGUI run the Sketch line drawing editor under the hood. Sketch windows have an IMAGESTREAM which Interlisp graphics primitives like IL:DRAWLINE and IL:DRAWPOINT accept as an output destination. DandeGUI creates and manages Sketch windows with the type of stream the graphics primitives require. In other words, IMAGESTREAM is to Sketch what TEXTSTREAM is to TEdit. The benefits of programmatically using Sketch for graphics are the same as TEdit windows for text: automatic window repainting, scrolling, and resizing. The downside is overhead. Scrolling more than a few thousand graphics elements is slow and adding even more may crash the system. However, this is an acceptable tradeoff. The new graphics functions and macros work similarly to the text ones, with a few differences. First, DandeGUI now depends on the SKETCH and SKETCH-STREAM library modules which it automatically loads. Since Sketch has no notion of a read-only drawing area GUI:OPEN-GRAPHICS-STREAM achieves the same effect by other means: (DEFUN OPEN-GRAPHICS-STREAM (&KEY (TITLE "Untitled")) "Open a new window and return the associated IMAGESTREAM to send graphics output to. Sets the window title to TITLE if supplied." (LET ((STREAM (IL:OPENIMAGESTREAM '|Untitled| 'IL:SKETCH '(IL:FONTS ,DEFAULT-FONT*))) (WINDOW (IL:\\SKSTRM.WINDOW.FROM.STREAM STREAM))) (IL:WINDOWPROP WINDOW 'IL:TITLE TITLE) ;; Disable left and middle-click title bar menu (IL:WINDOWPROP WINDOW 'IL:BUTTONEVENTFN NIL) ;; Disable sketch editing via right-click actions (IL:WINDOWPROP WINDOW 'IL:RIGHTBUTTONFN NIL) ;; Disable querying the user whether to save changes (IL:WINDOWPROP WINDOW 'IL:DONTQUERYCHANGES T) STREAM)) Only the mouse gestures and commands of the middle-click title bar menu and the right-click menu change the drawing area interactively. To disable these actions GUI:OPEN-GRAPHICS-STREAM removes their menu handlers by setting to NIL the window properties IL:BUTTONEVENTFN and IL:RIGHTBUTTONFN. This way only programmatic output can change the drawing area. The function also sets IL:DONTQUERYCHANGES to T to prevent querying whether to save the changes at window close. By design output to DandeGUI windows is not permanent, so saving isn't necessary. GUI:WITH-GRAPHICS-STREAM and GUI:WITH-GRAPHICS-WINDOW are straightforward: (DEFMACRO WITH-GRAPHICS-STREAM ((VAR STREAM) &BODY BODY) "Perform the operations in BODY with VAR bound to the graphics window STREAM. Evaluates the forms in BODY in a context in which VAR is bound to STREAM which must already exist, then returns the value of the last form of BODY." `(LET ((,VAR ,STREAM)) ,@BODY)) (DEFMACRO WITH-GRAPHICS-WINDOW ((VAR &KEY TITLE) &BODY BODY) "Perform the operations in BODY with VAR bound to a new graphics window stream. Creates a new window titled TITLE if supplied, binds VAR to the IMAGESTREAM associated with the window, and executes BODY in this context. Returns the value of the last form of BODY." `(WITH-GRAPHICS-STREAM (,VAR (OPEN-GRAPHICS-STREAM :TITLE (OR ,TITLE "Untitled"))) ,@BODY)) Unlike GUI:WITH-TEXT-STREAM and GUI:WITH-TEXT-WINDOW, which need to call GUI::WITH-WRITE-ENABLED to establish a read-only environment after every output operation, GUI:OPEN-GRAPHICS-STREAM can do this only once at window creation. GUI:CLEAR-WINDOW, GUI:WINDOW-TITLE, and GUI:PRINT-MESSAGE now work with graphics streams in addition to text streams. For IMAGESTREAM arguments GUI:PRINT-MESSAGE prints to the system prompt window as Sketch stream windows have no prompt area. The random circles and fractal triangles graphics demos round up the latest additions. #DandeGUI #CommonLisp #Interlisp #Lisp a href="https://remark.as/p/journal.paoloamoroso.com/adding-graphics-support-to-dandegui"Discuss.../a Email | Reply @amoroso@oldbytes.space !--emailsub--]]>

yesterday 4 votes
Exploring the web in 1995

By the end of 1995, the web moved outward and into the hands of everyone. The post Exploring the web in 1995 appeared first on The History of the Web.

2 days ago 4 votes
Gender and Sexuality Alliances in primary school at CIS?!

The Copenhagen International School is a wonderful private school located in the North Harbor of the city. It's home to over 900 students from around the world. This is where ambassadors, international executives, and other expats send their kids to get a great education in English while stationed in Denmark. As a result, it's perhaps the most diverse, inclusive school in all of Copenhagen. Lovely. What's less lovely is the fact that CIS seems to have caught some of the same gender-ideology obsession that has ravaged many schools in America. We thought Copenhagen would offer a respite from the woke nonsense that's been plaguing California — where some schools in our social circle ended up with a quarter or more of the student body identifying as trans or gender nonconformative — but it seems ideological contagions travel as fast as airplanes these days. It started last week, when the primary school, which includes kindergarten, declared its intention to spend every morning meeting for the entire week focused on gender dysphoria, transgenderism, they/them pronoun protocols, and coloring pride flags. That just sounded a bit odd and a bit much at first, but after reviewing the associated material, it actually looked downright devious. Just look at this example: Draw yourself in the mirror, then adorn it with trans colors? And the guiding example is a boy who sees himself as a girl? As you can imagine, many parents at the school were mortified by the idea of their children participating in this kind of overt indoctrination activities, and some of them let the school know. That's when the revisions started rolling out.  First, the program was revised to no longer apply to kindergarten and first grade, just second through fifth. Then the "draw yourself in the mirror and use trans colors to decorate it" activity was pulled from the program. Then the schedule was reduced from all week to just a single session this Monday while the rest of the material is being "reconsidered". And that's where it stands today. But that's not all. After talking to a number of other parents, I learned that CIS has other highly objectionable programs in this sphere. Like "Gender and Sexuality Alliances" where primary school students in G3-5, meaning kids as young as eight, are invited to join in lunch and recess meetings to talk more about gender, sexuality, and how to become a good ally to the 2SLGBTQIA+ community. According to one parent I spoke to (who's considering pulling their kids out over this), CIS hasn't wanted to disclose all specifics about the staff conducting these lunch and recess meetings with the children. Because while it's billed as "student led" on their website, the sessions are actually facilitated by CIS staff on campus.  I've asked the same question of the school administration, including what qualifications these individuals might have, and have not received an answer either. But ultimately, it shouldn't even matter, because this shouldn't even be happening! There's simply no responsible explanation for having kids as young as eight, or even as old as 11, in lunch and recess meetings with CIS staff to discuss gender and sexuality on school campus. It's preposterous, if not outright creepy. The school's mission is no cover either. The commitment to an inclusive school does not offer a license to indulge in this kind of overt indoctrination or inappropriate lunch meetings where minors discuss gender and sexuality with school staff. And it has to stop. CIS, like any other school, should not be a subsidiary of any specific interest organization. We don't want our kids to get their information about climate change from either Extinction Rebellion or fossil-fuel lobbyists. We expect our school to stay politically neutral on the international conflicts, like the one in Gaza. In higher grades where these topics are appropriate, they should be discussed in a context that also includes things like the Cass Review and the recent UK Supreme Court ruling. It's the same reason Copenhagen Pride Week saw a massive loss of sponsorship after trying to cajole major companies into a position on Gaza last year. Novo, Maersk, Google, and many others rejected this organization (and they're not returning this year either) for their partisan politics. It's bizarre that those same companies now have the children of their employees programmed by this organization's agenda at school.  CIS needs to return to its high-level mission of focusing on giving kids an excellent education, teaching them objectively about the world, and upholding general standards for kindness and caring. Not coloring partisan flags during school programs, not facilitating inappropriate meeting forums about gender and sexuality between staff and children.

2 days ago 3 votes
Is It JavaScript?

OH: It’s just JavaScript, right? I know JavaScript. My coworker who will inevitably spend the rest of the day debugging an electron issue — @jonkuperman.com on BlueSky “It’s Just JavaScript!” is probably a phrase you’ve heard before. I’ve used it myself a number of times. It gets thrown around a lot, often to imply that a particular project is approachable because it can be achieved writing the same, ubiquitous, standardized scripting language we all know and love: JavaScript. Take what you learned moving pixels around in a browser and apply that same language to running a server and querying a database. You can do both with the same language, It’s Just JavaScript! But wait, what is JavaScript? Is any code in a .js file “Just JavaScript”? Let’s play a little game I shall call: “Is It JavaScript?” Browser JavaScript let el = document.querySelector("#root"); window.location = "https://jim-nielsen.com"; That’s DOM stuff, i.e. browser APIs. Is it JavaScript? “If it runs in the browser, it’s JavaScript” seems like a pretty good rule of thumb. But can you say “It’s Just JavaScript” if it only runs in the browser? What about the inverse: code that won’t run in the browser but will run elsewhere? Server JavaScript const fs = require('fs'); const content = fs.readFileSync('./data.txt', 'utf8'); That will run in Node — or something with Node compatibility, like Deno — but not in the browser. Is it “Just JavaScript”? Environment Variables It’s very possible you’ve seen this in a .js file: const apiUrl = process.env.API_URL; But that’s following a Node convention which means that particular .js file probably won’t work as expected in a browser but will on a server. Is it “Just JavaScript” if executes but will only work as expected with special knowledge of runtime conventions? JSX What about this file MyComponent.js function MyComponent() { const handleClick = () => {/* do stuff */} return ( <Button onClick={handleClick}>Click me</Button> ) } That won’t run in a browser. It requires a compilation step to turn it into React.createElement(...) (or maybe even something else) which will run in a browser. Or wait, that can also run on the server. So it can run on a server or in the browser, but now requires a compilation step. Is it “Just JavaScript”? Pragmas What about this little nugget? /** @jsx h */ import { h } from "preact"; const HelloWorld = () => <div>Hello</div>; These are magic comments which affect the interpretation and compilation of JavaScript code (Tom MacWright has an excellent article on the subject). If code has magic comments that direct how it is compiled and subsequently executed, is it “Just JavaScript”? TypeScript What about: const name: string = "Hello world"; You see it everywhere and it seems almost synonymous with JavaScript, would you consider it “Just JavaScript”? Imports It’s very possible you’ve come across a .js file that looks like this at the top. import icon from './icon.svg'; import data from './data.json'; import styles from './styles.css'; import foo from '~/foo.js'; import foo from 'bar:foo'; But a lot of that syntax is non-standard (I’ve written about this topic previously in more detail) and requires some kind of compilation — is this “Just JavaScript”? Vanilla Here’s a .js file: var foo = 'bar'; I can run it here (in the browser). I can run it there (on the server). I can run it anywhere. It requires no compiler, no magic syntax, no bundler, no transpiler, no runtime-specific syntax. It’ll run the same everywhere. That seems like it is, in fact, Just JavaScript. As Always, Context Is Everything A lot of JavaScript you see every day is non-standard. Even though it might be rather ubiquitous — such as seeing processn.env.* — lots of JS code requires you to be “in the know” to understand how it’s actually working because it’s not following any part of the ECMAScript standard. There are a few vital pieces of context you need in order to understand a .js file, such as: Which runtime will this execute in? The browser? Something server-side like Node, Deno, or Bun? Or perhaps something else like Cloudflare Workers? What tools are required to compile this code before it can be executed in the runtime? (vite, esbuild, webpack, rollup typescript, etc.) What frameworks are implicit in the code? e.g. are there non-standard globals like Deno.* or special keyword exports like export function getServerSideProps(){...}? When somebody says, “It’s Just JavaScript” what would be more clear is to say “It’s Just JavaScript for…”, e.g. It’s just JavaScript for the browser It’s just JavaScript for Node It’s just JavaScript for Next.js So what would you call JavaScript that can run in any of the above contexts? Well, I suppose you would call that “Just JavaScript”. Email · Mastodon · Bluesky

3 days ago 4 votes