Upgrading to WordPress 2.5.1

After weeks of putting it off, I’ve upgraded to WordPress 2.5.1. I’ve been putting off the upgrade to WP 2.5.x because my WP install was a bit old (2.1.something, I think), and because I had a nagging suspicion (but no solid recollection) that I had mucked about in the WP source to make something work (bad idea), and I was concerned the upgrade might break it. This morning I decided to bite the bullet. If I did have custom changes to the WP source that I have lost, I haven’t noticed any ill effects. Which is not to say that everything went off without a hitch. Herewith some notes, hints, and suggestions on the upgrade.

First off I wanted to be sure I had good backups, because Murphy and I go way back. I host this site on DreamHost, and used their One-Click Installer option to set up WP originally. Because of this, I was able to upgrade with the One-Click Installer, which offers automatic backup of the entire WP directory tree, including your plugins, themes, etc. The whole tree is copied to a .old directory before any changes are made. Excellent. That only left backing up the database.

WordPress uses MySql , and there are a number of ways to backup a MySql database. Because my hosting account includes shell access (all DreamHost accounts do), I just did a full dump from the command line, which is dead simple and wicked fast:

mysqldump --opt -p -uMySqlUsername -h MySqlServername MyDBName > backup.sql

Note that while many resources will tell you to include you password in the above command by replacing -p with -pMySqlSecretPassword, this is a security risk on any system with more than one user. Don’t do it. Instead, just use -p, and mysqldump will prompt you for your password. The resulting backup.sql is a sql script that you can feed directly to mysql, which will recreate your entire database, data and all. Very nice.

So, precautions properly taken, I asked the One-Click installer to upgrade me. A couple of minutes later, I got an email telling me that my upgrade was successful, and instructing me to follow a link to a special page in my site’s Admin area that would complete the upgrade by updating my database structure. Which is when things took a turn for the worse.

The update database page would not load. The admin login screen would not load. The blog would not load. Half a dimension away, Murphy giggled maniacally as he enforced his Law. Jerk.

The error message indicated that one of my plugins was attempting to redefine a function already defined in one of the core WordPress files. Oops. I’ll just skip ahead here to something I learned after some quality time on The Google: It is recommended that you disable all plugins before upgrading from a pre-2.5 install to 2.5.x. Oops. Annoyingly (but perhaps predictably), the only way to disable a plugin is via the Admin interface. You know, the one that didn’t load. Oops.

Fast-forwards 20 minutes of increasingly irritated Googling, and I had learned that there is an entry in the MySql table wp_options named active_plugins (i.e., where option_name = 'active_plugins'). If you set the option_value field of this row to an empty string, all plugins are disabled. That was enough to let me access the Update Database page, complete the upgrade, and use the Admin interface.

Of course, the blog was still broken, because my theme templates rely on certain functions exposed by various plugins. I proceeded to turn on plugins one at a time, based on the error messages I saw, until things were working. The only problem I ran into was UltimateTagWarrior, which is no longer supported, as of WordPress 2.3. Shutup, Murphy.

The solution was not difficult, although it required a little more Googling than I expected. UTW was discontinued because WP got built-in tagging support in WP 2.3 (I believe). However, anyone who used UTW had theme templates containing calls to UTW-specific functions. In addition, UTW offered a number of tag display options not offered by the core WP install. So the plugin’s author Christine introduced a new plugin, UTW Theme Compatibility Thing, which offers all of the old UTW template functions, but uses WP’s native tagging system as the data source. Once I installed and activated that, everything worked, except that I had no tags on my posts. (Note: If you used icons with your tags, as I do, be sure to check the instructions on the Compatibility Thing wab page or the readme file; there are a couple of extra steps required to make them work.)

This turned out to be an easy fix as well, after more time on The Google. WordPress already includes a tool to convert UTW tags to WP tags. From the Manage tab of the Dashboard, choose Import, and then choose Ultimate Tag Warrior. Five clicks through the wizard later, and you’re all done.

As far as I can tell, everything is working now. If you have any problems using the site, or see anything funny, please drop me an email or a comment.

So far, I really like the new WordPress, and I’m looking forward to trying out the new image uploader and the Gallery. My only complaint so far is that the page preview has been moved out of the Write Post page; you now click to pop open a preview. Do not want. I’ll give it a couple of days to grow on me, and them I’m going to start looking for a plugin to add integrated preview to the Write page.

