Technology and Lent

filed under: , , , , , , , , , , , , , , , , ,

4045 days ago

This website

The plugin that provided the email notification feature for this website broke with a recent update to my blog software, and it’s not going to be easy to fix. So I’m not going to fix it.

Of course, that means that the affected people aren’t going to hear that they’re affected. Sorry about that! (I’ll tell personally the few I know.)

In fact, I’m likely to switch to ikiwiki …eventually. Textpattern seems to have lost its mojo, and there have been some long-standing issues with it (like no native tagging support!) that seem unlikely to ever get fixed. And I’m hip to the cool technologies now, so a more infrastructure-like framework (i.e. ikiwiki, with git) for my blog feels like a better answer. And schmonz volunteered to do most of the work :)

That also means I’ll probably abandon tru_tags …more than I already have. There hasn’t been anything to do with it in a long while, at least not that I felt was worthwhile to be done. Most of the features that remain to be implemented require a major refactoring of the core Textpattern code, and that just seems very unlikely to happen (by me or anybody else) any time soon. So hopefully it will remain useful to the people who still use it.

This year’s Lent

I have utterly failed at this year’s Lent give-up. I have been better at going to bed at a reasonable hour, sometimes for days at a time. But I simply can’t do everything I need/want to do in my life with the few hours that leaves me between work, kids, and chores. So sleep will continue to lose to projects – although less-so than it used to. There are some nice perks to getting more sleep – I’m much more on-the-ball and willing to take on mental tasks that otherwise seem hard. But that extra value doesn’t offset the lost value from just not being able to do all the things I need to do.


Speaking of Lent, I also broke a 5-year streak of vegetarianism a week or so ago. Benjamin, Liam, and I had some extremely delicious tilapia, also breaking both boys’ life-long vegetarian streaks. Kristina chose not to participate.

We had a bunch of reasons for deciding to do it. And a bunch of reasons to not do it (i.e. to stay vegetarian). I may blog about all the tradeoffs some day soon, but for now, suffice it to say that it was a very close decision, and I’m not sure what’s next.

I made a web app!

If you recall, I started using SmugMug for my online gallery a few years ago. But when I made the switch, I left behind an old gallery site (on Menalto Gallery 1) that I’ve been meaning to clean up for a long time. It broke a while ago, motivating me to finally migrate off that old software – to ZenPhoto, which had been my long-standing plan. It took a few days getting ZenPhoto to work (when it should have been easy!), but I got it there, and I shut off the old site.

I also started this exchange with the ZenPhoto dev in which I start by being too grumpy and then he finished by insisting that his software simply must be unsupportable for him to support it. Net effect: I had to get off ZenPhoto.

But I had no alternate destination for self-hosting my images. My long-term goal is to migrate the images to SmugMug, but I want to filter them down from “every picture I took during that time period” to “just the best ones, tagged and rated” (like all the other pictures I post to SmugMug). And it will take Nathan-weeks of work to get that done, so it keeps getting put off. So in the short term I just needed a new self-hosting product, and there just aren’t any good alternatives. They’re all either old or ugly or badly designed or some combination of those three.

So I made one myself. I’ve never made a web app from scratch before, but I am quite comfortable in perl, had used Catalyst from a prior job, and I’d heard then that Mojolicious is better. So I tried it.

And wow, was it easy. Probably 8 hours total from “install mojolicious” to “the gallery is up and running on the new software”. That’s only just a little more than I spent trying to get ZenPhoto to work. Many kudos to Mojolicious, perl, and pkgsrc.

Now… ZenPhoto does way more stuff. (TONS more… too much, actually.) And this new software isn’t really ready for someone else to use it. And it has no tests. And it only does one extremely simple thing (i.e. serve nested directories of images, in name-sorted order, with no metadata).

But the code is small, easy to read, and easy to modify. (Roughly 300 lines of code, 115 lines of CSS, and 80 lines of HTML template.) The site looks really good (in my opinion). And it doesn’t require a database – just a directory full of images. And with some app-level caching and the help of Mojolicious’s preforking web server and great documentation for setting it up under apache mod_proxy, it’s about as fast is it could possibly be on my old host and slow network connection.

So ZenPhoto is out and my home-grown software is in. Here’s hoping it doesn’t need maintenance!

Add a comment [1]

How I manage my inbox

filed under: ,

4281 days ago

It turns out that other people don’t use email the same way I do. And it turns out that some people think my email use patterns might have some useful ideas. It also happens to be the case that I’m well-known for being good at keeping track of things, and my inbox is basically the way I do that, so maybe explaining my inbox will help people get better at keeping track of things. So here it is :)

First rule: the only things in the inbox are things that are still underway, in real life. Once something is done, the email gets deleted, archived, or filed in a folder.

Second rule: only have a single inbox that receives messages that might result in a to-do for you. Mail rules that filter email lists and such into folders is fine – as long as that email list is passive-only. (And in the rare case where something from the list generates a to-do, move that email to the inbox.)

Third rule: the inbox has three statuses:

  1. New / unread – the things that you haven’t seen yet, or that you need to deal with in the short term (today or tomorrow, ideally). Example: an email from your mother with a question about her TV.
  2. Flagged / starred – the things that you need to deal with in the longer term (3 days – a few weeks). Example: an email reminding you to blog about your inbox usage rules.
  3. Read / not-flagged – things where someone else is responsible for taking the next step, but which you want to keep tracking. Example: a shipping notice from, for an item that hasn’t arrived yet.

Fourth rule: everything that I have to keep track of (i.e. my to-do list) goes into my inbox. I am constantly sending myself little one-line emails, because that’s how I manage my to-do list.

Some secondary rules:

  • If something sits in the “flagged / starred” category long enough, give up and archive/delete/file it.
  • Periodically review the entire inbox, cleaning out things that aren’t going to get done, and following up on things that have stalled.
  • The entire inbox (all three categories) should always be relatively short. I can gauge how overworked I am by whether my inbox has 5 things in it (ideal!) or 50 (WAY too many). I typically run at about 20. Looking at my (personal) inbox now, I have 6 unread, 8 starred, and 4 read.

Some notes about how this works in Outlook / corporate email:

  • I use flags for the long-term to-do items, and unread for the “new” status. I’ve tried setting flag reminder dates, or using different-color flags, and neither adds much value (for me) compared to the time spent managing them.
  • I delete most email once it’s handled, but I don’t have Outlook remove things from the Deleted folder until it’s a month old.
  • I keep all my sent mail. (Have it be locally archived if your company restricts mailbox size on the server.)
  • I keep a few key folders for explicitly filing things – but not many. It’s easier to search than it is to manually file and then try to guess where I filed something. It’s also very freeing to just accept that deleting email is OK.
  • I usually have a few project-specific folders under my Inbox, where I stash things I might need to reference later for a specific project. Once the project is done, I delete the folder.
  • I also keep a single “Save” folder that catches most things I think I might want to get back to someday, and then usually I have a few sub-folders for specific topics (like “sales” or “people”) – but I keep it to just a few folders.

Some notes about how this works in Gmail:

  • I use Gmail’s priority inbox because it is designed for me. It effectively (automatically) splits the “new” category into “email I need to see soon” and “everything else”, and then gives me a split view of my three categories, so the most urgent stuff is at the top, and the least urgent at the bottom. It’s perfect.
  • I archive every email, no matter how unimportant, once I’m done with it. No sorting or (manual) tagging – search is the answer here. And by archiving everything, I don’t have to pause and make a decision about whether to archive or delete. Sometimes I’ll forward an email to myself just to add keywords to it, so I can find it more easily later, but that’s it.
  • I do make use of Gmail’s automatic filters, to automatically tag emails. Most of that’s for shopping stuff (like Amazon) so I can spot it easily and mark it read (until the item arrives, when I archive it). Sometimes I’ll make a manual tag for temporary topic management (like “holiday planning”), but that’s rare.

