April 2007 Blog Posts

MIX07 - AJAX Patterns

The session on AJAX patterns was very cool. In one demo application (a photo album application), six specific patterns were addressed and a little on how to solve it was also shown.

Pattern - Script to Enable Interactivity
Sort of a no-brainer, but using script to enable interactive elements is sort of the basis of a rich application. In this particular pattern, it was more about making it easy to script what you're looking to do. ASP.NET AJAX offers a lot of shortcuts to help you do that scripting.

This pattern also addressed the notion of separating script from behavior. ASP.NET AJAX introduces the notion of "extender controls" that allow you to use server controls to modify the behavior of controls in the page. An example was shown where some existing markup got modified by adding an extender - a server control registering script to modify HTML on the client side. It's a great way to do the separation.

Pattern - Logical Navigation
AJAX applications have typically lost the ability to use the back/forward buttons and the ability to bookmark a page. ASP.NET Futures contains a "History" control that allows you to enable your AJAX elements to support state, sort of like ViewState, but on the URL. Modifying the page contents modifies the browser URL and, thus, enables logical navigation and bookmarking. As long as your scripts store enough history state to be able to recreate a logical view, this looks like a great way to overcome some shortcomings in AJAX.

Pattern - Update Indicators
Notifying a user of what changed when an AJAX request finishes is helpful so they can see the results of an action. The UpdateAnimation control in ASP.NET AJAX is one way to do that - it performs AJAX updates in an animated fashion so movement is the key for the user. There is a prototype UpdateIndicator control that scrolls the page to the location of the change and does a highlight animation on the change; this isn't in ASP.NET AJAX now but will hopefully be in the future.

Pattern - Smart Data Access
Possibly a poorly-named pattern, but the idea is that you should use HTML properly such that external services like search engine crawlers or programmatic site map generators can correctly access/index the content you post. Use tags in the correct semantic sense (e.g., if it's not a header, don't put it in <h1 /> tags). Also, keep in mind the way you display pages in non-scripted environments, such as in a search engine crawler or when the user has script disabled. Your content should look good either way.

Pattern - Mashups (Using External Services)
There's a lot of data out there, and a lot of services providing added value. Make use of them where you can. The example shown was a call to Flickr to get images and data.

What was interesting about the discussion of this pattern was less the "what" than the "how." Browsers don't allow cross-site scripting, so you have one of two options to get third-party data into your application.

You can use a server-side proxy where you create a proxy on your site that requests the third-party data. Your application then talks to your proxy to get the data. This is a good general-purpose solution and allows you to take advantage of things like caching calls on your site and gives you the ability to manipulate the data before passing it to the client (possibly optimizing it). The downside is that it does use up your server's bandwidth.

The other option is JSONP, which is a way you can add a script reference to your page that requests data in JSON format from a third-party service and when that data gets returned, it gets passed to a callback that you specify. ASP.NET AJAX supports this by allowing you to specify your own executor in an AJAX call, so the result of the call gets passed to your callback.

More Resources
AJAX Patterns
Yahoo! Design Pattern Library

MIX07 - Developing AJAX Applications with Visual Studio "Orcas"

I admit I've been lax and haven't been installing the Visual Studio "Orcas" releases. I've followed the cool stuff, but I haven't actually installed it. This session made me wish we were already in this.

The session was called "Developing AJAX Applications with Visual Studio 'Orcas'" but it should have been called "New ASP.NET Controls and How Visual Studio Supports JavaScript Development."

In the non-JavaScript developments, we see new controls of interest in ASP.NET 3.5. The ListView control is sort of like a repeater but gives you a little more control over list creation. For example, you could set a list template to something like <ul runat="server"></ul> and a list item template of <li><%# DataBoundField %></li> to make an unordered list... and the output HTML is no more or less than exactly what you specified - great control over the HTML. The DataPager control is an extender for any databound control that allows you to easily add paging - no more having to natively support it in your controls.

The JavaScript developments were the big show here, though. Full Intellisense for JavaScript including keywords, declared variables, properties, methods... even if you reference an external JavaScript file, it'll figure that out and give you Intellisense for all of those methods. And it's smart about it - it does dynamic type evaluation on variables, for example, and figures out that at the time you're asking for Intellisense it's, say, a number, so you only see the Intellisense for methods applicable to numeric objects. Hot.

To assist in the Intellisense effort, they've added XML documentation support such that the Intellisense is driven by the XML doc comments in your script. If you document your script, it'll appear just like standard .NET Intellisense with method descriptions, parameter information, and so on. To get around the loose typing of JavaScript, you add attributes to the XML doc comments to tell Intellisense what the expected parameter types and what the return type of the method is (<param name="myParam" type="String">Some Parameter</param>). Specifying the return type is how the Intellisense knows the way to treat return values from your methods. ASP.NET AJAX libraries will all be commented this way.

JavaScript debugging is vastly improved, too. If you have a script in your page, you can set a breakpoint in the page and *gasp* when you run the page it'll break on your breakpoint. This is a huge improvement because you used to have to figure out where in your ASPX the script really was and try to figure out whether the breakpoint was actually hit... and sometimes it wasn't... it was just a nightmare. Now? Brilliance.

MIX07 - Developing Silverlight Applications with JavaScript

I just emerged from a standing-room-only demonstration of how to work with Silverlight and JavaScript. It seems that the managed code way of working with Silverlight is a 1.1 thing that's coming soon (before Summer 07? I'd have to see the slides again); if you want to write a Silverlight application today, you'll be using JavaScript.

It looks like working in Silverlight with XAML with JavaScript is a lot like working with the HTML DOM in JavaScript. You get elements, you manipulate properties, you respond to events... and it's just as hard to debug as your standard client-side JavaScript app. The demos were interesting, showing how you do different things like start animations, intercept mouse events... but they were far from bug-free. I guess that's just one of the pain points for early adoption.

Beyond that pain point, though, it looks pretty good. No harder than doing stuff you're probably already doing, but with a much richer end result.

Two of the key things shown were the Downloader and the CreateFromXAML call.

The Downloader is a component that allows you to synchronously or asynchronously download content. It will also report on the status of the progress as it goes, so you can have an actual progress bar. This looks useful if you've got some large content like a lot of video where you want to download some to cache before starting the video playing. The Downloader supports ZIP, too, so if you have some compressed content to download, you're set to go.

The CreateFromXAML method is sort of like an "eval" call - it takes some XAML that you've built up in code and parses it into native XAML nodes that can be inserted into your application. This is handy for building XAML content programmatically - say, adding rows to a table.

I like what I've seen so far from Silverlight, but I've yet to get some hands-on. I think my next stop is the lab area where you can get some first-hand experience with it by going through some walkthroughs and such.

MIX07 Day 1 Keynote - Ray Ozzie, Scott Guthrie, and Cross-Platform Debugging

