Contains coding, but not narcotic.

Vim syntax highlighting for Synergy/DE

August 26th, 2012 3:42:46 pm pst by Sterling Camden

It’s been more than a year since John Cottrell of BusinessCraft sent me his vim configuration files for Synergy/DE syntax highlighting. Today I finally got around to looking at them. Despite John’s apologies, they seem pretty complete.

I’ve tested them on both Unix (FreeBSD) and Windows (7). John apparently developed them on the OS/X, so it should work there, too. See the README for installation. Please use the Issue tracker or leave a comment here about any issues you encounter. Happy vimming, and many thanks to John!

BitBucket repository

Posted in SynergyDE, Unix, Windows | No Comments » RSS 2.0

Managing simultaneous events in Synergy/DE UI Toolkit

January 14th, 2012 5:31:05 pm pst by Sterling Camden

synthesisI’ve written before (PDF) about the unique event model of the Synergy/DE UI Toolkit. For historical reasons, these events are often called “menu entries,” and even though they are handled in a synchronous, delayed manner you can’t have more than one such event pending at any given time. This didn’t cause too many problems back in the old days when they were almost limited to user-initiated events. But now that they’ve also become a standard means for converting asynchronous system-level events into synchronous Toolkit events, the need to generate more than one at a time has become something much more than academic.

Consider, for instance, an input field that needs to perform non-trivial processing at three points: when it is modified, when it is displayed, and when focus leaves the field. Each of these events can be hooked to a “method” routine, but if those routines need to do anything involving user interaction, then on Windows it needs to be deferred to the outer loop by means of passing an event to M_SIGNAL. Why? Because in an asychronous callback, the UI Toolkit can’t process Windows messages, so the user will not see any changes to the UI until after that event has been handled and the routine returns. Non-Windows platforms like Unix and OpenVMS don’t have that problem, but if your code is portable to Windows then you probably want to write it that way anyway.

Now, when the user types something in the field and then advances to the next field (via Tab, etc.), all three of those events will fire: first the “change” event, then the “display” event (to display the reformatted value after validation), then the “leave” event. All three associated methods will be called in that order. If each of them signals a menu entry event, then only the last one will be seen.

I’ve added a class to my Synthesis library to extend menu-entry signaling to maintain a queue of pending events. To make use of it, you replace M_SIGNAL with multi_signal. In the outer routine that consumes events, you change M_SIGNAL(…, D_REMOVE) (or testing g_select and g_entnam, after the older form), with a loop of calls to multi_remove, until it returns ^null. Each non-null return value will be a string containing an event that was signaled, in the order in which they were signaled.

To ease the transition, I’ve made multisignal somewhat compatible with M_SIGNAL. If the consuming code isn’t changed to the new paradigm, then it will still see the most recent event — whether it was passed to M_SIGNAL or multisignal.

See the test program (test_multisignal.dbl in the tests subdirectory) for an example of how to solve the scenario I related above.

With this feature, I’m putting a lid on Synthesis version 2.2.1. Any further changes will go in the next version.

BitBucket repository
tarball
Zip archive

Posted in .NET, SynergyDE, UI Toolkit, Unix, Windows | No Comments » RSS 2.0

feedmbox updated to grok RSS 1.0

October 3rd, 2011 5:00:45 pm pst by Sterling Camden

feedmboxNot too many sites use RSS 1.0 any more. It’s a completely different standard than RSS 2.0 — even the abbreviation stands for something different: RDF Site Summary (instead of Really Simple Syndication). But recently, I wanted to subscribe to a hilarious web comic called The Oatmeal, only to find that its feed uses RSS 1.0. Not to be discouraged, I decided to add RSS 1.0 support to my feed-to-email script, feedmbox. Download links below.

I’ve also updated the license to OWL 0.9. Enjoy!

BitBucket repository
tarball
Tags: , , , , , ,

Posted in ATOM, OPML, RSS, Ruby, Unix | No Comments » RSS 2.0

Synergy/DE command line utility for printing labels

September 11th, 2011 5:13:24 pm pst by Sterling Camden

I recently started brewing beer again, after a 13 year hiatus. Now that my first batch has been in the bottle for a couple of weeks, and my second batch is fermenting, I decided I should label my bottles to keep the batches straight. I found some removable bottle labels at OnlineLabels.com, which I ordered and received.

Next came the question of how to print them? Back in the old days, I would painstakingly copy/paste/align each label in Microsoft Paint for every batch. There had to be an easier way.

I took a look at Microsoft Publisher, which appears to have the necessary options, but for some reason they just don’t work.