Add a comment [2]

I picked a bag: Tumi T-Tech Presidio Filbert T-Pass Organizer Laptop Briefcase

filed under: , , , , , ,

4346 days ago

(See my previous post for context.)

What? Seriously? Tumi T-Tech Presidio Filbert T-Pass Organizer Laptop Briefcase? Let’s break that name down:

  • Tumi: The company who makes the bag. Well known for making quality, well-designed bags.
  • T-Tech: The “collection” (i.e. all the bags in the T-Tech line share key features and styling).
  • Presidio: Uh… an even more narrowly-defined “collection”.
  • Filbert: The model name of the bag. (Really, Filbert? Someone thought that was a good name? As my wife says, this bag is royalty!)
  • T-Pass: The brand name they use for their “checkpoint friendly” feature.
  • Organizer: It has dividers for paper.
  • Laptop: It is designed to hold a laptop.
  • Briefcase: It is carried by handles and/or a shoulder strap, and doesn’t have a flap over the top (in which case it would be called “Messenger”).

So yeah, their marketing department needs to be sacked. What I bought was the Tumi Filbert Laptop Bag. But apparently that wasn’t confusing enough.

On the other hand, their product design department seems quite healthy – this is a great bag. Let’s review the criteria:


Laptop bag 4.0, backlogs, and story form

filed under: , , , , , , , ,

4354 days ago

Laptop bag 2.0

Somewhere out there is a laptop bag just waiting for me to find it. But first, I have to spec it out.

Like Rands, I recently got laptop bag religion and I spent an excessive amount of time cogitating about features, price, tradeoffs, where to buy, and features again.

Then I got serious about it.

I haven’t yet found the bag, but in the meantime, I’ve written this blog post, because it provided the excuse I needed to really go batshit insane do a thorough job of my analysis. Not only does this post include a detailed list of requirements for my perfect laptop bag, but it also includes a glance into what I do in my life as a Product Manager. Hopefully one or the other of those is interesting enough to keep your attention :)


Back online!

filed under: ,

5575 days ago

