This blog is where I post about my consulting work with Microsoft Technologies, and other random tidbits that don't fit in my Photo Blog or my Iraq Blog.

Wednesday, September 22, 2010

Great tip on serving compressed CSS and Java Script files from Amazon S3

Fantastic performance tip on hosting compressed CSS and javascipt file from Amazon S3:

"Typically, I use a tool called Juicer ( http://github.com/cjohansen/juicer) to concatenate and compress my CSS and JavaScript files (with YUI Compressor and Google Closure Compiler, respectively) to ensure they're as small as possible and require the fewest number of HTTP requests ( http://developer.yahoo.com/performance/rules.html#num_http).

After that, I launch Terminal and run `gzip -9 filename.css && gzip -9 filename.js` to compress them as tightly as possible. This will give me filename.css.gz and filename.js.gz. I remove the .gz extension, and upload those files to S3.

Lastly, I add a custom HTTP header — `Content-Encoding: gzip` — to each of the files in S3. This tells the browser the same thing as Apache would if it were compressing them on the fly. The browser then knows to decompress the content after downloading it.

Since the files are pre-compressed instead of compressing on the fly (a la Apache), fewer server resources are used and the response times are faster. "

Original source: http://developer.amazonwebservices.com/connect/thread.jspa?messageID=194918&tstart=0#194918

Tuesday, September 14, 2010

Last day on the 3M VAS project