Then it occurred to me: why not write a little program using the Synergy/DE Windows Print API (which I helped design, after all)? I designed a command-line interface for specifying the origin, size, and spacing of the labels; as well as an image to print on them, optional outline (for testing alignment), and print preview. Implementation and testing took about an hour. ‘Tis a thing of beauty.

And so is the design for the labels for my first batch:

In case you’re wondering about the name — when I brewed my very first batch of beer in May of 1994, it was a nut brown ale. It turned out so good that I decided that was a good place to start for round 2. The good folks at Olympic Brewing Supplies provided an easy kit to get me back in the saddle. It isn’t my finest creation, but it’s a good bit nicer than anything you can buy in a store. Maybe I’m biased.

Anyway, I created a batch file to align for these labels, and I’ve included it as an example of usage. You still have to add the -image (or -outline for testing) and -n switches, but the spacing and sizing are all worked out for you.

Unfortunately, this program will only work on Windows platforms, because it makes use of the Windows Print API.

BitBucket repository
tarball
tarball

Posted in SynergyDE, Windows | No Comments » RSS 2.0

/me adds ACTION support to jab’s IRC protocol

September 7th, 2011 6:26:27 pm pst by Sterling Camden

I googled until my googler was sore trying to figure out how to support the “/me” command in my IRC client, jab. It doesn’t seem to be mentioned anywhere in the RFCs, and it isn’t supported as an IRC request. As far as I can tell, it’s a custom extension to the IRC protocol that clients and servers agree on by convention.

Finally, I stumbled upon this answer on dreamincode.net. It uses a special form of the PRIVMSG request. Everything’s the same except for the message, which must begin and end with a 0x01 byte, and the word ACTION must follow the first such byte. A space should follow that, followed by the text of the action.

Hopefully, this will bring relief to some other poor, google-weary bot author.

I added this to the protocol-irc module in jab, which you can download from one of the links below. While in jab mode, if your message begins with “/me “, then the remainder will be sent as an ACTION instead.

BitBucket repository
tarball
Tags: , , ,

Posted in Ruby | 2 Comments » RSS 2.0

url-picker can now count backwards

September 3rd, 2011 7:24:07 pm pst by Sterling Camden

the pick...

Antoine Amarilli emailed me to suggest an enhancement to my url-picker extension for urxvt: number the URLs in reverse order, so that the most recently displayed URL will always be number 1. His rationale is that in a terminal window, you’re usually focused on what has been displayed last, and being able to use the same set of keystrokes to launch the most recently seen URL allows the action to become somewhat automatic.

I liked Antoine’s suggestion, but I decided not to change the default behavior. I, for one, find the ascending order makes more sense when viewing my feeds in mutt, because my rss-to-email mechanism adds the item’s web link as a custom header, so it’s always the first link on the page. So, I decided to add a resource to control the order. If you want descending numbering, add this to your .Xdefaults (or other resource source):

URxvt.url-picker.order: descending

Now you can always launch the last one with the same finger!

BitBucket repository
tarball

Posted in Perl, Unix | 2 Comments » RSS 2.0

Sudoku snatched from the jaws of death

August 24th, 2011 12:43:25 pm pst by Sterling Camden

At the weekly IRC meeetings of the ##copyfree channel, Eitan Adler has been bugging encouraging us to assume maintainership of unmaintained FreeBSD ports. He provided the following script to list any ports that are installed on your system that have no maintainer:


#!/bin/sh
cd /usr/ports;
grep -F "$(for o in $(pkg_info -qao) ; \
    do
	echo "|/usr/ports/${o}|" ;
    done);" $(make -V INDEXFILE) | \
    grep -i \|ports@freebsd.org\| | cut -f 2 -d \|

In the list of 60 such ports on my system I happened to notice “games/sudoku” — a nice little curses console-based version of Sudoku that I play from time to time. The responsiveness of its keyboard interface makes me like it even better than my own Javascript version. I decided to adopt this little orphaned gem.

As soon as I attempted ‘port test’, however, I found that not only was this port an orphan, it was scheduled for execution! It was marked “deprecated” because no more distfiles were available. Apparently, the author’s site went 404. Yet, I obviously had it installed on my system. But did I still have the sources? Most of the time, a port’s “work” directory gets cleaned after installing or upgrading, and I periodically purge my /usr/ports/distfiles directory, too. How long had it been?

Unbelievably, I still had the tarball for sudoku in my /usr/ports/distfiles. I told Eitan I would host it myself, and he walked me through the changes I should make to the port and submit as a PR. The FreeBSD ports team approved the PR, and now I’m both the upstream and port maintainer for games/sudoku.

