Sometime this weekend, Amazon.com wishlists got a priority system; you can now mark items on a 5-rank scale from "Don't buy this for me" to "Must have", and wishlists can be sorted by priority.

This has been a long-desired feature and it's good to see it implemented, but I hope it'll be exposed through the webservices API soon; setting priorities on 17 pages worth of items with one form submit per item would be an exercise in frustration.

Stealth Disco is getting a fair amount of attention in various places.

Unsurprisingly, it appears to be stealth marketing, although I'm still not sure for whom.

StealthDisco.com is registered to

William L Hollister (CTLGDN-236318)
1323 N. Milwaukee #3
Chicago, IL 60622
US

Administrative Contact:
William L Hollister (236322) billhollister@yahoo.com
3126162594

Bill Hollister is a copywriter who joined Cramer-Krasselt's creative department in early 2003 after previous agency stints at Arnold Worldwide and Amster Yard. C-K is an "integrated marketing communications company" with offices in Chicago amongst other places.

Other people at C-K's Chicago office have phone numbers in the 312 616-2400 to 312 616-2600 range.

Stealth Disco is owned and controlled by a copyright at an Internet-facing marketing company from his desk at work. QED.

Update, minutes later: Okay, there's now a "who's behind this" link that basically says all that, but it wasn't there a few days when I first saw this and did the detective work.

If you're using browsing with Internet Explorer for Windows and you haven't tried it recently, it's time to give Mozilla Firebird a serious look. Firebird is faster, more standards compliant, more secure, and is designed with you in mind rather than large companies (ie: advertising blocking; popup blocking). Perhaps most importantly, Firebird is still getting better at an astonishing rate, while it's been years since the last IE update, and Microsoft has said there won't be another one, ever, without switching your OS to Longhorn when it's out in a few years.

If you've been reluctant because of how used you are to IE, then Jamie's guide to switching may be useful.

Help save the world; embrace the lizard.

The very first release of a textile 2 plugin for Blosxom is now available, based on Brad Choate's MT Textile 2 beta.

This is beta, or worse. It's been tested on all of half a dozen documents. The underlying engine it uses is also beta. You should expect both the plugin syntax and the markup syntax to change.

