Tired of Digg Sponsored Ads?

I visit digg.com on a daily basis for links to diverting and sometimes informative content. Recently, the site began displaying sponsored content (that is, ads) right in line with the actual content. Sure, there’s a pale gray disclaimer that these items are sponsored, but it’s subtle enough and my click instinct quick enough that I’ve clicked a number of links that seemed interesting only to find that they went to ads. I finally got tired of it and wrote a Greasemonkey script to hide these suckers If you’re a Greasemonkey user and a Digg user, you might find this user script useful.

Dr. FogBugz

Or, how I learned to stop worrying and import the bugs. Hrrmmmm.

So my company’s looking at switching from using the beastly Bugzilla bug tracking software to using something called FogBugz. It seems a decent enough piece of software, though the install process went as follows:

  1. Download and untar install files.
  2. Learn from the readme that it requires a PHP extension, a daemon, and (for me) a PHP upgrade. This is all rather more intrusive than most bug software I’ve seen, though to be fair, Bugzilla also has a lot of dependencies.
  3. Upgrade PHP.
  4. Run a script at the command line to make sure dependencies are all worked out.
  5. Start the daemon.
  6. Run a wizard on the Web to set up the database, etc.
  7. Buy and submit license key.
  8. Worry about importing bugs from old bug tracker into new one.

This last item is the one that’s taken up some four hours of my morning today. FogBugz apparently ships as an asp application, but there’s a PHP version that we’re using. For the Windows version, there’s a script to import from Bugzilla, but it’s hosed on Linux. It seems to tap into stuff set in the PHP extension that’s Windows-specific or something. So I worked a little magic using some PEAR classes and was able to connect to Bugzilla’s xml interfact to retrieve bugs.

But I was getting authentication errors. Apparently, if you’re not logged in, you can’t see bugs using Bugzilla’s xml interface. I tried a couple of things and finally just used links at the command line with the -source flag to get all of our bugs as text files. I had to browse to our Bugzilla install using links and login first, though, so that the cookie would be set and subsequent connections would be able to see the xml data rather than the “NotPermitted” error.

So, now I’ve got 700ish bug reports in a directory. Time to hack the import script to make it work using my data rather than the obfuscated methods available through the Zend extension. This was just a little tedious and mainly consisted of finding objects and function calls and replacing them with arrays and keys that hold the corresponding data from my parsed xml. That is, the shipped code gets an xml file and creates objects to hold the data, while my code slurps in the xml and creates a nested array for each bug; I had to make the import script read my arrays rather than looking for objects. There were a couple of little hitches that were easily fixed, and before too long, I had my 700ish bugs imported into FogBugz.

But I noticed when reviewing my new bug list that I had a bunch of bugs that weren’t mine, and others had bugs that should have been mine. Moreover, most of the bugs were assigned to just two of us. Why this happened I have no idea. To fix it, I wrote a script that reconciles user ids between the two systems and changes bug assignment in FogBugz for each bug to what the assignment in Bugzilla originally was. For example, say user X in Bugzilla has numeric id 5, while he has numeric id 22 in FogBugz (just because of the way the users were imported). Luckily, both systems use the email address as the login, so I could query both databases, get the numeric id for each, and then do a query for each bug that says (in English) “Change the assigned-to field for bug 700 to the numeric id 22 because the numeric id for assigned-to in Bugzilla is 5, and user 5 in Bugzilla corresponds to user 22 in FogBugz because they map to the same email address.”

And voila, my bug list is as it should be. I’m sure we’ll find problems here and there, but by and large, I’d say it was as successful an import as could have been hoped for.

Flock

Flock 0.1So I can’t say much about it yet, but I’ve spent the last couple of weeks tearing my hair out in an effort to release Flock 0.1, which my company is pitching as a tool for a new (social) browsing experience. There are many bugs yet (they’ll be cause for hair-tearing over the next month), but it feels like we’ve got a pretty solid alpha release. If you’re interested in finding out more or in getting on the list of people who’ll be given invites to try our software for the next wave of testing, head on over to flock.com.

 

 

 

 

 

 

 

Changes to XUL's getCellText() params

I learned after about an hour of puzzlement tonight that the parameters for XUL’s nsITreeView::getCellText() have changed. Formerly, you passed a numeric id corresponding to the row in a tree as the first parameter and a string matching the id attribute of the desired column as the second. This provokes errors in recent versions of Gecko because the function now expects an nsITreeColumn as the second parameter.

