05/10/2008

Blogging via Flock

Category
So there I was, experimenting with Flock, and noticed that it supports the MetaWeblog API. So I thought I'd give it a try to see if it allows me to add entries to this blog. Update: Yes. Yes it does.
Blogged with the Flock Browser

Tags: ,


05/07/2008

Delegate math revisited

Category politics
Two months ago, I mused about the state of the Democratic primary. Between then and today, a number of things have occurred:

  • The media painted Clinton's performance in the March 4 and April 22 contests as a "comeback", despite the reality that her wins were by far smaller margins than early polling had predicted.
  • Having long since exhausted all substantive policy discussions, the campaign devolved into a discussion of issues typically left to the tabloids - issues that have very little bearing on either candidate's ability to effectively govern - including a ridiculous debate televised on ABC that left me wondering if I was actually watching a TV version of the Weekly World News.
  • Barack shrunk Hillary's superdelegate lead from approximately 100 to approximately 20.
  • Hillary shrunk Barack's pledged delegate lead by 3.
That last figure seems the most stark to me. Her "big comeback" on March 4 (winning the primaries in Ohio, Rhode Island, and Texas) brought her a net total of 4 delegates, because Obama's performance in the Texas caucus outweighed Hillary's in the primary, netting him a total of 5 delegates for the state, and his win in Vermont netted him 3. Within a week, he had netted 9 more in Wyoming and Mississippi, so Hillary's next "big comeback" in Pennsylvania (again by far smaller margins than originally anticipated), which netted her 12, brought her a grand total of 3 delegates closer to Barack than she had been on March 3. Then they split Guam evenly. But due to the steady drip of superdelegates in Barack's direction, as of this morning she was actually far further from the nomination than she had been two months ago.

So what happened today? Well, that's still up in the air, but here's what we know so far:
  • Barack appears to have won NC by about 14% (including my early vote a week and a half ago). This should net him 17 delegates.
  • Hillary appears to have won IN by 4%, which should net her 2 delegates... except there's a catch. NBC is still labeling this "too close to call" because there are about 220,000 left to count, and most of them are in Gary. Which is actually a city. Which means it's "Barack-friendly" territory. So he's congratulated her on her apparent win there and she's claimed a win, but by morning he could actually get more delegates than her from IN.
  • Barack's net gain in the popular vote from today will be in the neighborhood of 200,000. This eliminates Hillary's argument that PA allowed her to pass Barack in the popular vote, which until today was only true if you count Florida and Michigan. I'm actually not opposed to including Florida, since Barack's name was at least on the ballot there, although the candidates had agreed to the DNC's request that they not campaign there, so the voters there made a decision without the luxury of getting to know the candidates in the same way as citizens of other states, a process which throughout the campaign has consistently favored Barack. In Michigan, on the other hand, Barack's name wasn't even on the ballot. To include those results now would be to adopt the approach of countries whose electoral process we tend to mock. Unless the remaining 220,000 in Indiana broke overwhelmingly for Hillary, not only will Barack's net delegate gain for one day be about 4 times Hillary's gain over the last 2 months, but it puts him back on top in the popular vote count, even if we include the two states that both candidates agreed prior to their primaries would not count.
So what happens now? Hillary's "magic number" (the spread she needs to catch up in pledged delegate count) is now 86. That's a 72-point spread (86-14), compared with the 40% spread she needed after March 4. 80-20 would actually bring her within 40 delegates, at which point she could probably make a case that it's essentially a tie and ask the remaining superdelegates to give her the nod. But recent polling shows him up by roughly 8 in Oregon and 12 i n South Dakota, and down by only 13 in Puerto Rico, 28 in West Virginia, and 34 in Kentucky. Were the results to match that polling precisely, Hillary could win 100% of Montana (for which no public polls have been released) and still wind up 128 delegates behind (144 if they split the state evenly).

Under just about any scenario, it's ridiculous for Hillary to continue, but it appears she's going to. However, Russert just announced that she's now cancelled the morning talk show appearances she had scheduled for tomorrow, which implies she'd been hoping to gloat about another big comeback but has now decided there's not much to gloat about. Chuck Todd made an interesting observation the other night: after tonight, there are now more uncommitted superdelegates (~270) than remaining pledged delegates (217). This essentially means the campaign is over. Each candidate will continue to air TV ads in the remaining states, and may make a few trail appearances, but for the first time, there's actually more to gain by courting the remaining PLEOs than by courting the remaining voters.