WordPress Plug-in Sought

I have a WordPress problem, and I’m hoping someone can point me at a plug-in that will help. If not, perhaps I’ll take a crack at it myself.

Like most bloggers, I use comment moderation to help prevent spam (along with Akismet, which does alot of the heavy lifting). I’m also using the option “Comment author must have a previously approved comment”. This option allows comments to bypass moderation if the commenter has a previously approved comment. In general, I prefer this approach - there are certainly some of you who comment here from time to time, and I’d rather your comments go live straightaway rather than wait on me to moderate. On the other hand, I’ve got about 10 comments right now awaiting moderation, because they aren’t really spam, but I don’t want to give the commenter a free pass to comment in the future. For example, my Ubuntu drive mounting tutorial draws a lot of thank-you comments, and many of them are very brief- they could be legit, or they could be someone trying to get me to approve one comment, so they can spam freely.

So what I want - I’d like an option on the Moderation Queue screen to approve a comment without “approving the commenter” so to speak. Anyone know of a plugin to accomplish this?

The Other Canned Meat

Back in June (when this site was still running on Blosxom), I disabled comments because of the amount of comment spam I was receiving. Over the course of several years I built a number of anti-spam measures into my Blosxom install, but without a moderation feature, I could only respond to spam that got past my tests by cleaning it up after the fact. Eventually, it was just too much.

When I switched to Wordpress in late August, I reenabled comments, because Wordpress offers comment moderation. I even added the following note to my comment form:

Hey Spammers! Comments are Moderated, so please save us both some time and move along. No matter how many you send, they’ll never show up. Really.

To the best of my knowledge, not a single spam has made it through- but not for a lack of trying. On an average day, I probably moderate 50 or so spam attempts. On an average day, I probably get <1 real comment.

Nearly three years ago, Mark Pilgrim posted a warning to those trying to develop anti-spam measures. Some folks criticized him for being too pessimistic, but he was dead on. From that post:

Spammers are smart and determined, and people are numerous and stupid, and spam pays. You can’t make it not pay. Going after their ISPs won’t help; they’ll auto-register somewhere else. (Already happening.) Going after their upstream provider won’t help; they’ll cut deals with the backbone providers and keep going. (Already happening.) Going after them in court won’t help; they’re already living under friendly governments. (Already happening.) You can’t stop them with Turing tests; they’ll hire child workers to read your images and manually register/post/ping/trackback/whatever. (Already happening.) Then they’ll attack you with the power of 100 million owned Windows boxes and knock you off the Internet. (Already happening.) They will keep coming and coming and coming until you give up, go home, cry uncle, take Prozac, get a regular day job to replace the one you quit when being an anti-spammer became your full-time job.

And they have kept coming and coming. I often get several copies of the same spam commented on the same post, each using a different method of encoding links: one with html <a> tags, one with wiki-like [brackets], and one with raw link text. Why bothering to figure out what kind of comment system you’re targeting when your automated spam-bot and cover every contingency, shotgun-style?

A couple of days ago, I got one that almost slipped past me. The following comment was left on this post about mounting an OS X partition from Ubuntu:

heyas all. my 40 gig drive is going to good use now. I have installed UBUNTU and have ordered KUBUNTU. I dont know how to install the driver for my ati radeon 9600xt. Actually i dont know if i am meant to be downloading and installing XFREE86 or the XORG version of the driver. I am downloading them both but i dont know how to do anything in Linux really. I dont know where I am meant to set up my modem or set up a net account. (no INETWIZ.EXE) So yeah, can someone help me out with getting my ATI driver installed? and does anyone know of a good long PDF file i can read and wrap my brain around. I’m still a Windows user, but I want to use Linux as much as possible. Thanks. :)

At first glance, it looks like a typical cry for free tech support, only tangentialy related to the topic at hand, as seen on many a help forum and blog comment feed. If it were legitimate, I’d allow it, even though I expect no one to help. But I’ve learned that not every spam contains a link in the body text, so I always check the link to the commenter’s web site. The site address was http://camera-digital.us, which looks like the kind of hokey “every variation on a theme” URLs that spammers and affiliate sites use. Even more curious, the authors email address was for the digital-camera.com domain- similar but different.