When I get some time, I plan to fully grok the code for this project, then look at enhancing it. For one thing, I’d like to keep some sort of score. With that in mind, I’ve put the sources into Bitbucket. You can download it from there, or via the tarball, or simply install the FreeBSD port.

Michael Kennett, the original author, released this source into the public domain in 2005. After I modify the code, I’ll release my version under the OWL, as usual.

BitBucket repository
tarball

Posted in C and C++ | 2 Comments » RSS 2.0

Hey, you got greasemonkey in my bitbucket!

August 14th, 2011 11:47:52 am pst by Sterling Camden

Bitbucket user srean complained on the Google Group about the white background in bitbucket’s code view. I agree — a black background is much better for viewing code, and the gray highlighted text is almost invisible against white.

I whipped up a greasemonkey script to correct this situation. It makes the background color of the highlight section black, with a default text color of SpringGreen. If you don’t like SpringGreen, you can of course modify the script. Enjoy!

I’m only going to publish this one on bitbucket.org, since you have to use bitbucket before you’d need it.

BitBucket repository

Posted in CSS, JavaScript, Web | No Comments » RSS 2.0

url-picker extension for urxvt now handles wrapped URLs

July 3rd, 2011 5:24:16 pm pst by Sterling Camden

Craig Balding emailed me about a “feature” that had already plagued me for some time in my url-picker extension for urxvt. Whenever a URL wrapped to a second line, url-picker would only see the portion on the first line. In many cases this only truncated useless parameters that you probably didn’t want to include anyway (I’m, looking at you, Facebook). But often some meaningful bits got truncated, forcing the user to resort to copy/paste. Not good.

In order to fix this, I had to change the way url-picker loops through the text. Instead of looking at the text row by row, I now gather all of the text to be considered into a single string in which to search for URLs. Because we’re dealing with Unicode here (that’s one of the reasons for using urxvt to begin with) I can’t calculate row and column by performing any clever math on the resulting offset. So instead, I build a hash of row => [start,end] and then search the hash for the offset of any URLs I find. Seems to work (after I refreshed my memory YET AGAIN on the syntax for Perl array references within hashes), but let me know if you encounter any difficulties.

the pick...

Now you can pick and launch even bigger ones!

Of course, you have to make sure that your terminal display doesn’t interrupt the URL in other ways. For example, for mutt you’d want to have the following in your .muttrc file:

set markers=no

Otherwise, you’ll get a “+” embedded at the beginning of each wrapped line.

BitBucket repository
tarball

Posted in Perl, Unix | No Comments » RSS 2.0

Ruby convert HTML to formatted text

May 14th, 2011 3:02:46 pm pst by Sterling Camden

There’s always something. I was happy with my Feed-to-Email utility, feedmbox, except for one thing: it really screwed up code examples. Looking into the routine that converts the HTML to text, I realized that I had not done anything to honor <pre> tags, so it collapsed all white-space code formatting into single space characters. Not the most readable presentation.

I decided that since I had already fought with this conversion previously, I should separate it out and publish it by itself so that other people who are looking for an HTML to text conversion for Ruby could have Google on their side. This also helped me to tune and debug it without having it all hooked up to my feeds.

I quickly solved the <pre> tag problem by splitting the text on a Regexp that matches a <pre> section, then only collapsing whitespace on the sections that don’t match. Then I sew the whole thing back together and do the other replacements (converting links, replacing HTML entities, removing tags, etc.).

Hope someone else finds this useful.

BitBucket repository
tarball

Posted in Regexen, Ruby | 1 Comment » RSS 2.0

hstee: Teeing off with Haskell IO

May 1st, 2011 3:25:13 pm pst by Sterling Camden

I started playing around with Haskell about a year ago, but I didn’t spend enough time with it or find the right resources to grok it. Recently, I stumbled on a fantastic Haskell tutorial: Learn You a Haskell for Great Good! It finally opened my eyes on what Haskell’s up to with function composition, lazy evaluation, IO and a lot of other things that I thought I understood before but didn’t. I highly recommend it, not only for learning Haskell but also for understanding Functional Programming.