Ray Ozzie opened the keynotes today and gave a general intro to MIX07. This was a pretty general overview and focused a lot on the release of Silverlight, Microsoft's Flash competitor. It was an interesting talk, but was mostly benign.

After that, Scott Guthrie came up and that's when the really good stuff started. Lots of great announcements:
  • Silverlight is out, released for download just a little bit ago.
  • Silverlight comes with a cross-platform .NET framework that runs in the browser. With that comes a lot of interesting things:
    • Initial support is for Firefox, IE, and Safari. Yes, it runs on Mac.
    • You can now write client-side code on any Silverlight-enabled browser in any .NET language you like.
    • Client-side code in .NET has HTML DOM access including all of the browser components (status bar, etc.) and runs thousands of times faster than JavaScript.
    • There are robust data services including LINQ and caching built-in.
  • There's a new service called Silverlight Streaming that lets you upload your Silverlight application and assets, up to 4GB, and Microsoft will host it for free. That's a huge bandwidth-saver for folks wanting to use Silverlight to stream video, etc.
  • New Visual Studio (Orcas) feature - Core CLR Remote Cross-Platform Debugging. You can runtime debug a Silverlight application executing in a browser on another machine, including remote debugging to a Safari instance on a Mac. This is huge. Guthrie demonstrated one of these sessions, intercepting events and changing values in the debug session on the fly and those values get real-time updated in the target session. Very, very cool.
  • Silverlight projects seem to work like other Visual Studio projects, including the ability to "Add Web Reference" and have your Silverlight applications call web services.
  • If you have a web application project in Visual Studio, you can put that in the same solution as your Silverlight app and then select "Add Silverlight Link" to your web application. When you build your web app, the Silverlight app automatically rebuilds and deploys.
  • The dynamic language support in .NET is growing. They've got support for Python and JavaScript and are adding official support for Ruby via IronRuby. They'll be releasing that source just like IronPython.
  • This dynamic language support has an additional meaning - you can write your Silverlight apps in any of those languages as well. And, again, they'll run cross-platform. Huge.
  • It installs in like three seconds. The demo showed a user experience for someone coming to a Silverlight app and not having the plugin installed. From the point where the user clicks the "Install" link to the point where the app is running was about three seconds. It was super fast.
  • After Summer 07 they'll be adding even better mobile support. It has pretty good support now (also demonstrated) but I guess they're adding more.
There seems to be a big focus on delivering video with Silverlight. Most of the demos they showed involved integrating video. It does a lot more than that, and I can envision a lot of cool XAML based apps I could write, but there's a huge video push, going so far as having NetFlix come in and demonstrate an application where you can watch movies on-demand.

The Silverlight community site is at http://www.silverlight.net. Check it out.

MIX07 - Day 0

The conference technically starts tomorrow, but I'm in town a day early to get settled so I can be there, bright-eyed and bushy-tailed. Or at least bright-eyed.

There was a mashup session that ran from 4:00p to 8:00p alongside registration, but by the time I got here, got registered, got to the room, and got something to eat... well, I also got a little tired and didn't really feel like throwing down with the mad technical skillz. Instead, I thought it would be prudent to take it easy - it's been a long day, and I do want to be ready to pay attention and learn in some of the great sessions planned.

My schedule looks like this:

Monday, April 30
9:30a - General Session
1:30p - Building Rich Web Experiences using Silverlight and JavaScript for Developers
3:00p - Using Visual Studio "Orcas" to Design and Develop Rich AJAX Enabled Web Sites
4:30p - AJAX Patterns with ASP.NET

Tuesday, May 1
8:30a - Front-Ending the Web with Microsoft Office
10:15a - Designing with AJAX: Yahoo! Pattern Library
11:45a - Developing ASP.NET AJAX Controls with Silverlight
2:15p - Go Deep with AJAX
4:00p - General Session

Wednesday, May 2
8:30a - How to Make AJAX Applications Scream on the Client
10:00a - Windows Presentation Foundation for Developers (Part 1 of 2)
11:30a - Windows Presentation Foundation for Developers (Part 2 of 2)

Interestingly, this isn't the schedule as I originally planned it on Friday. Even up to the last minute the times, places, and topics are changing. I don't know if this is the set of classes I'll actually be in or not, but we'll see.

Getting into the spirit of things, I've joined Facebook and Twitter since those seem to be ways folks are supposed to coordinate things. I'm not super taken with either one, but then, I'm not a big "social networker." I'll withhold judgment for now.

Xbox Live Marketplace Still Has DRM Troubles

So about eight months ago I had to send my Xbox 360 in for repair and they sent me back a refurbished console. Due to the crazy, crappy DRM scheme they have on the content you get from Xbox Live Marketplace (which includes Xbox Live Arcade games), that meant I had to jump through a bunch of hoops to get the games on my system to work correctly again.

Well, I just got my Xbox 360 back from my recent bout with the Red Ring of Death and guess what - they sent me another refurb.

Which, of course, means I get to go through the hoops a second time. That's right - I get to create a second dummy Xbox Live Silver membership (because I can't use the dummy account I created last time around), have them refund me points to that account, and then use that account to re-purchase everything. Again.

Net result is that I spent like an hour last night taking inventory of all of the Xbox Live Arcade games we've purchased, figuring out which account we originally bought them with, and determining the price for each game as listed in the Xbox Live Marketplace.

I then called Xbox Live Support and after explaining the situation to one of the representatives, he mentioned that I should just be able to go in with the account I purchased the games with, hit Xbox Live Arcade, and select the "re-download" option (without deleting the game from the hard drive first) and it should authorize the new console.

That doesn't work.

The call got escalated to the supervisor, who spent time going through my account and my wife's account and calculating up all of the things we've purchased. Problem there is that their history only goes back one year so they don't actually have a visible record of what you purchased beyond that... so they argue with you when you tell them, say, that you bought one of the Xbox Live Gold packages at a retail outlet over a year ago (because you've renewed since then) and it came with a copy of Bankshot Billiards 2, and yes, you'd like to have that re-authorized on the console as well.

After all of that, they still came up with a different number of points that they owe me than I did. You know why? Because they use the number of points you originally spent on the game as a guide, not today's prices. And prices have gone up, so now the game you paid 400 points for six months ago costs 800 points if you want to buy it today but they only want to give you the 400 points you originally paid. Obviously, that causes a little contention on the phone, but the best the supervisor can do is put a note in there that mentions your concern because...

...there's a guy named Eric whose job it is, apparently, to call all of the people that this happens to and hash out the whole "Points After Repair" thing (yes, they have an actual name for it, which sort of tells you something). I get to argue with Eric about the difference in what they think they owe me and what they actually owe me, and that discussion will happen in "approximately five business days."

And there it sits. A couple of hours of work and phone later and I'm hanging on for Eric to call me and give me points so I can re-purchase and re-download the games I already own so my console works like it should again. Awesome.

