Thursday, May 29, 2008

Spoleto Festival 2008: the break/s

From the Spoleto website:
Forged by the charismatic poet/hip-hop theater sensation Marc Bamuthi Joseph and featuring live music by remarkable human beatbox/percussionist Tommy Shepherd and DJ Excess with video by David Slzasa, the break/s explores the ascendancy of hip-hop worldwide. This dynamic new work puts hip-hop culture into personal, historical and political perspective while erasing boundaries between movement, spoken word, personal storytelling, and poetic revelation.

I'm not sure what about that spoke to me, but when I read it in the program I knew it was something I had to experience. I'm of the generation that grew up as rap and hip-hop was being forged in a crucible of agitated inner city youth and gangster and drug cultures. I watched it turn from fringe street music into a massive business, with the requisite wannabe's and sell-outs. I was curious what led to it being kicked off at that specific point in time, what drove that genesis. That journey is what Mark Bamuthi Joseph explored.

"This story starts in the middle..."

The performance was divided into several stories, all of which started in the middle of somewhere. The locations were as diverse as Wisconsin, Senegal, and unconsciousness. Marc performed a mix of dance, spoken word, rap and storytelling against a backdrop created by three large screens playing various videos to emphasize key points.

Those points were at times funny, touching, biting, introspective and self-loathing. No subject was too taboo, no cows too sacred. It was enlightening for me, a middle-class white man, to get a glimpse inside the mind of someone with a very different racial and socioeconomic background. It was also refreshing to see someone who has street cred to admit his own failings of ego and racism, such as the time he walked into a Tokyo hip-hop night club and expected to be treated like royalty only to end up standing in the corner by himself, ignored.

"The more acceptance I get from others, the less I accept myself."

I walked away from this performance with a better understanding of how hip-hop came about, from its roots in Africa through the birth of jazz and eventual social acceptance. I also understand now how people who grew up in the struggle that birthed hip-hop can undergo an identity crisis when people who are not part of their socioeconomic class want to participate. Validation of their art isn't what they were originally after. They were telling the story of their oppression. Now we're seeing the people who do it for the artistry and that's causing some internal struggles.

It was an interesting performance that will be food for thought for a very long time.

Wednesday, May 28, 2008

a couple of notes about Domino clustering

I was talking (yes real talk, not IM -- the horror!) with a fellow Notes developer last night and the subject of my ILUG presentation came up. I gave him a thumbnail sketch of what I'm going to be presenting and he seemed surprised that it was possible, so I wanted to spell it out a little more clearly.
  • Domino clustering happens natively in Domino. There is nothing OS specific to it.

  • Therefore you can cluster Domino servers on different server operating systems together. That's right, Windows/Linux, Linux/AIX, AIX/i50S... Domino doesn't care.

  • You can see this demoed LIVE at ILUG next week. I'm on at 9:00 AM on Thursday.

Sunday, May 25, 2008

A response to Devin

Devin was humbled recently by his office environment. I don't think mine is so bad, either.

That was the sunset on May 19th (two photos stitched together). Here was tonight's.

You may notice there is much less water in today's picture. That's because I live on a tidal river, and the tide gets an hour later each night. High tide tonight will be near midnight.

Saturday, May 24, 2008

Spoleto Festival 2008: Monkey: Journey To The West

Tonight we attended our first Spoleto* event of the year, Monkey: Journey To The West. This is a modern adaptation of a 16th century Chinese tale of a monkey who wants to be immortal and greater than the gods. When I got my copy of the Spoleto program in the mail back in February I read through it the same night. A few things struck me as "must see", and Monkey was one of them for one simple reason: Damon Albarn did the composition. Most people would be familiar with Damon from his work with Blur in the 90's or Gorillaz more recently. As I read more about the piece and learned that all the graphics design and animation was done by Jamie Hewlett, who co-created Gorillaz and did their graphics, and Chen Shi-zheng was involved (he created a 19 hour Chinese opera that has only ever been performed at Spoleto), I knew I had to see it.

The performance started shortly after 7 and finished a little after 9, with no intermission. Between those points, time absolutely stood still. The music was a blend of Albarn's unique style and traditional Chinese influences and instrumentation. The vocals were all in Mandarin Chinese (with supertitles) and there were at least a dozen Chinese opera singers. The soprano in the part of Guan Yin was exquisite, and the mesosoprano in the starfish costume was also a standout.

In addition to the operatic vocals the live action was mixed with animation. The first few acts were separated by fully animated cut scenes. As the piece progressed the animation was gradually incorporated into the performance, until at one point the live actor portraying Monkey was interacting with the animation.