Aside: I just saw a fox. And he didn't eat me. So I got that going for me, which is nice.

Okay, back to the analysis. If it turns out that Barack actually did win Indiana, I suspect there will be a flood of superdelegates flocking to Obama's banner (and possibly a few more defecting from Hillary's camp) to try to put this to rest once and for all. Otherwise they may just let this drag on. But because there are so few delegates left to gain in the remaining primaries, I think interest will wane rapidly from now until June 3. On the other hand, that's only 4 weeks away, so it's probably a wash. One theory I do have is that Barack will soon extend a pseudo-magnanimous gesture: "Okay, fine. Seat the Florida and Michigan delegations. With them included I'm still up by 100 pledged delegates, still up by 200,000 in the popular vote. I won. Get out."

04/23/2008

Magic Button

Category Domino Formula SmartIcon
For as long as I can remember (possibly 2001) I've always maintained some variation on a SmartIcon toolbar button that a former coworker called the "magic button": it allows new fields to be added to a document and existing fields to be overridden or deleted from the document, either while editing the document or while it's selected in a view. I've seen various approaches to this basic concept over the years, and each time I install Notes on another computer, I either consult the Google to find one I've used before or just reconstruct it from memory. It finally occurred to me that if I just posted the one I'm currently using here, not only would it be easier for me to find later, but some of you might find it useful as well. So here's the current incarnation of said magic button:

targetField := @Prompt([OkCancelEditCombo]; "Select Field"; "Select a field to override:"; ""; @DocFields );
updateTypes := "Text":"Number":"Time":"Delete Field";
updateType := @Prompt([OkCancelList]; "Select Type"; "Choose a type or action:"; "Text"; updateTypes );
@If(updateType = "Delete Field"; @Return(@SetField(targetField;@DeleteField)); "" );
newValue := @Prompt([OkCancelEdit];"New Value";"Enter the new value:"; @Text(@GetField(targetField )));
newTypeValue := @Select(@TextToNumber(@Replace(updateType; @Subset(updateTypes;3);"1":"2":"3" )); newValue; @TextToNumber(newValue); @TextToTime(newValue));
@SetField(targetField; newTypeValue)

I'm sure you can decipher the above, but here's what it does:
  1. Asks you which field you want to override. Type in a new one if you're adding a field. I've seen other versions where something like "---NEW---" is included in the field list prompt, and if you select that, it asks for the new field name... figured I might as well skip that extra step by just using [OkCancelEditCombo].
  2. Asks what data type the new value will be (text, number or time), with an option to delete the field instead - in which case the formula just deletes the field and exits.
  3. Asks what the new value will be, defaulting to the current value (if any).
  4. If the new value's data type is not text, converts the value to the selected type.
  5. Writes the new field value to the document.
This little button has saved me oodles of time over the years...

(cross-posted at BleedYellow)

04/22/2008

PercentRem.com

Category LotusScript Wiki
I just bogarted registered PercentRem.com. At the moment it's just a default instance of DominoWiki (although I did update the logo), but my current plan is to dedicate that wiki entirely to LotusScript. The language definitely has its limitations, but it's amazing what it can do when properly coaxed. My hope is to make this a living, breathing, centralized repository of tips, tricks, pitfalls, righteous hacks, and so forth. Let me know if you have any thoughts, ideas, suggestions, etc. Due to Ben's excellent versioning engine, I'ma just leave it wide open for the time being, so feel free to drop in any content that you feel would be a good fit. Over time I hope it will coalesce into a semi-structured reference on what the language truly can and can't do.

(cross-posted at BleedYellow)

04/15/2008

Cheap date

Category Domino LotusScript
I just had an epiphany... or maybe just an apostrophe. I'm in the middle of some code that does some date matching (determines which document to process based on date information posted from a web application). I don't have control over the date format posted to the agent, and currently the format is [Month abbreviation][unpadded day number][day number suffix] - i.e., Apr15th. I already knew that passing "April 15th" to the constructor of a NotesDateTime object would create an instance representing [04/15/2008 12:00:00]. But did you know that "Apr15th" will too? As it turns out, it actually ignores the suffix: "Apr15bogus", for example, creates a date with the same properties. Always good to find these things out before I resort to string parsing...