A couple of nice people (db48x and gavin) on #developers at irc.mozilla.org pointed me to some docs that helped me unpuzzle myself. First, the idl file for nsITreeview, which clued me in to the fact that the second parameter is no longer a string. Second, a link to a mailing list posting about the change.

Basically, the change was implemented in order to do away with the necessity to give treecols an id. By generalizing the function a bit to expect an nsITreeColumn, Gecko can now figure out which column to use in a number of ways. For example:

tree.columns.getColumnFor(treeColElement);
tree.columns.getNamedColumn(treeColID);
tree.columns.getColumnAt(index);

In my recent case, I knew the column name, so I passed tree.columns.getNamedColumn(‘identifier’) rather than just ‘identifier’ to the getCellText() function and it worked like a charm.

I post this pretty much for my own later reference.

Dork, dork, dork

It’s midnight on a Saturday night, and I’m at a dork party I wasn’t sure I’d go to. It’s at a big house, and I’m one of thirteen in one of the den/living rooms. We’re all scattered about on couches, folding chairs, and the floor. There’s enough cable running around on the floor to, to I don’t know what. To put a small-to-medium sized business’s IT staff to shame. There’s much talk of browsers and xcode and extensions and so on and so forth. I donned my best dork shirt for the event (it reads /(bb|[^b]{2})/, which means something to dorks) and have already gotten a good cackle from somebody over it. I occasionally have to stop my diligent work to go to a terminal and type “iwconfig eth1 essid ‘bret’; ifup eth1″ to get back on the network, because I keep getting dropped. The other den full of people is apparently more social than my room, which is full of relatively quiet people. I’m probably the quietest. It’s not nearly as painful as it could be. If only I could get this makefile to work blah blee bloopety blooblah.

Round Two is Hiring!

My company is looking to hire a couple of full-time senior developers. The following criteria must be met:

  • You must already live near or be willing to relocate to Silicon Valley.
  • You must have a minimum of five years of application development, with a focus on the following skills, in descending order of importance:
    • Mozilla application development
    • XUL
    • XPCOM
    • C++
    • javascript
    • CSS
  • Experience developing on two of the following three platforms: PC, Mac, Linux
  • Experience working on Open Source Software projects is a plus.
  • All the usual buzz words (self-starter, team-player, etc.) apply.

Send me a resume at abcdefg@hijklmnopqrstuvw.xyz (but replace abcdefg with my first name and hijklmnopqrstuvw.xyz with learnhouston.com) if you think you’re the person for the job. If you’re not the person for the job, but you might know who is, have that person send me a resume and include your contact information. There’s a small reward for whoever turns up a person we ultimately hire. Please don’t apply or send me resumes for those who don’t meet the criteria listed here.

Weird Button

Weird ButtonSo I’m working on adding a little button to a Firefox toolbar. If you click the button, it performs a default action. If you click a little arrow next to the button, it produces a menupopup from which you may choose another action. For an example, check out the Forward and Back buttons in Firefox. Clicking the main button moves you forward or backward; clicking the arrow produces a list of where you’ve been or where you can go. The thing is that by default, this sort of toolbar button is kind of big, and I want a tiny, unobtrusive little button. So I’ve been experimenting with different ways of implementing the button. In one case, it’s fairly small, but it’s got an extra arrow icon and has some extra horizontal space as a label placeholder, even though I don’t want a label.

My latest iteration breaks new ground in UI design. If you look carefully, you’ll see that there’s a little green bullet sort of thing (an icon squished down) and then a button wrapped around this small button in the shape of a sideways “U.” If you click the wrapping button, sure enough, you get the popup. If you click the inner button, you get the default behavior. I fully expect this sort of button to begin appearing in software packages very soon.

Auto-Updating Extensions

Eric Hamiter’s tutorial on how to enable extension updates is pretty handy. As he points out, in order to make it so that the “Update” button in the extensions manager actually does something for your extension, you simply provide a value for the updateURL paramater within your extension’s install.rdf and make sure there’s a valid RDF file being served up from that URL. This file contains information about the current version and from where the latest xpi file can be downloaded. When you highlight an extension in the extensions manager and click the update button, it checks the current version number against what’s listed in your remote RDF, and if yours is old, it pops up the update wizard that walks you through doing an update. Very nifty.

