The August 2007 Blog
send me a comment

Goto Considered Harmful (Tuesday, Aug 28)
[ permalink ] [ e-mail me ] [ ]


an xkcd webcomic.

JavaScript Charting Libraries (Sunday, Aug 26)
[ permalink ] [ e-mail me ] [ ]

I've been playing with JavaScript plotting libraries recently. These are libraries that allow you to create custom, dynamic graphs and charts on a web page using only JavaScript. I'd rather use SVG of course, but in this particular case I can't be sure that the end users will have an SVG plugin installed, and they're all on Internet Explorer (which does not yet support SVG natively).

I found a pretty good list of JavaScript charting libraries on the site, although by the time I found the list I was already playing with Plotr:

Examples of Plotr charts

I don't have any needs for complex charts and graphs, so the bar charts and pie charts that Plotr generates are good enough for me for now. I also like the way the code ends up looking in order to generate a chart -- the library has a good "feel" to it.

One thing I didn't like was the was the way the default color schemes turn out. They're very monochromatic, and I prefer a little more color differentiation. If you try out the library and want more color variation, you can do something like this:

function multiColorScheme (hex, dataset) {
	var color = new Plotr.Color(hex);
	var datahash = new Hash();
	var setKeys = datahash.keys();
	var result = new Hash();
	var increment = 75;    /* modify to your liking */
		result[index] = color.lighten(10).toHexString();
		color.r = (color.r + increment) % 255;
		color.g = (color.g + increment) % 255;
		color.b = (color.b + increment) % 255;
	return result;

Then when you're setting the options, you can do something like:

var options = {
	colorScheme: multiColorScheme('#FF0000', dataset), 
	/* other options here... */

There's probably a much easier way to do it, but that was my quick 10 minute solution. If you already know what colors you want, you can also list them explicitly like this (from one of the examples):

var options = {
	// pie charts
	colorScheme: [ '#1c4a7e', '#bb5b3d', '#3a8133', '#813379' ],
	// bar/line charts
	colorScheme: new Hash({ 'label1': '#1c4a7e', 'label2': '#bb5b3d' }),
	/* other options here... */

Anyway, it's pretty interesting stuff, especially the ExplorerCanvas library that allows you to draw using JavaScript and Canvas calls in Internet Explorer.

Podsmart (Friday, Aug 24)
[ permalink ] [ e-mail me ] [ ]

Having the Lotus Notes 8 client on Eclipse opens up some interesting possibilities. For example, here's a recent article from CIO magazine about an internal IBM project called "Podsmart":

The [IBM] Dublin intern team was charged with creating personal audio radio programming from text sources, including e-mail, calendar, news-feed, online articles and e-learning programs... In response to the challenge of creating personal programming, the interns generated an application that's built on Lotus Notes 8 (which is built on the IBM-developed and open-source Eclipse Java platform). The interns created a framework to connect different data sources and worked with a third party to translate text into audio.

Apparently Podsmart can take all your important e-mail and appointments and whatnot and turn it into an MP3 podcast for you to listen to on the road. What would be really cool is if you could call it from your cellphone when you don't have network access. No idea if we'll ever see it in the real world -- hopefully on alphaWorks...

SnTT: Serving GZipped Content on Domino (Thursday, Aug 23)
[ permalink ] [ e-mail me ] [ ]

UPDATE: Dwight Wilbanks pointed out in the comments why it might be better to avoid a .gz extension on the filenames. Good point, so I rewrote the instructions a bit.

I'm not sure how advantageous this will end up being in the end, but I've been playing with ways to serve gzip compressed files natively in Domino. The two "easy" ways seem to be:

Those require no change on the database/URL side and little configuration on the server side. There is also at least one gzip proxy servlet that I know of, although that may require you to rewrite your URLs.

Another way to do it is to follow the instructions that Michael Bourak has in his domBulletin configuration document [SIDEBAR: if you haven't used domBulletin before, you're REALLY missing out...]. I just noticed that Lance Spellman recently did a nice writeup of how to set this up on his Dojomino blog, so I won't repeat the instructions here.

However, I've been doing this in a slightly different way, so that I could store the files as File Resources in a database instead of on the file system. Here's how:

  1. Follow Lance's instructions for setting up the Web Site Rule

    GZip Domino Web Site Rule

  2. Compress your file in gzip format using your tool of choice (I use 7-Zip, with gzip selected as the compression type)

    7-Zip using GZip compression

  3. Add the file to a Notes database as a File Resource. File Resources are in the database design under "Shared Resources - Files".

    New File Resource Button

  4. After you've attached the file as a File Resource, right-click it and go to Resource Properties. Rename the file so you REMOVE the .gz extension, and ADD a gz/ to the beginning of the name to mimic a subdirectory (for example, "script.js.gz" gets renamed to "gz/script.js")

    Setting the MIME type for a File Resource

  5. (Possibly Optional) If the files you are serving are sensitive to MIME type headers, you can also hard-code the MIME type for the File Resource on the second tab of the Resource Properties dialog:

    Setting the MIME type for a File Resource

    Otherwise the Domino server sends the file down as "application/octet-stream" (at least my Domino server did). In my limited testing it didn't seem to matter, but it might matter to you.

The file is now available at http://yourserver/yourdb.nsf/gz/script.js, served up with GZip compression.

Why would you want to do this? Mostly for JavaScript and CSS files that are used heavily by your Domino applications, and are pretty large. You wouldn't want to do it for files that are still under development and/or change a lot (because you'd have to keep rezipping and reattaching the files), but for stable libraries it could work out pretty well.

It's also better to use a gzip compressed JavaScript library rather than a "packed" version of the library because (A) it'll end up smaller, and (B) it's a LOT easier to debug on the client side. If you're hyper-concerned about size, you could even compress a packed version -- I've read that using Packer with shrinkvars but NOT base62 (which requires client-side conversion) is the best combination of size and startup speed -- although you're again missing out on the client debugging side.

I can't really think of any other file type that this would work well for, except maybe a static XML file. Most HTML pages are far too dynamic. PDFs don't compress much these days, if you're using a decent program to create them. Image files barely compress at all, unless they're enormous bitmaps that you shouldn't be using in the first place.

And frankly, your corporate network might be fast enough and solid enough not to bother with such things as trimming 100K off a web page download. However, some networks might welcome such a thing -- satellite offices with high-latency, for example. If you're in that sort of situation though, you might be better off looking at Puakma WebBooster or a gzip proxy servlet or something. Those will add some kind of processor hit on the server (maybe minor, I'm not sure), but the clients will be snappier.

technorati tag: ,

Notes 8 Downloads (Friday, Aug 17)
[ permalink ] [ e-mail me ] [ ]

The "Part Numbers" you'll probably want for the Notes 8.0 downloads on the Passport site are:

There are other packages/platforms, but you can search for them yourselves. I'm not a phone book.

Funky String Splits (Monday, Aug 13)
[ permalink ] [ e-mail me ] [ ]

Someone please tell me if this is a bug, or if I'm just expecting the wrong behavior.

In LotusScript, when I do this I get an expected result:

answer = "&&&&"
splitAnswer = Split(answer, "&")

result is ["", "", "", "", ""]

And when I do this I get an expected result:

answer = "Boy&&Girl&&Dog"
splitAnswer = Split(answer, "&&")

result is ["Boy", "Girl", "Dog"]

But when I do this, the result is not what I want:

answer = "&&&&"
splitAnswer = Split(answer, "&&")

result is ["", "&&", "&", ""]

What I'm expecting there is a result array of ["", "", ""], but it looks like the Split code is getting confused when I have a delimiter of the same character twice, and the string that's being split consists only of that delimiter 2 or more times with no data in-between. This behavior is consistent if the delimiter is "&&" or "AA" or "==" or whatever.

It does seem to work properly if the 2-character delimiter is NOT the same character twice. For example:

answer = "&~&~"
splitAnswer = Split(answer, "&~")

result is ["", "", ""]

I'm testing on a 7.01 client. Do other versions do the same thing? Seems like a bug to me.

Lotusphere 2008 Abstracts (Sunday, Aug 12)
[ permalink ] [ e-mail me ] [ ]

Ben Langhinrichs just mentioned that the site for submitting Lotusphere 2008 abstracts was posted to the BP forum on Friday, and it's live. Here's the link:

The submission deadline is currently showing as September 7th, so there's already less than a month to get your abstracts in. I would guess that the page will redirect to some new information soon too. Maybe some official announcements about this sort of stuff.

SnTT: RandomHelper LotusScript Class (Thursday, Aug 9)
[ permalink ] [ e-mail me ] [ ]

UPDATE: I reposted the code on Aug. 12th with some updates. The code should now say version 1.1. If yours doesn't, please clear your browser cache and download again.

I've been working with some situations recently where I have to randomly distribute the contents of arrays (don't ask why). Over the years I've written various pieces of code in various places to deal with random things, so last night I decided to put them all together in a single class for easy reuse. Here's what I came up with:

