I'm pleased to report that my butt did not grow into the couch while I watched DVDs over the weekend while Barbara is away, as was predicted by some. [Cough!]
Our first arguably spring-like day happened Saturday, so I took the opportunity to get out on the bicycle. After getting a few chores done around the house, I used it as incentive to actually go to work and get ahead of the curve on an imminent deadline.
Though I usually prefer heat and sweat, it was a nearly ideal day for cycling. Pleasantly cool, nice breezes (especially when I was headed north instead of south), and sunlight. On the way home, I bumped into Oliver Banta on the Rock Island Trail; he's apparently taken up road cycling fairly seriously. I'll have to watch for him now, because he told me he's seen me commuting. I was embarassed that I had not recognized him. I managed not to bump into the folks strolling on the path who insist on stopping to chat with people they know blocking both lanes of the trail.
Barbara's in South Carolina, visiting her mother who is undergoing treatment for cancer. I would have liked to gone along, but the situation at the office is such that it's hard for me to take the kind of time away that Barbara wanted to spend with her parents.
On Sunday, a cat I have never seen before appeared on our back porch soliciting hand-outs. At first I thought it was Lorenzo, but this fellow's stripes were more black and gray, less tan. In fact, he looked very much like Penelope (aka Dr. Girlfriend), whom we took to Milwaukee to be adopted by Kelly and James, right down to the distinctive shape of his head.
He was neither collared nor neutered.
I tried to make friends and get a picture of him, but he was too skittish—probably not domesticated. Lorenzo was none too happy that he was around either, and that didn't help things. I managed to stay between them so no fight broke out while the other guy made his way off of Lorenzo's primary territory, but there was growling and hissing all the way. Fortunately, Lorenzo elected to return to the back porch instead of giving chase when the other guy finally ran off.
As part of the current upgrade effort, I decided it was time to go through and tag older blog entries, the ones written before the introduction of tags. These entries were categorized, and the filesystem was used to manage the categorization. Each directory represented a category, and each subdirectory a subcategory. The directories were given descriptive names, suitable for use with the pycategories plugin for pyblosxom.
An obvious approach to automating the retagging of these old entries was to use the category hierarchy itself to provide the tags. I wrote a python program to walk the directory tree, and add tags to the old entries.
I chose to ignore the general
category, though, because as a
tag general
doesn't provide much information. I think I might try
a more sophisticated approach to those entries, analyzing the content of
the entry to choose tags. I haven't worked out all the details, yet, but
I'm considering building a map of tagged entries, based on the frequency
of certain words or phrases that appear in them, then applying that map
to a histogram of the entries currently categorized as
general
.
In preparation for adding a tagcloud, I've started revising the layout of my blog. The goals are as stated before: to be standards compliant, readable, minimal, and to provide control to the user.
Progress can be seen here, complete with
ugly background colors for debugging. This iteration will include styles
for embedded code fragments, and markup for photos, along with a
fixed-fluid
two-column layout.
Comment welcome...
It's a reality of programming in C++ that all containers are not created equal, and do not receive equal protection under the algorithms. Or something.
Today at work, for example, I needed to scan a std::map,
and erase elements from it for which some predicate was true. The
typical way to remove an element from a map is to use the map's erase
method. There is an erase method that takes a range (a start and end
iterator), but no way to perform the erase based on the result of a
predicate. That is, there's no map::erase_if.
For sequence containers, there exists an algorithm,
std::remove_if(start, end, pred), but it operates by
reordering the elements of the range it's operating on, by assigning an
element from one position to another with operator=.
Because the first element of the pair that comprises a map::value_type,
the key, is const, it can't be assigned to.
typedef std::map<T,U> Map;
typedef Map::value_type Value;
extern bool predicate(const Value &v);
Map m;
// Wrong: compile error.
std::remove_if(m.begin(), m.end(), std::ptr_fun(predicate));
The next obvious thing to try is an explicit loop, with an explicit branch based on the predicate. The naïve implementation, though, will have problems.
for(Map::iterator i = m.begin(); i != m.end(); i++) {
if(predicate(*i))
m.erase(i); // ONOZ!
}
ONOZ!
because after the call to m.erase(i),
i is no longer valid: it refers to memory that has been
released. I suspect the increment clause of the for-statement puts us in
nasal
demon territory, but I'm not sure what the standard says.
To be honest, I knew the above constructs were wrong, but I didn't know if there was an idiom to get the behavior I wanted. After some research and some experimenting, the following is the construct I decided to use.
for(Map::iterator i = m.begin(); i != m.end(); /* increment in body */ ) {
Map::iterator current = i++;
if(predicate(*current))
m.erase(current);
}
Greasemonkey is an extension for Firefox that allows users (i.e., you and me) to run javascript programs of our choice, called user scripts, to change the look or behavior of web pages.
WorldCat is a service that lets you search the catalogs of libraries both nearby and around the world.
Amazon is, well, Amazon.
Atalib is a Greasemonkey script that runs on Amazon pages. It performs a search on WorldCat, and displays the result on the Amazon page, so you can see if the item is available from a library, near or far. WorldCat helpfully orders its results by distance, so you can easily determine whether the item you're interested in is available within biking distance, or if you will need to charter a jet.
To use Atalib:
Get Firefox if you're not using it already.
Install Greasemonkey. You'll have to restart Firefox after installing it.
Look for one of these two ways of installing the script.
Whichever you see, click the Install
button to install
Atalib.
It was fun to find out that a manual of Japanese etiquette is available through the Library of Congress, and that the library of the Nelson-Atkins Museum owns a copy of Introduction to the X Window System.