After about 40 days of offline-ness, is back up, mostly. is still down, but the rest of the websites are up. tru_tags (and instructions) are back up. The gallery is working. From a visitor’s point of view, everything (except is working as it was before.

Of course, all is not quite as it seems…


The long-overdue "I know what I did last summer" post

filed under: , , , , , , , , , , , ,

5616 days ago

Wow, according to my last post, it’s been 144 days since I blogged. Too long, but it’s a sign of how busy life has been. I’m going to use this post just to catch up quickly, then future posts will hopefully be more insightful:

  • I’m still a vegetarian
  • The new job is good (and I was promoted!), but time-intensive
  • The dogs are awesome
  • Buying the Honda Element was very much the right decision – it is perfect for the dogs and for Kristina’s plant (and dirt!) hauling
  • The new house is great
  • I did buy that motorcycle I had my eye on (and I love it!)
  • I sold my domain ( and replaced it with the one you see before you ( (And now has some very interesting content. But it’s a dumb name for a company.)
  • We all finally hired the right president

But of course, all of that put a ton of stress on my life and my wife, and we are still trying to recover from it. Speaking of which, she (my wife) also:

  • Turned 30, and got through a party that I think she would have preferred to delay
  • Took care of the dogs while I was traveling
  • Worked an internship
  • Took over as president of Pi Alpha Xi at OSU, and has had a stellar experience
  • Took a full load of classes this fall

Regular life things also happened. I’m sure I’ve forgotten many of them, but notable items include:

  • Discovered Pistacia Vera, an absolutely life-changing “dessert botique” (in Columbus!), that we now go to every weekend
  • Found DropBox and Carbonite, which are similar services that finally make file sharing and backup (respectively) just work the way they should have all along
  • Found Woot and its associated sites and got addicted; we’ve probably ordered 10 things from them so far
  • Amitai visited and during that visit, I bought a first-gen iPhone and hacked it to work with T-Mobile. (I love it!)
  • Had a very good Thanksgiving at my dad’s house, at which we learned some great news (that isn’t quite yet public)
  • Released two new versions of tru_tags, and used one of those releases to make this site’s archive page

So anyhow, it’s been really busy, and many parts of our life have fallen behind where we’d like them to be. The busyness hasn’t really been a problem… it’s just prevented us from doing other things we might want to be doing. I think our priorities are in the right place, though – I’m doing what I love, and Kristina is working toward a new life where she gets to do what she loves. I think that’s how things are supposed to be.

Add a comment

The Nerd Handbook

filed under: , , , , ,

5953 days ago

From The Nerd Handbook:

For any given piece of incoming information, your nerd is making a lightning fast assessment: relevant or not relevant? Relevance means that the incoming information fits into the system of things your nerd currently cares about. Expect active involvement from your nerd when you trip the relevance flag. If you trip the irrelevance flag, look for verbal punctuation announcing his judgment of irrelevance. It’s the word your nerd says when he’s not listening and it’s always the same. My word is “Cool”, and when you hear “Cool”, I’m not listening.

I received Managing Humans as a Christmas present, and it’s a fantastic book. It lead me to (back) to Rands in Repose which is now at the top of my list of great places to spend time on the internet. Enjoy :)

Add a comment

tru_tags: Releases

filed under: , , ,

6009 days ago

To learn more about tru_tags, check out the other tru_tags articles on this site.

Current Release

tru_tags 3.7 (for TXP 4.0.7 and above (including 4.2.0)) (download)

Forum announcement

This release includes two major things:

  1. a change to the way URLs are encode for “tags with spaces” and “tags-with-hyphens” and “tags+with+plusses” and “tags that-mix+them”. See this commit message for a great explanation of the problem and the fix.
  2. a performance improvement as suggested by whocarez on the forums


tru_tags: Usage instructions

filed under: , , ,

6009 days ago

To learn more about tru_tags, check out the other tru_tags articles on this site.


  1. Go to the releases page to get the latest release. Don’t save it – just open it in your browser.
  2. Scroll down a slight bit and follow the on-page instructions: copy/paste the big square block of characters into your Textpattern install, under Admin -> Plugins.
  3. Hit “Upload”.
  4. Remember to switch the plugin to “Active” in the plugin list.


Step 1: Create a new section

tru_tags depends on the existence of a special Textpattern section named “tag,” by default1. Create that section, using whatever settings you like. (You won’t be publishing articles to that section.) Here’s what I use2:

tag section configuration

1 You can use a different name, but you have to modify a setting in the plugin admin page to make everything work correctly. To do so, go to Extensions->tru_tags and update the Preferences.

2 Note that I use the ‘default’ page – that choice may not be right for you. This section will be shown whenever you click on a tag, to display the tag search results. You’ll want a page that has the correct layout/headers/footers. I use my default page, with <txp:if_section name="tag"> to change the page display in this case.

Step 2: Call the plugin from that section

To make tag searching and the default tag cloud work, you’ll need to call <txp:tru_tags_handler /> from the page you chose in Step 1. I replaced the default <txp:article /> with something like this:

<txp:if_section name="tag">
  <txp:tru_tags_handler />
<txp:else />
  <txp:article />

Note that tru_tags_handler uses the default “search_form” form for rendering its output, or you can override this with the form attribute.

Step 3: Configure your article form to display tags

To make each article show a list of all the tags associated with it, put someting like this in your article form:

  tags: <txp:tru_tags_from_article />

Step 4: Drop a custom tag cloud somewhere, if you want

If you’d like to show a tag cloud somewhere on your site (other than /tag/), put something like this in that page:

<txp:tru_tags_cloud />

See below for lots of styling and formatting options, including the ability to output a simple list instead of a cloud (using tru_tags_list).

Step 5: Start tagging!

Whenever you write an article, put your tags into the Keywords field in Textpattern. (The Keywords field hides behind the “Advanced Options” link on the left side of the “Write” page.) Tags should be separated by commas, and can have spaces1.

Make sure that your articles are in a section that is configured to be searchable. tru_tags will filter out articles from sections that aren’t searchable. This is a common question on the forum. Please look there first if you are having problems or have any questions – they are often addressed there.

1 Tags with spaces will generate urls with dashes, which will work correctly. Tags with dashes will also work correctly. Tags with both spaces and dashes will not work correctly.

Other optional configuration

Customize your page titles

You can use tru_tags_if_tag_search, tru_tags_tag_parameter, and txp:search_term to customize your page titles or tag search results. See below for details. For an example, do a tag search on this site and look at the titlebar.

If you don’t like the fact that all tags are shown in lowercase you can use ”text-transform: capitalize” in your CSS stylesheet, in conjunction with an appropriate class attribute on your tru_tags_cloud call, to capitalize the tags.

Customize your RSS and Atom feeds

By default, tru_tags includes article tags in the RSS and Atom feeds, using standard XML elements so that Technorati (and others) will discover the tags. If you don’t want this behavior you can turn it off by updating the Preferences on the Extensions->tru_tags tab in the Textpattern admin.

tru_tags also supports adding article tags to the ‘body’ of the feeds. That will let your readers see the tags also. This is off by default to preserve backwards compatibility. You can turn it on by editing the tru_tags preferences.

By default, the tags will show up at the end of your post in a paragraph that looks like “tags: trees, flowers, animals, etc” (with links, and with rel="tag"). If you want to customize this display, simply create a new ‘misc’ form (in the Textpattern admin) named “tru_tags_feed_tags”. Anything you put into that form will be put into the ‘body’ of your RSS/Atom feed(s). I suggest using something like this:

<h4>filed under: <txp:tru_tags_from_article /></h4>

This feature is even more powerful, though. You now have a generalized way to add content to your articles in your feeds. I use my tru_tags_feed_tags form to add a “Read more…” link to the articles, and to include all the user-posted comments in the feed. I’m sure there are other uses.

For reference, my complete tru_tags_feed_tags form contains:

<p><txp:permlink>Read more...</txp:permlink></p>
<h4 class="tags">filed under: <txp:tru_tags_from_article /></h4>
<txp:comments />

Create a tag-based archive page

This one is complicated, but quite useful. The goal is to create an ‘archive’ page that shows all the articles associated with each tag in your cloud. For example, check out mine.

Creating a tag-based archive page is very similar to creating a date-based archive page, so this may be easiest if you follow those instructions first, and then convert over to a tag-based archive from there. Or you might prefer to just follow these instructions:

There are three main steps: create a new section, call tru_tags_archive from that section (specifying a custom form), and use if_different and tru_tags_current_archive_tag in your custom form to display the articles associated with each tag. In detail:

Create a new section. I named mine “archive” and I used the default page, but you may need different settings. Note that you could probably do this without a whole new section, by just calling tru_tags_archive from a specific article or page (e.g. if you wanted it in your site’s sidebar), but this is how I did it. Here are my settings:

archive section settings

On the page for that section, call tru_tags_archive and set the form attribute. For example, you could do this:

<txp:if_section name="archive">
  <h2 class="article_title"><a href="/archive/">Archives by tag</a></h2>
  <txp:tru_tags_archive form="tag_archive" />

You’ll want to set the form attribute to the name of a form you haven’t created yet – so make something up that sounds about right (like “tag_archive”).

Some explanation: tru_tags_archive works by looping over all the tags in your tag cloud, and telling textpattern to search for all the associated articles, and render them – using the form you specified (with form). In the next step, we’ll customize the way each article is rendered to make the output just look like a list of article titles, grouped by tag. That’s the tricky part :)

Create a new form and use if_different and tru_tags_current_archive_tag to render the archive page. Give the form the name you used in the previous step (with form).

This bit is a difficult to explain. Basically, the form should just render each article however you want (usually with just a title and/or date). But something needs to render a header that shows the name of the current tag, so that has to be done here also. The problem is that you don’t want the header to appear above every article – you just want it to appear whenever the tag name switches to a new tag. That’s where if_different comes in. if_different does exactly what we want – it only renders the header (the tag name) if it is different from the last time if_different was called. So, that allows us to do something like this:

  <h2 class="archive"><txp:tru_tags_current_archive_tag link="1" /></h2>
<div class="archive">
  <h3><txp:permlink><txp:title /></txp:permlink></h3>
  <h4>~ <txp:posted format="%b %Y" /></h4>

And if everything was done correctly, that’s it! You should have a working archive page.

One last (optional) step: double-check that the page title for your archive section actually says something useful. Depending on how you manage your titles, it might not.

Show a “related tags” cloud

tru_tags has a feature that lets you show a cloud of tags that are related to the tags used in articles that are found by a tag search.

Got that?

To see an example, do a tag search on this site. (Click a link in the tag cloud.) When the search results come up the sidebar will have a new section in it called “Related Tags”. The cloud in that section contains all the tags used by all the articles in the search result. It’s a way to say “these other tags may be similar to the tag you just searched”.

Before you use this on your site, however, you should read the detailed instructions (below) carefully. This tag can have significant performance implications for your site, which your hosting provider might not be very happy about.

To use it anyway, put something like this into the appropriate page:

<txp:tru_tags_related_tags_from_search section="blog,reference" useoverallcounts="1" />

If you use the section attribute in your main tag cloud you should also use it here. See the documentation below for an explanation of why.

The useroverallcounts attribute causes the cloud to size the links according to how large they would be in the main cloud. That’s probably what you want, but it causes even more performance slowdown. See the documentation below for all the details.

Customize the tag display on the admin side

By default, tru_tags will show a list of tags on the ‘Write’ tab, in the ‘Advanced Options’ flyout, under the Keywords box, in the Textpattern admin.


If the list of tags gets too long, though, you may want to turn it off, which can be done by updating the preferences. Alternatively, you can install hpw_admincss and customize the admin-side CSS as follows:

.tru_tags_admin_tags {
	display: block;
	height: 100px;  /* set this to whatever you want */
	overflow: auto; /* this will cause a scrollbar to appear */

Turn on tag auto-completion on the admin side

If you have the jQuery Autocomplete plugin installed, tru_tags can auto-complete tag names in the Keywords field on the Write tab. In order for this to work, the jquery.autocomplete.css and jquery.autocomplete.min.js files have to be installed in a “js” folder at the root of your site. Once that is done, you will also need to turn on the feature using one of the configuration options on the plugin Extension tab (in the admin side).

Ongoing tag maintenance

Over time, you may find yourself with a number of articles that you’d like to re-tag, but with no easy way to update the tags on all those articles at once. See the Extensions->tru_tags page for a few tools that can help you with that.

That tab also has a feature that will allow you to redirect out-of-date tag searches to newer tags. For example, if you had been using a “netbsd” tag, but then deleted it, search engines might still have the link to the old tag search URL. You can use the Redirections feature to tell tru_tags to redirect all searches for the “netbsd” tag to the “geek” tag instead. If you don’t set a Redirect, tru_tags will generate the standard 404 page (unless you have overridden this behavior – see below).

Admin-side settings

There are a few other settings that you can control on the Extensions->tru_tags page, if you need them.

There are also a number of attributes available for each of the tru_tags tags. The attributes can significantly change the behavior of the tag(s), including enabling some features. Please read the instructions below for details.

Tag reference


This is the main function that drives tag search and shows the generic tag cloud. It should be called from the page that is used in the ‘tag’ section. It usually calls doArticles() (in the Textpattern code) to display tag search results, but if no tag was passed in the url it will call tru_tags_cloud instead.

This tag accepts most of the standard txp:article attributes, which will be applied during the tag search. Note that tru_tags_handler does not support using multiple sections with the section attribute, when doing a tag search. If multiple sections are passed, none are used.

If a tru_tags_handler is called for a tag that is no longer valid, it will redirect the user to the site’s default 404 page. You can override this behavior with the noarticles attribute, which accepts a URL that it will redirect to, instead. You can turn off this behavior by setting the 404redirect attribute to 0.

Note: In Textpattern, the limit attribute is defaulted to 10, to limit the output to 10 articles per page, and the txp:older and txp:newer tags are used to paginate the full list. The txp:older and txp:newer tags do not work with tru_tags, but the limit is still used by Textpattern when it outputs the articles. Therefore, tru_tags uses a default limit of 1000 when doing an article search. You can override this limit by setting the limit attribute on tru_tags_handler.

This tag will also accept all of the attributes used by tru_tags_cloud. See below for details.


This conditional tag can be used in an article form, and will render its contents if the current article has tags.


This tag can be used in an article form to return a list of tags associated with the current article. Typically (see below), each tag in the list will be a link (<a href=...>) to the tag search url for that particular tag.

  • wraptag, break, class, and breakclass attributes1, as defined by Textpattern.
  • generatelinks="0" will show the tags without generating links
  • linkpath can be used to generate tag links that don’t go to the default location. For example, setting linkpath="" will cause tru_tags to generate tag links like
  • linkpathtail can be used to specify a suffix for the linkpath-based link. For example, setting linkpathtail="/" will put a “/” on the end of the generated linkpath url.
  • texttransform can be used to change the capitalization of the tags. By default, tags will be displayed in lowercase, which is equivalent to setting this attribute to lowercase. You can also set texttransform to capitalize (Like This), uppercase (LIKE THIS), or capfirst (Like this).
  • title can be used to set the tooltip for all the tags.
  • usenofollow="1" will turn on rel="nofollow" in the links. This is off by default.
  • usereltag="1" (default) will turn on the rel="tag" attribute (used by Technorati), if you are using clean urls. Note that this won’t work if you turn off links.
    • Note: Article tags are included in the RSS and Atom feeds (by default).
  • useoverallcounts="1" will tell the tag list to render as a cloud (where each tag is sized according to its site-wide frequency). This tag isn’t sufficient on its own, however; once you set it you also need to set the cloud rendering attributes like maxpercent="200", setsizes="1", and setclasses="1" because these are all turned off by default. You’ll also then be able to use attributes like showcounts and sort. See the tru_tags_cloud documentation for details on these attributes.
    • Be careful, however, before turning this on. This attribute causes tru_tags to do an extra database query for each article displayed on a page. That extra query is equivalent to the query used to generate the overall cloud. This can cause a significant load increase on your server.

1 As with all Textpattern tags, class is only used if you specify an appropriate wraptag and breakclass is only used if you specify an appropriate break.



tru_tags_cloud can be used on any page, and is generally used to generate a simple tag cloud of all the tags used on your site. The cloud is really just a list of links, much like that generated by tru_tags_from_article, but with a style attribute set on each link to give it a font size ranging from 100% to 200%.

tru_tags_list can be used on any page, and is generally used to output a bulleted list of all the tags used on your site. By default, the tags will all have a font-size of 100%.

These two tags do the exact same thing – tru_tags_cloud just provides different defaults to tru_tags_list.

tru_tags_cloud and tru_tags_list both set the class attribute of each tag, specifying two (or three) classes. The first class groups the tags into categories, with classes of tagSizeSmallest, tagSizeMedium, and tagSizeLargest. Using these, you could make the smallest and largest tags have different styles than all the others.

The second class indicates the “step” of the current tag, with classes of tagSize1, tagSize2, and so on. These give you precise control over each tag size, if you want it.

The third class is only set on one tag, if you are currently on a tag search page. The current tag under search is given a class of tagActive (by default), or to whatever you set in the activeclass attribute.

If you use these classes to create special CSS rules, you may also want to set the setsizes attribute, described below.

  • wraptag, break, class, and breakclass attributes, as defined by Textpattern. tru_tags_cloud has a default break of a comma. tru_tags_list has a default wraptag of ul and a default break of li.
  • activeclass can be used to specify the class that should be given to the tag currently under search, on a tag search page.
  • countwrapchars, which controls the characters used to show the tag count, if showcounts is turned on. By default this is []. The first character will be put on the left side of the number, and the second character will be put on the right. For example countwrapchars="()" would show: life (3), tech (5)
  • excludesection can be set to a section or a list of sections that should be excluded from the tag cloud. This is an alternate to the section attribute, below, which is used to limit the tags to those from a specific set of sections.
  • filtersearch="0" will tell tru_tags to change its default behavior and include tags from all sections the tag cloud, ignoring the “Include in site search?” setting that the site administrator can set on the “Sections” tab (under “Presentation”). By default, tru_tags will filter out any section that is set to “No” on that tab. Note that you can still use the excludesection attribute to exclude specific sections from the cloud.
  • generatelinks="0" will show the tags without generating links
  • linkpath="" will cause tru_tags to generate tag links like
  • linkpathtail can be used to specify a suffix for the linkpath-based link. For example, setting linkpathtail="/" will put a “/” on the end of the generated linkpath url.
  • listlimit will limit the tag cloud to the specified number of tags. By default, it will keep the tags that are most frequently used (and discard the infrequently-used ones). It will not necessarily show exactly the number of tags specified, though. For example, if you set listlimit="10" and your site has 3 tags that have been used 10 times and 4 tags that have been used 7 times and 8 tags that have been used 3 times, the cloud will only show the top 7 tags, because it wasn’t able to fit the last set of 8 into the limit of 10. This behavior can be changed with the following attributes:
    • cutoff="exact" will tell listlimit to show exactly the number of tags you specify.
    • keep="random" will tell listlimit to keep a random set of tags, but tags with a higher frequency have a better chance of being included.
    • keep="alpha" will simply sort the tags alphabetically and keep the ones that come first in the list.
    • Note: setting keep (to anything) will automatically set cutoff="exact".
  • minpercent and maxpercent, which can be used to control the weighted font sizes in the tag cloud/list. tru_tags_cloud defaults to 100 and 200, respectively, and tru_tags_list defaults to 100 and 100.
  • mintagcount and maxtagcount can be used to hide tags that only have a few articles, or that have too many. They are defaulted to 0 and 1000, respectively. For example, mintagcount="2" would hide any tags that were only associated with a single article. If you do this, you may want to add a link to the default tag cloud, usually found at /tag/.
  • section, which tells it to limit the list to tags from the given section or sections. For example, <txp:tru_tags_cloud section="blog,reference" /> would only show tags from the “blog” and “reference” sections. By default, this is set to blank (to show tags from all sections).
    • Note: if you use section to limit the cloud to a particular section, it won’t limit the tag search feature to that section. The tag search finds (tagged) articles from all sections, no matter what. That’s a side-effect of the use of doArticles(), and I don’t think there’s anything I can do about it.
  • setclasses="0" will turn off the default class attributes.
  • setsizes="0" will turn off the default font sizing so you can control the sizes yourself (through CSS). It will leave behind the default CSS classes, which you can use to control the display of your cloud.
  • showcounts="1" will append a number indicating the number of times a tag has been used, to each tag in the list. For example, you might see: life [3], tech [5] in my tag cloud, if this was turned on. This is off by default.
    • This can also be used to put the counts in the title attribute of the links, which will make it appear in a tooltip. Use showcounts="title" or showcounts="both" (to show it in both places) to turn it on.
  • sort can be used to sort the cloud by tag frequency, rather than the default of alphabetically. Use sort="count" to sort by frequency in descending order, and sort="count asc" to sort by frequency in ascending order.
  • texttransform can be used to change the capitalization of the tags. By default, tags will be displayed in lowercase, which is equivalent to setting this attribute to lowercase. You can also set texttransform to capitalize (Like This), uppercase (LIKE THIS), or capfirst (Like this).
  • title can be used to set the tooltip for all the tags.
  • usenofollow="1" will turn on rel="nofollow" in the links. This is off by default.
  • usereltag="1" will turn on the rel="tag" attribute (used by Technorati), if you are using clean urls. Note that this won’t work if you turn off links. Note that this is off by default in tru_tags_cloud and tru_tags_list.
    • Note: Article tags are included in the RSS and Atom feeds (by default).

Note that you can use the attributes to make tru_tags_cloud and tru_tags_list behave exactly the same way. tru_tags_cloud is just a convenience function for generating a tag cloud using tru_tags_list. Therefore, it’s possible to have a tag cloud with tag counts showing, or have a bulleted list with variable font sizes, etc.

This conditional tag can be used anywhere and will render its contents if the current url indicates that there is a tag search going on. This can be useful if you want to do something like customize the titlebar when using the tag search.

  • tag will let you check if the search is for a specific tag (like tag=“tru_tags”)


This tag returns the tag (keyword) you are searching for. This way it is possible to render the ‘keyword’ searched for on a ‘tag search result page’ (/tag/keyword). This is generally used with tru_tags_if_tag_search.

  • striphyphens="1" will convert all hyphens to spaces in tag names. This is useful because tru_tags will convert spaces to hyphens when it does a tag search, and this undoes that conversion so you can display the tag name with spaces.
  • striphyphens="lookup" will actually look up the specific tag name that you have used, and return it. This is useful if you have some tags with hyphens and some with spaces, but it has to go query the database every time so it isn’t configured this way by default.
  • urlencode="1" will url-encode the tag name, so you can embed it in a link.


This tag works exactly like search_result_excerpt, except that search_result_excerpt doesn’t work correctly with tru_tags tag-searches, so this tag works around that problem. Use this tag in any situation where you would have used search_result_excerpt, even for regular (non-tru_tags) searches.


This tag supports all the attributes of search_result_excerpt.


This tag is deprecated. Please use txp:search_term instead.

This tag can be used anywhere and will return the text the user typed into the standard search box, during a regular search. This tag is not specifically related to tagging, but can be handy for customizing the titlebar on search result pages.

This tag is useful on the results page of a tag search. It generates a cloud of all the tags that are used by the articles found in that search, excluding the search tag itself. For example, if a tag search for “life” found three articles that were tagged as follows:

  1. money, health, life
  2. money, politics, life
  3. life

tru_tags_related_tags_from_search would generate a cloud containing “money”, “health”, and “politics”.

This is useful for generating a “related tags” cloud, as you can see in the sidebar of this site when you do a tag search.

Before you use this on your site, however, be warned that it’s not good for your site’s performance, and it’s a little bit of a hack (and therefore may break with newer versions of Textpattern). It is implemented by completely redoing the database query that found all the articles in the first place, which means that your site is essentially performing the search twice. Then, depending on the attributes you use, it may do a second query that is equivalent to the query that generates the “complete” tag cloud.

You may want to test this carefully if you have a hosting provider who charges you for CPU cycles. :)

If you decide to use this tag, be sure to minic the section and limit attributes from your tru_tags_cloud (or tru_tags_list) call, along with any txp:article attributes that you used in your tru_tags_handler call. If you don’t, the set of articles found/used by this tag won’t match the set that are displayed to the user.

  • All the attributes of txp:article
  • All the attributes of tru_tags_cloud / tru_tags_list.
  • useoverallcounts, which makes the cloud render using the frequency data for the site-wide tag cloud.
    • By default, tru_tags_related_tags_from_search outputs a cloud where the weights are based on the frequency of the tags in the search results. Using the example from above, “money” would have a weight that was double the weight of “health” and “politics”.
    • This attribute will change that behavior, making the tag sizes match the sizes used in the site-wide tag cloud. In other words, this cloud will look exactly like a subset of your sitewide cloud.
    • It will also add an extra database query to the mix (mentioned above), so consider performance carefully before using it.
  • tag_parameter, which will let you show a list of related tags for any arbitrary tag. This could be used with a hard-coded tag name, or by using the new attribute parsing features in 4.0.7.


This tag allows you to create a tag-based archive page (like this one). It accepts all the attributes that txp:article accepts. Your best bet is to follow the instructions.


This tag is only useful in concert with tru_tags_archive. Using these instructions, you can make a site-wide tag-based archive page (like this one).

This tag outputs the name of each tag as it is rendered by tru_tags_archive. It is meant to be used with if_different (a core TXP function) to generate headings for the archive page.

This tag only accepts one attribute:

  • link, which will render the tag name as a link. By default, tag names are only output as text.

Add a comment [129]

tru_tags: Feature list

filed under: , , ,

6009 days ago

To learn more about tru_tags, check out the other tru_tags articles on this site.

Core features

  • Tag any article with an unlimited number of tags
  • List all the tags associated with an article
  • Generate a tag cloud or simple tag list
  • Search for all articles tagged with a given tag
  • Clean URLs and rel="tag" support without mod_rewrite or .htaccess modifications
  • RSS and Atom support
  • Support for creating a tag-based archive page
  • Clickable list of tags in the ‘Write’ page of the Textpattern admin
  • Admin-side configurability
  • Admin-side tag maintenance and redirection tools
  • Tag links can go to external sites or alternate locations
  • Show a cloud of “related tags” in the search results page
  • Tag-based archive pages (like this one)
  • Designed with site security in mind
  • Clean, readable code

Advanced features

Adding tags to an article:

  • Tags can be multi-word, with spaces. (use commas to separate tags)

Listing tags for an article:

  • Supports standard textpattern attributes like wraptag / break / class / etc. (the default break is a comma)
  • Don’t have to generate links when showing tags
  • Can render article tags as a mini-cloud, including sorting and advanced cloud features

Tag cloud:

  • Supports standard textpattern attributes like wraptag / break / class / etc. (the default break is a comma)
  • Can filter a cloud to only show tags from specific sections
  • Can exclude specific sections from the cloud
  • Cloud automatically filters out future-dated articles and non-published articles
  • Uses percentages for font sizes, so the cloud can be in any container, with fonts of any specified size
  • Can specify min and max percentage sizes
  • Can show the number of times a tag has been used, after the link or in the title attribute
  • Don’t have to generate links when showing tags
  • Tags have the class attribute set in various ways, so you can take complete control over tag styling
  • Infrequently (or frequently) used tags can be hidden
  • Can sort the cloud by tag frequency (ascending or descending)
  • Can limit the cloud to a max of ‘N’ tags, with the ability to keep only the most-used tags or a random set (weighted by frequency)

Tag search:

  • Site admins can put the name of the tag currently being searched into titlebars or links to external sites (this is careful about scripting attacks)
  • A handy txp tag (tru_tags_search_parameter) to return whatever the user typed into Textpattern’s search field (this is careful about scripting attacks)
  • Renders search results just like the standard article list does. This means you have complete control over the tag search output formatting, and that it supports standard features like article excerpts, override forms, etc.
  • Customizable support for standard 404 pages

RSS / Atom feeds:

  • Includes article tags in the RSS and Atom feeds (which means that Technorati will correctly identify articles)
  • Can include article tags in the feed body
  • Can customise the feed body to change the look of the tags, and/or to add extra items to the feed


  • A few fancy javascript tricks to make it easy to use
  • List can be turned off or styled using CSS (and another plugin) if there are too many tags

Known issues (in the latest release)

  • tru_tags must use the Keywords field, and cannot use a custom field
  • No support for multiple tags at once (e.g. “life AND books”) tag search (but see this post for possibilities)
  • The tag cloud can be limited to just show tags from one section, but when you click a tag link from the cloud it shows articles from all sections
  • The tag search doesn’t support pagination. (It will show all the articles associated with a particular tag, no matter how many there are.)

Add a comment [9]

tru_tags: Roadmap

filed under: , , ,

6009 days ago

To learn more about tru_tags, check out the other tru_tags articles on this site.

This post contains an up-to-date list of all the (as-yet-unimplemented) feature requests that I’m aware of, with a rough indication of the order that I plan to implement them. If you have additional feature requests or want to suggest reprioritization of one of the features below, please add a post to the forum thread for this plugin. I’ll see it and update this page, and others will see the request also.

Group 1

  • Fix txp:older and txp:newer, and the broken limit attribute
  • Make txp:page_url work with tru_tags clean urls (see the forum post)
  • Add texttransform="capfirst" to tru_tags_tag_parameter (see forum post)
  • Make it possible to show a tag list in a popup (option/value) (see forum post)

Group 2

  • Limit cloud to tags from X recent articles, or within X time period
    • Order list by (oldest? newest?) article date
  • Color tags by age (of most recent article)

Group 3

  • Related article list (for a single article), based on number-of-matching-tags
    • Filter by section / category
    • Second-level sorting by date?
  • Limit cloud to a specific category

Group 4

  • Multi-tag search (tag1 + tag2)
    • General boolean logic ((tag1 or tag2) and tag3)

Group 5

  • Grouped index of tags – by section, category, alphabetical, etc
    • show articles for each tag?
    • single page per group
    • show tags (on the admin side) based on the category/section chosen
    • see Markus’s forum post about it
  • Grouping related keywords (admin-side)
  • Grouped-tag search (public side)
  • Color tags by category / section

Group 6

  • Move admin-side tag cloud to a better location (for big clouds)
  • Auto-complete typing in the Keywords field (admin-side)

Group “eventually”

  • mintagcount / maxtagcount, but based on percentages
  • Show a “related” cloud for general search-result pages (or other custom-generated article lists)
  • “There are [x] posts tagged: [tag_name]”
  • Alphabetical listing of articles in tag search result
  • Figure out Markus’s ideas about tagging, from the “Pivot” site (see forum post)
  • Sub-tags

Group “depends on the next release of Textpattern”

  • RSS feeds for individual tags

Recent events

filed under: , , , , , ,

6204 days ago

It’s been a while since I wrote and I have a small pile of small things that I wanted to write about, so I’m posting them all at once. In chronological order:

Cool blog / cool book

In my first case ever of one blog leading to another, Amitai’s blog led me to Bil Stachour’s blog, Journal Wunelle, on which I found this awesome post about evolutionary psychology and the book The Moral Animal. Bil writes intelligently, often, and interestingly, and his writeup of the book has led me to put it on my wishlist.

A combination street car and airplane

Check this out. Terrafugia has announced that they plan on creating the first commercially available flying car, called the Transition. I like living in this age :)