So I tried a google search for a line of text from the comment. The first three matches are blog posts with the exact same comment posted. In a couple cases, they actual comment was showing up in a Recent Comments list on the side of the page, but the original post that drew the comment was actually about Ubuntu.

So what’s the point of this post? None exactly- just like Mark’s post above, I don’t have a solution. I only know that the problem is getting worse.

Counting Posts

Daniel at The Web Design Journal emailed me to ask about the post count block that appears in my sidebar. For example:

There are 2 posts in the last 30 days, and 323 total posts.

There are a number of ways to get the total post count. The last 30 days post count is a feature I wanted to add when I switched to Wordpress and designed this theme. After searching for an existing solution, I ended up rolling my own. For reasons I don’t recall, I also wrote my own function for getting the total post count. I had meant to post it here, but had forgotten about it.

Instead of designing this as a Wordpress plugin, I added it directly to template. In my sidebar template, I added the following:

<p>There are <?php echo get_post_count_inlast(30) ?> posts in the last 30 days, 
    and <?php echo get_post_count() ?> total posts.  
    <a class="sidelink" href="<?php echo get_bloginfo('wpurl')?>/archive/">Archives &raquo;</a></p>

The special bits here are the calls to get_post_count_inlast() and get_post_count(), which are simple PHP functions I wrote to query the Wordpress MySQL database. I added these functions to functions.php in the theme directory for my theme. I’m not sure if all Wordpress theme include this file, but the default theme, on which I based my theme, already provided this file. In this file, I added the code for the two new functions:

function get_post_count() {
    global $wpdb;
    return $wpdb->get_var('select count(*) from wp_posts where post_status = "publish"');
}

function get_post_count_inlast($days=30) {
    global $wpdb;
    return $wpdb->get_var("select count(*) from wp_posts where post_status = 'publish' and DATEDIFF(CURRENT_DATE, POST_DATE) <= $days");
}

I’m no PHP expert, I’ve picked up just enough to make the tweaks I wanted to my templates, but I believe you could even include the function definitions directly in the sidebar.php file, as long as they’re inside a <?php ... ?> tag.

Hope someone finds this useful. If you decide to add this to your site, please drop me a comment, and be sure to fill in your site URL.

(The source code in this post is released under the GNU GPL (just like Wordpress), and comes with no warranty of any kind, express or implied.)

Notes on Converting from Blosxom to Wordpress

When I switched from Blosxom to Wordpress, I had intended to write a HOWTO explaining exactly how to accomplish the task. Unfortunately, this proved to be a real challenge, since no two Blosxoms are exactly the same - there are hundreds of plugins that can change the core behavior in ways both subtle and profound. Instead, I decided to write up some notes on what I did (and why), in hopes that it can help others who want to try and make the switch. Note: I’m using Wordpress 2.0.4, if you are on an older (especially pre-2.0) Wordpress, your mileage may vary.

After getting a basic Wordpress install setup on my webserver, I began by looking for a Blosxom import tool for Wordpress. I found Eric Davis’ import-blosxom.php, available from Eric’s software page. (Note: Houran Bosci has a modified version of Eric’s script which I only discovered after the fact, I’ve not tested it, but you may want to have a look at the changelog). Eric’s script didn’t come with any docs, so I tried dropping it into my wp-admin/import folder. I then went to the Import section of my Wordpress admin page, expecting to find a new option. Instead, the Blosxom import script’s output ( a series of instructions ) were oddly interspersed with the normal Import screen. I eventually found that the script had to be put directly in my wp-admin folder, and I had to go directly to that page with my browser.

Once you load import-blosxom.php in your browser, you get a page full of instructions. These instructions include the text for a Blosxom theme file, which creates a special RSS feed for your Blosxom site. It uses the extension .rss20 instead of .rss, so it shouldn’t conflict with your existing feed. You then fetch a copy of this feed, and the importer reads the feed to load your new Wordpress blog with your old content. Sounds simple, right? Yeah, I thought so too.

First, a few notes about setting up the special RSS feed. By default, it needs the theme plugin, which I didn’t use. You can break the theme up into multiple flavour files, but I found it easier to just install the theme plugin. Drop and go, as I recall. The theme plugin requires the interpolate_fancy plugin, which I did use, and the filesystem plugin, which I didn’t, but that was also a quick install.