(cross-posted at BleedYellow)

04/13/2008

Everything old is new again

Category Linux
As you may have noticed, I've recently become quite the Linux fanboy. Well, today I took it a step further. Yesterday my Dell Inspiron (which I'm using to post this) was running Windows XP with Ubuntu 7.10 running as a VMware virtual machine... today it's the opposite. Of the five computers in our apartment, the ratio is now 3 Linux (1 Ubuntu, 1 OpenSUSE, 1 Xandros) to 2 Windows... and one of those two isn't even mine; the other is Laura's Inspiron, and she hinted today that she might switch to Ubuntu soon too, since she uses exactly two programs: Firefox and OpenOffice - and she knows that both just come pre-installed with Ubuntu. Scratch that; I just remembered that she recently installed a third program: Aptana (which on Linux you don't install, you just unzip to a folder of your choosing, much like Eclipse on Windows). She's dabbling in PHP and had asked which IDE I would recommend. In short, we may soon be a Linux-only household; to the owner of the Latitude, don't worry... I'm leaving Windows alone on that machine.

Unlike on OpenSUSE, installing VMware on Ubuntu was a breeze:

apt-get install vmware-server

Only caveat: although it's free, you still need a valid serial number, and apt won't configure the package installation until you've entered one. Once installed, I spun up a new virtual machine (pointing it to an ISO of my XP CD), and in less than an hour had Notes reinstalled, complete with a data folder overwritten from the backup I'd saved to our NAS before converting. So Notes looks and behaves precisely as it did before. I decided to install Office 2003 because I loathe 2007. Nothing else... nice clean registry, so Windows is actually far snappier running as a VM than it used to be with all of the extra clutter.

On top of the base Ubuntu distro, I've added Skype, Eclipse, Aptana, and of course, Notes 8.0.1. When I tried to install it, the wizard window popped up, but it was just an empty panel. Mayhap I just didn't wait long enough, but after about five minutes, I killed it and just opted for the silent approach:

./setup.sh -silent -V licenseAccepted="true"

This installed Notes with Sametime, but without Symphony or the composite app editor. I'm actually not using Sametime at the moment; although it doesn't have all the fancies of Sametime 8, I actually prefer Pidgin (which is also pre-installed in Ubuntu) because it bundles all of my IM accounts (AIM, Yahoo, MSN, GTalk, MySpaceIM, and Sametime) into a single interface.

By the way, Jens Bruntt posted a great article last week on how he installed Notes on Ubuntu. The fix he outlined for the embedded browser isn't working for me yet (for instance, xulrunner didn't install in /opt, and including a reference to /usr/lib/xulrunner doesn't seem to fix the problem), but to be honest, I don't use the embedded browser much anyway. So far, the only thing I miss is iTunes, but between gtkpod and the Amazon MP3 Downloader, I'm pretty much covered on that front as well.

UPDATE: Designer works flawlessly in wine. My Windows VM is now sleeping peacefully, doubtless dreaming of a day when I'll come crawling back, telling it I can't live without it. Don't feel bad, Windows... it's not you, it's me.

(cross-posted at BleedYellow)

04/09/2008

SnTT: Ajax history manager

Category Show-n-Tell Thursday JavaScript
Julian's post about  JavaScript stack traces reminded me of something I wrote late last year and had been meaning to mention but never did.

Web applications have steadily become more interactive over the last couple of years, and have been evolving from a collection of pages to a sequence of interactions and events. On the one hand, this can be very positive for the user, as we're no longer forced to trigger an entire page refresh for every mouse click. On the other hand, one challenge this presents is that many users are still in the habit of conceptualizing site navigation and interaction in a context of page history; in other words, they expect to be able to click something (i.e. a button or a link), examine the result, then click the Back button and see what they saw before... and click Forward to return. This was already a problem before Ajax when POST requests were involved, but adding Ajax to the equation can compound this even more: by default, not only will clicking Back not show the user a previous state of the current page, in a "one-page application", it'll actually exit the application, possibly even your entire site.