Buckeye Blast

On April 1st, I attended the Buckeye Blast, a fun-day shooting event put on by Buckeye Firearms Association, an orginzation heavily involved in passing the concealed carry laws in Ohio, and of which I am a member. The event is a fundraiser for the organization, and my wife bought my ticket as a birthday present.

The day was a blast! (ha ha) I learned more about real-life shooting in that day than I had in all my previous training and shooting, and greatly improved my shooting skills. I met a bunch of new people, and even got my picture taken. The event was held at the very impressive Tactical Defense Institute – I highly recommend them.

The Principles of Beautiful Web Design

One of my birthday presents was an awesome book called The Principles of Beautiful Web Design. For years the “designers” have been saying that the “coders” can’t learn what it takes to design great websites; this book tries to prove that wrong. You can judge for yourself when I update this site’s layout :) (someday soon…)

The shooting on my birthday

The Virginia Tech shooting happened on my birthday. It’s a very sad, tragic event, and I’m sorry that such things happen in this world. It was initially reminiscent of the Case Western shooting which was a little closer-to-home for me.

My mom asked me what I thought about the shooting, and my response sums up my whole belief about the issue: “if someone there had had a gun, they could have stopped the attacker.” It’s a shame that Virginia Tech (like Case Western) has a ban on all firearms on campus.