Tutorials, no matter how good they are, always lead you down a successful path. You don’t really learn a language until you strike off on your own through the jungle and fight off the tigers, leeches, malaria, and unfriendly natives that you inevitably encounter. So as an exercise, I decided to implement the Unix standard tee utility in Haskell. You can download it from one of the links at the bottom of the page. This little exercise elucidated a number of areas for me:

  • Command-line parsing. Haskell’s GetOpt module, like a lot of Haskell code I’ve encountered, took a lot of staring before I understood it, but it’s robust. This tee utility only has two simple options that don’t take arguments, so it might be a good starting place for someone else to understand GetOpt.
  • Handling system signals. The -i option for tee means we have to be able to ignore SIGINT. That was easy enough on Unix, but then I found that on Windows the System.Posix.Signals module wasn’t even available! See the next item. After importing the GHC.ConsoleHandler, I still couldn’t figure out how to handle SIGINT differently than other signals. Presumably, if I installed a Handler instead of Ignore, that Handler would receive a ConsoleEvent argument, and I could do something with that. But for the life of me I can’t find where the ConsoleEvent type is defined.
  • Conditional compilation. A ton of googling led me to the {-# OPTIONS_GHC -cpp #-} pragma, which enables C++-style compiler directives, like #if. Then, we can look for the constant defined for Windows: mingw32_HOST_OS and import the correct module.
  • Lazy Strings. I never knew being so lazy could be so cool. The line theOutput <- getContents looks like it would read all of the data coming to stdin before proceeding to the next statement, but it doesn’t. Because a String is a list and lists are lazy by default, the elements of that list aren’t evaluated until they’re requested — which doesn’t happen until we start mapping them to the output in the line that begins with sequence.
  • List comprehension. Speaking of that line, just take a look at what that’s doing. This piece: [ hPutStrLn h l | l <- lines theOutput, h <- stdout:handles ] builds a list of IO operations by calling hPutStrLn on every combination of lines of output and file handles (first prefixing stdout to the list of handles). In most languages, this would be two nested loops: foreach line (foreach handle …). Is that not lovely?
  • IO. As I now understand it, main only executes the IO operations that get returned to its main level. Thus, the sequence is required to convert a list of IO () to an IO [()], so an IO gets returned to main, instead of a list. I still don’t have both feet in grokland on this, but I feel a lot more comfortable about it than I used to.
  • Partial application. Have a look at the line handles <- mapM (`openFile` mode) files. The mapM function, like map, takes a function and applies it to a list. The function, in this case, is (`openFile` mode). The openFile function takes two parameters: the path and the mode. In Haskell, if you call a function with some of the parameters missing, you get a function that can be called with the missing parameters. Because the parameter I wanted to supply later is the first parameter, I call openFile using infix notation (with the back-quotes) so the supplied parameter is the second parameter. That returns a function that can take a single parameter and pass it on to openFile as its first parameter, with mode as the second parameter. Cool, huh? In most other languages, you’d have to explicitly write that intermediate function, at the very least as a lambda.

No offense to Haskell Curry, but the name “Haskell” doesn’t seem to do justice to this language. Maybe it’s my childhood associations with Eddie Haskell of Leave it to Beaver, but to my mind “Haskell” doesn’t communicate the mathematical elegance of this language. It even makes Lisp start to look a bit rusty, which I didn’t think was possible.

BitBucket repository
tarball

Posted in Haskell | 4 Comments » RSS 2.0

Go sort it — Parallelism benchmark for Go

April 3rd, 2011 4:33:53 pm pst by Sterling Camden

Go benchmarksI’m excited about the Go programming language. I read the spec and Effective Go, I’ve been playing with the FreeBSD port, I signed up for the gonuts Google group, I attended the inaugural meeting of the Seattle Go Programmers, and I’ve even written an article on it for TechRepublic. I just need a T-shirt and a mascot plush toy to make my fandom complete.

Oh, and maybe write some real code.

Go’s built-in support for concurrency attracted me from the start. The syntax is simple. If you want to execute the “foo” function concurrently with the rest of your program, you just say:

go foo()

Go provides a special data type called “channels” to allow you to pass data back and forth between goroutines (their name for concurrently executing routines). Channels are typed, and with Go’s flexible yet precise type system you can therefore regulate the kind of data you can send and receive on each channel as much or as little as you like.

As I read about this in Effective Go, I began to imagine use cases for parallelism, and one that popped into my head is the mergesort. In a mergesort, you split the items to sort in half, sort each half, then merge the results. For each of the halves, you sort them the same way, splitting and merging until you get down to where each half is only one item. In a single-threaded model, you can’t do anything with the right half until after you’re done with the left half. Why not sort both halves at the same time?

So, we can change this (taking the “merge” function as given):


func SortInts(a []int) []int {
  if (len(a) < 2) {
    return a
  }

  var mid = ((len(a) - 1) / 2)

  return merge(SortInts(a[:mid]), SortInts(a[mid+1:]))
}

To this:


func SortInts_parallel(a []int) []int {
  if (len(a) < 2) {
    return a
  }

  var mid = ((len(a) - 1) / 2)
  left := make(chan []int)
  right := make(chan []int)
  go gosort(a[:mid], left)
  go gosort(a[mid+1:], right)
  return merge(<- left, <-right);
}

func gosort(a []int, c chan []int) {
  c <- SortInts_parallel(a)
}

The result was horrible. It ran so long, I finally had to kill it. Can you guess why?

The overhead of starting a goroutine and receiving its result over a channel outweighs the benefit of concurrency when the slice to sort is small. There's a threshold at which that is no longer the case. From my experimentation, it seems to lie somewhere between 25000 and 200000 elements. Thus, we can mix parallel and sequential sorts:


func SortInts_parallel(a []int) []int {
  if (len(a) < 2) {
    return a
  }

  var mid = ((len(a) - 1) / 2)

  if (mid >= Threshold) {
    left := make(chan []int)
    right := make(chan []int)
    go gosort(a[:mid], left)
    go gosort(a[mid+1:], right)
    return merge(<- left, <-right);
  }

  return merge(SortInts(a[:mid]), SortInts(a[mid+1:]))
}

For arrays with a million or so elements, this beats the pants off both the original naive mergesort (by almost 3:1) and the built-in "sort" package's SortInts function (by about 2:1), depending of course on the data.

I've often observed that a well-written quicksort generally out-performs a mergesort on a smaller number of elements, so when we drop out of concurrent mode, why not switch to quicksort as well? Especially since the built-in "sort" package provides one! Here's that mod:


func SortInts_combo(a []int) []int {
  if (len(a) < 2) {
    return a
  }

  var mid = ((len(a) - 1) / 2)

  if (mid >= Threshold) {
    left := make(chan []int)
    right := make(chan []int)
    go gosort(a[:mid], left)
    go gosort(a[mid+1:], right)
    return merge(<- left, <-right);
  }

  // Degrade to quicksort

  var left, right []int
  left = a[:mid]
  sort.SortInts(left)
  right = a[mid+1:]
  sort.SortInts(right)

  return merge(left, right);
}

Interestingly, this version seems to perform roughly the same as the mergesort-only version. But don't trust me! Go grab the sources yourself from one of the links below and time these routines on your system. You can adjust the number of elements in the array, the threshold for concurrency, and the types of sorts to perform, all via command-line options.

My conclusion: Yes, you can use Go's concurrency to reduce the elapsed time required for potentially parallel operations, if you do so judiciously. Goroutines aren't free, but they aren't terribly expensive, either. Go for it!

Oh By The Way -- you may notice that testsort.go calls runtime.GOMAXPROCS(64) -- I found from experimentation that concurrency doesn't help much if you don't set this to at least (number of actual processors) minus 1. Anything at or above that number seems to behave the same. Apparently, Go will only use additional processors if you tell it that it can, but it doesn't hurt it to tell it to use processors that you don't have. I'm on FreeBSD 8.2-STABLE amd64. YMMV.

BitBucket repository
tarball

UPDATE 2011-04-03: Rob Pike corrected my terminology re: concurrency vs. parallelism.

Posted in Go | No Comments » RSS 2.0

Oi: Object-integer mapping for Synergy/DE

March 28th, 2011 2:44:50 pm pst by Sterling Camden

synthesisOne of the most important features about the (new since version 9) object-oriented syntax in Synergy/DE is that it’s not a purist’s OOP. You can mix object-oriented and imperative programming at will. Thus, if you want to start using object-orientation in a decades-old application, you don’t have to rewrite a large portion of your existing code in order to do so.

However, not all existing code is well-suited to adding objects. In particular, existing routines that expect an argument of a primitive type (alpha, decimal, integer) cannot be passed an object instead. Since Synergy/DE supports boxing of primitives, you could go and change the type of each such parameter to object (@*), but then you’d have to go and change every place where those routines are called in order to box the existing primitive parameters. That could become a huge effort, and for the majority of cases it would add an unnecessary performance penalty.

In the case of the optional method data arguments passed through UI Toolkit routines to callback methods, Synergy/DE introduced a new parameter type, “any”. You can pass either an object or a primitive to an “any” parameter, but in a routine that accesses it in any way other than to pass it on, the parameter must be declared with a compatible type for the object passed. A good example of this would be a selection list that you’d like to load from an ls. In order to get a reference to the ls through to the load method, you can pass it as an optional argument to l_process. In the load method for that list, declare the corresponding argument as type @ls, and you can then use it.

But what if you do your list processing within a wrapper routine, so you don’t have control over the argument list? One way to attach data to a list is via the l_user routine, which stores or retrieves a record associated with the list for user-defined purposes. You can’t store an object (like an ls) in that record — Synergy/DE does not support that kind of serialization. What you need instead is a way to convert the object reference into a primitive type that you can then use later on to restore the reference. That’s the purpose of a new class I just added to the Synthesis library: Oi, which stands for Object-integer.

For any object, you can call Oi.o2i, passing the object, and retrieve a unique integer that only refers to that object. if you call it more than once for the same object, you’ll get the same integer (unless you drop it in between). To reverse the operation, pass the integer to Oi.i2o, and you’ll get back the object reference.

Naturally, this involves maintaining a reference to each object so registered within Oi. Thus, when you’re all done with an object, call Oi.drop and pass it either the object reference or its integer value, and that object will no longer be tracked.

Using Oi, you can therefore pass an integer around to any place that needs an object reference, without having to deal with the difficulties of passing an object. Obviously, a cleaner approach would be to change an API here or there, or store object references as properties of other objects. But the evolution of large systems doesn’t always lend itself to a proper redesign in order to get from point A to point B. Oi is intended to help you along your migration path, not to become a permanent solution or a recommended practice.

BitBucket repository
tarball
Zip archive

Posted in .NET, SynergyDE, Unix, Windows | 1 Comment » RSS 2.0

feedmbox: pipe feeds to email

March 14th, 2011 5:38:20 pm pst by Sterling Camden

feedmboxI’ve been using Newspipe for a while now to send my subscribed feeds to an email folder, but there are a few things I don’t like about that arrangement. Newspipe is not actively maintained. I thought about porting it to FreeBSD (it isn’t in ports yet) — but it’s somewhat Windows-centric (it uses a .INI file, for example), and it’s licensed under the GPL. That makes three strikes. I decided instead to write my own utility in Ruby to do just what I need.

From the links below you can download the feedmbox utility. The README should tell you all you need to know. It takes OPML input and turns that into email output by polling each feed in the OPML document and converting each new item into an email message. Feedmbox uses a SQLite3 database to keep track of which items it has seen before.

To convert HTML to text, I started with this version from Chew, and then tweaked it to my own requirements. Chew’s version didn’t preserve “title” or “alt” tags from images — mine prefers “title”, but will use “alt” if “title” is not present. Chew’s also used CGI.escape, which doesn’t handle all HTML entities. I switched to using the “htmlentities” rubygem instead.

So, I have all of my feeds specified in a file named sterling.opml in my Personal folder. I want my feed emails to go to my Mail/feeds folder, which is in mbox format. I added a crontab entry to periodically execute the following command:

feedmbox.rb ~/Personal/sterling.opml >> ~/Mail/feeds

That, my friends, is Really Simple Syndication.

BitBucket repository
tarball

Posted in ATOM, OPML, RSS, Ruby, Unix | 2 Comments » RSS 2.0

tr-rectify: Now with more righteous discussions

March 5th, 2011 2:46:07 pm pst by Sterling Camden

tr-rectify logoSince I first published the tr-rectify Greasemonkey script to ease my TechRepublic reading experience, Chad Perrin joined the project. He and I have improved the script apace. Among the changes we made a while ago is that for every element the script hides, it sports a little white-on-blue “+” that you can click to expand it. We then made tr-rectify remember which elements you left expanded and which collapsed, so you can tune your visibility preferences.

One problem that regulars experience with the TechRepublic discussions is in “catching up” — returning to a discussion of one or two hundred comments, and trying to find all the comments that you haven’t yet read. In thinking about how to solve this problem, I thought about adding a widget to allow you to hide all comments posted before a specific date/time, but that has complications not only in the implementation but also in usage.

Then it occurred to me to use our existing framework for collapse/expand. All comments now start out in life expanded, but they each get a little “-” in the upper right-hand corner. If you click it to collapse the comment, all that’s left of it is a “+” with which to re-expand it. Since every comment on TechRepublic has a unique message ID, I use that ID for recording your preference for expanding/collapsing that comment. This works both in Expanded and Collapsed discussion modes.

So, to use this facility for weeding out comments you’ve read, just collapse each one as you read it. You can always expand it later. If you want to take a peek at all comments, just disable Greasemonkey temporarily by clicking on the monkey icon in Firefox’s status bar.

BitBucket repository
tarball

Posted in CSS, JavaScript, Web | 1 Comment » RSS 2.0

tr-rectify: Greasemonkey script for TechRepublic

January 27th, 2011 12:58:10 pm pst by Sterling Camden

greasemonkeyI’ve been meaning to learn more about Greasemonkey for years. The ability to customize your experience by executing JavaScript for specific URLs seems to hold out possibilities that I haven’t yet imagined. But I never had a pressing reason to dig into it, until TechRepublic’s recent site upgrade.

I write for TechRepublic on a weekly schedule, and I’m considered the “host” of the IT Consultant blog. So I spend a lot of time on the site, mostly reading and responding to comments from readers. I also read the works of some of the other writers and join in on their discussions. My usability goals therefore include minimizing page reloads and vertical scrolling.

TechRepublic’s redesign helped me in one way: they now offer an “Expanded” mode for discussions, so I can see all responses at once without loading a new page to read each one. I can respond in situ as well, so I don’t lose my place in the discussion. Kudos.

But the vertical space issues pretty much cancel out those benefits. TR made all the fonts bigger, especially headings. As a result, even after collapsing one of the upper sections, real content gets less than half of the screen on my 17″ notebook display without scrolling. They also added a lot of white space between sections, and all sorts of bells and whistles like “featured comments” that I have to scroll over to get to the threaded discussion. Finally, the content area has a fixed width, thus wasting a lot of horizontal space — which naturally pushes more content in a vertical direction.

Time to get up close and personal with the Slippery Simian.

The Greasemonkey script that you can download at the links below applies to all pages on www.techrepublic.com, and accomplishes the following:

  • Reduces font sizes, especially for the headers.
  • Reduces padding and margins in the discussion.
  • Makes three sections invisible: the header, the “featured comments”, and the huge section that only contains a link to the previous and next articles.
  • Sizes the left and right sections based on the browser width. Since TechRepublic sends me checks, it would be imprudent for me to suggest that you could modify this to hide the right section completely. I gave it 25% of the width, and allocated 70% to the content (the extra 5% is needed for padding slop so it doesn’t wrap). On really wide screens, that 25% is too much for the ads, but 70% is probably still good for the content.

Naturally, you can adjust all of the above to your own preferences. Some people like the bigger fonts. I don’t.

As you can see in the script, the only Greasemonkey feature I used is GM_addStyle, so all my changes reflect mere CSS adjustments. I could have gone crazy with the DOM, but the result gives me just about everything I want.

BitBucket repository
tarball

Posted in CSS, JavaScript, Web | 32 Comments » RSS 2.0

bbnew: remotely create a repository on BitBucket

January 14th, 2011 12:44:39 pm pst by Sterling Camden

I love BitBucket as a host for Mercurial. It’s quick, and convenient. The only speed bump for me was having to go to the web site to create a repository. Well, no more. I’ve whipped up a little script in Ruby that uses BitBucket’s REST API to create a repository. If successful, it clones it via SSH. All in one glorious, command-line-driven step.

Enjoy.

Thanks to Matthew Watson for the comment correcting the API documentation.

BitBucket repository
tarball

Posted in Ruby, Web | 3 Comments » RSS 2.0

Urxvi — keyboard navigation for rxvt-unicode (urxvt)

January 2nd, 2011 5:26:22 pm pst by Sterling Camden

I really like the rxvt-unicode (urxvt) terminal window for X11. I’ve been extending it a lot for my own needs. There’s only one glaring piece of functionality that seems to require the mouse: scrolling and selecting text. I thought I’d remedy that.

In my ideal world, I’d be able to press Scroll Lock, and then use vi key bindings to move the cursor around, scroll back in the history, and select text for the clipboard without ever touching the mouse. When I’m done, Escape or Scroll Lock again should take me back to normal terminal operation.

So be it. If you install the extension from one of the links below, that’s what you get out of the box. That’s why I called it “urxvi”.

But! I know that some of my keyboard-centric brothers and sisters live on the other side of the denominational divide known as the editor wars, preferring emacs or some other editor. Thus, I have made urxvi’s key bindings and behavior completely configurable. All you have to do is provide your own rcfile for the purpose. I’ve even provided the default bindings through a global rcfile (urxvirc), to serve as a starting point.

I probably went a little overboard on the scripting language used in the rcfile.

I call it Slips, for “Sloppy Lisp.” It’s an S-expression syntax, but with not so much punctuation as Lisp. It includes a lot of neat features (like lamdbas and witheringly lazy evaluation), along with a lot of glaring omissions (like list processing and I/O). It’s basically everything I needed to create the default key bindings, plus a few extras. I’ll add functionality to this mini-language as it’s required.

Implementing a pseudo-Lisp interpreter in Perl brought me closer in tune with the true nature of the Universe, especially since I did it in such a sloppy fashion. This certainly isn’t turtles all the way down — more like turtles afraid to reach second base. Actually, I was surprised at how well Perl served this purpose, especially considering my own lack of Perl-fu.

BitBucket repository
tarball
Tags: , , , , ,

Posted in Lisp, Perl, Unix | 15 Comments » RSS 2.0

More performance tuning in Ruby

December 22nd, 2010 1:13:20 pm pst by Sterling Camden

With the amount of spam I receive on a daily basis, the speed with which I can scan and identify it directly affects my productivity.

This morning, the Shower Power (one of those involuntary surges of inspiration that invariably seize me whilst bathing) delivered a new idea for optimizing my Bayesian spam filter’s algorithm for computing spam probability — based on an odd empirical finding. It turns out that my filter scores almost all of the email I receive as either 0.000 or 1.000 spam probability. That’s because (following Paul Graham’s suggestion) I only consider the top 15 (a tunable number) most significant phrases, and the majority of emails contain at least 15 phrases that have only occurred in a statistically significant number of either spam or non-spam messages, but not in both. You may recall that I not only score individual words, but also combinations of up to three (tunable) adjacent words. Those multi-word phrases, being much rarer in usage than individual words, point the finger of fate with greater certainty when they occur only in spam or not spam, and often at that.

Given that circumstance, my optimization is simple and rather obvious: rather than collecting all of the probabilities for all phrases in the message and then sorting out the top 15 most significant, collect only the top 15 most significant as we consider each phrase — and when we have 15 whose significance is within 0.02 of certainty (in either direction), stop. This saves all of the database queries for all of the remaining phrases. In a simple test case using actual emails I have received (about 50% spam), the number of database selects dropped by about 90% — reducing the overall execution time by about the same factor.

Better yet, my reduction in array manipulation improved the performance even more for Rubinius, which seems to have a performance problem in that department. Using the new version, Rubinius runs about four times faster than the MRI (Matz’s Reference Implementation) — depending always on the specific data. Thus, I’m switching to using Rubinius for this process — and thus, for getlessmail as well.

Because the number 15 is tunable via the IsSpam#max_significant property or the -c/--count switches to isspam, users can affect this performance. A low number will perform best, but of course if you go too low then the computed probability will be less accurate. On the other end, you’re better off using -1 (no limit) than using a high number (say, 100 or more), because at some point the overhead of the optimization will outweigh its diminished benefit for a larger array.

Now if I can only think of a way to speed up database updates…

BitBucket repository
tarball

Posted in Ruby | 1 Comment » RSS 2.0

Bidirectional text display for urxvt

December 19th, 2010 4:22:41 pm pst by Sterling Camden

I received an email message a while back in which the signature included the author’s name in both Latin and Hebrew characters. I was pleased to see the Hebrew characters rendered properly in my mutt session, having recently reconciled my terminal window with Unicode. However, having studied Hebrew in college, I could see immediately that the Hebrew text was being displayed left-to-right instead of the usual right-to-left.

I brought this to the author’s attention, thinking that he should swap the characters in his signature. It turns out, though, that Unicode has an algorithm for supporting bidirectional display of mixed text that is presented in logical, as opposed to visual, order.

Next stop: my terminal window, rxvt-unicode (aka urxvt), which makes Unicode part of its name, should know how to handle this, right? In the man page we find:

A somewhat difficult case are right-to-left scripts, such as hebrew: rxvt-unicode adopts the view that bidirectional algorithms belong in the application, not the terminal emulator (too many things — such as cursor-movement while editing — break otherwise), but that might change.

Hrumph. I don’t think so. Should vim, and mutt, and cat, and every other application have to reorder text as it’s being displayed (but not, presumably, as it’s being piped)? No, I think this needs to happen at the visual vehicle itself: the terminal window.

Fortunately, urxvt sports a fine extension mechanism using Perl, and it just so happens that a Perl module for bidirectional support is available. It gives some warnings on FreeBSD using Perl 5.12.2, but since stderr is not usually visible for urxvt, I decided to use it anyway. You can download the extension I created from one of the links at the bottom of this post. See the README for details. I constructed this extension so you can enable and disable it by a keystroke, and you can also specify the initial state.

It isn’t perfect. When editing or entering text, you probably want to turn it off to avoid confusion — but then you can turn it on and do a quick Ctrl+L in vim or mutt to see the result.

Good luck — מזל טוב

BitBucket repository
tarball

Posted in Perl, Unix | 3 Comments » RSS 2.0