« June 2005 | Main | August 2005 »

July 31, 2005

Transmission

My sister bought me a copy of Transmission by Hari Kunzru, which I read and enjoyed on our recent cruise. It's about...mmmm...well, it's about an Indian programmer, and a Bollywood star, and an English entrepreneur, and a computer virus, and the partial intersection of those.

In ways it calls to mind Kurt Anderson's Turn of the Century, which I also enjoyed. Turn of the Century is much more ambitious, but Transmission is somewhat better written (and much shorter). Both feature some "hacking" as one of their several plots, and both have scenes that take place in the leafy confines of Redmond, Washington. Books like these always surprise me with how much Microsoft in general and Bill Gates in particular have infiltrated the mainstream literary consciousness.

The two books came out almost exactly five years apart and I think reflect the change in the public attitude in that time towards computer malware. Situations that Andersen can basically play for a laugh -- a little casual 0wNing here, some root access there -- in Kunzru's era can only lead to dark and evil things.

Posted by AdamBa at 08:24 PM | Comments (0) | TrackBack

July 30, 2005

Monad in Public Beta

You can now get Monad without going through betaplace. Just download the WinFX SDK Beta 1. Or to use its full name, the "Microsoft® WinFX ™ Software Development Kit for Microsoft® Pre-Release Windows Operating System Code-Named 'Longhorn', Beta 1 Web Setup".

These are the same Monad bits we made available on betaplace last month. What is new is that you don't have to agree to an NDA to get it. So this is the first completely public beta of Monad (it's also a full WinFX SDK so you get the Avalon, Indigo, etc. SDK bits also). Download it, use it, tell your friends.

Posted by AdamBa at 08:54 AM | Comments (3) | TrackBack

July 28, 2005

Art of Science

Back at the AM they had a nifty Art of Science competition. Princeton, under the leadership of Shirley Tilghman (President) and Maria Klawe (Dean of Engineering) is working hard to integrate engineering into the mainstream of campus. This competition was part of that. There's some really cool images in the gallery, like this one of "Snow" or this one of "Hell".

(I learned of this because I was given a set of postcards by our friendly neighborhood Princeton Development person who was out in the area today. The Development office is in charge of fundraising and they like to keep in touch with alumni who might feel like tossing a few shares of stock their way. And if you are wondering where Princeton gets its money from, look at some of the pictures in this photo log by David Dobkin, former "Death Graphics" professor and CS department chair, now Dean of the Faculty. You've got Microsoft VPs, Amazon VPs (and above), some Google and Network Appliance people in there...and that's just one month.)

Posted by AdamBa at 10:51 PM | Comments (0) | TrackBack

James Doohan, R.I.P.

One thing I missed when I was on the cruise last week was the death of James Doohan, who played Scotty on "Star Trek". I'm not a huge trekkie, but Doohan lived in Redmond and came to a group meeting back in 1996, which is how I will remember him.

Posted by AdamBa at 10:46 PM | Comments (1) | TrackBack

Ten [Adjective] Ideas

Josh Ledgard picked up on Mini's exhortation "I would love if this 'ideas' caught on as a blogs.msdn.com meme and everyone took a chance to reflect on Microsoft changes they think would best suit the company, its employees, and shareholders" and posted his Ten Insane Ideas for Microsoft. Good stuff! Anybody else out there want to take the ball and run with it? Go, meme. Go! Hmmmm...

Meme.

Big meme.
Little meme.

Big memes and little memes.

Black and white memes.

"Hello!"
"Hello!"
"Do you like my crazy idea about Microsoft?"
"I do not."
"Good-by!"
"Good-by!"

OK, no more posting after 10:30 at night.

Posted by AdamBa at 10:34 PM | Comments (0) | TrackBack

Intern Fair

Today I manned a Monad demo booth at the Microsoft intern fair. It was from 3:30 to 7, which a break from 4:30 to 5:30 for a Steve Ballmer speech. Monad was very popular, I spent the whole time talking and typing with 3-5 people listening. Very encouraging to see people so excited about your product. The only problem was it was a pretty warm day, and the event was in a tent, so it got a bit toasty in there. Steven Sinofsky has a discussion of the event, including a link to some photos.

