October 2009 Blog Posts

Charting Hanselminutes

Before I even get into this, let me preface it by saying Scott's a friend of mine and he's a great guy. I told him I was posting this before I did it. It's just some interesting data that I got in an interesting way and thought folks would be interested. It's also intended to totally crush Scott's spirit. (I kid! I kid!)

So.

I was just writing about how I was seeing more and more video blogs and was thinking about the earlier days of Hanselminutes when it seemed like the show was shorter. I wanted to make sure it wasn't just my mind playing tricks on me so I did some data gathering. This is actually about the process I went through.

The idea: create a graph of the Hanselminutes podcast duration over time so a trendline can be established.

At first I thought it would be pretty straightfoward - I could grab the RSS feed and just parse out the duration info. Turns out they don't actually list how long each show runs, so I had to change my tack and analyze the MP3 durations directly.

Step 1: Getting the MP3s.

I'm not a Powershell guru but this sounded pretty Powershell-ish to me. The thing is, I already had some tools that would do some of the job for me, so I didn't write the whole thing in Powershell. It went like this:

  • Grab the RSS feed for the show by just right-click and save-as from the site.
  • Get the URLs for the MP3s. I used a command-line XPath query tool for that, looking at /rss/channel/item/enclosure/@url. That gave me a nice list of the URLs to the show.
  • Get the MP3s. This is where I did a little brute force Powershell scripting. I suppose I could have saved the list of URLs to a text file and then wrote a script that read in the lines from the text file, but I didn't. I did a regex search-and-replace to create a script that looks like this:
$client = new-object system.net.webclient;
$client.DownloadFile("http://perseus.franklins.net/hanselminutes_0185.mp3", "hanselminutes_0185.mp3");
$client.DownloadFile("http://perseus.franklins.net/hanselminutes_0184.mp3", "hanselminutes_0184.mp3");
$client.DownloadFile("http://perseus.franklins.net/hanselminutes_0183.mp3", "hanselminutes_0183.mp3");
$client.DownloadFile("http://perseus.franklins.net/hanselminutes_0182.mp3", "hanselminutes_0182.mp3");
...

Like I said, pretty brute force... but I'm not running this a bunch of times, I'm just doing it once.

Step 2: Getting the Duration from the MP3s.

This was harder than I thought. What you actually have to do for this is get the MP3 tag info and get the duration from that.

I used the open source TagLib# and wrote a tiny console app using SnippetCompiler that looked like this:

DirectoryInfo dir = new DirectoryInfo(@"C:\Documents and Settings\tillig\Desktop\Hanselminutes");
FileInfo[] files = dir.GetFiles("*.mp3");
foreach(FileInfo file in files)
{
TagLib.File tag = TagLib.File.Create(file.FullName);
Console.WriteLine("{0}\t{1}", file.Name, tag.Properties.Duration);
}

Again, could I have done that with Powershell? Sure, but I'm not too strong in Powershell and I haven't had a chance to get too far beyond pretty basic stuff. And, again, I'm running it once.

So that gets me a tab-delimited text file with the name of the MP3 file and the duration.

Step 3: The Graph.

This was a simple import into Excel and add a graph. I won't go through that.

The Result:

Hanselminutes Duration Graph

I was right - there is an upward trend in the Hanselminutes duration.

So... interesting.

UPDATE: If you want the data for your own enjoyment, here you go.

The Problem with Video Blogs

A few blogs I read have started experimenting with video blogging and it's made me realize that I'm not a video blog... watcher(?).

If content is written, I can read it at my leisure. I can search through it, I can get it on my Blackberry during a boring meeting, I can do pretty much whatever. I can read a few paragraphs, switch to something else, and come back. Worst case scenario, I forget where I was and I can very quickly skim the article again to jog my memory.

Audio content is OK, but not great. It demands a bit more attention.