Today marks my last official day on the 3M VAS project (http://vas.3m.com).  It's been fun getting to develop a production site for a major company with Silverlight 4 and Azure!

Mike Hodnick, one of my colleagues on the development team has a nice wrap up post about the project on his blog:  http://hodnick.com/post/1121185443/vas3m

(Just to be clear: 3M VAS is very much alive and well.  This is just the end of a major release cycle and most of the development team is moving on to other projects.)

Tuesday, September 7, 2010

Moving to Google Voice as my primary public phone number

I've been playing around with Google Voice for a while know and I really like the speech to text transcription it does on voicemails, and so I've decided to start using it as my primary phone number for all business stuff.

Interesting to note how much Google and Amazon cloud stuff I use in my day to day life... and nothing from Microsoft... hmmm...

Friday, August 13, 2010

Desktop performance tweaking: using an SSD for ReadyBoost and Virtual Memory Paging File

Little known fact: Windows 7 CAN use an internal SSD drive for ReadyBoost.

Example scenario where it makes "some" sense: You have an existing Windows 7 desktop that could use a performance boost, but you don't have time to reinstall/migrate the boot drive to an SSD.

* Install a cheap SSD, and configure it for ReadyBoost (just right click on the drive the same as you would a USB Flash drive). NOTE: ReadyBoost will only use 4GB of the drive.

* Move your virtual memory paging file from the boot drive to the SSD.

* Move any data files you are working with actively to the SSD (such as source code if you are developer).

Total time to implement: About 10 minutes
Performance improvement: Noticeable/useful but not magical

Wednesday, July 7, 2010

BUG: VS2010 outsmarts itself and auto "fixes" references and breaks the build server!

Classic Problem: .NET project builds fine on local developers workstation but fails on the build server because the developer referenced DLL's that were in the GAC on their workstation but don't exist on the build server.

Classic (POOR) Solution #1: Install the files on the build server and add them to GAC. This "works" but it's a maintenance hassle and the build master may not want you to install obscure tool FooBar.dll on "his" build server.

Classic (BETTER) Solution #2: Create a lib directory (or whatever your local naming custom happens to be) in your source tree, copy FooBar.dll into the lib directory and change all of your references to point to the files in the lib folder instead of the GAC. Now the build server will get the dll's it needs from source control and your project should build happily. Problem Solved!

Insidious new VS2010 BUG (probably a "feature"): You try and solve the problem using Class Solution #2 above. You create a lib directory, you copy dll's into it, you delete the problem references, you recreate the problem references, you checkin your changes, and YOUR BUILD IS STILL BROKEN! WTF?

It turns out the Visual Studio 2010 believes it is smarter than you are! When you added your new reference by browsing to the dll, Visual Studio looked at the file and said "Ah ha!" is see the exact same dll in the GAC and I'll add the reference as a GAC reference instead because this stupid developer obviously doesn't understand the power and beauty that is the GAC!

Being an experienced .NET developer after several failed builds you smell a rat, and open the project file in notepad and see the following:

    <... stuff deleted for clarity ... />



    <... stuff deleted for clarity ... />

Now that dog don't hunt because System.Windows.Controls.Data.DataForm.Toolkit.dll and System.Windows.Controls.Toolkit.dll don't exist in the GAC on the build server.

You are SURE you changed both of those references to files references, and so you delete them and re-add them as file references again just to be sure. Same screwed up result...

And so now in frustration you manually edit the project file(s) like this (below) to create the file references that Visual Studio 2010 wouldn't let you create through the UI.

     <... stuff deleted for clarity ... />



     <... stuff deleted for clarity ... />

Success! Your solution builds on the build server!

And you are reminded yet again that GAC is evil...

Monday, July 5, 2010

Repo: fullscreen bug in Silverlight 4 crashes browser in 4 mouse clicks

This app is a demonstration of a bug in Silverlight 4 that will crash your browser in about 4 mouse clicks.

Instructions: Click the "Full Screen Toogle" button and close the resulting messagebox a few times and then... poof!  (you might want to bookmark the page first :-)

Here is the code to reproduce the bug:


using System.Windows;
using System.Windows.Controls;

namespace Silverlight.Fullscreen.Bug
    public partial class MainPage : UserControl
        private bool firstClick = true;

        public MainPage()

        private void button1_Click(object sender, RoutedEventArgs e)
            if (firstClick)
                //this firstclick logic is just a convienence so that you don't get a message box the first time the page opens
                //it is NOT need to reproduce the bug...
                image1.SizeChanged += Image_SizeChanged;
                firstClick = false;

            Application.Current.Host.Content.IsFullScreen = !Application.Current.Host.Content.IsFullScreen;

        private void Image_SizeChanged(object sender, SizeChangedEventArgs sizeChangedEventArgs)

UPDATE: This bug appears to be Windows specific. I can't reproduce it on a Mac...

Wednesday, June 9, 2010

What I'm working on: Image Analysis at 3M

I'm working on an interesting project at 3M.  The Visual Attention Service (https://vas.3m.com/) is an online service that will analyze an image and tell you what parts of the image a viewer is most likely to look at in the first few seconds.

A very useful thing in designing advertising... what will users notice first?  The surgeon generals warning or the 10% off coupon?

So here's a real world example of the tool in action:

If you are not familiar with this image it's a classic bit of software developer humor about compiling and testing code.

It turns out that the tool believes that most people will notice the scary monsters first NOT the kittens (as shown by the heat map below)...

DISCLAIMER: No kittens where actually harmed in the creation of this blog post.

Monday, May 24, 2010

Customer support issue: Installing Silverlight on the Mac

I was just dealing with an escalated end-user problem with a production Silverlight application here at *nameless* Fortune 500:

User:  I can't get your Silverlight app to install on my "new" Mac.

Support: What browser and OS version are you running.

User: I'm using Safari on a G5 tower running OSX 10 something.

Me:  Um... The G5 is a PowerPC based computer.  Apple announced their retirement in 2005, hasn't sold them since early 2006, and the current version of OSX doesn't install on them...  And no, Silverlight doesn't run on them either...


Wednesday, May 19, 2010

Solved: RIA Services work on development server but fail on IIS

I'm building a prototype Silverlight 4 application using the Silverlight Business Application template as a starting point (I chose this template so that I could get ASP.NET forms authentication working "quickly").

My test app worked fine in the development web server (aka Casini if you are old enough to remember that), but it didn't work in IIS.

After some digging I found this post: Deploying Application built using RIA Services RC which solved my problem.  Solution: disable basic and integrated (aka: NT) auth.

Details from Saurabh's post:  "WCF (and by association RIA Services) has a limitation that it does not support MultipleAuthenticationSchemas enabled in IIS. So if you are using Forms Authentication in your application (if you built your application using the Business Application template, Forms Auth is the default there) you need to make sure that for the IIS VirtualRoot that hosts your WebApp Forms Auth is enabled. Forms Auth + Anonymous will also work fine but Forms Auth + Integrated Auth is not supported."

Wednesday, March 31, 2010

The iPad and the future of "computers"

Eric Sink has a great post today discussing the future of computers:


The key points that caught my attention (paraphrased and reinterpreted by me):
  1. The iPhone and iPad represent a shift in the "computer" market towards simpler devices for consumers that do what they want and they can't screw up. These devices will start to meet the computing needs of most users. No need for a "real" computer, and no need to call your geeky relative to come fix it regularly.
  2. "Computers" as we know them today with numerous options and a high degree of complexity will become a niche product for a relatively small number of users with specialized needs.
  3. Microsoft is set to miss this seismic shift in the computer landscape.

Tuesday, February 2, 2010

Souce code for deleting Google/Gmail Contact Groups

Over a year ago I posted a little utility for deleting unwanted groups out of your Gmail Contacts.

Blog post here: http://blog.scrappydog.com/2009/01/deleting-4000-gmail-groups-or-repairing.html

Application install here: http://scrappydog.com/GoogleGroupCleanup/publish.htm

I wrote this for my own use because a bad replication tool had created 10,000+ bogus groups in my Contacts, and I REALLY didn't want to delete them by hand!

Apparently, it has saved a fair number of other people's bacon as well...

Today "Ben" asked if I could post the source code for my tool? And so here it is (not much to it):

using System;
using Google.GData.Contacts;

namespace GoogleGroupCleanup
class Program
static void Main(string[] args)
Console.WriteLine("Google Gmail Group Cleanup Tool");
Console.WriteLine("Written by: Eric Bowen (googlegroupcleanup@scrappydog.com)");
Console.WriteLine("This application is provided WITHOUT any guarantee. Use at your own risk.");
Console.WriteLine("This application will delete ALL groups from your Gmail account.");
Console.WriteLine("It will NOT delete any of your contacts or email.");
"This application deletes up to 1,000 groups at a time. If you have more than 1,000 groups to delete you will need to run it multiple times.");

Console.Write("Enter Google email address (this will not be stored): ");
string email = Console.ReadLine();

Console.Write("Enter Google password (this will not be stored): ");
string password = Console.ReadLine();

var service = new ContactsService("gmail-group-cleanup");
service.setUserCredentials(email, password);

var groupQuery = new GroupsQuery(GroupsQuery.CreateGroupsUri("default"));
groupQuery.NumberToRetrieve = 1000;
var groupsFeed = service.Query(groupQuery);

int counter = 0;
foreach (GroupEntry group in groupsFeed.Entries)

Console.WriteLine(counter.ToString() + " groups deleted");
catch (Exception ex)
Console.WriteLine("Press any key to exit");