Speaking of live action, the performance was filled with gymnasts, acrobats, contortionists, martial artists, and traditional Chinese circus performers. At times there were so many people on stage doing various things it was hard to keep up. Oh, and did I mention that many of the vocalists were performing while suspended 20 feet over the stage? The aerial work was stunning, whether it was on wire or the scene with the contortionist/acrobat who was hanging from long silk panels.

So far the only US dates for the show are during Spoleto. If you can get to Charleston before it ends on Sunday, June 8th, you won't be disappointed.

About Spoleto Festival USA

For 17 days and nights each spring, Spoleto Festival USA fills Charleston, South Carolina’s historic theaters, churches and outdoor spaces with over 120 performances by renowned artists as well as emerging performers in disciplines ranging from opera, theater, music theater, dance, and chamber, symphonic, choral, and jazz music, as well as the visual arts.

This marks the 31st year of Spoleto Festival USA. I've been in Charleston for 11 years, and in that time have seen Taiwanese dancers, Balinese puppets, several operas (including two world premiers and a US premier), Abby Lincoln's final public performance, David Sedaris, African drummers, counter-tenors singing Sephardic hymns that haven't been performed outside Spain in over 100 years, and a whole lot of other stuff. The depth, breadth and quality of performances is astounding.

And if there isn't enough at Spoleto to interest you, there is also Piccolo Spoleto. Where Spoleto focuses on high art, avant garde performances, and big names, Picocolo Spoleto is all about approchable art, with many performances and exhibits targeted at children. And while tickets for Spoleto events go as high $180, Piccolo has many free events and ticket prices are much more moderate.

Thursday, May 15, 2008

SnTT: Disable the Print Screen Key (Win32 API)

We've all heard that you can't disable the Print Screen key in Windows, which means $KeepPrivate and setting the form properties to disable printing were of limited use. It turns out that Windows has had a way to do it since Windows 95, and it's still present in Windows XP and Vista: RegisterHotKey.

A Limitation That Works To Our Benefit

According to the MSDN documentation, "the RegisterHotKey function defines a system-wide hot key." Furthermore "the system posts the WM_HOTKEY message to the message queue of the window with which the hot key is associated." So what does that mean to you?

Whenever anything happens in Windows, messages are generated. Applications respond to these messages either by handling them or surfacing them as events for developers. That's how Notes uses Ctrl+A to select all the documents in a view, but when a user double-clicks on a document you have an event you can program. It's all about the messages, and who handles them.

In some other development environments you can create your own message handler, or hook. Notes doesn't allow you do that kind of low-level integration, and while that's frustrating for me in this case that works to our benefit! All you have to do is reset the Print Screen key so it gets directed to Notes. Notes isn't programmed to be aware of the message so it gets ignored. The end result is the Print Screen gets pressed and absolutely nothing happens.

The Code


Declare Function FindWindowByClass Lib "user32" Alias "FindWindowA" (Byval lpClassName As String, Byval lpWindowName As Long) As Long
Declare Function GetTickCount Lib "kernel32" () As Long
Declare Function RegisterHotKey Lib "user32" (Byval hWnd As Long, Byval id As Long, Byval fsModifiers As Long, Byval vk As Long) As Long
Declare Function UnregisterHotKey Lib "user32" (Byval hWnd As Long, Byval id As Long) As Long
Declare Function GlobalAddAtom Lib "kernel32" Alias "GlobalAddAtomA" (Byval lpString As String) As Long
Declare Function GlobalDeleteAtom Lib "kernel32" (Byval nAtom As Long) As Long
Declare Function GetActiveWindow Lib "user32" Alias "GetActiveWindow" () As Long


Const MOD_ALT = &H1
Const MOD_SHIFT = &H4

Dim g_hWnd As Long
Dim g_Print As Long
Dim g_AltPrint As Long
Dim g_CtrlPrint As Long
Dim g_ShiftPrint As Long

Sub Queryopen(Source As Notesuidocument, Mode As Integer, Isnewdoc As Variant, Continue As Variant)

'Get a handle to the Notes client window so you can tell Windows which window to hook the hotkeys to
g_hWnd = FindWindowByClass("Notes", 0)

'Register new identifiers for our custom hotkeys. GetTickCount returns a number that's based on the system clock,
' so you know it won't be duplicated.
g_Print = GlobalAddAtom(Cstr(GetTickCount))
g_AltPrint = GlobalAddAtom(Cstr(g_Print) + Cstr(GetTickCount))
g_CtrlPrint = GlobalAddAtom(Cstr(g_AltPrint) + Cstr(GetTickCount))
g_ShiftPrint = GlobalAddAtom(Cstr(g_CtrlPrint) + Cstr(GetTickCount))