I know this is a big issue, but I don’t want to dwell on it. My middle sister (privately) wrote a great piece about her feelings and reflections after the event, and there’s a lot more like that on the web. I’ll leave it to others to hash out all the nuances, but I did want to get my broad-stroke opinion out in public.


There is other news, about life, work, and family, but most of it isn’t really good fodder for a public forum. Suffice it to say that all three have been interesting, hard, and good. This is a good time, for me.

Add a comment [3]

tru_podcast: A podcasting plugin for Textpattern

filed under: , , ,

6309 days ago

A friend of mine, Amitai, has been wanting podcasting support for his blog for a long while. He uses Textpattern, as I do, and it doesn’t support podcasting. Until recently, it was impossible to create a plugin to support it, but changes made in Textpattern 4.0.4 have made it possible. I therefore offered to help him create a podcasting plugin, and the net result was that I wrote it myself :)

I’m publishing it here as tru_podcast. It was designed to be simple, although I’m sure the feature requests are going to come piling in immediately, and it will grow. It supports Atom and RSS, with a single “enclosure” per article. The media file is specified via one of Textpattern’s custom fields.

I don’t actually use the plugin, but you can see it in use in Amitai’s music feed. Check out the feature list, releases, and usage instructions, and let me know what you think.


Add a comment [2]