Now, by default, Blosxom doesn’t show all posts, only the most recent (by default, 10). This limit is applied for any theme/flavour, including feeds. The number can be configured via the $num_entries variable in the Blosxom script. I played around briefly with trying to use the config plugin to allow me to change the number of entries for only this feed- I didn’t want anyone visiting the site or fetching the feed to get all my entries accidently. Unfortunately, config could not do what I wanted (plugins are just loaded too late, I believe), so I cheated and made a copy of my blosxom.cgi, changed $num_entries, and used that one to fetch the special feed. I also had to disable my moreentries plugin, although I can’t remember exactly what it was breaking.

Now, the importer doesn’t fetch your new feed directly, you have to fetch and save a copy (curl or wget are good for this), copy the file to your server, and edit the import script to point to this file. This is for safety, to make sure you only import what you want to import. My first attempt revealed a few deficiencies in the rss feed and the importer.

First of all, I used Markdown to author my posts in Blosxom, and intended to keep doing so with Wordpress. However, the RSS feed contains the rendered HTML, which is what gets imported into Wordpress. This imports your posts just fine, but I wanted to maintain my Markdown formatting in case of future edits. I ended up disabling Markdown long enough to fetch the feed with the original Markdown formatting intact.

The next hurdle was URIs. In an earlier post I discussed some of the steps I went through to ensure all of my old URIs would work in Wordpress, but the very first hurdle was preserving the post slug. In Wordpress parlance (and I believe, in publishing in general), the slug is a short name for an article. Specifically for Wordpress, the slug is the ‘file name’ of the post URI. The original import-blosxom.php created a slug for each post based on the title, similar to Wordpress’s default mechanism for creating slugs. However, in order to keep my old URIs working with a little mod_rewrite magic, I needed the slugs to match the original filenames used to store the Blosxom posts. I hacked this in as follows:

  1. I modified the rss20 theme file to include the original file name, by adding a line to the <item> section:

    <slug>$fn</slug>
    
  2. I re-fetched the feed to pick up the change.

  3. I edited import-blosxom.php to use the slug. I replaced this line:

    $post_name = sanitize_title($title);
    

    with this:

    $slug = ''
    preg_match('|<slug>(.*?)</slug>|is', $post, $slug);
    $post_name = $slug[1];
    

Now, my after import, my Wordpress slugs matched my Blosxom post names, making support of old URIs much simpler (see The Permalink Problem for more). But I wasn’t done yet.

Now, this is going to seem petty to some of you, and that’s fine. But it bothered my that the Wordpress post numbers of my import posts were backwards. The most recent imported post was post 1, and the oldest imported post was post 300-and-something. Even though you should never see the post number since I use fancy URIs, I bugged me. So, I fixed it. It may also be worth noting that though these iterations, I ended up futzing my Wordpress DB by hand to remove prior imports and reset the post numbering. Hopefully, if you’re following along at home on your own import, you’ll get this all right the first time.

The problem is, Blosxom renders posts in reverse chronological order, like every other blog. The import script reads the rss file and imports the posts in the order in which they appear in the file (which is to say, reverse chronological). But I wanted my posts numbers to be chronological. Yes, I’m a geek. Came to terms with it years ago. Anyway, remember earlier that I couldn’t get config to change the number of entries for the feed? I was, however, able to use it to install a custom Blosxom sort method, like so:

  1. Config has to run first, so i renamed the installed config plugin to 000config, the standard Blosxom hack for plugin load ordering.

  2. In my Blosxom content directory, I created config.rss20, the theme-specific config file for the rss20 theme:

    package config;
    
    
    sub sort {
      return sub {
        my($files_ref) = @_;
        return sort { $files_ref->{$a} <=> $files_ref->{$b} } keys %$files_ref;
      }
    };
    
    
    1;
    
  3. Another fetch-import cycle, and my posts were numbered chronologically.

Almost there. I had my content (including comments), but the comment and posts-per-category counts were all 0. It seems Wordpress stores these numbers in the database instead of calculating them on the fly, and the importer didn’t update them. A couple of quick sql statements set everything right:

UPDATE wp_posts p SET comment_count = ( SELECT count( * )
FROM `wp_comments` c
WHERE c.comment_post_id = p.id ) 

UPDATE wp_categories c SET category_count = ( SELECT count( * )
FROM wp_post2cat p
WHERE p.category_id = c.cat_id )