'Now register the hotkeys
Call RegisterHotKey(g_hWnd, g_Print, 0&, VK_SNAPSHOT) 'PrintScreen
Call RegisterHotKey(g_hWnd, g_AltPrint, MOD_ALT, VK_SNAPSHOT) 'Alt+PrintScreen
Call RegisterHotKey(g_hWnd, g_CtrlPrint, MOD_CONTROL, VK_SNAPSHOT) 'Ctrl+PrintScreen
Call RegisterHotKey(g_hWnd, g_ShiftPrint, MOD_SHIFT, VK_SNAPSHOT) 'Shift+PrintScreen
End Sub

Sub Queryclose(Source As Notesuidocument, Continue As Variant)

'Unregister the hotkeys
Call UnregisterHotKey(g_hWnd, g_Print)
Call UnregisterHotKey(g_hWnd, g_AltPrint)
Call UnregisterHotKey(g_hWnd, g_CtrlPrint)
Call UnregisterHotKey(g_hWnd, g_ShiftPrint)

'Delete our custom entries
Call GlobalDeleteAtom(g_Print)
Call GlobalDeleteAtom(g_AltPrint)
Call GlobalDeleteAtom(g_CtrlPrint)
Call GlobalDeleteAtom(g_ShiftPrint)
End Sub
This LotusScript was converted to HTML using the ls2html routine,
provided by Julian Robichaux at

The Downside

Come on... you knew it couldn't be all good. :-) While this code in active Print Screen is disabled SYSTEM WIDE. Here I have it enabled in a form's QueryOpen, but you could do some tests, say for $KeepPrivate or check user roles, to enable it selectively. (Yes, I know end users can remove $KeepPrivate.) If I put this into production I would be nice and actually tell them that Print Screen is disabled, though. I'll leave that as an exercise for the reader.

Sources: Digital Inspiration blog
Answers.Com RegisterHotKey sample
vbAccelerator clsRegHotKey

[Update 5/16/08 - Removed two unused constants]

Monday, May 12, 2008

SnTT: Field-level LastModified during document save

My friend Cal was having some problems trying to figure out whether certain fields on a document were modified during a document save. Of course you could use the old trick of ripping through NotesDocument.Items in PostOpen, store the values, then compare the values on save with what the original values were. But Cal didn't need to know what changed, he just needed to know whether it changed. And so we went on a wild goose chase together.

The NotesItem class includes a LastModified property. But guess what: while the front end document is open it reports the same date as NotesDocument.LastModified, even if the field hasn't actually been changed. Notes holds the UI document open all the way through to PostSave, so there are no form events where the UI document is empty, which actually makes sense.

The solution is to make Notes think the document isn't open. Enter Delete. I've written about Delete a couple of times before; it removes an object from the Notes cache immediately. Combining this knowledge with some other techniques, we end up with the following

Sub Postsave(Source As Notesuidocument)
'Ignore new documents
If Source.IsNewDoc Then Exit Sub

Dim db As NotesDatabase
Dim session As New NotesSession
Dim doc As NotesDocument
Dim maildoc As NotesDocument
Dim tmpID As String

Set db = session.CurrentDatabase
tmpID = source.document.UniversalID

'Force the front end document to close

'Delete it from the cache
Delete source

'Reopen the backend document
Set doc = db.GetDocumentByUNID(tmpID)

' Checks for field(s) that have been modified and sends a notification.

Forall item In doc.Items
If (item.LastModified >= doc.LastModified) Then
Set maildoc = New NotesDocument( db )
maildoc.Form = "Memo"