tru_podcast: Usage instructions

filed under: , , ,

6309 days ago

To learn more about tru_podcast, check out the introductory article, the releases page, or the feature list.

Table of Contents


  1. Go to the releases page to get the latest release. Don’t save it – just open it in your browser.
  2. Scroll down a slight bit and follow the on-page instructions: copy/paste the big square block of characters into your Textpattern install, under Admin -> Plugins.
  3. Hit “Upload”.
  4. Remember to switch the plugin to “Active” in the plugin list.


Step 1: Rename one of your custom fields

tru_podcast uses a custom field named “tru_podcast”. Name one of your unused custom fields “tru_podcast” on the Admin -> Preferences -> Advanced tab.

tru_podcast custom field

Step 2: Upload a media file (a podcast)

Whenever you want to create a new episode, upload a media file to a web server. You can use Textpattern’s “Files” features, if you want. (Note that it is possible to FTP large media files to Textpattern’s files directory, and then use the “Files” tab in the admin to alert Textpattern that the file is there.)

Step 3: Start podcasting!

Find the tru_podcast field on the “Write” tab. It will be hiding behind the “Advanced Options” link.

Put the URL of the media file into that field. If you uploaded a file through Textpattern’s “Files” interface, just put the ID# of the file into the tru_podcast field. If the file is somewhere else on your web server, you can use a relative URL. Write whatever you want in the article, and save it.

That’s all it takes – the file will appear in your RSS and Atom feeds as an enclosure, and podcast clients (iTunes, for example) will identify it correctly.

You’ll probably want to install Rob Sable’s rss_admin_show_adv_opts, which will automatically expand the “Advanced Options” section of the “Write” page, when you are writing articles. That gives you easy access to the custom fields.

Step 4: Include links in your articles (Optional)