That’s everything I have in my notes. Hopefully, there’s enought here to help others with a similar conversion. If you find other conversion issues or have questions about my process, please leave a comment below and I’ll try to help

Odds and Ends

It’s been a busy week, but I’ve managed to find time for a little recreational computing here and there. Here’s the latest on some of my recent entries.

  • My Wordpress conversion is largely completed. I still need to get a comments Atom feed set up, and I’d still like to tag some of my pre-conversion posts, but I’m otherwise nearly done.

  • I still haven’t quite gotten tag pages working as I want, but I’ve got it working with redirects, for now.

  • I’m still making little tweaks to Tranquility, the Wordpress theme I created for the site, as well as some of the meta parts of the site. I haven’t finished the About or Colophon pages yet, but I did get the Licence page finished, and a number of minor display tweaks made.

  • I replaced my lousy V5 WRT54G with a $30 refurbished V1.1 and a copy of OpenWRT White Russian RC5, which rocks.

  • The one thing I’ve always wanted from my router has been DNS resolution of my DHCP host names; none of the Linksys firmwares across two models of router have done it, and neither did the last version of Sveasoft I tried (the last before the subscription fiasco). Works perfectly with OpenWRT; with a quick edit to the device’s /etc/hosts file, my static IP machines (my server, and the router itsself) also now have DNS-resolvable names.

  • Less than a week after I fixed my page titles, Google has reindexed most of them, so now my search hits have titles again.

  • Technorati is still showing lots of bad links from my test site, which is 410 Gone.

  • I still need to write up my Blosxom to Wordpress conversion method, which I promised to do. Hopefully by next weeked.

Every Old Problem is New Again

My recent redesign and switch to Wordpress was started about 6 months ago, and was allowed to languish until a couple weeks ago, when I found the time to finish the project. As a result, I keep running into little bugs/issues that I should have caught before I launched- stuff I thought about 6 months ago, and forgot about until now.

One example is tweaking for search engines. A couple of years ago, I made some tweaks to my Blosxom templates to help search engines better index my site. I added post titles to permalink (single post) pages, to make sure Google, et al, show more than just “jclark.org” above every hit on my site. I also added <meta name='robots' ... /> entries to ensure that category and date archive pages weren’t indexed, only permalinks (and the main index page). Of course, I forgot to add these changes to my Wordpress templates, and Google has recently reindexed me, so I’m back to square one.

I updated my header template (header.php) last night to get the post title back onto permalink pages. This was surprisingly easy, as WP offers a function aimed squarely at this purpose:

<title>jclark.org<?php single_post_title(' - ');?></title>

The function single_post_title will only output a value if the current page is a permalink page, optionally inserting a prefix (I use ' - '). This allowed me to update the header template used all across the site, without building my own switching logic. Because the entire html <head> section is in my header template, adding the robot meta directives will require a bit of switching logic; maybe I’ll check to see how single_post_title() is implemented and steal be inspired by that code.

The Permalink Problem

The conversion from Blosxom to Wordpress began (in my head, at least), over a year ago, when I began to consider switching from categories to tags as a way to reduce the “friction” of writing. Blosxom is good at many things, but its filesystem based storage isn’t well suited for tagging. After exploring several possiblilites, I decided I’d move away from Blosxom; eventually I settled on Wordpress.

The biggest hurdle I faced was dealing with permalinks. Blosxom supports two styles of permalinks: date-based and category based. I decided to go with category style permalinks (e.g., /weblog/Apple/macbook.html) when I first started using Blosxom because the URIs are “hackable”; you can whack the end (filename) off the URI and you’ve got the URI for the category. This worked fine when the site was category based, but fails with tags. For this reason, I’ve configured Wordpress to use date based URIs (e.g., /weblog/2006/01/01/macbook/); I also decided to drop the “.html” bit since its not necessary.

However, Cool URIs Don’t Change. There are plenty of old links to my site out around the Internets, which use category based-permalinks, that I don’t want to break. Even the internal links within existing posts on this site will continue to use the old URIs, at least until I can get around to cleaning them up. I wanted to keep supporting these existing URIs, so I needed to make sure I can support the old permalinks.

Wordpress supports category based permalinks, but with some caveats. If I configure the whole site to use category permalinks, then date-based URIs don’t work. If I configure the site to use date-based permalinks, category-based URIs don’t work. After searching for a plugin to help without success, I tried the Wordpress forums. When that failed to turn up a solution, I poked around the code looking for a solution.