In the middle they kicked everyone out of the fair to go see SteveB talk. No matter what you say about Steve (and generally I say nice things about Steve), the guy is a great salesman. He could sell specs to the Indigo team. Listening to him talk about the future of the company you get incredibly pumped up about all the opportunities. When he says this is the greatest time to work at Microsoft, he either truly believes it, or I never want to play poker with him.

While I was standing listening to his talk someone saw my nametag, introduced themselves and said they had ready my first book and enjoyed it. That also warmed the cockles of my heart.

Posted by AdamBa at 12:57 AM | Comments (2) | TrackBack

Alaska Cruise

Last Week we cruised on the Norwegian Star to Alaska. We did the typical Alaska Cruise n00b things: Mount Roberts Tramway in Juneau, White Pass & Yukon Route up and Sockeye Cycle down in Skagway, and the Great Alaskan Lumberjack Show in Ketchikan. We also had a day sightseeing in Glacier Bay. I did not make it to the Yukon, but I did see a Yukon license plate (in Skagway) and a road sign for the Yukon town of Carcross (on the Klondike Highway in Fraser, B.C.).

It was a good cruise and the weather was very good, partly cloudy at the beginning and then sunny at the end. Beyond the shore excursions we walked around the cities a bit, but mostly they sell the same tacky Alaska souvenirs or the same crap that you see in stores at Caribbean cruise ports: tanzanite, alexandrite, Ebel watches, etc. that probably only have value to people who have been trapped for days on a cruise ship with no external stimuli.

From a technology point of view, the Star has an Internet Cafe, as well as Wi-Fi in various common areas (for a fee). I used none of that and was off the grid for a week. They also have a bridge cam on the website linked to above. Currently it's night but if you view it on Thursday between around 10 am and 1 pm you might see some good glacier views.

Besides this cruise we've done the Disney Magic and the Explorer of the Seas in the Eastern Caribbean. All 3 ships have advantages and disadvantages: the Star has freestyle dining and sails from Seattle, and the kids programs are pretty good, but the buffet food is lousy, the entertainment isn't so good, and they don't have a good cabin for a family of six. The Disney Magic has lame kids' programs and scheduled dining, but had a great cabin for us, they do feed the kids meals in the program, and the shows were good. Royal Caribbean has the best kids programs, the buffet is good, and the cabin is good, but the kids food isn't that varied and it also has scheduled dining. And neither Disney nor Royal Caribbean sail out of Seattle (any more). So we still haven't found the perfect cruise line.

Posted by AdamBa at 12:35 AM | Comments (1) | TrackBack

July 26, 2005

Origin of the Phrase "Proudly Serving My Corporate Masters"

So today Mini-Microsoft had a post that linked here 3 times, and one of them was to this article about the phrase "Proudly Serving My Corporate Masters". Not the origin of the phrase per se, but when it entered my consciousness. This was an old article from late 2000 on the "pre-blog" website, and I realized there was <gasp> no place for people who wanted to discuss this topic of note. So I am posting this blog entry just for that purpose. Further proof that I'm a hopeless link addict.

P.S. As a bonus Microsoft historical investigation, here's one about the phrase FYIFV.

Posted by AdamBa at 01:39 PM | Comments (0) | TrackBack

switch -file, and Regex Hooha

Here's another cool thing in Monad. You know in Perl you have the <> syntax for ripping through files: you get code sequences like:

open FH,"filename";
while (<FH>)
    if (some-regular-expression) {
        # code to handle lines that match
    }
    elsif (another-regular-expression) {
        # code to handle lines that match
    }
    # etc.
}
close FH;

Well, Monad has a -file option on the switch statement which can do similar things, especially when combined with the -regex option on switch (which tells it to do regex instead of exact matching):

switch -file "filename" -regex {
    "some-regular-expression" {
        # code to handle lines that match
    }
    "another-regular-expression" {
        # code to handle lines that match
    }
    # etc.
}

If you want to run through a bunch of files, then you can enclose the switch in a foreach. Also, in a switch statement $_ is the matched object. So putting this all together you get a basic grep (looking for the word "FileInfo" in all *.mshxml files) that looks like:

foreach ($f in resolve-path *.mshxml) { switch -file $f -regex { "FileInfo" { ($f.Path + ": " + $_ ) } } }