For people reading your site via their web browser, you can link to the media file from your articles with something like:

This article has a podcast!  <txp:tru_podcast_link linktext="Right here!" />
<txp:else />
No podcast here!

Step 5: Use a category to create a podcast-only feed (Optional)

You don’t have to create a special RSS feed for podcasts – the “enclosures” will simply show up in your normal feed(s) any time you specify a media file – but you can do so if you want. Simply create a new category for all your podcasting, and use the feed for that category as your podcast-only feed.

Step 6: Other types of “podcasts” (Optional)

You don’t have to limit yourself to audio; tru_podcast supports any type of media (video, images, etc.). As long as your server knows the correct MIME type for your media, everything should work.

Step 7: Advanced configuration (Optional)

The source code of tru_podcast has a few well-commented settings (right at the top) that you might want to change, especially if you use Textpattern’s “Files” features for your podcasts and if you’re using a non-default /files/ directory. If you run into problems with your podcast clients, you might want to try editing the plugin and changing those settings to see if it helps. (I don’t know of any problems with any clients, at the moment.)

Tag reference


This tag will generate an <a href... link if the current article has a podcast URL set. The generated link will automatically have rel="enclosure" set in case an old podcast client is looking for it. You can pass any attribute to this tag and it will be passed on to the <a> tag, except linktext as indicated below.

  • linktext will set the content of the <a>...</a> link. If you don’t specify linktext, it defaults to the URL of the media.
  • Any other attribute desired can be passed to the <a>. For example, <txp:tru_podcast_link linktext="test" junk="worthy" /> will generate this HTML: <a href="/some/media.url" junk="worthy">test</a>


This conditional tag will render its contents if the current article has an associated media file (in the tru_podcast custom field).


This tag will return the URL of an associated media file, if any.

  • full="1" tells tru_podcast_get_url to convert relative URLs to full URLs
  • protocol can be used in conjunction with full="1" to specify a protocol other than “http://” for the generated full URLs.
  • convertnumber="0" will turn off the automatic conversion of file index numbers (from Textpattern’s “Files” interface). This is only really useful if you want to get directly at the text entered into the tru_podcast custom field.

Add a comment [12]

tru_podcast: Feature list

filed under: , , ,

6309 days ago

To learn more about tru_podcast, check out the introductory article, the releases page, or the usage instructions.

Core features

  • “Enclosures” (1 per article) in RSS and Atom feeds
  • Tags to generate links (in the article) to that enclosure
  • Support for any media type, including audio, video, and images, with correct MIME-type handling
  • Support for relative URLs
  • Support for files uploaded via Textpattern’s “Files” feature

Known issues


Add a comment

tru_podcast: Releases

filed under: , , ,

6309 days ago

To learn more about tru_podcast, check out the introductory article, the feature list, or the usage instructions.

Current Release

tru_podcast 1.2 (download)

Forum announcement

In case anyone (ahem, schmonz) is still using this, it has been updated to work under Textpattern 4.4.1.


Emergency hard drive recovery: success!

filed under: , , ,

6317 days ago

Waaaay back in April of 2006, my cousin Karen (and her husband David) had a hard drive failure, resulting in the loss of all their digital pictures of their baby daughter Ella. They didn’t have backups, and they didn’t have prints. Computer shops weren’t able to help, and clean-room data recovery was too expensive. Eventually, they gave up on it and sent an email to the family asking if we could send them copies of any pictures we had.

I, being a geek, offered to take a look at the drive and see if I could get anything off of it. They, lacking any better options, sent the drive to me so I could give it a shot.

I dropped the drive into my NetBSD machine and sure enough, the BIOS recognized it. That meant that the drive was still physically working, and that I might have a chance at getting whatever data was left off the drive. I was able to mount the drive (read-only) and read data from it, which meant that there was a good chance of finding at least some of the pictures.

I did a bunch of googling and learned a lot about home-brew data recovery. To sum it up, I learned that you need:

  1. A copy of the dd utility that supports the conv=noerror argument. (netbsd’s dd does)
  2. A handy program that knows how to find images on a raw drive image. (See below)

I was able to make a copy of the bad drive (onto a good drive of mine) using dd and the instructions on this page. There were a lot of bad drive sectors encountered during the copy, which was to be expected given the fact that the drive had failed in the first place, but I was hopeful about finding at least some of the images. And having the drive copy was a big win – it meant that I could work with a copy that wouldn’t get worse if the hard drive took a dive.

The hard part was finding a program that could recover the images. For a long time I thought I was going to have to write my own, and that seemed a daunting task, but I finally found this guy who had this exact same problem and already wrote this program. It was exactly what I needed – a program that would find and extract images from a raw drive!

The only problem was that jpg-recover was running at about 15kb/s. At that rate, getting through the 80gb hard drive would have taken about 60 days to finish. I didn’t have 60 days (without interruption!) to wait.

So I dug into the code and discovered that it was horribly innefficient. It was reading data one byte at a time, checking for an image after each byte read, and just generally not being smart about performance. I set about improving it.

I was able to do so. My version takes more memory (a configurable amount) but it runs much faster: at about 12000kb/s. That’s 800x faster :) At that rate, it only took about two hours to finish, finding (after some tuning) 4,422 potential images, of which 187 were uncorrupted pictures of Ella – including this one.

That felt good :)

I’ve published my version of the program as jpg-recover-faster. It’s a perl script, so you’ll need perl. I make no guarantees about the lack of bugs – use this script at your own risk. It may eat your children. ;)

You’ll want to read the comment at the top of the script before using it, and the other pages listed above will help you figure out how to use it. Feel free to post comments here with questions or suggestions.

Add a comment [9]

Recipe / HOWTO for printing from linux/unix/BSD to Windows

filed under: ,

6326 days ago


This recipe tells how to configure a linux/unix/BSD machine and a Windows machine such that the unix machine can print to a printer attached to the Windows machine, even if it isn’t a postscript printer. This could also be adapted to work for OSX client machines.

How it works

Starting from the unix machine, a print job travels thusly:

  1. User prints something to a CUPS-configured print queue
  2. CUPS generate a postscript version of the printout, using Ghostscript and/or foomatic and/or gimp-print
  3. CUPS passes the postscript file to Samba which passes it over the network to a network-shared (virtual) postscript printer on the Windows box
  4. The virtual printer takes the poscript file and gives it RedMon which gives it to Ghostscript (on the Windows box), which prints it out to the actual printer

There’s a bit of work on the Windows side to set up Ghostscript and the virtual printer, and another bit of work on the unix side to set up Samba so you can print over the network, and then another bit of work to set up CUPS so it can accept printjobs and route them to Samba.


I'm in Textpattern!

filed under: , ,

6344 days ago

I recently submitted a patch to Textpattern to refactor some of the code to eliminate a lot of duplication and allow me to generate tag-based RSS feeds from my plugin. My patch has been applied to the “crockery” branch and will be a part of Textpattern 4.1. Cool!

Update: I’m in it again (in 4.0.5 and 4.1) with my comment patch. Cooler!

Add a comment [2]

Patch to allow (escaped) HTML in Textpattern comments

filed under: , ,

6356 days ago

(In case the title didn’t warn you, non-geeks probably won’t be interested in this article.)

Textpattern has a “feature” whereby HTML tags are completely stripped out of visitor comments, presumably to close a common security hole. I’ve created a patch for Textpattern 4.0.4 that changes it such that HTML tags in comments are allowed, but the relevant characters (<, >, &, ‘, “) are converted to entity codes and therefore aren’t treated as HTML delimiters and therefore aren’t a security concern.

Net effect: it’s possible to post HTML code examples in article comments. I’ll post such a comment right after I post this article, just to prove the point.

