Blogging in Lisp


Lisplog is a templating system that blends Apache and Hunchentoot to aid in the maintenance of a blog-like web site.

It is open source, written in Common Lisp, and the code is at

I'm looking for work. My resumé is at

Sizing An iOS Custom Keyboard for Scaled Apps

Submitted by Bill St. Clair on Fri, 05 Aug 2016 19:24:19 GMT

I've been writing a custom iOS keyboard for Learning Touch, a novel way of entering text that we're hoping will be easier for people with non-steady hands, though it works fine for the rest of us, too. Can't give any more details until the patent request has been filed, but that will be soon.

I lay out the keyboard myself, with sizes designed to work on a standard 768x1024 pixel iPad, and scaled to the screen size of the device on which it's running. This works fine, for apps that have been updated for each device's screen size, but it failed for old apps that were scaled and/or run in letterbox mode; the keyboard was too wide, so part of it was invisible off the right edge of the screen.

I was just using the hardware bounds, in logical pixels. I needed to scale to the view size, which is narrower for scaled apps. The simple (Swift) code below takes the hardware size from UIScreen.mainScreen.bounds.size and the parent view size (that view is set outside this function and referenced with the getParentView() call).

Strangely, I found no hint of this algorithm in a bunch of Google searches, so I'm posting it, to hopefully make it easier for the next guy to find.

    public static func screenSize() -> CGSize {
        var size = UIScreen.mainScreen().bounds.size
        if let parent = getParentView() {
            // Accomodate for old apps that need to be scaled.
            let vw = parent.frame.width
            let factor = vw / size.width
            size.width = vw
            size.height *= factor
        return size

Unfortunately, there doesn't appear to be any way to tell if an app is running in letterbox mode, so you'll tend to size the keyboard vertically bigger than ideal for those.

Add comment   Edit post   Add post

Conway's Life in JavaScript

Submitted by Bill St. Clair on Thu, 26 May 2016 11:31:13 GMT

I was awake in the middle of the night a couple days back, so I spent two hours and wrote a minimal version of Conway's Life in JavaScript. Lots of potential work to do, but probably better to just use Golly, if my renewed interest in Life lasts for long.

I wrote my first Life in 1976 or thereabouts, in Fortran on a PDP-11/10 under DOS-11. Its display was via three D/A converters driving X, Y, and brightness on a video monitor. It got slow and warbly when lots of cells were full, due to having to visit each cell for a while to pump the brightness, wait for the eye to see it, then go to the next cell.

Add comment   Edit post   Add post

Mac OS X 10.11.4 Beachball on Wake from Sleep

Submitted by Bill St. Clair on Sun, 03 Apr 2016 15:26:31 GMT

Since updating to 10.11.4 on my 2011 iMac, my machine often beachballs on wake from sleep. Sometimes it eventually stops beachballing, so that I can enter my password, but often not. I have held the power button for 8 seconds on a few occasions, to power down. Restarting takes a long time, since I work with a lot of open applications.

Today, I discovered that if I SSH into the Mac from my iPhone (I use the "Serverauditor" app for that), and kill the "distnoted" process, the beachballing stops immediately. I did that as follows:

$ ps aux | grep distnoted
_spotlight  1119 0.0 0.0 2470808 1968   ?? S  Thu08PM 0:00.24 /usr/sbin/distnoted agent
billstclair 5057 0.0 0.0 2434840  680 s008 S+ 11:07AM 0:00.00 grep distnoted
billstclair 5058 0.0 0.0 2470808 1284   ?? S  11:07AM 0:00.01 /usr/sbin/distnoted agent
$ kill -kill 5058

Note that I chose the Process ID (PID) for the /usr/sbin/distnoted process for my User ID (billstclair).

I haven't tried it yet, but I think this will work just as well, and doesn't require you to choose and type a PID:

$ killall -e -kill distnoted

Of course, this will only work if you enable "Remote Login" in System Preferences/Sharing, and have an SSH client on another computer in your network.

1 comment   Edit post   Add post

Google Authenticator, in Your Web Browser

Submitted by Bill St. Clair on Sun, 28 Feb 2016 12:02:39 GMT

In anticipation of version 2.1 of the SMF forum software, which supports two-Factor authentication, I have written, in a single JavaScript-heavy web page, a near-clone of the Google Authenticator smart phone app. This allows you to enter one or more secret keys for two-factor authentication, and get the time-varying passwords you need to log in. Some of the administrators for a forum I maintain don't have smart phones, so they'll need an alternative if they are to use two-factor authentication.

It should work with any web site for which Google Authenticator works, assuming your computer's time is properly synchronized, which most modern computer's are.

It is entirely contained in one HTML file, and all the computations are done locally on your computer by the JavaScript in that file.

Documentation included in the file.

GitHub link at the bottom for the programmers in the audience.

Add comment   Edit post   Add post

Another Old Friend

Submitted by Bill St. Clair on Thu, 25 Feb 2016 02:34:25 GMT

I field-stripped and cleaned another old friend today. No rust here either. God bless the Bullfrog company!

M1A Field-Stripped
Springfield M1A field-stripped and cleaned

Springfield M1A
Springfield M1A reassembled after cleaning

Add comment   Edit post   Add post

Firefox Discontinuing Tab Groups

Submitted by Bill St. Clair on Fri, 12 Feb 2016 14:21:42 GMT

I saw a notice in the upgrade notes today for Firefox 44.0.1 that as of version 45, they're discontinuing the "Tab Groups" feature. Oh, NOOOO! Mr. Bill. I currently have 78 pages open in 7 tab groups. Fortunately, there are a few options that the Firefox folks recommend, or you can do nothing, and Firefox will save your tab groups when you upgrade to version 45.

I decided to install the Tab Groups addon. It automatically converts your existing tab groups, and its user interface is indistinguishable, to me, from the old built-in functionality, except there is now a help page that allows you to save and restore your tab groups. In particular, if you forget to install the add-on before the feature disappears from the standard Firefox distribution, you can restore from the save that Firefox does when it destroys your tabs.

Worked for me. Tab groups safe from the evil decisions of the Firefox development team. :)

Add comment   Edit post   Add post

Barlow's Declaration Turns Twenty

Submitted by Bill St. Clair on Tue, 09 Feb 2016 11:53:05 GMT

Jan Haas of AP at Wired - Its Been 20 Years Since This Man Declared Cyberspace Independence - On 8 February, 1996, John Perry Barlow first published the Declaration of Independence of Cyberspace. It is as true, relevant, and important today as ever. Thank you, sir!

A Declaration of the Independence of Cyberspace
by John Perry Barlow

Governments of the Industrial World, you weary giants of flesh and steel, I come from Cyberspace, the new home of Mind. On behalf of the future, I ask you of the past to leave us alone. You are not welcome among us. You have no sovereignty where we gather.

We have no elected government, nor are we likely to have one, so I address you with no greater authority than that with which liberty itself always speaks. I declare the global social space we are building to be naturally independent of the tyrannies you seek to impose on us. You have no moral right to rule us nor do you possess any methods of enforcement we have true reason to fear.

Governments derive their just powers from the consent of the governed. You have neither solicited nor received ours. We did not invite you. You do not know us, nor do you know our world. Cyberspace does not lie within your borders. Do not think that you can build it, as though it were a public construction project. You cannot. It is an act of nature and it grows itself through our collective actions.

You have not engaged in our great and gathering conversation, nor did you create the wealth of our marketplaces. You do not know our culture, our ethics, or the unwritten codes that already provide our society more order than could be obtained by any of your impositions.

You claim there are problems among us that you need to solve. You use this claim as an excuse to invade our precincts. Many of these problems don't exist. Where there are real conflicts, where there are wrongs, we will identify them and address them by our means. We are forming our own Social Contract. This governance will arise according to the conditions of our world, not yours. Our world is different.

Cyberspace consists of transactions, relationships, and thought itself, arrayed like a standing wave in the web of our communications. Ours is a world that is both everywhere and nowhere, but it is not where bodies live.

We are creating a world that all may enter without privilege or prejudice accorded by race, economic power, military force, or station of birth.

We are creating a world where anyone, anywhere may express his or her beliefs, no matter how singular, without fear of being coerced into silence or conformity.

Your legal concepts of property, expression, identity, movement, and context do not apply to us. They are all based on matter, and there is no matter here.

Our identities have no bodies, so, unlike you, we cannot obtain order by physical coercion. We believe that from ethics, enlightened self-interest, and the commonweal, our governance will emerge. Our identities may be distributed across many of your jurisdictions. The only law that all our constituent cultures would generally recognize is the Golden Rule. We hope we will be able to build our particular solutions on that basis. But we cannot accept the solutions you are attempting to impose.

In the United States, you have today created a law, the Telecommunications Reform Act, which repudiates your own Constitution and insults the dreams of Jefferson, Washington, Mill, Madison, DeToqueville, and Brandeis. These dreams must now be born anew in us.

You are terrified of your own children, since they are natives in a world where you will always be immigrants. Because you fear them, you entrust your bureaucracies with the parental responsibilities you are too cowardly to confront yourselves. In our world, all the sentiments and expressions of humanity, from the debasing to the angelic, are parts of a seamless whole, the global conversation of bits. We cannot separate the air that chokes from the air upon which wings beat.

In China, Germany, France, Russia, Singapore, Italy and the United States, you are trying to ward off the virus of liberty by erecting guard posts at the frontiers of Cyberspace. These may keep out the contagion for a small time, but they will not work in a world that will soon be blanketed in bit-bearing media.

Your increasingly obsolete information industries would perpetuate themselves by proposing laws, in America and elsewhere, that claim to own speech itself throughout the world. These laws would declare ideas to be another industrial product, no more noble than pig iron. In our world, whatever the human mind may create can be reproduced and distributed infinitely at no cost. The global conveyance of thought no longer requires your factories to accomplish.

These increasingly hostile and colonial measures place us in the same position as those previous lovers of freedom and self-determination who had to reject the authorities of distant, uninformed powers. We must declare our virtual selves immune to your sovereignty, even as we continue to consent to your rule over our bodies. We will spread ourselves across the Planet so that no one can arrest our thoughts.

We will create a civilization of the Mind in Cyberspace. May it be more humane and fair than the world your governments have made before.

Davos, Switzerland
February 8, 1996

Add comment   Edit post   Add post

Hello Again Old Friend

Submitted by Bill St. Clair on Mon, 08 Feb 2016 20:02:10 GMT

I think it's been over three years since I took my Colt AR-15 out of the safe. I used to go to the range at least once a week, with the AR quite often, though it had to share time with the M1A, the 444 Marlin, and my two most fun rifles, a Henry lever-action .22 and a 44 Marlin. Hand-loaded cowboy-action .44 Magnum lead-bullet loads make that Marlin one sweet rifle to shoot.

But I stopped improving and lost interest. Also, ammunition got a lot more expensive. Well, for some reason I decided today to field strip, clean, and oil the AR. Not a speck of rust, thanks largely I think to the Bullfrog Rust Blocker Emitter in the safe.

I usually clean and lubricate with BreakFree CLP (Cleaner, Lubricant, Preservative). That may also share responsbility for the lack of rust. Sometimes I use Bullfrog Rust Hunter Gun Wipes.

I clean the barrels of my rifles with exclusively Hoppe's BoreSnake Rifle Bore Cleaners (which I forgot to put in the image below). Since I discovered them many years ago, I haven't used a regular cleaning rod. I use shotgun cleaning patches soaked with BreakFree to clean the outside, but the inside stays shiny with only BreakFree on the BoreSnake. And a softly-sharpened wooden dowel helps with the nooks and crannies.

Must be time to take this rifle to the range.

Click on either image for the full-resolution version.

Colt AR-15 field-stripped
Colt AR-15 field-stripped and cleaned

Colt AR-15
Colt AR-15 reassembled after cleaning

Add comment   Edit post   Add post

Mail-in-a-Box Rocks!!

Submitted by Bill St. Clair on Tue, 19 Jan 2016 20:15:08 GMT

A couple of years ago, I set up a low-end Dell rack-mount server box for a friend of mine. It's running a bunch of Wordpress sites and a mail server in a server room in Montana. Rock solid.

In order to set up the mail server on that box, I followed a Howto I found on the web. It took a day or two to get just the email set up, and I never felt very confident about it, though it works to this day.

Well, that Montana hosting company charges $70/month to house, power, and feed the net to the box. In a few hours yesterday and today, I set up a Digital Ocean droplet for the web sites and another for the mail server. Two times $10/month = $20/month total. We'll switch over soon, and maybe my friend can get someone to buy her Dell server.

To set up the mail server droplet, I used Mail-in-a-Box, following Digital Ocean's installation instructions. It took an hour total (I still have to set up the DNS, but that shouldn't take long).

Yow! Mail-in-a-Box rocks!!

Add comment   Edit post   Add post

ReadErl Is Live

Submitted by Bill St. Clair on Sat, 31 Oct 2015 02:30:20 GMT

As my first Erlang project, I decided to create a multi-user RSS aggregator, sort of a simplified version of Google's now defunct "Reader". I named it ReadErl. I bought the domain, put up a static HTML "coming soon" page, and created an Erlang shell to fill in. My initial idea was to write the code in Erlang and use Chicago Boss for the web framework.


Then I discovered Elixir and the Phoenix web framework. Blown away. So I switched ReadErl to use those, created a simple Phoenix project, edited its default templates to make the result look pretty much like my original static HTML page, started up a brand new $5/month Digital Ocean droplet, and got it running there.


After getting up the initial page, I decided I wanted it to self-document the versions of the software on which it's based. That's now displayed in small type at the bottom of the page.

Here's how I did it (thanks to utkarshkukreti for the better way to get the :vsn of an app):

<div class="small text-center">
  <%= :erlang.system_info(:system_version) %><br/>
  Elixir: <%= System.version %>,
  Phoenix: <%= {:ok, vsn} = :application.get_key(:phoenix, :vsn); vsn %>

Add comment   Edit post   Add post