Bridging NNTP and RSS #

The CS Department likes to set up newsgroups for each class to allow professor/TA/student conversations (though this custom is being supplanted by Whiteboard's discussion boards). I'm not a big Usenet person, and checking said newsgroups would involve me having to remember to go out of my way and fire up Pine. However, since (timely) announcements are often posted in newsgroups, reading them regularly is necessary. One thing that I check often (perhaps too often) is my RSS newsreader, so the obvious thing to do would be to bring newsgroups to it. Since I very rarely post, having read-only access for the most part wasn't bothersome (i.e. in those situations I can in fact fire up Pine).

The result is nntp2rss.pl, a simple Perl script that uses the Net::NNTP module to generate a feed based on a newsgroups. There are two parameters (given as a query string), group to specify which group to fetch, and limit to determine how many of the most recent messages should be displayed (the NNTP server is specified as a constant within the script). This results in URLs such as:

http://localhost/cgi-bin/nntp2rss.pl?group=pu.cs.302&limit=15

The script handles some transformation of message bodies (newlines and conversation to HTML entities) as well as inclusion of sender/subject/date (these do have RSS equivalents, but not all aggregators display them).

N.B. I wrote this script in the spring of 2003. A search today turned up a fancier project that has appeared in the meantime. However, their approach is centralized, and wouldn't work for campus-only newsgroups like mine.

Moving house #

Iterations++ #

Members Palette Mockup 2Further tweaking of the revised members palette results in this design. First, the 4-bit depth is gone for sure, so that's one thing to cross off of my list. Additionally, as it can be seen the labeling is done by putting all members in a grid. The window is small enough that I can make it fixed size (well, except for the collapsing of the thumbnail and hints sections, though even that may be left out), and so the mini scrollbar was taken out. This frees me to use full-height buttons for the other commands (I'm also planning on adding support for icon states, as it can be seen). Finally, since I see this mode as being superior to the old members palette in every single aspect, there won't be any need for a toggle.