So how can we get around this? Ironically, most workarounds I've seen (including the one that I implemented and am about to describe) make use of the HTML element that was often used to provide Ajaxy behavior before what we now consider to be "true" Ajax gained widespread use: namely, the iframe. When an iframe's location changes, an entry is added to the browser's history (in some browsers... more on that later), even though the location of the page containing it has not changed. As a result, clicking the Back button will simply return the iframe to its previous location without modifying the container's location. Similarly, once that's occurred, the history contains an entry in the forward direction, so clicking Forward at that point will again navigate only the iframe, still leaving the container location intact.

How does that help us? Chances are, those familiar with JavaScript's Function.apply() have already guessed where I'm headed with this. As I commented on Julian's post, a handle on a function can be passed as a parameter to another function. This is used all the time in Ajax requests to specify a callback function: once the request has been processed, the specified callback function is executed to respond to the result of the request. In this case, however, we're not associating a function with a request for remote data (or submission of data); instead, we're actually associating a function (and the parameters that should be passed to it) with navigation. Here's how it works:

  • Instead of calling the function directly, we pass a handle on the function (along with an array of parameters to call it with and an optional scope) to another function - AjaxHistoryManager.register(). For example:

    function sayHello (sender, recipient) { this.innerHTML = recipient + ', ' + sender + ' says hello.'; }
    AjaxHistoryManager.register(sayHello, ['Me', 'World'], document.getElementById('helloDiv'));


    NOTE: the lack of parentheses after the reference to sayHello is intentional; we're not calling the function at this point, just passing it as an argument.

  • The register() function creates an object to store the function handle, parameter array and scope object (which defaults to the passed function if no scope is specified), pushes that object to an array that stores all of the function calls that have been registered since the container page was loaded, and increments a counter.
  • Finally, register() sets the source of a hidden iframe to the URL of a Page design element (assuming you're using Domino; a very minor tweak to this would allow it to behave identically in PHP, ASP, JSP... pretty much anything), including a query string parameter indicating the current counter value.
  • The Page loaded in the iframe has only one job: it includes a script tag that (using computed text) passes the counter value to window.parent.AjaxHistoryManager.execute(); this function retrieves the object stored earlier and calls the associated function with the stored parameters, binding "this" to the correct scope object. The reason I almost never use "this" in JavaScript is that any number of factors can cause a function to lose a handle on the scope you originally intended it to have, which will cause any references to "this" to apply to the new scope. That's not a problem in this case, because we're calling .apply() on the function to be run, which allows us to explicitly specify a scope object. So, in the example above, "this" refers to the HTML element that was passed as the scope object. If the function you're registering doesn't have any references to "this", you can leave off the scope parameter entirely and just pass the function handle and a parameter array.

The result is that the registered function is still called almost immediately (depending on how long it takes your server to send the 94 byte overhead for the iframe Page), but the browser history now contains an entry associated solely with that event. Ergo, executing a series of events in this manner allows the user to execute them again (with the same parameters and scope each time) simply by clicking Back and Forward.

You can see an example of this behavior here (the sample database is also available for download). On that page, click the "Increment Counter" button a few times, then click Back and Forward (Alt+Left / Alt+Right also work)...  the displayed counter will increment and decrement based entirely on those navigation events. This works correctly in Firefox and I.E., but not Safari or Opera. In Opera, navigation does appear to update the iframe, but the stored function is not called; in Safari, clicking Back actually navigates the entire container page. In both cases, though, the function is still executed initially upon registration; in other words, your application will still work, but will not have the benefit of triggering previously executed functions again via navigation events. I still have never had to support either of these browsers within an enterprise context, but if anyone has ideas on how to extend this approach to fully support either or both, let me know.

One last disclaimer: this approach is best suited for "read-only" operations. For example, user interaction causes some change to a portion of a page (i.e. resorting data), and we want reverse navigation to "undo" that change. This approach gets a whole lot messier if a POST is involved: if the methods being executed are actually updating data in the database, then executing them in reverse order needs to revert the database content to its previous state - whether by resetting field values on one or more documents, or actually removing documents that were added by the executed method(s).

(cross-posted at BleedYellow)

04/06/2008

The rest of the story

Category Musings
Saw a few postings about how various bloggers got into Notes, so I figured I'd wax nostalgic as well.

During the holidays in late '97, shortly after my 20th birthday, I came to the vivid realization that I had no idea what I wanted to be when I grew up. Which was a bit awkward, since I was already three semesters into my pursuit of a degree in music. Having worked at Chick-Fil-A on and off for the previous five years, I decided I'd just go back and man a grill until I'd gotten over my career angst. But my father ( a.k.a. "Pops" ) had another suggestion; at the time, he was a server admin working at a large telecom... large enough that they had a whole team of people whose job was creating and deleting email accounts... all day long. In fact, they were a bit short-staffed, and he suggested I apply. He warned me it might be boring but would pay slightly better than what I'd been planning to do, and I wouldn't smell like chicken when I got home. He booted up his Thinkpad, and I got my first look at Lotus Notes ( 4.5, in case you were curious ). That's right: I'm a second-generation Yellowbleeder.

A few weeks later, I'd received a crash course in basic Notes administration from the contract agency and was happily creating and deleting Notes accounts all day. Part of our process was to leave the Notes ID in the address book so that we could call the user, walk them through installation of the client and initial workstation setup, at which point the ID file would be automatically downloaded to their machine and removed from the account record. But to ensure that we had a safe copy of the ID, we'd also save the file locally and then attach it to a document in a custom database that tracked when the account was created, the initial password (to allow for password resets... this was 4.5, after all), and various other bits of info about the user. So, as you might expect, I spent a lot of time in this particular database. I thought the icon was rather boring, and decided to replace it with something a bit more interesting, and easier to spot at a glance on the Workspace... Unfortunately, during my crash course, nobody mentioned any development-related concepts... say, for instance, that the database icon was a design note stored within the database itself and, therefore, determined how the chiclet would display for everyone, not just me. Imagine the lead administrator's surprise when he glanced at the icon for the ID vault database one morning and noticed it had been changed to the Grateful Dead "dancing bear":



Though embarrassed to admit that I'd made the change without realizing the impact, in retrospect I'm quite glad that happened, because I was finally told about the nature of design notes and their role in the NSF structure. I'd soon automated the bulk of my job duties, and over the next few months became "the administrator's developer", creating various in-house tools for user and server administration. Ten years have passed. I still don't know what I want to be when I grow up (bah, like that'll happen), but I do know that at some point when I wasn't looking, something originally meant to pass the time and pay the bills evolved into a career, and then into a passion. We few, we happy few...

And yes, as far as I know, the icon for that database is still the dancing bear. And now you know... the rest of the story.

(cross-posted at BleedYellow)

04/03/2008

Uptime

Category Domino Linux
Yesterday (April 1... I know it's technically April 3 now, but for me it's still Wednesday) was mildly momentous. Although the following graph hasn't quite caught up yet (UPDATE: now it has), the server that hosts TimTripcony.com broke its uptime record:



As the graph indicates, the red X's (which hover, on average, closer to 0) are from the server's stint as a Windows box; the blue represent its shiny new Linux identity. Since the conversion in early December, it's only had one reboot... and that's only because we had a brief power outage (bad Timmy, no UPS). Other than replacing the hard drive (with one that was actually older than the Windows drive, just hadn't ever been used), the hardware is the same - same motherboard, processor, NIC, RAM, etc.... it just stays up now. No babysitting: no weekly defrag, no chkdsk to try to keep it from tanking, no weird behavior if I ignore a security update on a server that's only externally accessible on ports that I'm securing via Domino anyway... it just stays up. Is Linux administration "harder" than Windows administration? Sure... if, like me, you don't originally come from a UNIX background, there's a lot that may seem counter-intuitive about it. You may spend a bit more time on "the Google" looking for the exact syntax of various commands. But I'd personally rather support something I rarely have to touch - even if that occasional interaction isn't quite as intuitive as its Windows equivalent - than have to constantly babysit a system just to keep it operational.

(cross-posted at BleedYellow)

04/02/2008

Sametime Advanced on BleedYellow.com

Category Sametime BleedYellow
We are pleased to announce the availability of Sametime Advanced on BleedYellow.com!!

Check it out for yourself!

(cross-posted at BleedYellow)

Hire Me

Elsewhere

What the Quote?

"Put up your duchess."

Alex Belt

"I'm an anonymous coward."

Dan Huddlestun

"You're like a lint brush."

Laura Tripcony

"I knew that was what they were doing. I could feel it in my puke glands."

Laura Tripcony

"Oh no, he's being eaten by code!"

Laura Tripcony

Apparel

Lotus Rocks

I write the code that makes the young girls cry