[nsftools logo]
August 2007 Blog
home :: blog :: tools :: tips :: about :: search

blog links
Current Blog
. . .
Blog RSS Feed

I'm @jrobichaux on
Follow @jrobichaux on Twitter
. . .
Bruce and Julian's podcast
TakingNotes Podcast Logo

Archive Index
. . .
January 2015
November 2014
October 2014
September 2014
November 2013
August 2013
June 2013
May 2013
March 2013
January 2013
December 2012
September 2012
May 2012
April 2012
January 2012
October 2011
September 2011
August 2011
June 2011
May 2011
April 2011
March 2011
February 2011
January 2011
December 2010
November 2010
October 2010
September 2010
August 2010
June 2010
May 2010
April 2010
March 2010
February 2010
January 2010
December 2009
November 2009
October 2009
September 2009
August 2009
July 2009
June 2009
May 2009
April 2009
February 2009
January 2009
December 2008
November 2008
October 2008
September 2008
August 2008
July 2008
June 2008
May 2008
April 2008
March 2008
February 2008
January 2008
December 2007
November 2007
October 2007
September 2007
August 2007
July 2007
June 2007
May 2007
March 2007
February 2007
January 2007
December 2006
November 2006
October 2006
September 2006
August 2006
July 2006
June 2006
May 2006
April 2006
March 2006
February 2006
January 2006
December 2005
November 2005
October 2005
September 2005
August 2005
July 2005
June 2005
May 2005
April 2005
March 2005
February 2005
Lotusphere 2005
January 2005
December 2004
November 2004
October 2004
September 2004
August 2004
July 2004
June 2004
May 2004
April 2004
March 2004
February 2004
Lotusphere 2004
January 2004
December 2003
November 2003
October 2003
September 2003
August 2003
July 2003
June 2003
May 2003
April 2003
March 2003
February 2003
January 2003
December 2002
November 2002
October 2002
September 2002
August 2002

main site links (blog, tools, etc.) are available at the top of the screen

site disclaimer

The August 2007 Blog
send me a comment

goto

an xkcd webcomic.

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 cssjuice.com 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();
	datahash.merge(dataset);
	var setKeys = datahash.keys();
	var result = new Hash();
	var increment = 75;    /* modify to your liking */
	
	setKeys.each(function(index){
		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.

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...

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: ,

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

  • IBM Lotus Domino Server 8.0 for Windows 2003 English: C13NGEN (500 MB)
  • IBM Lotus Notes, Designer, and Administrator 8 Clients: C13NFEN (450 MB)

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

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.

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:

https://www-926.ibm.com/events/lotus/lsph2008.nsf/cfpstart

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 www.lotusphere.com page will redirect to some new information soon too. Maybe some official announcements about this sort of stuff.

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: ,

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.

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 95°F/35°C at 7:30 PM, with a heat index that makes it feel like 102°F/39°C. I haven't seen the high temp for today, but I wouldn't be surprised if it got to 100°F 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...

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.

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

Happy birthday Ed!

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: ,


For questions concerning this site, please contact the webmaster