Using this class, you can do things like this:

Dim randy As New RandomHelper Dim arr As Variant Dim msg As String Dim i As Integer '** pick a random number from 1 to 10 Print randy.GetRandomNumber(1, 10) '** pick a random number from 0 to 1,000,000 Print Format(randy.GetRandomNumber(0, 1000000), "#,#") '** get 5 random numbers from -100 to 100 (numbers may repeat) arr = randy.GetRandomNumberArray(-100, 100, 5) Print Join( Arrayappend(arr, ""), "; " ) '** mix up an array of numbers from 5 to 10 arr = randy.GetMixedNumberArray(5, 10) Print Join( Arrayappend(arr, ""), "; " ) '** get a set of 5 non-repeating lottery numbers between 1 and 64 msg = "" arr = randy.GetMixedNumberArray(1, 64) For i = 1 To 5 msg = msg & arr(i) & "; " Next Print msg '** generate a random 8 character password (repeating letters ok), '** using symbols from ASCII 33 to ASCII 90 msg = "" arr = randy.GetRandomNumberArray(33, 90, 8) Forall cnum In arr msg = msg & Chr(cnum) End Forall Print msg '** get a random letter from A to G arr = Split( "A,B,C,D,E,F,G", "," ) Print randy.GetRandomElement(arr) '** randomly mix up the letters from A to G arr = randy.RandomizeArray(arr) Print Join(arr, "; ") '** do a random walk, starting at 0, with 25 steps in increments of 1 arr = randy.GetRandomWalk(0, 1, 25) Print Join( Arrayappend(arr, ""), "; " ) '** GetRandomElement and RandomizeArray will '** also work with Lists (and instead of returning an '** Array, they return a List). HOWEVER, be aware '** that the tag-value pairs are NOT changed, only '** the order in which each pair appears in the List Dim testList List As String testList("A") = "Apple" testList("B") = "Banana" testList("C") = "Carrot" testList("D") = "Doughnut" Print "Random food is " & randy.GetRandomElement(testList) arr = randy.RandomizeArray(testList) '** arr is now a List msg = "" Forall stuff In arr msg = msg & stuff & "; " End Forall Print msg '** get a shuffled array of numbers from -20,000 to 32,000 Dim startTime As Single startTime = Timer arr = randy.GetMixedNumberArray(-20000, 32000) Print "First element: " & arr(Lbound(arr)) & _ "; time: " & Timer-startTime & " seconds" & _ "; count: " & (Clng(Ubound(arr)) - Clng(Lbound(arr)) + 1&)

You never know when that sort of thing could come in handy. I was able to replace the function-specific code I already had in my application with this class pretty easily.

technorati tag: ,

New Podcast, New Truck (Wednesday, Aug 8)
[ permalink ] [ e-mail me ] [ ]

Bruce and I finally recorded another podcast. Go take a listen.

In it, Bruce mentions I got a new truck. I did indeed. Here it is:

2001 Ford Explorer Sport Trac

It's actually a used truck (2001 Ford Explorer Sport Trac, 74,000 miles), but it's new to me. We sold my old car to my wife's cousin who's heading off to college, so I needed something else. Finally got myself a truck. 4-wheel drive and everything. Yeehaw.

Hot Hot Hot (Tuesday, Aug 7)
[ permalink ] [ e-mail me ] [ ]

We took the kids to Six Flags Over Georgia today, for a family fun day before school starts in a couple weeks. Man was it hot. Here's the weather for 7:25 PM, after we got home:

Weather in Atlanta at 7:25 PM

That's right, it was 95F/35C at 7:30 PM, with a heat index that makes it feel like 102F/39C. I haven't seen the high temp for today, but I wouldn't be surprised if it got to 100F around mid-afternoon (at who knows what kind of heat index).

But you know what? The kids had a blast, red cheeks and all. They were real troopers, and we kept them wet with the water rides and made them drink lots of water. And we all got Wendy's Frosties on the way home -- ice cream never tasted so good...

How Easy Should It Be? (Monday, Aug 6)
[ permalink ] [ e-mail me ] [ ]

Tons of fun going on in the comments of Rob McDonagh's recent entry on his Captain Oblivious blog: Exhibit A, McDonagh vs Eclipse Development. Grab some popcorn and pull up a seat.

Ed Is Down With Notes 8 (Monday, Aug 6)
[ permalink ] [ e-mail me ] [ ]

Here is Ed Brill trying on outfits for the upcoming Notes/Domino 8 World Tour:

Happy birthday Ed!

SnTT: Recompile LotusScript Using Notes API Calls (Thursday, Aug 2)
[ permalink ] [ e-mail me ] [ ]

Yesterday, John Head mentioned in the comments to one of Nathan Freeman's blog entries that he'd like a way to be able to recompile LotusScript -- using LotusScript. I knew I had written that code before, so I scrounged around and found this:

There's an example of calling the code in the Initialize block.

For another quick reference on a related subject, I wrote some notes on when recompiling LotusScript seems to be required some time ago. It's probably not a complete reference, but it's a start anyway.

technorati tag: ,