posted @ Friday, April 27, 2007 9:33 AM | Feedback (7) | Filed Under [ Gaming ]

BlogML 2.0 Impressions

I've been looking for a while to migrate off this infernal pMachine blog engine I'm on. The major problem is how to migrate my data to the new platform. Enter BlogML.

BlogML is an XML format for the contents of a blog. You can read about it and download it on the CodePlex BlogML site. They're currently at version 2.0, which implies there was a 1.0 somewhere along the lines that I missed.

Anyway, the general idea is that you can export blog contents in BlogML from one blog engine and import into another blog engine, effectively migrating your content. Thus began my journey down the BlogML road.

If you download BlogML from the site it comes with an XSD schema for BlogML, a sample BlogML export file, a .NET API, and a schema validator.

I didn't use the .NET API because pMachine is in PHP and all of the routines for extracting data are already in PHP, so I wrote my pMachine BlogML exporter in - wait for it - PHP. As such, I can't really lend any commentary to the quality of the API's functionality. That said, a quick perusal of the source shows that there are almost no comments and the rest looks a lot like generated XmlSerializable style code.

The schema validator is a pretty basic .NET application that can validate any XML against any schema - you select the schema and the XML files manually and it just runs validation. This actually makes it troublesome to use; you'd think the schema would be embedded by default. If you have some other schema validation tool, feel free to ignore the one that comes with BlogML.

The real meat of BlogML is the schema. That's where the value of BlogML is - in defining the standard format for the blog contents.

The overall format of things seems to have been thought out pretty well. The schema accounts for posts, comments and trackbacks on each post, categories, attachments, and authors. I was pretty easily able to map the blog contents of pMachine into the requisite structure for BlogML.

There are three downsides with the schema:

First, the schema could really stand to be cleaned up. This may not be obvious if you're editing the thing in a straight text editor, but when you throw it into something like XMLSpy, you can see the issues. Things could be made simpler by better use of common base types that get extended. There are odd things like an empty, hanging element sequence in one of the types. Generally speaking, a good tidy-up might make it a lot easier to use, because...

Second, the documentation is super duper light. I think there are like 10 lines of documentation in the schema, tops, and there's nothing outside the schema that explains it, either. Without going back and forth between the schema and the sample document, I'd have no idea what exactly was supposed to be where, what the format of things needed to be, etc.

Third, and admittedly this may be more pMachine-specific, there's no notion of distinguishing between a "trackback" and a "pingback." There's only a "trackback" entity in the schema, so if your blog supports the notion of a "pingback," you will lose the differentiation when you export.