' Person to be notified.
maildoc.SendTo = "<name>"
maildoc.Subject = "<subject>"
Set rtitem = New NotesRichTextItem( maildoc, "Body" )
Call rtitem.AppendText( "The iteration for """ + doc.Title(0) + """ was changed by " + session.UserName + "." )
Call rtitem.AddNewLine( 2 )
Call rtitem.AppendText( "Link to Document -> " )
Call rtitem.AppendDocLink( doc, db.Title )
Call maildoc.Send( False )
End If
End Forall
End Sub

This LotusScript was converted to HTML using the ls2html routine,
provided by Julian Robichaux at

Monday, May 05, 2008

Dining With Friends 2008 wrapup

This was our 10th year hosting a Dining With Friends party and it was a very successful event. We completed 13 of the 15 planned dishes, only ran out of one of them during the party, and all the leftovers fit into one refrigerator. We had over 115 people attend, making this our biggest year ever, and donations so far are just over $4,000. The menu consisted of (the links are to the recipes, in Word 2003 format):

[UPDATE 5/9/08: I had the wrong shrimp recipe posted. The one posted now is the one we served.]

The learning curve was almost vertical as we took on this challenge. We both enjoy eating Indian food, but neither of us had ever made it. First there were the ingredients, which are called different things. For example, depending on who wrote the recipe they could refer to lentils, gram beans, or dal. Dal simply means "bean", so that sometimes adds to the confusion. Ghee, a type of clarified butter, was alternately called butter or clarified butter, or usli ghee, asli ghee, or desi ghee. Remove the ghee part from those for even more variations. They're all the same thing, though. Chili powder might mean the mixture we know if the recipe has been Westernized, or Kashmiri chili powder, which contains bhut jolokia peppers. The two can not be interchanged, by the way. Kashmiri chili powder is a biological weapon.

Some of the techniques we had to master are unique to Indian cooking. Brown-frying onions is a laborious process and it can't be done in large batches. Making ghee isn't difficult, but the timing is precise. 30 seconds too long at too high of a temperature and you've got burnt butter. Grating garlic, onions and ginger is a challenge when you're doing it in terms of 60 garlic cloves, 20 onions and the equivalent of 2 feet of ginger at a time. Folding ground spices into yogurt and letting them hydrate is another thing that's surprisingly easy to mess up if you don't mix it thoroughly or you mix too vigorously.

We learned a lot about multiplying recipes, too. If a single iteration calls for 4 cups of water, multiplying it by 8 doesn't necessarily mean you need 2 gallons. And just because strict multiplication says you should use 7.667 tablespoons of Kashmiri chili powder doesn't mean it's wise (that was some crazy hot Tandoori chicken). By the way, is a godsend. The thing I love is you can put in a multiplier and it does it for you. Thinking gets difficult when you're in this kind of situation.

Time, as always, was the enemy. In particular the Pistachio Chicken Korma took much, much longer to prepare than I anticipated. Shelled pistachios were $7.00 for 4 ounces, and I needed 24 ounces. That would have been $42.00 for pistachios and I thought that was ridiculous. So I bought 3 pounds of pistachios and shelled them to get the 1.5 pounds of pistachio meat I needed. That took about 2.5 hours. Then I had to boil them, let them cool, and peel the skins off. Peeling was another 2 hours. That put me so far behind that we didn't get the last two dishes finished and we were about 15 minutes late getting the food on the table. Next time I'll buy the shelled pistachios, and I have incredible respect for anyone who does pistachio anything by hand.

As you've probably guessed by now, Myron and I did all the cooking. We had a friend, Anne, who volunteered to help on Saturday. She came over at about 11:30 and while I peeled pistachios she peeled shrimp, and while Myron and I were getting the house pulled together she was cooking that as well as the semolina. I bought 25 pounds of basmati rice and intended to prepare it, but I ran out of time. She asked if we needed to cook it; I told her I wasn't going to bother, so she took it upon herself to do so and it was a hit. Without her we would have been in even worse shape and I can't thank her enough.

The party started at 6:00 and at 5:10 Myron and I stopped cooking and ran around to get the back porch and dining room put together. At 5:45 I started putting the food out. At 6:15 I got in the shower, and by 6:25 everything was under control and we had a great time. :-) Clean up took most of Sunday, mostly because we were both so exhausted. It's amazing what cooking full-tilt for 3 days, 18 - 20 hours a day, can do to you. My feet and legs still hurt, but we'll be doing it again next year. :-)

The obligatory cleanup photo...

One of the recipes is still taped to the cabinet. I type them up in Word, then print them out and put them in page protectors. These get taped on the cabinets so we can easily reference them without having them laying on the counters. As you can see, counterspace is at a premium.

After all that cooking the stove was an absolute mess.

There were times when all 6 burners were going, plus the oven.

Lots of wine was consumed. I bought 20 bottles and 7 were unopened. The punch bowl on the table with the red tablecloth was where we had the Cuban Sangria. That is a delicious mix of red wine and coconut rum, with fresh fruit.

And lots of beer. 104 were purchased, 12 are left. The Post-It notes were to tell people which variety was in each cooler.

This was the sunset on Sunday, after we finished cleaning up and were sitting down to leftovers.

Speaking of leftovers...

A lot of that is going to end up in the freezer.