(A brief aside. If you want to explore the Wordpress codebase, I recomment this excellent online cross-reference.)

I ended up creating a simple plugin that uses the “generate_rewrite_rules” action hook to add additional URI rewriting rules to the internal set used by Wordpress to resolve each URI. I hope to make it available as a plugin someday when I have time to make it more generic; currently its hardcoded to solve my problem. Here’s the heart of the code, if you want to build your own version:

function add_permalink_style($rewriteobj) {
    $extra_rewrite = $rewriteobj->generate_rewrite_rules('/%category%/%postname%.html', EP_PERMALINK);
    $extra_rewrite = apply_filters('post_rewrite_rules', $extra_rewrite);

    $rewriteobj->rules = array_merge($rewriteobj->rules, $extra_rewrite);
}

add_action('generate_rewrite_rules', 'add_permalink_style');

To help me test everything, I tossed together a quick and dirty test suite, a simple list of links to test from my browser. The code above allows them all to pass.

Because my old permalinks all included .html at the end, I can use the rewrite rule above to strip it out. I originally was doing that with a mod_rewrite rule in my .htaccess file, but that caused problems for old permalinks to my category archives. Since the mod_rewrite rule was stripping the .html suffix before wordpress could see the URI, category URIs (e.g. /weblog/Apple/OSX/) and category-style post permalinks (e.g. /weblog/Apple/OSX/howto-install-carbon-emacs/) matched the same pattern, and Wordpress thought the first example was for a post named “OSX” in the Apple category. I believe this is the same thing thats causing my tag URIs (e.g., /weblog/tag/wordpress/) to fail at the moment; the only workaround I’ve found requires a mod_rewrite RewriteRule, but only works with a browser redirect. I’m still working on this problem, as I really don’t want to use redirects. Also, for reasons I haven’t quite figured out, the above makes category permalinks work (and without a category URI prefix, see below), even though the rule expects a post name (slug) with .html appended- but I’m not going to argue with success.

Another issue I ran into was Wordpress always wanting a prefix in front of category archive links. For example, my Apple category’s archive link (by default) was /weblog/category/Apple/. Even though my plugin’s extra rewrite rule seems to make URIs like /weblog/Apple/ work, I wanted the catgeory links on my Archive page to omit the extra prefix, for consistancy. Wordpress allows you to change, but not omit, this prefix. I came up with a cheap hack for that problem; since I could already handle the URIs without the prefix, I only needed to change the URIs generated on the archive page via Wordpress’ wp_list_cats() function. I was able to do this in my plugin by hooking into the list_cats filter:

function fix_category_links($content) {
    $content = str_replace('/category/', '/', $content);
    return $content;
}

add_filter('list_cats', 'fix_category_links');

It’s a hack, but it’s a hack that works.

At this time, I believe all the old permalinks from my Blosxom blog (both posts and categories) should work, as well as the new date-based permalinks. A key part of all of this was to import my existing Blosxom content while preserving the filename (slug in Wordpress parlance), I’ll cover this and rest of the import process in a subsequent post. If you should find any links that don’t work, especially from external sources, please let me know. Now if I can just fix those tag URIs….

Converted

Well, I’ve (mostly) finished my converstion to Wordpress. If you’re viewing this site in your browser, the theme you’re seeing is called Tranquility, and I created it about 6 months ago, when I first started trying to convert to Wordpress. After a 6 month hiatus, it’s nice to finally show it off. Please leave a comment and let me know what you think.

If you’re reading this in your feed reader of choice, then you’ve successfully been redirected from the old rss feed, or the old Atom 0.3 feed, to my shiny new Atom 1.0 feed. Please come have a look at the website as well.

I’ve done my best to ensure that everything’s still here and still working, including old permalinks. I’ll have another post in the near future discussing the issues I had (and some solutions) with my existing permalinks; for now, please let me know by dropping a comment or an email (see the About page for my email info).

I’ve switched from hierarchical categories to tags; this is the first tagged post, but I hope to tag the older posts as well. You can still browse the old categories in the Archives.

I’ll have more to say about the conversion in the near future. For now, it’s late, and I’m done for the night.

Update: First bug- the tag links below don’t seem to be working. Oops.