Anyway, I planned on importing my blog into Subtext, so I set up a test site on my development machine, ran the export on my pMachine blog (through a utility I wrote; I'm going to do some fine-tuning and release it for all you stranded pMachine users) and did the import. This is where I started noticing the real shortcomings in BlogML proper. These fall into two categories:

Shortcoming 1: Links.
If you've had a blog for any length of time, you've got posts that link to other posts. That works great if your link format doesn't change. If I'm moving from pMachine to Subtext, though, I don't want to have to keep my old PHP blog around (hence "moving"), and, if possible, I'd like to have any intra-site links get updated. There doesn't seem to be any notion in BlogML pre-defining a "new link mapping" (like being able to say "for this post here, its new link will be here") so import engines will be able to convert content on the fly. There's also no notion of a response from an import engine to be able to say "Here's the old post ID, here's the new one" so you can write your own redirection setup (which you will have to do, regardless of whether you update the links inside the posts).

I think there needs to be a little more with respect to link and post ID handling. BlogML might be great for defining the contents of a blog from an exported standpoint, but it doesn't really help from an imported standpoint. Maybe offering a second schema for old-ID-to-new-ID mapping (or even old-ID-to-new-post-URL) that blog import engines could return when they finish importing... something to address the mapping issue. As it stands, I'm going to be doing some manual calculation and post-import work.

Shortcoming 2: Non-Text Content
If you've got images or downloads or other non-text content on your blog posts, it's most likely stored in some proprietary folder hierarchy for the blog engine you're on... and if you're moving, you won't be having that hierarchy anymore, will you? That means you've got to not only move the text content, but the rest of the content into the new blog engine.

There is a notion of attachments in BlogML, but it's not clear that solves the issue. You can apparently even embed "attachments" for each entry as a base64 encoded entity right in the BlogML. It's unclear, however, how this attachment relates back to the entry and, further, unclear how the BlogML import will handle it. This could probably be remedied with some documentation, but like I said, there really isn't any.

This sort of leaves you with one of two options: You can leave the non-text content where it is and leave the proprietary folder structure in place... or you can move the non-text content and process all of the links in all of your posts to point to the new location. One way is less work but also less clean; the other is cleaner but a lot of work. Lose-lose.

Anyway, the end result of my working with BlogML: I like the idea and I'll be using it as a part of a fairly complex multi-step process to migrate off pMachine. That said, I think it's got a long way to go for widespread use.

Bus Ride to Eugene, Littermaid Elite, and Points After Repair

Saturday was a hell of a day.

We got up at around 7:00a and got out of the house basically ASAP so we could get to Jenn's parents' house in time to get in their motorhome and head down to Eugene for Jenn's grandma's 79th birthday party. That's like an hour and a half drive, which isn't as bad when you're riding in the Adamson Bus, but it's still a long trip.

We got there and Jenn's grandma was very pleased to see us. It was a surprise party and the entire family was there.

Now, when I say "the entire family," I mean like 40 or 50 people. The rockin' part was that it was raining and we had planned to have the party outside, but instead we had it indoors in a space that was, oh, maybe 500 square feet. You can imagine the chaos - not enough chairs (or enough room for chairs) ended up meaning people sitting on the floor, sitting on laps, standing in the hallway... and it got hot.

So that lasted for about four hours. And the thing is, I like Jenn's family and all, but I don't really know anyone and every time we get together it's like this whirlwind of faces that only look mostly familiar and only results in me being confused and claustrophobic. I don't really have anything to talk about with them because none of them are tech people and I really don't follow sports or family gossip. So it's nice to see them, but I won't lie, it's not super duper fun.

After that, we hopped back on the bus and headed home. We got back somewhere around the 6:30p timeframe and on the way home we planned on stopping at my parents' house because it was my dad's birthday, too. We got there sometime around quarter to seven, but they weren't home so I planned on calling him later in the evening. I actually feel bad I didn't get in touch with him earlier, but he's going to have to throw me a bone on this one because I was sort of predisposed.

Sunday was errand day so we ran around and did the shopping and so on. Groceries ran far more than I anticipated because we ended up picking up a lot of high-ticket items (cleaning supplies and so on) that we had been putting off. Not great on the pocketbook, but had to be done.

We also picked up one of those automatic cat boxes. We like to occasionally go away for the weekend and the new cat generates a looooot of poop so we want to make sure the box is always clean and doesn't need to be dealt with for a couple of days at least. We went with the Littermaid Elite after looking at a lot of these things because not only did it seem to be the most popular model, but it also didn't lock us into proprietary refills or materials beyond the little litter receptacle (which runs about $0.30 each and last around five days - so maybe $2/month, which is better than some of the ongoing costs of the other boxes). The only thing we were afraid of was whether they'd use it.

As I was putting it together, I got to about step seven of ten and had to put the clean litter in the box. I poured it in, turned around, put the litter box down, picked up the instruction manual and turned around to do step eight... but the cat was already in the box taking a fresh crap - even before I got the box put together - so I'm no longer afraid they won't use it. I couldn't even finish putting it together before it was used.

Jury's still out on whether I like it or not. It works great on the clumped-up pee balls, but if the cat poop is... well, soft... it sort of attaches to the rake that cleans the box. I cleaned it off the rake manually the first time, but I left it when I saw it again this morning. I'm going to see if the situation somehow rectifies itself.

I also checked on my sick Xbox, which is on its way home from Xbox Hospital. They are sending me another refurbished machine - it has a different serial number than the one I sent in - so I'm going to end up going through the Xbox DRM problems again. Support actually has a name for this process now - "Points After Repair." I called them and said I noticed that the serial number was different and that I was disappointed I'd have to go through this again and they were all, "Well, just set up [yet another] Xbox silver account before you call, then when you call in give us your repair number and ask about 'Points After Repair.' We'll hook you up." Ridiculous. Because that didn't cause all nature of pain in my ass last time.

Design For Testability vs. Static Utilities

I follow the whole "design-for-testability vs. design-for-usability" debate and, in the interest of full disclosure, I'm a fan of not designing for testability. Part of what I design has to be a usable API and I can't have a lot of the cruft required in testable design when I get to my finished product.

I mean, think about it - if the .NET Framework was built using design-for-testability, there's no way like 80% of the people using it today would have been able to pick it up. Considering the inability to solve a FizzBuzz problem, somehow I don't think having everything infinitely pluggable and flexible solely to support the testing of the framework would have made it any easier to use.

Now think about the notion of the static utility class. Everyone has one (or more) of those classes that are sealed and only provide a few static helper methods. I mean, for .NET 1.1 folks, who didn't have their own static String.IsNullOrEmpty implementation?

On my project, we have a lot of static helpers that read, process, and cache configuration data. The basic algorithm is something like this:
  1. Check the cache for the data. If it's there, return it.
  2. Data wasn't in cache, so open the config file.
  3. XML deserialize the file or do whatever other processing needs to happen.
  4. Cache and return the result.

Here's some basic sample code:
public sealed class ConfigService
  private const string CacheKey = "CacheKeyForConfig";
  private const string ConfigPath = "/Config/myfile.config";
  public static System.Collections.ArrayList GetConfiguration()
    System.Collections.ArrayList retVal = null;
    string configPath = ConfigPath;

    if(System.Web.HttpContext.Current != null)
      retVal = System.Web.HttpContext.Current.Cache[CacheKey]
        as System.Collections.ArrayList;
      configPath = System.Web.HttpContext.Current.Server.MapPath(configPath);
    if(retVal == null)
        throw new FileNotFoundException(
          "Unable to read default configuration file.",

      //... read/process the file... set the return value...

      if(System.Web.HttpContext.Current != null)
          new System.Web.Caching.CacheDependency(configPath));

    return retVal;

From an API standpoint, it's a one-liner: ConfigService.GetConfiguration()

But how do you test that? If you're running FxCop, your static utility class "ConfigService" needs to be sealed. That sort of limits your abilities to mock with several frameworks out there. The simple fact this is a static method is limiting to some frameworks.

Now, granted, you could write a class that provides cache retrieval services specific to this helper and go to the trouble of instantiating that class and... you know what, I'm already tired of typing that out. I don't need all that. I'll never sub in a different cache provider for anything other than testing. I don't want the consumer of the method to even have to know about any of that (so they shouldn't have to pass the cache instance in as a parameter, for example).

But I do want to have this thing tested. If the object is in cache, does it just return the object without further processing? If it's not, does it read the file and does it then cache the results? I want the design simple, I want it usable, and I don't want a lot of moving pieces. In fact, ideally, the code would be about as simple as the sample I posted.

So you need to mock a few things, specifically around HttpContext. (Possibly other things based on the implementation, but we're going for simple here.)

You can't really readily do that. Or can you? What if your test looked like this:

public class ConfigServiceTest
  public void GetConfiguration_NoCache_FileExists()
    //...place a known good configuration in a temporary location...
    string pathToTemporaryConfig = ExtractConfigToTempFileAndGetPath();

    // Set up calls for the cache
    MockObject mockCache = MockManager.MockObject(typeof(System.Web.Caching.Cache), Constructor.Mocked);

    // Set up calls for the server utility
    MockObject mockServer = MockManager.MockObject(typeof(System.Web.HttpServerUtility), Constructor.Mocked);
    mockServer.ExpectAndReturn("MapPath", pathToTemporaryConfig);

    // Set up calls for the context
    MockObject mockContext = MockManager.MockObject(typeof(System.Web.HttpContext), Constructor.Mocked);
    mockContext.ExpectGetAlways("Cache", mockCache.Object);
    mockContext.ExpectGetAlways("Server", mockServer.Object);

    // Use natural mocks to ensure the mock context is always returned
    using(RecordExpectations recorder = RecorderManager.StartRecording())
      // Ensure any call for HttpContext always gets returned
      System.Web.HttpContext dummyContext = System.Web.HttpContext.Current;

    System.Collections.ArrayList actual = ConfigService.GetConfiguration();
    Assert.IsNotNull(actual, "The configuration returned should not be null.");
    // ... do other assertions that validate the returned config ...


Using TypeMock, I was able to easily mock a web context and test this code without having to impact the design or the API usability.

It sounds like I'm shilling for TypeMock, and maybe I am a little. On a larger scale, though, I'm just happy I'm able to get full test coverage without sacrificing my usable API.

And if someone reports a defect with this code? Piece of cake to get a mocked test into place that replicates the behavior and even easier to track down the issue because I don't have all of these additional unnecessary layers of abstraction to fight through. The code is simple - simple to read, simple to understand, and simple to troubleshoot for the next developer who has to try and fix it. You have to love that.

Office Food

I'm not sure whether it's out of necessity or boredom that odd office food concoctions get generated. I know I've made up some crazy stuff - some good, some not so good. For example, I know you can't make Coke Blak by just combining coffee and Coke.

I think it'd be interesting to compile a list of office-based recipes - things you can make with the stuff you find around a typical office (coffee, sugar packets, cup-o-noodles, etc.). I found a recipe for chai tea based on office supplies, though I admit I haven't tried it yet.

Here are a couple of things I've made (try at your own risk, YMMV):

1 can Sierra Mist (or 7-Up, Sprite, etc.)
1 packet Crystal Light On-The-Go
This is reasonably tasty and a good change from the norm if you like this sort of thing and your office only carries standard soda flavors. Pour the can of pop into a cup and pour the packet of Crystal Light into the pop slowly. Stir slowly with a stir stick until thoroughly mixed, pausing when you see the foam start to rise. If you do anything fast, you're going to have a mess on your hands.

3/4 mug coffee
1/4 mug hot water
1 packet hot chocolate
2 packets creamer
Mix contents together thoroughly and enjoy. The water helps to make chocolate a little more prevalent and make it feel less... thick. Depending on your mood or personal taste, you may just go with the full coffee/no water approach.

1/2 mug hot water
1 black tea bag
Put the tea packet in the mug of hot water and leave it. Freaking over-steep it. The tea's got to be strong because once you take the tea bag out, you've got to fill the rest of your mug with ice and let the ice melt, and that's going to water down the tea. You'll need to experiment with this one based on personal taste - I like really strong iced tea, so I leave the tea bag in for a looooong time.

Follow the iced tea recipe but add four to six sugar packets to the tea before adding the ice. (If you remember your high school chemistry, solids generally dissolve better in hot liquids.)

If you have a recipe or link to contribute, leave it in the comments. I think it'd be cool to get a big list of office food recipes.

Exasperating Problems

I love my wife dearly, but sometimes she's just frustrating. For example, when she has some technical problem (say, with the iPod or the computer) that she needs solved, I'll come in and help her out, but she gets impatient - as I'm trying to explain the answer, she's already stopped listening. She doesn't want to hear why the answer is what it is, she just wants to have her immediate problem solved right now thank you very much.

I do my best to be very pleasant during these exchanges, but it's exasperating, and it takes its toll on my sanity. Take, for instance, a recent exchange I had with one of my co-workers trying to determine why a particular method was returning a value he didn't expect:

Travis: Okay, so the thing is returning this answer to you because –
Michael: I need to know how to get it to return this other thing though.
T: Right, but after that, you’re going to need to know how to –
M: But how do I get it to return the answer I want?
T: Well, you have to do set this parameter this way before you can –
M: That sounds really complicated. I’m just trying to do something simple. How do I get it to do what I want?
T: I’m getting to that, but there are a few steps that –
M: I’m already not listening. What if I just type this in here and hit this button? [He types something in and hits the button.]
T: Um, that’s not going to –
M: Hey, that’s not working. What about if I try this other thing and hit the button? [Types this other thing in and hits the button.]
T: That’s not going to –
M: It’s not working. I don’t understand why it’s not working. I just need it to –
T: [Exasperated] Look, hon, I can’t tell you how to do what you want to do until you stop and listen to me.
M: [Silence]
T: I just totally called you "honey," didn’t I?

Yeah, I did. It was exactly like one of the exchanges I've had altogether far too often with my own very loved - but very impatient with technology - wife.

It got really hot in that cubicle for a couple of seconds. And then we laughed our asses off.

Anchored By IT

I understand that the IT department does their best to help people solve problems and offer services that improve...

You're asleep already, aren't you?

Okay, the short version: The company IT department is a good thing, and what they do is meant to help. I'm totally on board with that. I used to be in the IT department. We weren't out to screw you, I promise.

Here's the deal, though:

There are a certain quantity of problems that need to be solved, and your computer has a fixed amount of capacity to solve them in. Your disk isn't getting any faster, your CPU isn't going to magically process at an extra gigahertz faster. You've got what you've got. With that, besides getting work done, you probably also want to:
  • Back things up - It'd be a shame if you lost your work.
  • Stop the spread of viruses - You don't want to get infected, now, do you?
  • Keep company data secure - If someone breaks into your car and steals your laptop while you're picking up donuts for the morning meeting at the store, they shouldn't get access to your proprietary data

Each of those things are valuable, but they also eat resources on your system. In some cases, not a trivial amount, either.

I have a 1.7GHz processor and 1.5GB of RAM. It's not a super powerhouse, but it should be enough to get the job done. It took me eight full minutes to boot up and log in this morning, and my machine is still tanked. Why?

Say you're getting ready to ride in a bike race. Your computer is your bike. "We got you a pretty decent bike," says IT, "This bike will definitely get you over the finish line." You look the bike over, check the specs, and take it out for a spin. Hell, yeah, that bike will do the trick.

"Now, it's a long race, so you're going to need some supplies. We're here to help you," says IT. And they are - it is a long race, and you do need some supplies. You're thinking maybe a couple of energy bars and some water.

"First we're going to strap this 30 gallon drum of water on your back. Yeah, it's pretty heavy, but you have a fast bike. Oh, and in the event you need to take a break and get off the bike, you don't want the bike rolling away (?!) so here's an anvil. It's okay, though, you have a fast bike. Oh, and we know the first leg of the race is basically a huge hill, but later in the race you'll want more high gears, so we replaced all of the low gears with high gears so you don't have to pedal as hard later on. But you have a pretty fast bike, so it should be okay."

You struggle onto your bike and it barely moves. No one seems to be terribly concerned about this, though, because, crap, man, you have a fast stinking bike so it has to be you causing the issue. And if you complain?

"Yeah, um, I need some water, but I really don't think I need a drum of water - I only need a water bottle."

"Well, you can give us back the drum of water, then."

"Can you give me a water bottle? I do need water, just not a drum."

"Um, no - all we have is a full drum of water. If you only want a bottle, you're on your own."


The cumulative effect of the daily incremental backup, real-time virus scanner, real-time disk encryption, and everything else that runs in the background to help me out is killing me. I booted up this morning and with the startup cost of all of these services, I'm surprised they don't send someone downstairs to personally punch me in the junk every morning, too. I mean, think about it - whenever I read or write a file, it goes through both a real-time AES 256 encryption and the real-time virus scanner, neither of which I have control to configure because it's all centrally administered "for us." I look sideways at this thing and the CPU is pegged and the disk light is on solid for three minutes.

But, hey, if I don't want to suffer the cost of the incremental backup software (that runs for probably an hour each morning), I can uninstall it. Is there any other backup mechanism? No - if I uninstall it, I'm on my own. Or I could set it to run when I'm not at work... but, oh, wait, you need to be connected to the network to have it run, and the whole point of my having a laptop is so I can take it home with me at night and work disconnected if I need to. There's no time when I'm not working on my computer that it's connected to the corporate network. (Not that it matters; I only have about a 30 - 50% success rate on completing a backup at any given point anyway.)

Don't get me wrong, I appreciate what the IT department does for me and they're a necessary piece of the puzzle. I just feel a little anchored down lately by all the help, is all, and I don't think folks consider the overhead of all of these helpful-but-necessary services before rolling them out.

New Sony DVDs Not Working In Some Players

Remember how I just bought a new DVD player because my old one wasn't playing movies? Now that I think about it, the movies it was having trouble with were Casino Royale and Stranger Than Fiction. The symptoms were basically the same as a bad disc - you put the disc in, the player tries and tries to read it to no avail, and you end up ejecting the disc.

From Slashdot...
"It seems that the most recent DVDs released by Sony — specifically Stranger Than Fiction, Casino Royale, and The Pursuit of Happyness — have some kind of 'feature' that makes them unplayable on many DVD players. This doesn't appear to be covered by the major media yet, but this link to a discussion over at Amazon gives a flavor of the problems people are experiencing. A blogger called Sony and was told the problem is with the new copy protection scheme, and they do not intend to fix it. Sony says it's up to the manufacturers to update their hardware."

Did I just buy a new DVD player because Sony screwed me?

At least I didn't buy a new Sony DVD player. It's a Samsung. :)

posted @ Monday, April 16, 2007 10:19 AM | Feedback (0) | Filed Under [ Media ]

Electronics Dying

I'm having a hell of a time with the electronics at my house lately.

Jenn's iPod has been having trouble syncing with the latest iTunes. Last Tuesday my Xbox gave me the Red Ring of Death. This weekend, my DVD player stopped reading discs and I encountered this awesome Windows Update issue where it pegs the processor at 100% for an indeterminate amount of time. Oh, and I think the connections for the center channel and the left rear channel on my receiver are going wonky.

Freaking awesome.

I'm starting to wonder if I'm coming upon that time where all of the warranties are failing or something - sort of like the seven minute conversation lull, but for electronics warranties.

There are a couple of positives to this, actually.

First, I picked up one of those DVD/VCR combos where the DVD is a recorder and can dub from VHS. (It also does high-def upconversion on both the DVD and VCR.) This is really cool because it allows me to take some of the videotapes we have of home movies and out-of-print stuff and convert to DVD. Tried it with my copy of The Maxx and it worked like a mad bandit. It also means one set of cables for two components - no longer do I need separate TV or receiver inputs for the DVD and the VCR. Very cool.

Second, it's giving me an opportunity to re-evaluate a lot of things. How the home theater is put together, for example. I have a lot of interesting ideas we can put into place by reorganizing things and moving older components that don't get a lot of use to other rooms (the CD player can move to a different room because we don't use it much and the DVD player can play CDs). I'm also looking at how much time we really spent with the Xbox, and it's a lot. While that thing is busted, I've played my other consoles, read books, put puzzles together, watched movies I've been wanting to watch for a while... It's sort of crazy how it's become such a central part of what I do in the evenings and it makes me wonder if that's really how it is or if I just get lazy after playing for a bit and could actually do all these other things even with the Xbox around.

Xbox Support should be sending me a box to return my Xbox for repairs sometime this week, hopefully by Wednesday. It'll be up to 10 business days before they send it back, then up to another five business days for it to arrive, so we're looking at nearly three weeks. Better make the most of it!

Of course, it does sort of put a damper on some of my media center plans, since I can't very well set up a media center connected to an Xbox without an Xbox.

Speaking of media center stuff, we were wandering around the mall this weekend and meandered past the Apple store. They had some Apple TVs on display and I showed Jenn how you could navigate around and listen to your music and such that you get from iTunes. (Unfortunately, it doesn't really do all the stuff I need it to, so it's not an option, though a well-configured Mac Mini might fit the bill. Anyway, I digress).

As we were looking at it, poking through the menus, Jenn turned and asked, "Is this is what you want to do with our movies?"

"Yes," I said. "I want to be able to navigate through, see the cover art, select a movie to watch, and watch it, all without having to search through the binders full of DVDs. This, right here, is precisely what I've been trying to do."

"Okay," she said, "I get it now. That will be very cool."

Breakthrough! I admit it was sort of hard to see the full effect when I showed her during my test run with Windows XP Media Center in a virtual machine over a wireless network, but I guess I assumed she was still getting the idea. Apparently not, but now she gets it and is on board.


Xbox 360 Red Ring of Death

Xbox 360 General Hardware FailureSonofabitch.

There I was, playing a little Marvel: Ultimate Alliance, when the Xbox locked up on me while loading the next level. It's happened before, so I turned the Xbox off (the control was unresponsive after several minutes) and turned it back on again.

And I saw the Red Ring of Death.

Apparently this is common enough to have a knowledge base article all to itself.

This is actually the second Xbox 360 I'll have had - my last one failed on my birthday last July. Different failure, but both times I've had to send it back to be fixed. Hopefully I won't have to go through the DRM hoops I had to go through last time to get my Xbox Live Arcade games to work on whatever console comes back to me.

posted @ Tuesday, April 10, 2007 9:52 PM | Feedback (0) | Filed Under [ Gaming ]

Xbox 360 QWERTY Keyboard; Dashboard Update; Sound Quality

A couple of Xbox 360 topics this morning.

Xbox 360 QWERTY Keyboard AttachmentFirst, from the Gamerscore Blog, we find that this summer they'll be releasing a miniature QWERTY keyboard attachment for your Xbox 360 controller. It was just last night I was complaining about the stupid virtual keyboard and having to run the thumbstick around to send a message. I'll definitely be picking one of these up.

You can see Flickr photos of the keyboard attachment as well as a press release about it and an upcoming dashboard update. (The feature I'm looking forward to in the dashboard update: "A richer Achievement notification pop-up will showcase the name of the unlocked Achievement and the gamerscore value without needing to leave the game to check the Achievements list.")

Second, something I've noticed lately is that in certain games and during certani music tracks, I'll hear a static/crackling sound when I have the sound running through my receiver. I don't hear the static when I listen to a CD or watch a DVD through the Xbox, I don't hear it in most games, and I don't hear it from any other component in my home theater - it's just certain bits of sound from games and digital media. I also don't really hear it when I listen through just the TV speakers via analog stereo connections.

I called Xbox Support about it to ask what the deal is. I explained the situation in detail (it took a while to get the details straight; I don't think they have very many people calling with complex issues) and after maybe half an hour on the phone, we arrived at two conclusions:

1) Certain games and sounds are not well optimized for digital output. Particularly in Xbox Live Arcade games (which is where I'm hearing the most static), QA doesn't always take the time to ensure that the sound is good on a high-resolution audio system. Since I'm not hearing it in all games and/or all media, it has to be a media/game specific problem that can be chalked up to bad sound engineering and QA.

2) I am a nitpicky perfectionist when it comes to audio/visual quality. Jenn doesn't hear the static until I point it out, but it's blaringly obvious to me. It makes me wonder if there is a lower population of Xbox 360 owners also having that Xbox 360 connected to a reasonably high quality home theater system where the problem will evidence itself. Regardless, once I hear the issue, I can't not hear it, so I just put up with it when it rears its ugly head. Again, it's not in all games, just a few. (Bejeweled 2 is a particular offender.)

Consider this a request to game companies and QA everywhere - test out your games not only on a standard user's low-end A/V system but also on a higher-end system to make sure your game holds up.

Gmail Inbox ATOM Feed

I may be the last to the party on this one, but I just noticed it through the automatic feed discovery mechanism in IE7 - Gmail has an ATOM feed of your inbox. Using this URL:


All you need to do is subscribe to it and log in using your Gmail credentials. That's pretty cool!

To The Guy Who Just Called Me...

...yes, I am absolutely positive that we do not manufacture chainsaw parts at Corillian.

3G iPod Borked by iTunes 7

I think Jenn's been hit by the iTunes 7 problem that a lot of other folks have seen. She has a 3G iPod and we recently updated to iTunes 7.x (I don't remember the exact version, but we had been putting off the upgrade for a while and finally bit the bullet fairly recently).

Anyway, I've had to replace the battery in that iPod once already, and it was, oh, within the last year or so, so the battery is good. What we're seeing is that she can play the iPod all day long - like six to eight hours - without issue on battery power alone, but the second she plugs it into iTunes to sync up, the screen flashes that the battery is dead and the iPod refuses to sync.

This happened after we saw the dreaded "1418 error" and I had to do some fancy footwork to restore the iPod. It's working now, but it won't sync.

I'm thinking we might be screwed, which sort of sucks. That iPod has given us years of good service and it's not broken, it just won't sync. I can't say I'm terribly pleased, but since I can't definitively pin the cause on the software, I can't really say there's no issue. Or can I?

Is this going to force me into an upgrade?

Not Feeling Accomplished

I don't really feel too great about this past weekend and I'm not sure that I can explain why in a way that most folks will understand. Let me give it a run and see how we fare.

There are three goals for me on any given weekend. I want to get a little more rest than I typically get throughout the week. I want to get the tasks done that I have to get done. I want to get something done that I want to get done.

The difference between those last two goals is subtle but important. The former is in respect to chores that you don't really want to do but you know need to get done. Cleaning up around the house, doing yard work, getting the shopping done. (Yeah, some people like yard work. Let's not argue semantics - there are things you don't like doing that you have to do. That's what I'm talking about.) The latter is in respect to the fun things - the things you want to do but never get enough time for. Reading comic books, playing video games, that sort of thing. Fun stuff.

I usually try to break the weekend up so that I work really hard on Saturday and get everything done that I have to get done and then on Sunday take it easy and do the things I want to get done. Jenn seems to like intermingling the two - do a little work, have a little fun, do a little more work... we end up at the same spot, but I usually don't feel like I'm having nearly as much fun if it's sandwiched in between work. I want to get the work done and then go have play time where I don't have to look forward to any work until Monday.

Now let me throw in there that I'm very much a task-driven individual and I need closure. I like being able to "check things off my list," so to speak. If there are ten things to do, I'll get all ten done, and when they're all done I've got closure on the set of tasks and I feel good. I feel accomplished.

With that in mind, here's how the weekend went:

Saturday I got up between 7:00a and 8:00a and went outside to pressure wash our awning in the back of the house. (It had mildewed over the winter so there's a blackish section on it that I was set to scrub off.) The weather wasn't great, but at least it wasn't raining. I got both Roombas and the Scooba running to clean the floor and headed out. (I noticed that one of the Roombas had run over something sticky - presumably cat vomit or something, so I had to clean that out before setting it loose. Freaking awesome.)

First I grabbed the ladder. The ladder sits in the corner of the garage by the garage door and every time I pull it out to use it, it gets snagged on this little wire that connects power to the sensor that stops the garage door from closing on, say, your pets as they run under the door. The builder never really secured the wire down, and the connections were just raw wire twists hanging out there, so I decided it was time to address that. A little electrical tape and some cable staples later, I had the ladder pulled out and in the backyard.

Next I grabbed the pressure washer and headed out back. Reeled out the awning, hooked up the pressure washer, and turned on the hose.

I was sort of curious why the pressure washer would have water running through it when it wasn't turned on - just the water was on - but it was something I borrowed from my parents who got it from my grandfather's estate when he passed and Granddad was sort of known for "jimmying" things that probably should have been thrown out anyway.

Turned on the pressure washer and the gun just started shooting water. There's a trigger on the gun for the washer, but it's apparently just there for show. That would have been nice to know before the thing started spraying around like a firehose. (Note: Every time I pressure wash, I borrow some relative's pressure washer and it's always some dicey deal like this. I'm not borrowing a pressure washer ever again. I'll be buying my own so I know it works.)

Of course, before I could get it under control, it shot this awesome clean spot into my back patio, so now I have this little clean section that stands out like writing in the dirt on a car that hasn't been washed. Faaaantastic.

Climbed up the ladder, took the pressure washer up, and started spraying.

Did you know that pressure washing doesn't remove mildew? I sure didn't. Try as I might, the pressure washer had somewhere around no effect. Brilliance.

Since I had the pressure washer out, one of the other jobs I knew needed to be done was to clean a few of the spots around the house that got dirty over the course of the winter. It was a pain, and I pressure washed both shoes and one leg in the process (damn that stupid gun that won't stop squirting!) but I got that part of things done.

I decided to try some shower cleaner on the mildew since, you know, shower cleaner is supposed to get rid of mildew. I sprayed it on, left it the prescribed amount of time, and used a push broom to scrub around on the awning. It mostly worked, though it only did about half the job. Even though it left a minty-fresh smell, I decided to go get some actual outdoor cleaner at Home Depot.

Picked up some stuff called "30 Seconds" which specifically says it'll work on mildew and is safe for vinyl. Exactly what I needed. Picked up that and a cheap one-gallon sprayer. (I have a five gallon stainless steel sprayer, but it's not really something you can haul easily up a ladder and my parents are using it right now anyway.)

Got it home and read the instructions. In the biggest, reddest letters on the package, it said, "THE SURFACE MUST BE DRY." Hmmm. It was crappy weather outside and had I just hosed the awning down. That wasn't going to be drying anytime soon, so I packed everything in.

That was probably two to three hours' worth of no awning getting cleaned right there. I'm all set to do it some other day, but I really didn't check much (except the cleaning of a couple of dirty spots on the house) off my list.

I then set about helping Jenn weed a section of flowerbeds along the side of our house. It was pretty well out of control and since the flowers have started blooming, the weeds have, too.

Jenn had been working on this the whole time I was busy not accomplishing anything with the pressure washer so she had it mostly under control. What she needed was someone to get the weed whacker and cut down this ridiculous grass area that borders our property and the people behind us. So I did that - got out the weed whacker and two 40' extension cords (that section is pretty far away from the closest outlet) and cut down that grass. Mostly.

I realized that wasn't going to do much but just make the grass short. It was damp out, so I couldn't spray Roundup on it, and even if I could, after a couple of weeks it comes back. I noticed when I was at Home Depot they had some extended treatment Roundup, so I made a mental note to pick that up next time I was there. That said, net zero on the grass area - the grass was shorter but not gone.

Of course, I had the weed whacker out, and another thing on the list was that the lawn needed to be edged. I set about doing just that and got about a third of the way done before I ran out of weed whacker string. I could have sworn we had a bunch of extra, but we didn't. Add that to the list of things to buy at Home Depot and chalk one more item up that I can't actually get done.

About that time we had to leave to go pick up some wedding photo reprints, so we brought everything in, got ourselves cleaned up and changed, and headed out on the town.

We went everywhere. We picked up our reprints, hit the mall, stopped at Toys R Us (I got a "Spider-Man Mr. Potato Head," which is pretty cool), and finally ended up at Fry's Electronics because I needed to get a cheap, low-capacity IDE hard drive for the media center computer I'm building. That (and the Potato Head) was the only thing I really wanted to get done in town.

Fry's doesn't carry cheap, low-capacity drives. I was looking for the sub-100GB, sub-$50 sort of thing. (Granted, cost was the primary driver here - if I had found a large-capacity drive for less than $50, that'd have been fine.) The cheapest drive they had was closer to $100 and was around 250GB. I realize that the market for the sort of drive I'm looking for is reasonably small, but come on. In the end, no hard drive. Gotta order that online.

The end of our journey on Saturday brought us to the video store to rent a movie. The only movie I really wanted to see that was out was Children of Men. Guess what movie they didn't have in stock.

Got home, ate some dinner, and watched Open Season. Good, funny, but not really what I was in the mood for. I liked it, but it left me... unfulfilled.

Bed time. Total tally of things I got done that were on my list of things to do: zero.

Woke up altogether too early on Sunday and decided to read a little. I'm reading Broken Angels right now and loving it. Jenn went downstairs to play some Xbox and I read for around two hours. That was nice and was definitely on my list of things I wanted to do.

Now, before I continue on Sunday, remember that I was really hoping to do things I had to do on Saturday and things I wanted to do on Sunday. Yeah, plans change, I get it, but I sort of figured I could at least skew the day towards the "things I wanted to do" side. I wanted to read my book, read some comics, play some Xbox (specifically finishing up the side missions on the game I'm playing), and put some shelves up in the office to arrange the myriad Star Wars stuff on.

Okay, so I read my book for a while and I was feeling pretty good about things. I took my shower and headed down to quickly pay my bills online and get on with the day.

Paying bills took far, far longer than it should have. Actually, it wasn't the bill paying that took the time - it was more the time spent gathering up paperwork and things that need to be submitted to the insurance company to get reimbursement for various expenses. It was stupid, lame, only-sort-of-accomplishing-something, mindless paper gathering. I hadn't realized it needed to be done, but there it was, and it wasn't doing itself. It took probably around an hour to get all that done. But that's okay - I've still got the whole day, right?

I was almost done with that when I ran upstairs to get something and noticed that where the Roomba had run on Saturday it really wasn't clean. A few minutes of inspection showed me that Roomba's brushes weren't spinning. Oh, wait - this is the Roomba that sucked up the cat vomit. Must have burned out the brush motor with the sticky whatever-it-was. Dammit.

I got what I went upstairs to get (I don't even remember what it was) then brought it and the Roomba down. I finished up the bills and got onto the iRobot web site to see if there were any troubleshooting steps that mentioned what to do if Roomba sucks up cat vomit. Interestingly enough, there's nothing about that. I searched out the support line just to find out they're not open Sundays, so I cobbled together a support email and sent that off.

About the time I was finishing that up, Jenn started taking the wedding photo reprints we picked up Saturday and putting them in the wedding album. Unfortunately, we couldn't find the paper that we wrote the order of the photos down in so we sat down together to figure it out again. Once that was done, the pictures had to be secured to the pages, then the pages had to be secured in the album. All of this "securing" got done by me with archival tape.

Now, I like the idea of scrapbooking and photo albums and such. It's a romantic notion where you can pore over the precious memories you made while immortalizing them in a creative way. In practice, though, not so much. This was a lot of tedious work and really was somewhere around zero fun. Oh, and it only took about two hours.

We were well into the afternoon by the time I got to play any Xbox. I put in Marvel: Ultimate Alliance and started running through the "training simulator missions" (which are basically these little side missions). I hadn't really run through any and was almost done with the storyline for the game so I figured now was the time to do it - before I finished the plot and wasn't able to come back and finish.

Some of the missions are fun, some are a little tedious, but they all contribute toward your characters' growth and, frankly, I love the Marvel universe so even the tedious ones were decent. The thing is, they all take about 10 - 15 minutes to complete and there are probably 30 of them. I got about two hours into that and decided to take a break, switching to some puzzle/arcade games I have.

Around three hours in, Jenn came down from doing whatever she was doing. (I think she was working on a pillow - a sewing project left over from Christmas.) I love Jenn dearly but she'll tell you herself that she can't go more than a couple of hours doing solo projects before she gets bored, so I was totally expecting her to come down, which usually means it's time for me to finish what I'm doing. Plus it was nearing dinner time, so I wrapped up what I was doing and started looking at food options.

(There are some that might argue I got freaking three hours to play and that's plenty for anyone. Sure I did. And, yeah, it's a lot of time. But in that time, try as I might, I really didn't accomplish - in the games - the goals I was trying to accomplish. Did I try for too much? Maybe. Did I feel like I "got my gaming in?" Not really, no.)

We ate dinner and watched Miss Congeniality 2, which wasn't a great movie and I wasn't terribly into it, but there wasn't really anything else on and it was getting too late to really want to start any new projects.

So, let's tally Sunday up: I really only count the reading in the morning toward the "things I want to do" list, though if you want to argue it, fine, I'll count my non-goal-attaining gaming session, too. I generally did more work than having fun, so no goal there.

All in all, I didn't really finish any of the work I set out to get done during the weekend and I didn't get much of the fun in, either. It was pretty much just a wasted weekend and I'm not feeling very accomplished at all.

Add to that the fact I'm trying to fight what could become a pretty major scope-creep issue on the project I'm working on and I'm struggling with some technical issues due to a couple of defects I've uncovered in tools we're using (neither of which are doing wonders for my mood and both of which stuck with me through the whole weekend) and I didn't really come out smiling this morning. I'm exhausted and I'm not having a good time.

Jenn, ever sympathetic before we went to sleep last night: "I don't know what's wrong with you - it seemed like every other weekend to me." Hmmm. Maybe it was. Maybe I set myself up for disappointment. Regardless, I'm going to need some serious chemical mood enhancement to get me through today. Time for the Monday-morning-two-hour-planning-meeting! Woohoo!