Finally, .Net has capture groups, like Perl, as discussed here; the groups wind up in the Monad variable $matches, so $matches[0] is the text matched by the whole regex, automatically numbered captures wind up in $matches[1], $matches[2], etc., and named captures (specified via (?<name>regex) in .Net) wind up in $matches["name"] ($matches is a hashtable, so $matches.name also works). Viz:

switch -file c:\boot.ini -regex { "(?<arcname>.*)=`"(?<displayname>.*)`"" { ("NAME " + $matches.displayname); ("ARC " + $matches.arcname) } }

The regular expression is:

"(?<arcname>.*)=`"(?<displayname>.*)`"

(Trust me, wade through it and you'll learn something.) That is put everything up to the first equal sign in a capture called arcname, then put everything between the double quotes in a capture called displayname (recall that the backtick ` is the Monad escape character, it escapes the double quotes here).

UPDATE: Lee Holmes had a blog entry about Monad regular expressions. In fact, it was an internal email about his entry, pointing out the switch -file syntax, that inspired this one.

Posted by AdamBa at 11:30 AM | Comments (0) | TrackBack

Square-Wheeled Bicycle

My father was telling me about a former math student at McGill name Stan Wagon who built a square-wheeled bicycle and a road to ride it on. Sure enough, he has a website with a photo. There's more info on the web; this article goes into more detail. Here's a quote: "Just as a square rides smoothly across a roadbed of linked inverted catenaries, other regular polygons, including pentagons and hexagons, also ride smoothly over curves made up of appropriately selected pieces of inverted catenaries. As the number of a polygon's sides increases, these catenary segments get shorter and flatter. Ultimately, for an infinite number of sides (in effect, a circle), the curve becomes a straight, horizontal line."

Posted by AdamBa at 11:25 AM | Comments (5) | TrackBack

July 24, 2005

"Find the Bug" in Polish

I have been out the last week on a cruise, about which more later, but check out what was waiting for me when I got back: a copy of Find the Bug that had been translated into Polish. This is quite cool! The cover is pretty good also. It has a code excerpt (not from the book) with a little buggy critter chewing up pieces of it.

Posted by AdamBa at 12:28 PM | Comments (0) | TrackBack

July 16, 2005

Monorail Fur is Flying

Three years ago the residents of Seattle vote to tax themselves to pay for a 14-mile monorail line. Actually this was the fourth (I think) vote on the subject. It initially started as basically a joke proposal that was so ridiculous that nobody bothered to mount a formal opposition, and much to everyone's surprise it passed. Then various plans were voted on, and finally it was approved by fewer than 1000 votes, and things got underway. Except the financing plan fell through and the executive director just quit; the Seattle Weekly summarizes the whole sordid mess.

Leaving aside the folly of a city trying to build public transit with no state or federal help, monorails are actually cheaper to build than other public transit systems because there is little or no right-of-way to acquire. But they have a problem in that they uglify the airspace. The most amusing of the current foofaraws is between competing visions of the monorail. Cascadia Monorail, the company that is contracted to build the thing, put out a press release for its renderings; meanwhile the Downtown Seattle Association has competing renderings. The Cascadia images are supposed to show how light and fluffy the monorail will be and the Downtown Seattle ones are supposed to show how dark and oppressive it will be, but trying to tell the difference between the 2nd avenue visions of Cascadia (light/fluffy) and DSA (dark/oppressive) is like doing one of those "Hocus Focus" spot-the-six-differences puzzles in the paper (hint: it's the guardrail for the pedestrian walkway). Meanwhile, an organization called Team Monorail has decided--possibly for amusement value, but more likely in a serious attempt to wrest the contract away from Cascadia--to come out with their own vision for the monorail, which would presumably be even lighter, fluffier, and cheaper than Cascadia's.

Stay tuned to see how this all turns out, or you can rent the Simpsons episode if you can't wait.

Posted by AdamBa at 08:37 PM | Comments (1) | TrackBack

Baseball News

I went to the Mariners game last night. A couple of momentous things.

First, for those of you who follow baseball, Baltimore Orioles first baseman Rafael Palmeiro entered the game with 2999 hits. A little action on the slide rule reveals that put him just one hit away from 3000. Palmeiro, who reveal a few years ago that he "corks" his "bat", also has over 500 home runs, so he is no doubt destined for Cooperstown (despite certain nincompoops who say he shouldn't be).

Palmeiro batted in the first inning as flashbulbs popped all over the stadium on every pitch (must make it tough to see the ball). Joel Pineiro, the Mariners pitcher, had just given up a home run and a double so he was a bit rattled, and walked Palmeiro. But in the third inning he came to the plate...and grounded out to the first baseman. But in the fifth inning...Palmeiro strode to the plate, mighty shillelagh in hand, and verily did he smote the ball into the left-field corner for a double and #3000. The Safeco crowd gave him a nice long ovation as the dugout and bullpen emptied out for congratulations. Then in the seventh inning he got a single, on his way to 4000 (Pete Rose got his 4000th hit while playing for the Expos, a game my father saw, and claims I also saw although I'm not sure I did).

The other event of note at the game was that the Mariners and Verizon and Verrus introduced something called "OrderUp" where you can order food on your phone. Each food item has a two-digit code (nachos == 14, super pretzel == 46, 187 ml of Merlot == 72, etc) and you text a message with your codes to a certain number. Then they text back asking for your seat number, then they text back asking for your credit card/expiration, then they text back a final confirmation. Then some short time later (they claim 5-7 minutes, but our order took 20) they deliver your food. Tax and tip are all included so you can enjoy your $4.75 chocolate malt in peace.

Posted by AdamBa at 07:31 AM | Comments (5) | TrackBack

July 14, 2005

The Hello World Collection

This is a website featuring the "Hello World" program in over 200 programming languages ("Hello World" became famous as the first example in The C Programming Language (that version is here).

Someone pointed out that Monad (or MSH as we tend to refer to the language) was not on there, so I submitted it. There was a bit of debate over what program to submit and finally we decided on the most basic one:

"Hello World!"

which works because in Monad objects that reach the end of the pipeline are output (the program above is really an object -- the System.String initialized to "Hello World!" -- sent down the pipeline, except there is nothing after it on the pipeline, so it is sent to the default outputter, which displays it to the console).

Posted by AdamBa at 10:08 PM | Comments (0) | TrackBack

July 13, 2005

Monad and RSS, Part 5

First, I'll 'fess up that in a previous post I referred to the &$scriptblock notation as "eval"ing a script block, but that's wrong. Our language dev said it should just be "calling" the scriptblock. "Eval", in scripting languages, means taking a string (not a script block) and running it back through the parser (hope I got that right, Bruce!).

Anyway, in the possibly last installment of this series, I'll improve the display of the individual entries. In part 3 I talked about the file "rss.format.mshxml" that we could create. Now expand the file to contain the following:

<View>
    <Name>RSS20.Feed</Name>
    <ViewSelectedBy>
        <TypeName>System.Xml.XmlElement</TypeName>
    </ViewSelectedBy>
    <ListControl>
        <ListEntries>
            <ListEntry>
                <ListItems>
                    <ListItem>
                        <PropertyName>pubDate</PropertyName>
                        <Label>Date</Label>
                    </ListItem>
                    <ListItem>
                        <PropertyName>Title</PropertyName>
                    </ListItem>
                    <ListItem>
                        <ScriptBlock>if ($_.Description -is [System.Xml.XmlElement]) { $_.Description.get_InnerXml().SubString(0,100) } else { $_.Description.SubString(0,100) }</ScriptBlock>
                        <Label>Text</Label>
                    </ListItem>
                </ListItems>
            </ListEntry>
        </ListEntries>
    </ListControl>
</View>
<View>
    <Name>RDF.Feed</Name>
    <ViewSelectedBy>
        <TypeName>System.Xml.XmlElement</TypeName>
    </ViewSelectedBy>
    <ListControl>
        <ListEntries>
            <ListEntry>
                <ListItems>
                    <ListItem>
                        <PropertyName>dc:date</PropertyName>
                        <Label>Date</Label>
                    </ListItem>
                    <ListItem>
                        <PropertyName>Title</PropertyName>
                    </ListItem>
                    <ListItem>
                        <ScriptBlock>$_.Description.SubString(0,100)</ScriptBlock>
                        <Label>Text</Label>
                    </ListItem>
                </ListItems>
            </ListEntry>
        </ListEntries>
    </ListControl>
</View>
<View>
    <Name>Atom.Feed</Name>
    <ViewSelectedBy>
        <TypeName>System.Xml.XmlElement</TypeName>
    </ViewSelectedBy>
    <ListControl>
        <ListEntries>
            <ListEntry>
                <ListItems>
                    <ListItem>
                        <PropertyName>created</PropertyName>
                        <Label>Date</Label>
                    </ListItem>
                    <ListItem>
                        <PropertyName>Title</PropertyName>
                    </ListItem>
                    <ListItem>
                        <ScriptBlock>$_.content."#text".SubString(0,100)</ScriptBlock>
                        <Label>Text</Label>
                    </ListItem>
                </ListItems>
            </ListEntry>
        </ListEntries>
    </ListControl>
</View>

Some explanations:

  • The names of the feeds intentionally match the "feed names" (RSS20, RDF, etc) from our hash table in part 4.
  • For a list view, the property name is automatically used as the label unless you override it using the <Label> tag.
  • The script block for an RSS20 excerpt is there because I discovered some feeds send the Description as a string, others as a #cdata section. Other feeds may do this also and may need a similar script block.
  • The choice to display the first 100 characters (via the Substring() call) is completely arbitrary on my part.

Now, once you have this in place, you can just change the list in get-feeds.msh from:

$_

to

$_ | format-list -view ($feedname + ".Feed")

and each feed will show its Date/Title/Text properly.

There has actually been some discussion that the type for a System.Xml.XmlElement would be enhanced to include the namespace, so you could do this without having to specify the -View parameter to format-list, but that's still being worked out.

Posted by AdamBa at 04:08 PM | Comments (0) | TrackBack

July 11, 2005

Water

Yesterday I ran the Seafair Half Marathon in Bellevue. What you see more of at races these days is people with water backpacks or belts. It is good to stay hydrated during races, but now there is some concern that people are doing too good a job. The term hyponatremia has entered the runner's lexicon. It refers to having a low sodium level in your blood plasma, due to dilution from drinking too much water. Extreme hyponatremia can be fatal.

According to this Wikipedia article, the average person can rid themselves of about 1.5 liters of water. So if you head out on a 2-hour run with a 3-liter Camelbak, you may be courting disaster.

My father has always been a skeptic of the "drink eight glasses of water a day" meme, and in particular the notion that by the time you feel thirsty, you are already dehydrated (because it makes no sense for humans to evolve like that). On my last visit to my doctor I asked him about drinking water, and his comment was "the dumbest kidney is smarter than the smartest nephrologist." He said that your body will adjust to whatever amount of water you drink, within reason, and there's no reason to drink any more than what you would normally consume at meals. So I started doing that, and I have not noticed any difference in my energy level or weight. The only noticeable change is fewer trips to the bathroom.

During a long race of course it's important to drink water because you sweat so much, but it's not usually a problem because they hand out water every mile or two; at the Seafair Half-Marathon they were also handing out some high-tech drink called Amino Vital. So I just plan to drink that and don't bring any water of my own; the only hassle is having to wait in line to get water, and trying to drink it from a paper cup while running.

During training runs you don't have that support, of course, but so far I've always just cowboyed it up with no water. What might be more useful than water, and actually inspired me to run with a fanny pack of some sort, is those energy goo things. At the race I didn't plan to do this because at mile 7 they were handing out Clif Shot packets.

My goal for the race was to break 2 hours, which I had never done before. If you run 9-minute miles you'll finish a half marathon in one hour and 58 minutes, so you basically have 2 minutes, spread over 13 miles, that you can cumulatively fall behind the 9-minute-mile pace. Ideally, for a race like this you will finish running no slower than at the start.

I was a bit late getting to the start line of the race due to a long line for the port-a-potties, so I had to weave through a lot of people and hit the first mile in 9:15. At mile 3 it was 27:25, which means I had chewed up 25 seconds of my 2 minutes...thus roughly on target to hit exactly 2 hours. Luckily at that point I was passed by two women named Cheryl and Kim, who woke me up and proceeded to pace my sorry keister for the next 3 miles. By then I was warmed up. I got my Clif Shot at mile 7, along with two glasses of water (since I had been told I needed to drink fluids along with the Clif Shot to make it work best). After juggling all that into my body I hit mile 10 in 89:30, which was good. In a previous race I had hit 10 miles in 90 minutes even but then proceeded to bite it for the last 3 miles. So I concentrated on running the eleventh mile at the same pace. Right at mile 11 I passed the person who was designated to run a 2 hour pace (she had a sign on her back) and from then on it was gravy. I finished in 1:56:09, an 8:52 pace and 5 minutes faster than my previous best. And it was the first half marathon I finished where the notion of running another one right away didn't seem absurd. Thus, I can start thinking about running a full marathon.

Posted by AdamBa at 10:05 PM | Comments (1) | TrackBack

Now He Is Six

Our third child just turned six today. This poem by A.A. Milne always seems appropriate:

When I was one I'd just begun,
When I was two I was nearly new,
When I was three I was hardly me,
When I was four I was not much more,
When I was five I was barely alive,
But now I am six! As clever as clever!
And I think I'll stay six now for ever and ever!

Posted by AdamBa at 07:52 PM | Comments (0) | TrackBack

Lego Sandcrawler!!!!!!

My dreams have been answered...Lego has a Star Wars Sandcrawler.

Posted by AdamBa at 05:38 PM | Comments (2) | TrackBack

July 09, 2005

Monad and RSS, Part 4: Script Blocks

Monad has the notion of script blocks, which as you may guess are blocks of script. For example, I can write:

$sb = { write-host "FOO" }

And now $sb is a script block object. You can evaluate it by preceding it with an ampersand:

MSH> &$sb
FOO

or by calling the Invoke() method:

MSH> $sb.Invoke()
FOO

In this case there is no difference between "eval"ing (as using the ampersand is known) and invoking a script block, but if you want to pass or pipeline data into a script block then it does matter. For today, we'll use Invoke() to execute our script blocks, and what you need to know is that any parameters passed to Invoke() will be bound to a variable call $args before the script block is executed.

We'll use script blocks to solve the problem that Scott Allen was trying to solve; dealing with the plethora of syndication formats out there (to paraphrase Harpo Marx, or somebody, the nice thing about standards is there are so many to choose from).

So raise your eyes, stranger, to that age-worn rampart which confronts all else: there stands the following bit of code:

$feedtable = @{
    "RSS20" =
        @{ "id" = { $args[0].rss.version -eq "2.0" }
           "title" = { $args[0].rss.channel.title }
           "items" = { $args[0].rss.channel.item }
           "itemtag" = { $args[0].pubDate } }
    "RDF" =
        @{ "id" = { $args[0]."rdf:RDF" -ne $null }
           "title" = { $args[0]."rdf:RDF".channel.title }
           "items" = { $args[0]."rdf:RDF".item }
           "itemtag" = { $args[0]."dc:date" } }
    "Atom" =
        @{ "id" = { $args[0].feed -ne $null }
           "title" = { $args[0].feed.title }
           "items" = { $args[0].feed.entry }
           "itemtag" = { $args[0].created } }
    }

This declares a hashtable called $feedtable (in the declaration of a hashtable a key and value are separated by an equal sign; each key/value declaration must be a separate statement, thus must have a line feed or semi-colon between them). For each entry in the hashtable, the key is a string (which doesn't matter much right now), and the value is another hashtable. This other hashtable has four keys, with the following values:

  • "id" - the value is a script block which determines if an RSS feed is of a certain format
  • "title" - the value is a script block which returns the title for a feed in that format
  • "items" - the value is a script block which returns the array of items for a feed in that format
  • "itemtag" - the value is a script block which returns the "tag" (the string that uniquely identifies the item, so we can tell whether we have seen it before) for an item.

So the first three script blocks assume that $args[0] will be an RSS feed in its entirety, and the last one assumes that $args[0] is an individual item. As long as we respect that contract when we invoke the script blocks, then everything works.

OK, so if you want to use this, then get-feeds now looks like (I removed the declaration of $feedtable since it is shown above):

# get-feeds.msh

$regpath = "HKCU:\Software\Microsoft\MshReader"
$feeds = get-childitem $regpath

# loop through all stored feeds

foreach ($f in $feeds) {

    # get the URI for the feed from the registry

    $feedpath = combine-path $regpath $f.MshChildName
    $feeduri = $(get-property $feedpath).URI

    # read the content from $feeduri as XML

    $wc = new-object System.Net.WebClient
    $global:rssdata = [xml]$wc.DownloadString($feeduri)

    # try to match it to a feed

    $feedname = $null
    foreach ($ft in $feedtable.Keys) {
        if ($feedtable.$ft.id.Invoke($rssdata)) {
            $feedname = $ft
        }
    }

    if ($feedname -eq $null) {
        write-host $feeduri "unrecognized"
        continue
    }

    # display title and feed name

    "== " + $feedtable.$feedname.title.Invoke($rssdata) + " [" + $feedname + "]"

    # get list of items already seen

    $seenlist = [array]($(get-property $feedpath).SeenList)

    # display title and date of each item

    $feedtable.$feedname.items.Invoke($rssdata) |
        foreach-object {
            $itemtag = $feedtable.$feedname.itemtag.Invoke($_)
            if (!($seenlist -contains $itemtag)) {
                $_
                $seenlist += @($itemtag)
            }
        }

    set-property $feedpath -Property SeenList -Type MultiString -Value $seenlist | out-null
}

So we first invoke all the "id" script blocks on a feed, in turn, until we get a match. If we do, then $feedname will be one of the strings "RSS20", "RDF", etc. and from then on, whenever we want to deal with the details of the format of a feed, we invoke the appropriate script block from $feedtable.$feedname (that is the simplest syntax for hashtable lookup; $feedtable[$feedname] would also work).

This all works great, and to support a new format, we just have to add the appropriate value in the $feedtable hashtable. The only problem is that one line towards the bottom that just has

$_

This is where the contents of an item are actually displayed, and it still relies on the formatting information we defined in rss.format.mshxml back in part 3. And tha formatting is still specific to RSS 2.0. So next time, we'll tackle that problem.

Posted by AdamBa at 01:38 PM | Comments (1) | TrackBack

July 08, 2005

Test Post

Testing 1,2,3...I am having trouble posting entries, apparently due to the Movable Type-CPanel interaction bug that surfaced this week.

Posted by AdamBa at 09:37 AM | Comments (1) | TrackBack

Communication at Microsoft: Blogs, Bugs, and Other

A little while ago Lee Holmes filed a bug in our bug database about how the get-history cmdlet works. Basically if you write

$a = get-history

then if there is one item in the history $a will be a scalar, and if there is more than one $a will be an array.

Lee filed the bug against me because I "own" the get-history cmdlet from the PM side, but it's actually not get-history that is causing this. The cmdlet is just outputting objects; it's the Monad parser which is converting the result into a scalar or an array. The output of get-process, get-childitem, etc. would all have the same behavior. In general this is not a problem, if you want to print $a, or pipe it into another cmdlet, or use it in a foreach block. One problem, however, is if you want to refer to the first element of history, then you would use $a[0], but if $a were a scalar, this would fail.

Monad could have done this differently...we could have designed it so that if a cmdlet output a single object then it became an array with one element, instead of a scalar. Or perhaps we could have done something like Perl, where the context determines if a value should be treated as a scalar or an array, and automatic conversion is done. We could have done that, but we didn't, and given the choices we made the language is consistent, so you can't just tweak one part of it.

Anyway Lee filed this bug and I resolved it back to him as "By Design", but then a few days later he opened it back up saying "We really should fix this." So I chonked it right back to him. We are nearing a milestone and need to get our bug counts down; this means that using the bug database as a form of communication works pretty well because people check their bugs often, but I also don't want bugs lurking around on my plate.

Then I noticed that he had written a blog item about including the ID of the last history item in his prompt. Which is exactly the scenario that causes trouble: you want to grab a single history item, when the output of get-history might be a scalar or an array. So then I understood why he had filed the bug.

From his script I can see that Lee solved the problem by using the @() syntax, which will convert a scalar into an array of length 1 and keep an array unchanged--exactly what you want. I made a similar change between the second and third versions of my get-feeds.msh RSS reader. The amusing thing is that I never talked or emailed him about this; the communication was entirely through the bug database and our blogs.

A similar thing happened with the last version of get-feeds.msh. I had switched to use -contains to check if an value existed in an array. One of the testers (he tests the MSH language itself, thus is probably one of the three greatest experts worldwide) pointed out that -contains technically returns the matching elements in the array, not a boolean. However, the -eq operator, when comparing an array to a scalar, does do what I want. Compare these two:

MSH> (1,2,3) -contains 2
2
MSH> (1,2,3) -eq 2
True

That would probably work since 2 is "true"; the problem occurs when the element you are looking for won't evaluate to true:

MSH> if ((0,2,4) -contains 0) { "TRUE" }
MSH> if ((0,2,4) -eq 0) { "TRUE" }
TRUE
MSH> if (("a",$null,"b") -contains $null) { "TRUE" }
MSH> if (("a",$null,"b") -eq $null) { "TRUE" }
TRUE

Now in my scenario it wouldn't matter much because I am comparing strings with dates in them...but still it is more correct to do it with -eq.

So there the conversation was a blog entry followed by email.

I am actually having a problem trying to play with the formatting of the RSS output, which is the next improvement I had planned to post about. I know which developer I need to ask about it, but I have to decide which arrow in my quiver I used to resolve this.

I could blog about it, but not much point in displaying code that I know doesn't work (I have posted some code that could be improved, like the -contains to -eq change, but at the time I posted it I thought it was right). I could file a bug, but at this stage every bug filed raises the stress level. I could email him, but it might be hard to explain. I could go talk to him, but then I wouldn't have the script on my machine to show him. Hmf. And to think that our group, for whatever reason, doesn't use Instant Messenger, or that could be another choice.

Maybe I'll type up a memo, print it out, and interoffice mail it to him.

Posted by AdamBa at 08:44 AM | Comments (0) | TrackBack

July 06, 2005

The Silly Season

It's review time at Microsoft, so along come the annual complaints about the review system, and in particular "the curve".

Microsoft grades employees on a scale from 1.0 to 5.0, with 3.0 being "meets expectations". Only grades 2.5 through 4.5 are usually given, since 2.5 means "about to be fired" and 4.5 means "about to be promoted", so why bother rating someone outside of that range.

Although 3.0 is "meets expectations", Microsoft employees all have an unspoken goal of beating expectations, so in reality merely meeting expectations actually means not meeting them when you factor in the unspoken goal. Thus the expectation is that everyone will get at least a 3.5, and a 3.0 is considered a bad thing. Got that?

At some point a rule was established in every group of a certain size, about 1/3 of employees should be rated 3.0 or below, 1/3 should be rated at 3.5, and 1/3 should be rated 4.0 and above. In order to determine where the curve falls for a group, the managers hold a "ranking and rating" meeting where employees are stack ranked from top to bottom. As a result of this meeting, the rating that your immediate manager gives you may be adjusted as part of fitting your larger group to the curve.

This sets off a lot of predictable complaints about how unfair this is, in ways so obvious I won't bother listing them. What few seem to acknowledge is why the system is in place. Like most dumbass-at-first-glance-and-wouldn't-it-be-better-if-everyone-was-just-great-and/or-honest systems, it exists because the previous, simpler way--the one people are pining for--was abused by some people, in a way that punished the honest people for being honest. It's the same reason expense report rules get stricter, and vacations reporting gets stricter, and travel policies get stricter...some teams were promoting people like crazy and was that fair? With the curve, you force every team to limit their promotions and rewards.

Plus a grade is based on your level on the Microsoft ladder. So a level 62 producing a certain result might get a 4.5 and a level 65 producing the same result might get a 3.0. Thus, it's not pure dog-eat-dog competition for the same pie. It's...something more complicated.

Yes, this system is unfair to the team where everybody does a great job relative to their level. Right. Where is that team? I've never worked on it. When you survey people, something like 80% of them think they are above average. I guess if you believe that, then the Microsoft review system is patently unfair.

And it's the same everywhere. I actually had a section in my first book about ranking and rating (aka ranting and raking, as in ranting about how good your employees are and raking everybody else over the coals) and when my sister was proofreading the book she said that part was boring, because there was nothing unique to Microsoft about it. I guess you could tweak it a bit...maybe make it more like 1/4 who had to be 3.0 or below...and make half the review based on team goals...but basically I don't think this topic is worth writing about any more. So I'll stop.

Posted by AdamBa at 09:35 PM | Comments (3) | TrackBack