In some ways the new palette should be simpler to code up than the old one (since there's no scrolling to worry about, and inactive members will be drawn as disabled instead of being hidden). The expanding/collapsing of the thumbnail and hints sections may be tricker, but I'm planning on moving to Carbon Events and this should let me smoothly move controls during that operation (if the Finder can do it for its Get Info window, so can I). I think it's about time I switched to using HIViews for my custom controls, which means requiring Mac OS X 10.2 or later, but that's something I can live with (it's not like I have installs of 10.0 and 10.1 lying around to test against anyway).

The plan is to do a bit of refactoring, by keeping the MembersPalette interface the same, but completely rewriting its implementation. We'll see how good my object design and encapsulation really is.

Apple MockupThe funny thing about this design is that it bears a strong resemblance to the original one that Apple had sent me, back when the plan was to turn Iconographer into the quasi-official icon editor for Mac OS X (perhaps I was being subconsciously influenced by it, but I didn't make the connection until I was done). I rejected it back then due to its bulkiness, which perhaps isn't as much of an issue now (if nothing else, Mac OS X has acquainted people with interfaces that take up a lot of space).

Finally, in light of this pretty significant interface change, and because I'm adding support of icon states, the next version should really be 3.0 (I've been stingy with bumping version numbers anyway).

Prettification #

Photoshop, a man's best friend #

Members Palette Mockup One of the issues with Iconographer's UI in its current iteration is that it requires a lot scrolling to get from member to member (screenshot). With monitor aspect rations tending to the wider side lately, it makes sense to take advantage of extra horizontal space.

Therefore, as an alternative in Iconographer 2.6, I'd like to have a members palette that looks something like the one to the right (thanks go to Microsoft Word and OmniGraffle for inspiration). The palette is then twice as wide as it normally is, and so the preview and color ones can be put side by side underneath (since they're of unequal length - though I may tweak that too).

There's still a few issues:

  • I don't have enough room for the 4-bit member (in the Huge variety). Since support for them is deprecated anyway, it may not matter at all. I am considering dropping support for pre Mac OS 8.5 icons altogether in fact.
  • I'm still not sure how to label the different icon and mask depths. I can use mini icons (Icon Machine style), or some kind of clunky label (e.g. "32/8/1-bit icon") for each grouping.
  • How will this mode be activated? Is can be just a matter of resizing the window to be wider (but since intermediate values won't be allowed, how will it occur to the user to do that in the first place?). Or it can be another option in the preferences, along with the current "Display Scaled" setting. However, I have a feeling that's also not very discoverable.
  • The super-tiny "Add Member" and "Info" buttons are bugging me more than ever (though they also have key shortcuts and menu items). I may have to go back to using normal sized scrollbars, which would let me have regular sized grow-boxes, which in turn lets me make those buttons 16 pixel tall, better than the current 11.

Further Sidebar Tweaking #

In my quest to further simplify/improve the sidebar, I've decided that having both a "Categories" and a "Recent Posts" list was too space consuming and not all that useful (when reading other people's sites I don't usually make much use of the recent entries list, instead I just go from page to page (whether they be per entry, day or month)). The idea was to combine the two in a way very similar to the "Monthly" list*, with each category name and a couple of recent entries under each one. The initial code was very simple:

<MTArchiveList archive_type="Category">

   <span class="archiveListHead"><a href="<$MTArchiveLink$>"><$MTArchiveTitle$></a></span><br />

   <MTEntries lastn="2">
      <span class="archiveSubList"><a href="<$MTEntryPermalink$>"><$MTEntryTitle$></a></span><br />
   </MTEntries>

</MTArchiveList>

This achieved what I had initially intended, but ironically enough it turned out that's not quite what I wanted. This listed the most recent couple of entries for all categories, even those in which I hadn't written in ages, like Grendel and Meshroom. Ideally I would place some kind of restriction, so that only entries within, say, the past 30 days would be listed. Unfortunately the MTEntries doesn't support combinations of the lastn and days attributes. Turning to the MT plugin archive, I found DateTags. It seemed like its MTDateLoop tag would let me loop within entries of the past 30 days. However, it didn't seem to respect neither the Category context that it was in, nor the lastn parameter for the MTEntry. Doing those comparisons by hand didn't seem all that fun (and would probably have required more plugins to be downloaded), so I looked for another way.

The final solution still required more plugins, but it was to very simple, straight-to-the-point ones: MT-Epoch and Compare. Using MT-Epoch I can convert dates to epochs (seconds since Jan. 1, 1970) and then subtract the entry date from the current date, printing only those entries where the difference is less than 30 x 24 x 60 x 60 = 2,592,000. This meant adding these two lines just inside the MTEntries block:

<MTIfLess numeric="1" a="[MTDate convert_to_epoch='1'] - [MTEntryDate convert_to_epoch='1']" b="2592000">
entry listing code..
</MTIfLess>

However, it then turned out that Compare, even when in numeric mode, doesn't evaluate expressions (not MT ones, arithmetic ones). Fixing this was a simple manner of adding a couple of eval's after embedded expressions were expanded.

The lesson from all of this is that presumably there is a point at which it becomes more time-effective to either start writing my own plug-ins or even my own journal/CMS system. We'll see.

* While browsing around the MT plugins directory, I also happened upon DateHeaders, which appears to the same thing as my MTMacro/ArchiveYear combination. A rewrite is in order at some point.

And a fancy hammer at that #

I needed to keep my bookmarks in sync between my main computer, beria (a TiBook running Safari) and my on-the-go one, loungelizard (a Toshiba Portege R100 running Firebird). The usage pattern is that most of my serious browsing is done on my Mac, but I do ocasionally use the Portege for surfing, mainly to look stuff up. Therefore a two-way sync wasn't necessary, but it would have been nice to have the same set of keywords and the bookmark toolbar on both computers.

If I was going to be launching a web browser, chances were that I at least had web access, therefore doing this sync-ing over HTTP seemed like the best idea. I was already running Apache on beria, so I decided to write a CGI script that exported my bookmarks. I could then fetch it using the Windows build of wget and stick it in the right place (%AppData%\\Phoenix\\Profiles\\default\\hash.slt\\bookmarks.html).

Safari uses XML for its bookmarks file, more specifically the Apple .plist format. This is somewhat annoying to parse, since it uses <key> and <array/dict/string> pairs to specify values, and so if I'm looking for a value, I need to find its key first, and then get the next tag in the hierarchy. There appeared to be an XSLT that did this conversion, but I couldn't get it to work with the Perl XSLT library that I had found on CPAN. After some messing around with XML::Smart, I went for the lowest level method and parsed it all using XML::DOM.

The net result is this Perl script that exports to HTML. Since I have a lot of bookmarks, I added caching, so that if Safari's bookmarks file hasn't been touched since the last execution, it uses the last generated converted file. Since Safari doesn't have built-in support for keywords, I had previously hacked in that functionality using a method very similar to this article (though done using Perl of course). Therefore my bookmarks exporting script also loads my keywords script, and outputs those keywords to the generated Firebird bookmark file.

Fetching on the Windows side was done by replacing my Firebird shortcut with one that invoked a Perl script (thank you ActiveState) which first pinged beria, and if that suceeded initiated the wget command (the pinging had to be done first since wget had a tendency to zero out the destination file even if the HTTP connection couldn't be established). I would have used a DOS shell script (for better portability), but I couldn't find a way to do the same ping test first. Note that exec calls start and not the Firebird .exe directly since start seems to return immediately, letting the Perl process exit (simply using fork instead didn't seem to work, perhaps because I couldn't figure out how to detach the forked process's stdin/out/err).

Archive Fun #

One thing that had been bothering me about my current layout was that the monthly archive list looked so disheveled and ragged. I thought that a hierarchical view, with each month under its respective year, would be a lot better. After a bit of exploration, it appeared that I couldn't get that effect with the regular MT tags, and I wasn't feeling adventurous enough to write my own plugin. Therefore, the only option left was to see what I could put together using existing plugins.

After some digging around at the MT Plugin Directory, I came across MTMacro and ArchiveYear (actually, that's a bit of a lie, I had used MTMacro earlier, together with MTEntry in order to implement this tip on entry linking). The plan was very simple, define a macro like this:

<MTMacroDefine name="yearArchive" tag="yearArchive">
  <MTMacroAttr name='year'><br />
    <MTArchiveYear order="descend" skip="yes" columns="1" year="[MTMacroAttr name='year']" >
      <MTArchiveYearIfEntries>
        <span class="monthArchiveList">
          <a href="archives/<$MTArchiveDate format="%Y_%m"$>.html">
            <$MTArchiveDate format="%B"$>
          </a>
        </span><br />
      </MTArchiveYearIfEntries>
  </MTArchiveYear>
</MTMacroDefine>

(I don't know why I had to use <span>'s instead of <div>'s, but if I hadn't then the padding wasn't taking effect (though other CSS attributes like border did work)). With that macro in place, it can be invoked like this in place of my regular monthly archive list:

<yearArchive year="2004" />
<yearArchive year="2003" />
<yearArchive year="1999" />
<yearArchive year="1998" />

This requires me to add a new macro call for each year, but I think I can manage to remember that. In any case, this all seems great, but in fact it didn't work. It turned out that MTArchiveYear didn't support embedded expressions in its year parameter. Seeing as I had to get my hands dirty with plugin code, I took the shortest possible path. Since MTEntry did support embedded expressions, I simply lifted its parsing calls and added them to the archive_year function that implemented the tag. The diffs are here.

An alternative would be to keep using the old MTArchiveList based archive, see if the previous entry's year can be stored in a variable, and then that variable is different from the current month's year, insert some sort of header. To be tried some other time.

P.S. Just to show how prophetic Peopleware can be, even for small things like this: I expected the entire thing to take one hour, and it took two.

Done for now #

Stopped at 3401 words and learned LaTeX well enough to be able to piece something together (thanks TeXShop). Results: Thor: Whiteboard Capture and Indexing. Also added a "Papers" sidebar on the front-page with all of the other things I've written.

Writing++ #

2399 words. Must learn LaTeX.

Writing away #

Began work on write-up. 1034 words and counting