I'm not one of those folks who can write a term paper and watch a movie and talk to someone all at the same time. The result of me trying to multitask my I/O like that is nothing gets my full attention. I won't know what's going on in the movie, my paper will end up taking a long time to write and won't make sense, and the conversation will dwindle.

I bring that up because with audio content, I can't listen while I'm working. I'll lose my train of thought. (I can listen to music, but generally stick to stuff that doesn't have words or stuff I've heard so many times I don't focus on it.) I can't listen while I'm home, either, because generally the audio blogs/podcasts I'm into aren't things my wife's into.

That leaves my 15-minute-each-way daily commute. Given that, it takes me two or three days to get through an hour-long show like This American Life. Five days per week means I get about one-and-a-half podcasts in. I have to really pick and choose. In many cases, I end up doing a lot of deleting without listening because I can never catch up. (I'm looking at you, 30-minutes-three-times-a-week-Planet-Money. And has Hanselminutes been getting longer or is it just me?)

Which brings me to video blogs/podcasts/whatever. This is the worst of all worlds.

  • I can't do anything with them while I'm working because it's not even just audio content, it's video, too.
  • I can't do anything with them on my commute because it's video. Plus, most times the video is on a site like YouTube where you can't even download it and listen to the audio.
  • I can't do anything with them at home because, frankly, if I'm going to sit down and watch something, there are plenty of more entertaining things I can watch to help me unwind than technical videos.

It's the same problem I have with the phone. Instantly single-threaded. I might be able to do something that doesn't require much brainpower at all, but basically, phone + me = useless.

COMPLUS_Version and the .NET Framework Runtime

I just spent a couple of days debugging a weird problem. We have a fairly large product that has several Visual Studio solutions in it, all of which target .NET 3.5. No, that's not the problem. The problem was that we were able to build each solution separately in the correct dependency order just fine, but when the whole thing ran together in an automated fashion, the build would fail.

The failure message indicated that an extension method was not being recognized. Something like:

'Foo' does not contain a definition for 'Bar'

Again, it would build on its own, but not in the larger environment. What gives?

I figured the problem had to be the targeted .NET environment - that the project was targeting .NET 2.0 when run in the larger build but .NET 3.5 when run alone. And I was right, but not how I thought.

As it turns out, a custom build task run in an earlier build was setting an environment variable called COMPLUS_Version to v2.0.50727, which forced everything after that to run in .NET 2.0.

I had no idea such an environment variable existed. Doing a quick Google search on it, the only documentation on it has to do with build and test environments forcing things to run in different .NET versions, like if you're building something for .NET 1.1 and want to see how it runs in .NET 2.0. I searched MSDN and other sites, but I can't actually find any "official" documentation on this. It's just one of those things you figure out.

Valid settings for COMPLUS_Version seem to be the same as the names of the folders you see when you go to the %WINDIR%\Microsoft.NET\Framework directory, like:

  • v1.1.4322
  • v2.0.50727
  • v3.5

...and so on.

Setting the value will force future processes in that space to use the specified .NET runtime, like:

set COMPLUS_Version = v3.5

That would force everything to run in .NET 3.5.

And we tried that - doing a set to .NET 3.5 to force everything to that runtime, but we then ran into another issue: We were using the vsdbcmd.exe program to do some database work during a build (that's another story) and if you force it to run in .NET 3.5 you get the error:

To run this application, you must first install one of the following versions of the .NET Framework:
v3.5
Contact your application publisher for instructions about obtaining the appropriate version of the .NET Framework

That made no sense to me since I obviously have .NET 3.5 installed.

The answer was to get rid of COMPLUS_Version entirely. After the custom build task ran, set the variable, and completed its work, we used the MSBuildCommunityTasks "script" task to unset the environment variable:

<PropertyGroup>
  <SetCode>
<![CDATA[
  public static void ScriptMain() {
    System.Environment.SetEnvironmentVariable("COMPLUS_Version", null);
  }
]]>
  </SetCode>
</PropertyGroup>
<Script Language="C#" Code="$(SetCode)" Imports="System" />

Doing that removes the variable from the process space and later executables can allow the CLR to choose which environment to target automatically.

One Year Retrospective with Windows Home Server

A little over a year ago I was looking for a storage solution for my media center and landed on Windows Home Server. A year in, is it still all I thought it would be?

Mostly.

The Good Bits:

  • Expandability. I've upgraded the RAM in it and added a bunch of drives to it. It just keeps getting bigger, and that's awesome. I don't have to mess with partitioning things or allocating space to this or that. It just works.
  • Computer Backup. The fact it backs up all of the Windows computers on my network is great. It's almost worth the price for that peace of mind alone.
  • Redundancy. The "file duplication" thing it uses to store two copies of a file on two physical spindles is great. I don't worry about a drive going out because I won't lose my important data.
  • Photo Sharing. I can get to my photo library from anywhere - computer, Xbox 360, Playstation 3 - and it just works.
  • Appliance-Like Functionality. Stick it in the corner, attach to network, plug it in, turn it on. It really is that simple and maintenance-free.

The Decent Bits:

  • Music and Video Sharing. While the photo sharing works great, the whole DLNA/UPnP media sharing bit of Windows Home Server is built on Windows Media Connect, which is unacceptably old. To get newer music types working, you need an additional plugin like Asset UPnP or you need to be accessing the music like a file from a network share. Same thing for video sharing (though I've not found a plugin like Asset UPnP for video).
  • Online Backup. Since Windows Home Server is built on Windows Server 2003 but has some differences to it, it's hard to find an online backup service for it that's affordable. Mozy, for example, classifies it as a "server OS" so you have to pay the expensive business pricing for it... even if you're only storing the same stuff on there that you'd normally have on your PC. You end up either paying through the nose or rigging up something to get around the backup restrictions.

The Not-So-Great Bits:

  • File Access Time. Streaming music or pictures works pretty well and I've seen no hiccups there. On the other hand, the original intent for this system was to store and serve my DVD library. I've got somewhere around 800 discs in my collection (considering a TV season might be six discs, give or take). With 100 - 200 movies in there (which is where I was testing things), the speed is reasonable and except for a few network hiccups, you could play a full DVD image over the network to a Windows Media Center. Looked beautiful. You get 6TB of storage on that thing with 800 disc images on there and the file access time tanks. I thought my network was just getting bogged down or there was bandwidth trouble since I was seeing a ton of the little "hangs" where the picture and sound would freeze while watching a movie. I upgraded my network equipment and got no better result. It's totally file access time. As such, I'm going to have to reinvestigate which video format to store my movies in and switch to something a little more network-and-file-access-time-friendly. Unfortunately I think that'll mean giving up some of the features I was hoping to keep (like the menus and "special features" videos).
  • Developer Resources. I'm a developer and I've considered developing a plugin for Windows Home Server (not sure what, but thought it might be interesting) and... there's pretty much nothing out there on this. Not the major use case for people out there, but still - lame.

Knowing all of that, would I still recommend a Windows Home Server? Sure. The good things far outweigh the bad things. The file access time thing leaves me with a little egg on my face as far as my wife is concerned, though. ("So we bought that and it's not working?") Seeing as how the point was to get a functional video library and that's the part that's failing right now... well, I've got some more work to do.

Family Technology Advances

I play the IT guy in my family just like the rest of you geeks out there, but some of the folks in my family have been making strides in learning about tech stuff lately and I've been pretty impressed. My mom has figured out how to get on Xbox Live all by herself and play Beatles Rock Band with me online. That's huge. But bigger still - my Grandpa just recently got his very first email account and has sent his first email. Huge, I'm telling you. I can't tell you how proud I am of both of them. Great stuff that just makes me smile.

Pop-Under Dialogs are Killing Me

I've had to delete a few large directory trees in the last week or so and every time I do there's trouble. Let me walk you through it.

I navigate to the folder I want to delete, click it, and hit Shift+Delete. I don't want it to go to the Recycle Bin. Next thing I see is this awesome dialog for the next five full minutes, possibly longer:

"Preparing to Delete" dialog

This lasts an interminable time and usually around the time I begin wondering what's up, I realize: the confirmation dialog has popped under something else I'm working on. It won't even be in a consistent spot. Sometimes it's on a wholly different monitor than the "Preparing to Delete" dialog.

"Confirm Folder Delete" dialog

OK, so I click "Yes" because I do want to delete the folder. I go about my merry way. At some point in the next, oh, ten or fifteen minutes, I notice that the progress dialog doesn't seem to have... progressed. Time to start searching again. And what do I find if I minimize literally everything I've got open? Another confirmation pop-under:

"Confirm File Delete" dialog

Honestly, I thought I'd already confirmed that I want the folder gone. But here we are, and we don't want to see this again, so I click "Yes to All" and hope for the best. Another five minutes or so later, things are looking hung again... what gives? Minimize everything again. Oh, there it is.

"Confirm File Delete" dialog redux

Seriously? I could have sworn I clicked "Yes to All" on a nearly identical dialog not... oh, right, five minutes ago. You must have forgotten.

Now, I also hate when dialogs pop up and steal focus. BlackBerry Desktop Manager does that while you're synchronizing and makes your computer unusable because every focus-stealing dialog has so many hot keys on it that if you're typing an email, you're bound to hit some hot key combination that formats your BlackBerry if the dialog pops up and steals focus.

What about having the confirmation dialog show up in the task bar and flash?

That way I would be able to see something is demanding my attention without needing to minimize everything, and if it pops up in a place I'm not expecting, I can easily switch to it by selecting it in the task bar.

I'm on WinXP right now at work (don't ask, I don't like it, either). Did this get fixed in Vista or Win7? Doubting it.

Laser Hair Removal: Treatment 26

It's been a bit over a year since I posted about my hair removal progress and as I just finished up treatment #26 a week or so ago, I thought I'd recap a bit... if anything, as a note to self.

I started the process of getting my facial hair removed a little over two years ago. My facial hair is, to put it mildly, very coarse and causes all nature of dermatological issues if I let it grow even a little bit, not to mention it destroys sheets, pillowcases, necks on shirts, etc.

Hair removal is painful. Don't let anyone tell you otherwise. The more coarse your hair, the worse it is.

To that end, I started the first few treatments using a Dermo Flash, which is a less painful, more broad-spectrum sort of hair removal system. That helped to thin things down, but after the first few treatments we saw diminishing returns because it wasn't powerful enough. I then switched to a MeDioStar laser-based treatment which was much more effective but also much more painful.

Since then, I've been alternating between the MeDioStar and a Syneron eLaser that combines laser and radio frequency. I've been having good results with this, with some spots on my chin and upper lip being the only stubborn areas we're still working on.

Something to think about if you're considering getting this done: You're in for the long haul. That's not just if you're getting your face done, but anywhere. They can do a lot in a few treatments, but you're not going in for five or six treatments and calling it good if you want to actually clear an area out. And once you've started, you can't really turn back because you start getting patchy and it doesn't look all that great.

Also, even today, it still hurts. Not nearly as bad as it did in my first treatment, but it hurts. On the upper lip it's enough to bring tears to your eyes.

Had I known all that... I probably still would have done it. I don't get the nasty ingrowns like I used to, I don't tear up my pillowcases anymore, and I can kiss my wife without removing the top layer of her skin with my sandpaper beard.

I have a few more treatments (a total of 30) and we'll see where I'm at then.

Zuma's Revenge

I ended up getting a copy of Zuma's Revenge, the sequel to the original game that sucked both Jenn and I in so bad on PC and, later, on Xbox Live Arcade.

The premise of the original game is that you're a little frog who sits in the middle of the screen. A line of colored balls scrolls in from off-screen along a path. As they scroll in, you can spit additional balls into the line to form chains of three or more, making them disappear. If the line gets too long, you lose. Here's a screen from the original Zuma:

The original Zuma.

It's surprisingly addictive and fun. Fortunately, you get that and more with the sequel.

This time, they add new features like boss battles (at the end of several levels, you "fight" against a computerized opponent), movement (in some levels your frog scrolls left and right or can hop from one location to another), and power-ups (shoot cannonballs that destroy balls on-screen or lasers to precisely remove individual balls). Here's a screen from the new game.

Zuma's Revenge!

Seriously fun. Jenn and I have been playing quite a bit since we got it and have had a blast.

Now, admittedly, the main game seems to be slightly easier than the original Zuma. I'm not sure if that's intentional or if maybe my hand-eye coordination has increased since playing the original, but we were able to get through the story mode of Zuma's Revenge fairly quickly. Thankfully, there are a bunch of other game modes in Zuma's Revenge that let you keep coming back for more, and those are more challenging (if that's what you're looking for).

Only real downside I can see is that they don't have it on Xbox Live Arcade, just PC. I'm not a PC gamer, really, and our computer's not geared for PC games, so I had to switch from full-screen to windowed mode and turn off the HD graphics. It still looks great, it was just slow with all the bells and whistles on.

If you're into puzzle games, Zuma's Revenge is worth checking out.

(Full disclosure: I got a free license for the game from Popcap.)

Pre-Ordered Windows 7

I went ahead and pre-ordered my upgrades for Windows 7 today. I opted to get the "family pack" upgrade - three licenses to upgrade to Windows 7 Home Premium for $150. At $50/license, I couldn't say no. I'll start the upgrade with my Media Center front ends and do our primary laptop last, just so if anything happens to go south I'll always have a working computer to go searching for help/fixes. Not that I anticipate anything going wrong, just... well, things that should be easy never are for me. I always seem to find that one edge case.

Anyway, if you're looking to upgrade more than one computer, that three-pack might be the way to go. Considering a single upgrade license for Windows 7 Home Premium is $120, three licenses for $150 is a steal.

Barrage of Post-Weekend Random Crap

I have a bunch of random thoughts I sorta need to get down and they're bigger than tweets but none really is big enough for a standalone blog entry. Most are non-technical, so... tune out if you like. At least for this one.

Had a great time playing Beatles Rock Band with my friend Jeff and my parents over Xbox Live on Saturday. Mom's figured out how to get on Xbox Live all by herself which is super cool, and my dad came on later. Got 100% on Expert-level drums on "Do You Want To Know A Secret" and "While My Guitar Gently Weeps," which, while probably not the most-awesome-drumming-feat-ever, made me feel pretty good. (I got 100% on Hard-level drums on Rock Band 2 for "Livin' on a Prayer" earlier in the week, which also made me pretty happy.)

Speaking of drums, I've been having some troubles with my Ion Drum Rocker kit lately and it's been a pain to troubleshoot. For a while I was getting disconnected at random intervals from the console and the green pad would hit at random times without me touching it. Kind of kills your streak (and your mood). I switched my setup so I wasn't running the drums through a USB hub and the random disconnects disappeared, but the random hits didn't. Instead, it switched to be random hits from the kick pedal instead. (Actually, either the kick would stop responding entirely or it would hit like a machine gun without you touching it. Either way, still kills your streak.) I've been talking to both Ion support and Rock Pedal support and have been doing all sorts of troubleshooting shenanigans - rearranging cables, trying different USB ports on the Xbox, and even switching the sensor on my pedal for a new one. You can't reproduce it on demand, though, so I have to play a ton to see if any of these things have fixed it. I haven't seen any trouble since I swapped out the pedal sensor (after which I got all those good scores, noted above) so maybe that fixed it.

Now that I've typed that out, I've jinxed it, but still.

I picked up a Rubik's Cube this weekend with this $5 Target gift card that was burning a hole in my pocket. I got the guts up this morning to mix it up. We'll see how long it takes me to figure it out. Haven't ever solved a Rubik's Cube before so we'll see.

One of my favorite things in the world: when you put a bag of tea in your cup and the little string pulls off. That's happened to me twice in two days. Maybe I just don't realize my own strength or something, but I'm thinking maybe they need to figure out a better way to attach those strings than staples.

I was talking to my sister yesterday about various podcasts that we listen to and it got me thinking about how iTunes podcast management blows. I always - always - have to manually delete podcasts I've listened to even though I have my settings such that it should auto-delete podcasts I've listened to. Not sure how a play count > 0 doesn't constitute "listened to," but it apparently doesn't.

While I'm on iTunes, where's the multi-user support on that thing? Multiple users, one computer, one library. Is that really so uncommon? As it stands, you still have to do a bunch of manual manipulation to get that working.

Other stuff that's been bugging me...

Incorrect grammar and/or spelling. I don't claim to be perfect on this stuff, but there are some that just get me. Lately:

  • The phrase is "hear, hear!" when you agree with someone, not "here, here."
  • When you get provoked into doing something, you're "goaded" into it, not "goated." A goat is an animal. A goad is a stick used to prod an animal.
  • You can ask me a question or you can make a request, but you don't have "an ask" for me. "Ask" is a verb.
  • The spelling for an informal affirmative that you're thinking of is "yeah" (pronounced "'yaə").
    • "ya" is either an abbreviation for "young adult" or is an informal version of "you" ("What do ya think?") and would be prounced like "'yə".
    • "yah" rhymes with "saw" and is the sound you make when you want to make your horse go. "YAH! YAH!" <cracking whip>
    • "yea" is pronounced "'yā" and is used in formal voting (rhymes with, and is the opposite of, "nay").

People asking for an opinion they don't want. Sort of like if someone asks, "Do you think I should buy this shirt?" and you say "no" and they buy it anyway. If you already have your mind made up to buy the damn shirt, why'd you bother asking for my opinion?

OK. I'm done for now.

Convert a Relative Path to Absolute Path with jQuery and ASP.NET AJAX

I was messing around with relative paths to files (e.g., "../images/error.gif") and needed to convert them to absolute paths (e.g., "http://server/images/error.gif") on the client but couldn't figure out how. Then I saw this nifty trick to HTML encode things using jQuery and it gave me an idea.

String.toAbsolutePath = function(relativePath) {
  /// <summary>
  /// Converts a relative file path into an absolute file path.
  /// </summary>
  /// <param name="relativePath" type="String">
  /// The string with the relative path, like "../foo/bar.gif"
  /// </param>
  /// <returns type="String" />
  var path = $("<div style=\"background-image:url('" + relativePath + "');\"></div>").css("background-image");
  if (path.startsWith("url(")) {
    path = path.substring(4);
  }
  if (path.endsWith(")")) {
    path = path.substring(0, path.length - 1);
  }
  if (path.startsWith("\"")) {
    path = path.substring(1, path.length);
  }
  if (path.endsWith("\"")) {
    path = path.substring(0, path.length - 1);
  }
  return path;
}

Basically, I'm using the CSS style "background-image" and feeding in the relative path, then resolving it immediately. Turns out the browser converts that to an absolute path for you. At least, Firefox 3.5.3 and IE 7 do, which is what I was testing with at the time.

The path.startsWith and path.endsWith checks are because sometimes the URL comes back like:
url("http://server/images/error.gif")
...with the url("") wrapper, and sometimes it comes back like:
http://server/images/error.gif
...without the wrapper at all.

Note the String.startsWith and String.endsWith methods come from ASP.NET AJAX so if you wanted to do it in just jQuery, you'd have to regex your way out of it or do a little more brute force work.

Of course, in the end, I figured out a different way to do what I was doing so I didn't actually need to convert the path at all, but I thought this was sort of neat so I'd post it for folks. I didn't really test it in a bunch of browsers or anything, so YMMV. "Works on My Machine."