To use:

  1. download mttextile-2_0b.zip from Brad Choate's page
  2. download textile2-0-1i.zip
  3. create lib and lib/Text directories in your plugin state directory2, if you don't have them. install extlib/Text/Textile.pm from mttextile-2_0b in that directory
  4. install textile2 from textile2-0-1i.zip in your plugin directory
  5. look at textile2's configuration variables, consider changing them
  6. install the meta plugin if you don't have it installed
  7. rename plugins with numeric prefixes to ensure proper ordering, if necessary. meta needs to be before textile2, and is required. If you're using it, SmartyPants needs to be after textile2. Although it's not as important (or necessarily right), most other plugins that do text changes probably should be after textile2; that would include macros, wikiwordish, imagesizer (which isn't actually needed, in its stock form), and the like.3
  8. create a test story with meta-markup: textile2 in its header
  9. hope

The textile2 syntax is both more regular and more extensive than the textile 1 syntax, and is intended to be at least mostly backwards compatible. In at least one way that matters to me, it isn't, though1, so this plugin is designed to be usable side-by-side with the earlier textile plugin. If you're willing & wanting to switch over entirely, configure the $handle_textile_1 variable to 1 and remove the textile plugin; then meta-markup: textile will invoke textile2.

1 With textile 1, there doesn't have to be any space between the final '!' on an image link and following text; with textile 2, there does.

2 That's your plugin directory, not your plugin state directory; thanks to Andy Fragen for the note.

3 This step added following Andy Fragen's difficulties -- thanks for being a guinea pig, Andy!

That should be a h1 (well, h4, with my configuration)

this is a blockquote

this ia a normal paragraph

  1. this is
  2. a numbered
  3. list
  • this is
  • an unnumbered
  • list
this isa wikistyle table
with tworows andthree columns

Up to there, that's all textile-1 syntax too

this is a code block

this is a paragraph with id "first"

  1. Multi-level
  2. lists
    1. are now
    2. supported
  3. although
    1. it's not obvious
    2. how you would
  4. format them
    1. if you didn't have one
    2. parent item between
      1. each
      2. sublist

This is code here.

This is a test link

this should go back to first

bq.* Can blockquotes
* contain lists
* now?

Feedster, a great RSS-based blog search engine, has a new Backlog feature; you create an RSS feed for the full history of your blog and tell Feedster about it, and it does a one-time load of the whole thing.

There are a few different possible ways for Blosxom bloggers to generate this feed.

The easiest way, for people who started their blogs this year, would to use the built-in date-filtering system; for example, http://molelog.molehill.org/blox/2003/index.rss is an rss feed of all my posts from 2003.

If you have pre-2003 entries, you'll have to be a little more clever. A minimal solution, which has some other possible uses, is to use a very small plugin like the following:

package numentries;
use CGI;
sub start {
  $blosxom::num_entries = CGI::param('numentries') 
    if defined CGI::param('numentries');
  1;
}
1;

then give Feedster an url like http://molelog.molehill.org/blox/index.rss?numentries=1000 (where '1000' is high enough to include all your entries).

I've done more or less that -- rather than create a whole plugin for that, I've just included that snippit in my catch-all plugins for small things like that, jtl.

Update: specified CGI::param rather than just param, as new versions of CGI.pm require.

One of the huge mostly untapped promises of CSS is user stylesheets -- the ability of users to control the presentation as much as website owners/designers do. Almost all the modern browsers I use support them (I don't think Camino provides an interface, yet), but none except Opera ship with interesting example.

David Baron wrote up some useful notes on how they should be written nearly 4 years ago; although CSS has come a long way since then, these are stll the best notes I know of on this subject.

Have I just been missing something? Can someone point me at a great repository of useful and interesting user stylesheets to play with?

notestips explains an IE/win bug that can lead to missing or garbled text. They propose a workaround, which I'm now using here.

IE users, please let me know how this works for you, whether it fixes the missing text problems or not.

As previously mentioned, Sean Nolan has a very cool public Amazon RSS service, which he graciously supplies source for -- in ASP and XSLT.

I wanted to tweak a few things (remove the reviews from the description, give better feed titles for browsenode and authorsearch feeds (alas, only slightly better for browsenode), better links for the channel URL), but I don't have an ASP system, so I rewrote the scripts in perl.

If anybody's interested in tweaking further, the source is available under the same terms as Sean's original. You'll need perl, XML::Simple, LWP::Simple, XML::RSS and an Amazon developer's key; the URL arguments should be drop-in compatible with the original.

Dive Into Mark nicely summarizes some of the most-recent Recent Unpleasantness in the RSS world.

Nowadays, namespaces are funky, and funky is wrong, because everyone must do RSS exactly as UserLand does. The RSS validator is now known as Mark and Sam's validator, where Mark and Sam are grand arbiters making lots of value judgements that people "be on our case about".

Thank you, Brad. Thank you for proving exactly why we need a new format that is vendor-neutral, freely extensible, and thoroughly specified. I couldn't have said it better myself.

echo is looking promising, at least. Thank goodness.

Anthony Towns has a new blog, and he makes a pretty reasonable and interesting Blosxom suggestion

I think what would be nice is having blosxom see the files,

 -rw-r--r--    1 aj       aj            323 May 25 20:29 foo.txt
 -rw-r--r--    1 aj       aj             80 May 26 13:10 foo.txt-1
 -rw-r--r--    1 aj       aj            103 May 26 14:40 foo.txt-2

and magically translate that into an original entry, with two dated updates. You could then mark the files as uneditable once you've finished writing them, and not worry about accidently revising history.

A simple version of this would be pretty easy -- a plugin with a story() handler that looks for the -## files and just appends them, with an "Update ...:" header.

There are some interesting questions though about how it should act in the face of date sorting and specification; when showing index.html, should foo be listed as May 25 20:29 or May 26 14:40 (the former would be easier; the latter would be doable by supplying an entries()). When showing /2003/05/25 what should be shown? How about /2003/05/26?

Backup Brain points to this MacEdition Guide to CSS3 Selector Support, which shows some interesting patterns: IE6/Win is pretty dismal, IE5/Mac is decent, and current versions of Mozilla and Safari (and others that use the same underpinnings) are pretty good.

The surprising standout is MSN for Mac -- it's got nearly complete support. This is IE/Mac's Tasman rendering engine with a different UI on top of it, and presumably Microsoft could release a very nice IE6/Mac pretty easily -- but of course, they've said they are't going to.

As everyone who cares has already heard, Microsoft has announced the death of Internet Explorer for Macintosh.

I've not used IE/Mac in a while (first I moved to Chimera/Camino, then Safari), but I think the "ho hum" responses a lot of people are having a little unfair.

First, competition is a good thing; it leads to innovation and experimentation, and the best ideas can then be used by everybody. Second, IE/Mac is (and I get funny looks from people who know me every time I say this) a damn fine browser.

Eric Meyer is mourning too, and points out some of the major advances IE/Mac brought to the table. Now, nearly all of us (well, those of us who aren't using IE/Win, at least) are benefiting from these ideas in Mozilla proper, Safari, and the Mozilla-based browsers like Camino, Firebird, and galeon.

I wish to never see Courier again. It's ugly enough when large enough and done well, but when you combine X's rather lacking font implementation with small font sizes, it's useless. Useless, I tell you -- a code face in which you can't differentiate '{', '}' and '|' might as well be scribbled instead.

I have a variety of perfectly acceptable monospaced fonts (JMK's neep being my favorite -- I'd love to have that on OS X), and I've configured my browsers to use them rather than Courier for monospaced text, and that helps some. It doesn't do a damn thing, though, for pages that use <font face="Courier"> or equivalent CSS rules. I could click "always use my fonts", but that's killing a fly with a baseball bat.

Is there a CSS selector style I'm just missing, that would let me put a rule in a user stylesheet to say "always override Courier with Neep"?

Update: Example screenshots added

Courier This is Courier -- note how hard the braces and parentheses are to differentiate, how the '=' and '>' aren't vertically centered, and just how generally ugly it is.


Lucida Typewriter This is Lucida Typewriter, which I believe is a standard system font on Windows and thus nearly as ubiquitous as Courier. Note that braces and parenthesis are easily differentiated, as well as opening and closing braces.


Luxi Mono This is Luxi Mono, a good choice as a default mono face for current Linux systems (and in fact, it is the default "monotype" face for the Phoenix/XFT combination). The letterforms look a lot like Courier, nothing to really throw people off, while still being much easier to read.


Neep This is neep, my preferred coding face. Every character is readily distinguishable -- note the 'l's and single quotes. That does mean the letter forms aren't as close to Courier's as, say, Luxi's, but I'm more than willing to live with that for a face that's easy to read and never ever confuses me.

Ted Mielczarek has given the best example I know of why browser behavior should be user-extensible, whether via XUL or something else.

His flashblock Phoenix / Firebird plugin puts the user in control of Flash-based advertising: no more animated ads that can't be turned off, no more bits of the browser screen that don't respond to mouse wheels for no good reason. And all without giving up Flash entirely and putting up with the plugin popup windows, and having to switch to a different browser for the very occasional times you actually want to see Flash content.

I think Firebird is going to be my default Linux browser for a while now, and I may just switch on OS X too.

And for you Windows users out there, let me say again -- if you're using IE and haven't tried Mozilla or Firebird in a while (or ever), it's time. You'll be glad you did.

Oh wow, Mr. Williams Larason was in a horrible car accident, and I stand to make millions, all thanks to Barrister sabinus chibuikem, or so he says in a recent comment.

This is of course just a variant of the Nigerian 419 scam and hardly worth noticing, much less mentioning, except for the move to weblog comments and the small window that gives into the workings of the scam.

The message was posted from 192.116.126.198, part of a block assigned to SKY2Net ltd/gilat, apparently for use in Israel. The user got to this site via a Yahoo! search for 'names 20 to 55 years men and there email address in france.'; right now, this is hit #83 -- did he leave 82 comments before getting to me?

For reasons that are mostly sound and too long to go into here, I'm slowly upgrading a RedHat 7.2-ish box to RedHat 9-ish, without doing anything so crass as using the official upgrade software or rebooting the machine.

At the moment, glibc has been upgraded to 2.3.2, gcc to 3.2, XFree86 to 4.3, most of gnome to 2.2ish (not that it matters much, since I'm using garnome 2.4.2 for the bits of gnome I use), and python to 2.2, and the bare minimum of miscellaneous packages to make rpm happy with those bits.

Everything is working fine and dandy, and the improvements I was looking for are here -- except phoenix / MozillaFirebird no longer shows smart quotes properly. A curly apostrophe (&#8217;) shows up as a y-umlaut; a curly left double-quote (&#8220;) as an acute accent (I think), and a curly right double-quote (&8221;) as an upside-down exclamation point. They're in the source as numeric entities, so they aren't getting binary-mangled somewhere along the way, nor are they being interpreted as the wrong encoding or character set, so I'm pretty sure that just leaves font display problems.

I recompiled MozillaFirebird from CVS source, and that version does the same thing. Mozilla 1.4b works correctly.

Anyone have any ideas?

RDFWeb has an RSS family tree available (also as an SVG file, for those who are all cool and cutting edge, which apparently isn't me).

I haven't seen the "RSS Futures document" from Netscape that it mentions, and I think RSS 1.0 also inherits from at least Netscape RSS 0.91 and possibly up through Userland 0.92. It also doesn't list Userland RSS 0.93 or 0.94, but they'd go in the obvious place and don't have any impact on the rest of the tree.

Update: Rael Dornfest saved a copy of the "RSS Futures document" last time Netscape made it available.

Doug Alcorn had an emacs save-buffer-same-timestamp function, useful for editing Blosxom posts. I idly mentioned wanting to set it up to be auto-bound to C-x C-s for story files in my Blosxom tree, and before I could remember/figure out how to do that he posted an updated version.

LazyWeb wins again!

Sam Ruby points out a difference between the two RSS 0.91 specs that I missed in my comparison. Oops!

Netscape's <channel> can contain an optional <textinput> element; UserLand's may not, but has a very very similar <textInput> element.

This is similar to the confusion in OPML RSS subscription files over "htmlurl" and "htmlUrl"; could it be that Radio's XML parser is case insensitive and/or the UserLand folk(s) just think XML is?

I upgraded from Blosxom 1.x to 2.0, and plugins are acting weird. They're running, but...it's hard to describe. Sometimes they work, sometimes they don't. Any ideas what's going on?

One possible problem is that you copied & pasted your configuration variables, including the 'my' on those lines. In Blosxom 2.0, those need to be declared without 'my' so plugins can see them; if they have the 'my', they're private to blosxom, and plugins can't see the plog name, the data directory, etc.

On the Blosxom mailing list, Dave Walker asked about ways to profile Blosxom. There were a few suggestions, such as using time or Devel::SmallProf, but neither of those knows anything about how Blosxom works, and can't give information at very useful levels of detail (time isn't detailed enough; SmallProf is actually too detailed -- if all the time's going in Storable, you'd really rather know if it's from calendar or categories).

Frost Back pointed to the MTTimer Movable Type plugin and asked if anybody could port it.

I'm pretty sure the answer is "no" -- the plugin architectures are radically different, and MTTimer's tag-based approach just doesn't make any sense in a Blosxom world. That doesn't mean there aren't other ways of getting good information, though.

Presented here are two (count them: 1, 2 -- yes, two) completely and totally different ways to do Blosxom profiling. They both require Timer::HiRes but are believed to be otherwise dependancy-free.

Pure Plugin Profiling

The first one is for profiling a plugin at a time, and is minimally invasive; it uses a pair of plugins, "timer_start" and "timer_end". These plugins need to be named in such a way that they 'sandwich' the plugin you're interested in; for instance, if you have a plugin named '65wikiwordish' that you want to profile, you'd install these as '64timer_start' and '66timer_end'.

Together, they measure the time used in the sandwiched plugin's start, filter, head, date, story, foot, and end functions, and write the times out to standard error; usually, that will end up going to a log file.

This method isn't able to measure the time in 'entries', 'template' or 'interpolate', nor in the anonymous functions returned by those. As such, it isn't suitable for profiling plugins such as search (which uses entries), flavourdir (which uses template) or interpolate_conditional (which uses interpolate).

The output looks like (all on one line)

TIMER: date:0.003872 end:0.000100 filter:0.001381 foot:0.000099 head:0.000090 start:0.005967 story:0.012366

For best results, leave this running a while to get multiple result sets, rather than assuming the first one you see is representative. See below (after the invasive method) for information on a summarizing tool.

Incredibly Invasive Instrumentation

The second method replaces your whole blosxom.cgi script with one with lots of instrumentation added. It divides the whole Blosxom execution time up into multiple overlapping bits (in this version, 29 plus up to 9 per plugin). The 'instrumentation.txt' file included presents a hierarchical outline of how these bits relate to each other, but you'll likely need to dive into the blosxom.cgi source to figure out exactly what's included n what -- that's okay though, right, since f you aren't comfortable doing that you aren't trying to profile at that level anyway, right? right.

For each plugin, there's a "plugin_whole_name" bit, which includes all the time spent in the plugin, plus one "plugin_function_name" bit for each function the plugin actually uses; these may well be useful even without digging into the other bits.

The output format is the same as for the first method, except it's tagged with "TIMES" instead of "TIMER", and it's much much longer.

Summarizing

The included 'blos-times' script will the output of either of these (or both, comingled, optionally along with other stuff -- ie, it's okay to throw a whole error log at it), and produce possibly useful summary data. For each defined 'bit' it finds, it will display the minimum time, maximum time, total time, and the average time (mean) per run. Someone with more statistical interest than I might want to add median and standard deviation, but what's there is there.

Using

Download, unzip, and use. If you use the alternate blosxom script, make sure to configure it before you install it, and don't erase your real one. The longer you run it, the better the information you'll get from it, but it chews up disk space so keep an eye on it.

No software comes with a guarantee, and this is no different; that said, it's even less supported than most of my plugins, but it's presented in the hope of being useful or inspiring.

Hyatt has a brief introduction to the magic of XBL, showing how the cool Zen Garden could be even cooler if all the world were Gecko.

I'm using Blosxom 2.0rc2 and some plugins, like 'meta' and 'SmartyPants' are working just fine, but others, like 'buy_from_amazon' and 'ping_weblogs_com' aren't; it's like they're not there at all! What the heck's going on?

You may be tripping over a perl bug; Perl 5.6.0 as shipped with Mac OS X 10.2 (Jaguar) has this problem, as do at least some compilations of 5.5_003.

To work around the bug, change line 149 of blosxom.cgi from

    my($plugin_name, $off) = $plugin =~ /^\d*(\w+?)(_)?$/;

to

    my($plugin_name, $off) = $plugin =~ /^\d*(\w+?)(_?)$/;

. (the only change is transposing the ')' and '?' at the end).

If you're interested in the details of the perl bug, read on; if not, feel free to stop here.

Still here? Okay.

The problem seems to lie in setting the values of capture variables (like $2) for parenthesis that don't match. In the original expression, the (_) doesn't match anything when the expression finally matches, so $2 should be undef; it's not, though, it's "_".

If you walk through the RE evaluator, there's a pretty plausible way this could happen -- at some point, the (\w+?) is matched against "ping_weblogs"; since the ? makes the + non-greedy, the matcher tries to make a match by continuing in the expression; it matches the final "_" against the (_), sets $2 to "_", and goes on, only to run into the "$"; since it's not at the end of the string, the evaluator backtracks to the last choice it made -- and it should clear out the capture variables it set on the way. Possibly as a slightly misguided optimization, it does not -- after all, it'll get set again if the expression matches, right? Finally, the evaluator's matched the whole "ping_weblogs_com" against the (\w+?), and it continues on; it doesn't match the "_" in "(_)", so doesn't set $2, but it turns out that's okay -- that whole group is optional. It gets to the "$", which matches, and it's done, we have a match! But $2 is still set to "_" from the earlier failed match attempt.

The fixed version works just alike, except the (_) isn't optional -- it always matches, it just sometimes matches the empty string. Thus, when the evaluator gets to the final match, and checks (_?) against the end of the string, the parenthesis DO match, and do get filled in -- with "".

This seems to be fixed in 5.6.1, and $2 is properly either "_" or undef in the original version of the expression; the changed version still works too (although the choices are now "_" or "").

This fix will be incorporated into 2.0rc3, due out any day now, so this FAQ entry will hopefully have a short shelf-life as such, but the details of the bug may stay interesting longer.

<link rel="stylesheet" type="text/css" href="blosxom.css" />

A stylesheet link like that won't work with Blosxom for two related but different reasons.

First, it's using a relative URL for the stylesheet, but what that means will vary depending on how the page is accessed. http://molelog.molehill.org/blox/, http://molelog.molehill.org/blox/Computers/Internet/Web/Blosxom/FAQ and http://molelog.molehill.org/blox/2003/04/29/, for instance, will lead to three different meanings for what "blosxom.css" means (it's slightly worse than that, actually! http://molelog.molehill.org/blox/2003/04/29 leads to a fourth meaning for "blosxom.css").

So, you need to specify a full path for your stylesheet. But what full path? That leads to problem #2.

Blosxom serves up blog pages only; it doesn't serve up individual files. If you specified "$url/blosxom.css", Blosxom would go looking for the "blosxom.txt" story and the "css" flavour. Your stylesheet (as well as other related files, such as images) need to be put in a directory where the webserver can get to them directly, not via Blosxom, and you need to give a full path for that.

For instance, I use:

<link rel="stylesheet"
type="text/css"
href="/blog/flavours/$flavour/molelog.css"
title="Default">

It's well known that <link> with "stylesheet" and "alternate sylesheet" relationships can be used to provide multiple user-selectable stylesheets (at least when they're using a non-broken browser).

What isn't so well known is that there are actually three types of stylehseets: persistent, preferred, and alternate. Although alternate stylehseets are differentiated, reasonably enough, by 'rel="alternate stylesheet"', the difference between persistent and preferred isn't so obvious.

Preferred stylesheets are those that are replacable with alternate stylesheets, and are probably what you want to be using for your main stylesheet if you're usign altenate stylesheets. Preferred stylesheets have a rel attribute of "stylesheet" and have a title.

Persistent stylesheets are used in addition to whatever preferred or alternate stylesheet the user has selected. You probably don't want to use any of these if you're supplying alternate stylesheets. Persistent stylesheets have a rel attribute of "stylesheet" and no title.

Thanks to Netscape DevEdge for explaining this. I never would have figured it out on my own by experimentation, and had somehow completely missed it in the HTML spec.

Most of my plugins' instructions include like "Look at your error log.". What if your hosting provider won't let you, though?

Well, first, consider getting a different hosting provider -- this one obviously isn't concerned with making it easy (or even possible) for you to do interesting work.

What if that's not an option, though?

Well, the SeeError plugin is a partial solution. In normaly use, it redirects all error output to a temporary file, then appends it to the end of the served page, and removes the temporary file.

If the $handle_die option is enabled, then any raised exceptions will cause a "Possibly-Fatal Error" message to be output to the browser, along wih whatever error text is available. This mode is useful if the only output you're otherwise getting is "fatal server error".

This is not a perfect solution. Drawbacks include, but may not be limited to:

  • error output before seemore is loaded is lost
  • error output after seemore's end() is called is lost
  • if there's a fatal error, no other error output will be printed, even if $handle_die is set; nor will the temporary file be cleaned up
  • this plugin can't be usefully controlled via blosxom's normal enable/disable mechanism; in particular, disabling it will appear to work but will lead to sustained disk-space loss as temporary files are created and not removed. do not leave this plugin installed but disabled.
  • the $handle_die option gives quite a bit of spurious output; it's invoked any time an eval fails, even though that's a perfectly normal occurance, and as far as I can tell it can't differentiate the important times from the unimportant.

Using:

  • download the plugin, unzip it, and put the plugin file in your plugin directory
  • turn on $handle_die if you need to (ie, if you're getting "Fatal server error" rather than blog output)
  • configure the $tmp_dir if you need to; the default should work for unix-like systems.
  • browse to your blog and scroll to the bottom; any error output will be appended. (Depending on your html formatting, you may actually need to look at the page source to see it)

There's an interesting distributed discusson on RSS's past, problems, and possible future going on, includng a concrete proposal for how to move RSS 2.0 to a fully-embeddable namespace-protected format.

William at MyDimension points out the right way to mark external links -- CSS3 attribute selectors.

div.content a[href^="http:"] {
background: transparent url('/images/aoutside.gif') 100% 50% no-repeat;
padding-right: 10px;
}

div.content a[href^="http://my-dimension.com"],
div.content a[href^="http://www.my-dimension.com"] {
background: inherit;
padding-right: 0px;
}

Of course, you can guess the drawback, I'm sure -- that's right, it doesn't work in most users' browsers. It works in gecko-based Browsers (ie, Mozilla, Camino, Galeon) and Safari (and other KHTML-based?), but not in Opera or IE.

William credits As Days Pass By for the method.

Inspired by Danny O'Brien's lucky Google VIM macro, but being both an Emacs user and even lazier than him, I've whipped up some automatic lucky Google macros.

Proper nouns, acronyms, and anything in {{double braces}} gets linked to a Google search for that term, with the "I'm Feeling Lucky" option turned on.

I'm sure there's problems with them -- in particular, I'm worried about the proper noun one leading to nested <A>s -- but they seem to be working pretty well, and they're kinda spiffy, so here you go.

I may turn off the completely automatic ones after a while, but I think I'll be keeping the double braces.

Update: I'm now running a new version of these, with the following improvements:

  • the double-brace one matches inner-braces rather than leftmost-braces, making the display on my example look better
  • the REs are spread out and somewhat commented, using perl's /x mode, so there's some hope of understanding what they do
  • the nested <a> problem is taken care of. Unfortunately, this required a new feature in the macros plugin, a 'redo' flag, which causes the macro to keep being run over a block of text as long as it's still changing it; the nested-anchor stripper needs this to be able to deal with an arbitrary number of anchors within another anchor; for any specific maximum, you could just repeat the macro definition that many times.

If you want to use these now, you can as always grab a copy of the actual plugins that I'm running, but as those are by definition works-in-progress they're more likely to have problems (and be harder to install, and be underdocumented) than the real releases.

You're probably using classic MacOS to create your stories, but MacOS X or some other Unix system to run Blosxom.

Normally on MacOS, text files' lines end with carriage returns, while on Unix they end with linefeeds. Thus when a MacOS text file is moved to a Unix machine without being translated (or vice versa), it looks like one long line with some funny characters in it.

The easiest way to translate files is to let your file transfer software do it for you -- in FTP clients, you want to transfer text files in 'text' mode as opposed to 'binary' or 'raw'.

Another option is to create and edit your stories with a text editor that can use either convention, and tell it to use Unix-style (linefeed) line endings.

Calendar's been updated.

Feature changes:

  • New configuration variable $first_dow lets you control which day of week weeks start with
  • New variable $count available in templates, the number of stories in the day/week/month/year
  • Besides $year_calendar, year calendars are built for each year from the current year back to the first year with stories, named $year_calendar_2003 and so on.
  • The default templates include story counts in appropriate places.
  • When generating a month calendar for year with no month specified, choose the last month in the year with stories in it, rather than always choosing December; use December if the year has no stories at all.
  • When saving the cache, try to create the plugin state dir if it doesn't exist.
  • When counting stories, ignore any stories with a timestamp that matches $^T. This does mean that during the second a new story is posted, a generated calendar may not be quite right, but also makes the cache work much better with plugins that dynamically create 'stories' that shouldn't get counted, so long as they set the timestamp to $^T (such as a not-yet-released version of AutoCorrect) -- that's the whole point of these $^T changes.

Bug Fixes:

  • In month calendar, include 'week_foot' for partial last week, if there is one (ie, include the final <tr>)
  • Clear the cache if the day changes, not just when stories are added
  • Properly count the number of stories to tell when to clear the cache; 0+5i accidentally used the number of hash buckets filled rather than the number of items in the hash -- oops
  • If a year before 1970 is (apparently) requested, forcibly switch to year 2000 and log the full requested path, to try to figure out what causes this. Earlier versions would die when trying to build the month calendar. If you see "Bad year ... requested" lines logged, please let me know.

Changed for reasons only I care about:

  • Use $^T rather than time in various places

Things I'd like to be able to do, but can't reasonably without Blosxom changes:

  • use the built-in interpolation system, including any interpolate plugin that's installed
  • create months for appropriate dates in static mode

To install:

  1. download and unzip the plugin.
  2. Copy it to your plugins directory. Make sure it's world-readable.
  3. Modify a head or foot file to include $calendar::calendar, $calendar::month_calendar or $calendar::year_calendar
  4. Try it out — load your blog in your browser. If you see a calendar, great!
  5. Look at your error log. Verify you have an 'enabled' line.
  6. If you're wanting to verify caching is working, load the page again, and now look for an error log line "calendar debug 1: Using cached state"
  7. Once you're satisfied it's working, edit the $debug_level configuration variable to 0. There are a couple other configuration variables you may wish to change, too.
  8. Drop me a note to let me know you're using it; if you're having problems, let me know and I might be able to help. If everything's working okay, please let me know that, too.

Molelog is running this, with some customized templates and stylesheets.

Stylesheet:

.calendar { }
.calendar table {
	margin-left:		auto; 
	margin-right:		auto;
}
.calendar table .prev-link {
	margin-left:		0; 
	text-align:		left;
}
.calendar table .next-link {
	margin-right:		0;
	text-align:		right;
}
.month-calendar, .year-calendar {
	border-collapse:	collapse; 
}
.month-calendar-head, .year-calendar-head {
	font-size:		110%;
	font-weight:		bold;
}
.month-calendar-day-head, .year-calendar-subhead {
	font-weight:		normal;
}

.month-calendar {
	text-align: 		center;
}

.month-calendar-day-noday,
.month-calendar-day-link,
.month-calendar-day-nolink,
.month-calendar-day-this-day,
.month-calendar-day-future {
	font-family:		Georgia,New Century Schoolbook,Times,serif;
}

.year-calendar-month-link, 
.year-calendar-month-nolink,
.year-calendar-this-month, 
.year-calendar-month-future {
}

.month-calendar-day-future, .year-calendar-month-future {
	color:			#83660F;
}

.month-calendar {
	background:		#fff3de;
	border: 		1px solid #83660f;
}
.calendar th {
	border-bottom: 		1px dotted #83660f;
}
.Saturday {
	border-left:		1px dotted #83660f;
}
.Sunday {
	border-right:		1px dotted #83660f;
}
.Saturday, .Sunday {
	background:		#f5deb3;
}
.month-calendar-day-this-day, .year-calendar-this-month {
	background:		#a5e4ff;
}
.year-calendar {
	background:		#fff3de;
	border: 		1px dotted #83660f;
}

calendar.calendar.html":http://molelog.molehill.org/blog/flavours/html/":

<div class="calendar">
  <table>
    <tr>
      <td colspan="2">$calendar::month_calendar</td>
    </tr>
    <tr>
      <td class="prev-link">$prev_month_link</td>
      <td class="next-link">$next_month_link</td>
    </tr>
  </table>
  <table>
    <tr>
      <td>$calendar::year_calendar_2001</td>
      <td>$calendar::year_calendar_2002</td>
      <td>$calendar::year_calendar_2003</td>
    </tr>
  </table>
</div>

calendar.month_head.html:

<table class="month-calendar">
  <caption class="month-calendar-head">
    <a title="$monthname $year ($count stories)" href="$url">
      $monthname $year
    </a>
  </caption>

calendar.next_month_link.html:

<a title="$monthname $year ($count)" href="$url">
  $monthabbr '$year2digit&rarr;
</a>

calendar.next_month_nolink.html:

&rarr;
calendar.next_year_link.html:

<a title="$year ($count)" href="$url">
  '$year2digit &rarr;
</a>

calendar.next_year_nolink.html:

&rarr;

calendar.prev_month_link.html:

<a title="$monthname $year ($count)" href="$url">
  &larr; $monthabbr '$year2digit
</a>

calendar.prev_month_nolink.html:

&larr;

calendar.prev_year_link.html:

<a title="$year ($count)" href="$url">
  &larr; '$year2digit
</a>

calendar.prev_year_nolink.html:

&larr;

calendar.year_hear.html:

<table class="year-calendar">
  <caption class="year-calendar-head">
    <a title="$year ($count)" href="$url">$year</a>
  </caption>

Tamara asked on the Blosxom mailing list if my macros plugin was capable of making external links open in new windows like this.

My first answer was no -- it's missing two features that that uses, <MTIfMatches> and MTMacros' 'rebuild'. Furthermore, I don't really think MTIfMatches belongs in macros; it's a better fit for a somewhat fancier interpolate-conditional.

I'm not sure how exactly MTMacros' 'rebuild' works, and it may well be a useful feature to steal borrow...I should look at that.

I realized this morning that there is in fact a way, though; it's not quite as clean as Adam Kelsey's, since it's simply text based rather than tag-based, but it seems to work just fine.

The magic is in these macros (use the download link to get a good straight-text version):

define_macro({
  type => 'pattern',
  pattern => qr'<a\s(?![^>]*class)([^>]*href="/)'ms,
  body => '<a class="relative" ${1}',
  inhtml => 1
});

That looks for 'a' tags that don't have a 'class' attribute, with an 'href' attribute that starts with a slash, and adds a 'class="relative"' attribute.

define_macro({
  type => 'pattern',
  pattern => qr'<a\s(?![^>]*class)([^>]*href="http://[^/]*molehill\.org[:/])'ms,
  body => '<a class="local" ${1}',
  inhtml => 1
});

That looks for 'a' elements that don't have a 'class' attribute, with an 'href' attribute that starts with an a "http://", and has my domain name before the next / or :, and gives them a 'class="local"' attribute.

define_macro({
  type => 'pattern',
  pattern => qr'<a\s(?![^>]*class)([^>]*href)'ms,
  body => '<a class="remote" ${1}',
  inhtml => 1
});

That looks for 'a' elements that don't have a 'class' attribute, but do have an 'href' attribute (that prevents it from applying to anchors used just for naming); and gives them a 'class="remote"' attribute; that's right, since every non-remote link has been given a 'local' or 'relative' class.

I'm also using some stylesheet magic:

a.remote {
	padding-right:		12px;
	background-image:	url(/icon/aoutside.gif);
	background-position:	right;
	background-repeat:	no-repeat;
}

and an icon apparently from WebGragpics.

I didn't add "target" attributes, but it should be clear how to do that -- simply put them before the 'class' in the replacement text.

As I said, this isn't quite as clean, and it's not 100% correct -- the word "class" in an href could confuse it, for instance. But it's pretty close, and it's doable now. (it could be improved by replacing the (?![>]*class)s with (?![>]*\bclass=")s, but that still wouldn't be 100% right, and I wanted to present what I'm actually using and have tested).

The AllConsuming plugin has been updated.

Feature changes:

  • Per-list templates are possible; when loading a template bit <bit> in flavour <flavour> for list <list>, it first looks for allconsuming.<list>.<bit>.<flavour>; if not found, it then looks for allconsuming.<bit>.<flavour>, as before.

Bug fixes:

  • Better error reporting if LWP can't be loaded for some reason
  • Caching is optional -- for real this time, missed a bit in 0+3i, so it was actually always used. I still don't think you'd want to not use it, though.
  • If the plugin state dir doesn't exist, try to create it, and report an error if we can't.
  • don't die if a list is configured for random selection but is empty
  • Amazon Associate ID is a configuration variable, not embedded in the default templates -- for real this time; fixed it one place in 0+3i, but missed it anothre place (the cover image links)

Changed for reasons only I care about:

  • The perl variable '$^T' (time the script started) is used instead of 'time' (current time) in various places; this is marginally more efficient, but was really done for consistency with some other plugins where it matters more.

Installation:

  1. Verify you have the requirements for one of the networking implementations installed (SOAP::Lite or the LWP suite of modules or a 'curl' or 'wget' executable); if not, choose one to install
  2. Verify you have a Storable with lock_retrieve installed; if not, decide whether you really want to try to use this without caching, or install it.
  3. download and unzip the plugin.
  4. Copy the plugin to your plugins directory
  5. Configure the username variable; it won't do anything until you do. Configure your Amazon Associate ID if you have one.
  6. Add $allconsuming::reading, $allconsuming::finished, or the like to one of your flavour files. See the included POD documentation (perldoc allconsuming) for the complete list.
  7. Try it out -- load your blog in your browser.
  8. If everything is working, set $debug_level to 0; if not, check your error log to make sure the plugin is being loaded, and see if it's logging any errors
  9. Drop me a note letting me you're using it and how things are working for you.
  10. Enjoy!

Things still to do, still active from 0+1i:

  • locally cache the amazon image files, an