But let’s say I want to force an update (or at least prompt the user to let him or her know that a new version exists. Supposedly, there are some configuration options you can set to cause extensions (and Firefox itself) to automatically update (thanks to Nigel McFarlane’s Firefox Hacks for this):

extensions.update.autoUpdate /* set to true */
extensions.update.severity.threshold /* set to 0 (lowest severity) */
app.update.autoUpdateEnabled /* set to true */
app.update.enabled /* set to true */

That didn’t work for me, presumably because there’s some sort of timer. It seems to me as if I’ve heard at some point that different versions of Firefox do their updates at different times once a week. But say I have an important security release for my extension and want to prompt people to upgrade immediately, whether they’ve just installed it two days ago or whether they’ve had their browser open for three weeks without a restart (a tempting method for checking updates would be on browser load).

Luckily, Firefox’s mechanism has interfaces exposed that allow you to tap into some of the functionality. Unfortunately, there’s not enough exposed to be extremely useful, but there’s enough to get by. Specifically, there’s a function available through the nsIExtensionManager component that allows you to display the extensions manager wizard, as follows:

var nsIUpdateItem = Components.interfaces.nsIUpdateItem;
var gExtensionManager = gomponents.classes["@mozilla.org/extensions/manager;1"]
.getService(Components.interfaces.nsIExtensionManager);
var itemType=nsIUpdateItem.TYPE_EXTENSION;
//The guid here is the guid for the extension in question.
var items = gExtensionManager.getItemList(‘{e9f3a1cb-98a9-4384-879b-c6d1e39ef5bf}’, itemType, { });
var updates = Components.classes["@mozilla.org/updates/update-service;1"]
.getService(Components.interfaces.nsIUpdateService);
updates.checkForUpdates(items, items.length, itemType, Components.interfaces.nsIUpdateService.SOURCE_EVENT_USER, window);

The trick, then, is to check the current and remote versions of the extension and to display the wizard only when there’s a discrepancy. Else you wind up showing a blank wizard. This is easily enough managed by querying the extensions RDF for the version number and then polling a remote script that serves up the current version of your extension (I use a different output source here than the updateURL RDF because all I really need is the number, and I want to conserve bandwidth. I could find no way to check the remote version using built-in interfaces without spawning the update wizard, though I may have overlooked or misunderstood some code. In pseudocode, the routine runs as follows:

  • Check a timer to see if we need to check for an update.
  • If so, query the extensions rdf to get the installed version number.
  • Check a remote file for the current version number of the extension.
  • If there’s a difference, use the code given above to pop up the upgrade wizard, which walks the user through the process.
  • Set the timer to now plus the update check interval.

Naturally, you kick this off in an onload handler so that any time your browser is started, it checks immediately for updates and then checks periodically for as long as the browser’s open.

Round Two Launches

In February, I started a new job that it’s been really hard describing to people.

>> “What do you do?” they’ll ask.
<< “I program stuff.”
>> “What do you program?”
<< “Web services.”
>> “What’s a Web service?”
<< “It’s something that allows another application to access your data.”
>> “But isn’t your company tied up in Firefox somehow?”
<< “Yes. I write Web services that we hope will help enhance the browsing experience.”
>> “How?”
<< “I can’t really say very much about it right now. I’m writing extensions to go along with the Web services.”
>> “How’s your company going to make money?”
<< “Nice weather we’re having today, huh?”

Well, we finally launched our Web site yesterday after a lot of work by a guy named Joel Apter, whom I hooked up with as a developer resource on the Spread Firefox project, and a designer named Bryan Bell who’s great at icon work in particular and who can be contracted for pretty darned reasonable rates. These guys did the bulk of the site so that I could work on my mysterious Web services and extensions with limited distractions. And I think they did a great job.

I spent some time the night we launched doing some benchmarking and tweaking to make sure our site scaled pretty well, and I’m happy to say that we weathered a slashdotting with aplomb, the site hardly affected by the heavy traffic.

For now, our site doesn’t say a whole lot about what we do. Out of the gate, our offering is sponsorship of several popular Firefox extensions. Basically, we’ve given money and other resources (server infrastructure) to these developers both to support their great work and to attach our name to their popular products. We have a lot more on the horizon, and with a little luck and a few more twelve-hour days on my part, we’ll have a beta release of what we hope will be a pretty exciting extension near the end of the month.