I’ll be announcing the patch in the txp-dev mailing list and on the forums, and inviting Textpattern developers to use this article as a place to test such comments. Hopefully it will be merged into the next official Textpattern release, so I don’t have to maintain this patch for more than a few months.

Add a comment [12]


filed under: , ,

6363 days ago

Just a few quick updates, between work and sleep:

Fun Stuff

At work the other day I spotted a background image that I really liked on a neighbor’s computer. I tracked down the source and discovered a treasure trove of fantastic backgrounds. The best ones are found by clicking the “Flame Favorites” links on this page (try this set, for example). You can learn more about Flame Fractals at lines and colors or

Work / Life

Work has been relatively insane the last few weeks. That’s the biggest reason I’ve been offline so much recently. On top of that, we’re hosting Thanksgiving Thursday, so we’ve been doing a lot of work to prep for that. The craziness will continue until about the end of the year. It’s good work, though, and I’m enjoying it.


Joel has posted a rather amusing article about usability in Windows Vista, Microsoft’s next version of Windows. He demonstrates the type of thinking that’s necessary for making great products. It’s also the type of thinking that makes great Business Analysts :)

Add a comment

Easy email redundancy for hardcore geeks

filed under:

6451 days ago

If you already host your own mail (preferably with qmail) and are comfortable with sending your email to Google’s Gmail service, try this:

  1. Configure your existing mail server as usual (spam filtering and saving non-spam mail) and also forward the non-spam mail to your Gmail account.
  2. Also configure a special email address (you-fromsecondary@specifichostname.yourdomain.ext) to do spam filtering and deliver mail to your Maildir/Mailbox, but don’t forward it to Gmail.
  3. Find a friend you trust who will let you use their server as a secondary mail server. Configure that server to accept mail for your domain.
  4. On that server, forward all mail to the special address at your primary server (you-fromsecondary@specifichostname.yourdomain.ext), and forward it to Gmail. Don’t save it to your Maildir/Mailbox.
  5. Configure your DNS records to point to your secondary server as a second MX.
  6. Configure Gmail so you can send email from Gmail and have it look like it came from you@yourdomain.ext.

Congratulations! You now have a working secondary mail server and a permanent archive (in Gmail) of every email that is sent to you, even after you delete them off your server. All email will still end up on your primary server (eventually), even if it goes down for a while (as long as the secondary doesn’t go down also). While your primary server is down, all your email will still be delivered to Gmail immediately. You have a quick-n-dirty form of webmail, via Gmail, and an easy way to search all your old email. You don’t have to change email addresses.

Enjoy :)

Add a comment [2]

Massive (paid-for!) update to tru_tags

filed under: , , ,

6493 days ago

I’m pleased to announce the public release of tru_tags v1.8, sponsored by Simon Finch, a consultant / web developer in the U.K.

This release of tru_tags contains two new features: a new type of tag cloud and the ability for article tags to render as a mini-cloud. I also massively refactored and condensed the code, making it much easier to read/understand and hopefully much easier to maintain.

The first new feature can be seen by clicking one of the links in my tag cloud (over in the sidebar). On the resulting page, you’ll see that a second cloud appears (in the sidebar) under the heading “Related Tags”. It is showing you all the tags that are related to the tag you clicked on.

I mentioned that this version was sponsored by Simon Finch, and it’s true – he paid for these specific features, because he needed them for a consulting project he was working on. That has me excited in all sorts of ways:

  1. My plugin is being used in the real world (in an online store!)
  2. Work that I originally did for my own benefit is now helping others
  3. I’m earning income that is derived from that original work
  4. I’m earning income from open-source software!

As usual, you can download this version from the announcement page and you can find out how to use it on the instructions page.

(For those of you waiting for other features, they’ll be coming soon in a v1.9. I wanted to get v1.8 out the door with just the features for Simon, so I’ve had to delay the rest of these.)

Thanks, Simon!

Add a comment [1]

Agile for Managers

filed under: , ,

6574 days ago

At minimum, my career at ThoughtWorks was a full-tilt education in “how to make Agile methodologies work.” I’ve experienced the best and worst of agile processes, and I have a very strong sense of what works, what doesn’t, and what’s irrelevant.

(For you non-geeks out there, “agile” is the name for a family of processes used to develop software. If you’re curious, you should follow the link below.)

When I came to NetJets I wanted to get all that knowledge out of my head and codify it somewhere, because my head is a notoriously bad place to store details. So I set about writing up “Agile for Managers” – an introduction to the spectrum of agile methodologies, with detailed notes about every major issue I could think of. Obviously, the target audience is the manager of a software shop; someone familiar with software development realities, but not necessarily familiar with agile methodologies.

I didn’t record all the deep insights and little details that really make it work – that would be found in “Agile for Analysts” and “Agile for Project Managers” and “Agile for Developers.” Instead, this is a roadmap to the core ideas, and a memory trigger (to me) for those details.

I wrote it all down as a TiddlyWiki, with the intent that I’d give a talk about it at NetJets. I never gave that talk, but the presentation still stands on its own. I’ve published it on this site, now, and hopefully the world will find it, and find it useful.

Before I give you the link, a warning: TiddlyWikis have issues with Internet Explorer, and with Greasemonkey. If you’re using either, please switch to Firefox and/or turn Greasemonkey off. (If you must use Internet Explorer, go ahead – it will probably work.)

With that, here it is: Agile for Managers. I hope you enjoy it – I put a lot of work into it.

If you have questions or issues or comments, please post them as comments in this article.

Add a comment

tru_tags: A tagging plugin for Textpattern

filed under: , , , ,

6625 days ago

When I first created this blog I wanted it to have tagging support, which doesn’t come built into Textpattern (my blog software). At the time (Christmas 2005), tagging plugins for Textpattern were virtually nonexistent. Hunting around the web, I found ran_tags, chh_keywords, rss_unlimited_categories, and ajw_technorati_tags. They were all unworkable for me, because of bugs or complexity or feature-set, so I was left without tagging support.

So I wrote my own, based on ran_tags. I published it on the textpattern forums and subsequently released about a dozen new versions, each with new features to make it more powerful and/or easier to use. The plugin has seen a lot of adoption, and seems to be popular among the textpattern community. You can see it in use on this site.

It’s written with ease-of-use, simplicity, and security in mind, and it has a very rich feature set. To learn more, please check out the features list. There is one (potential) downside for some users, though. To help keep the code simple, I call out to the Textpattern code to actually do the tag search. That means that articles can only be tagged via the Keywords field, rather than using a custom field. Some people use the keywords field for other purposes, so they can’t use tru_tags. There are also a few other minor annoyances documented on the features page.

tru_tags can be downloaded from the releases page, and you can learn to use it by reading the detailed usage instructions. If you have questions, please post comments to any of these articles, or in the forum, and I’ll get back to you quickly.


Add a comment [46]

First post!

filed under: ,

6627 days ago

...from my new NetBSD machine, running Firefox on X, that is :)

Just a quick note to the geeks out there that I’ve gotten X working on my NetBSD machine, along with:

  • Xfce as the window manager, although I tried KDE and Gnome also
  • XDM as the machine logon screen
  • Firefox as the browser
  • Java 1.5 working as a Firefox plugin (which required Linux emulation, via Suse)
  • Thunderbird as the email client
  • OpenOffice as the office suite
  • The BitStream fonts so web pages don’t look ugly

So that’s pretty cool – I was just able to log in graphically, check my email using Thunderbird, open a Word doc attachment and make changes. Then, just for kicks, I played some online java games, to prove that I could :)

But here’s the best part: I did (nearly) all of it using pkgsrc, just by typing “make install” in the right places. (And yes, the linux emulation just happened automagically.) Damn, but I love NetBSD.

Add a comment [6]