Scott Hanselman

Coding4Fun Hardware Boneyard - Using the CueCat with .NET

September 16, '06 Comments [7] Posted in Coding4Fun | Programming
Sponsored By

In an ongoing Mardi Gras celebration of the soon-to-happen Coding4Fun Redesign, I got permission from the rockin' awesome Dan Fernandez to published a Coding4Fun article here on as an exclusive. This article will be republished on the new redesigned site very soon, along with a "Coding with the FingerPrint Reader" article and possible a fabulous super-secret IR/Robot/PowerShell article.

Dig up your CueCat and enjoy.

Coding4Fun Hardware Boneyard - Using the CueCat with .NET

Summary: In this rogue installment of "Some Assembly Required" column, Scott Hanselman borrows Travis Illig's CueCat BarCode scanner and creates a plugin for Windows Live Writer than lets him blog more easily about books he's reading. We decode the bar code info, change UPCs into ISBNs, call Amazon's Web Service via REST and integrate with Windows Live Writer all in one article. Whew!

The CueCat BarCode Scanner

180px-Cuecat1Here's what Wikipedia has to say about the CueCat BarCode scanner:

The :CueCat is a cat-themed handheld barcode reader developed in the late 1990s by the now-defunct DigitalConvergence Corporation, which connected to computers using the PS/2 keyboard port and later USB. The :CueCat enabled users to link to an Internet URL by scanning a barcode appearing in an article, catalog or on some other printed matter. In this way a user could be directed to a web page containing related information. The system that supported this functionality is no longer in operation.

Ah, nothing like the smell of obsolete hardware to get me thinking. You can get CueCats all over, there are millions of them, including on ebay. I asked around and my buddy Travis Illig loaned me his. It's ripe for hacking.

Decoding the CueCat Output

The CueCat speaks a funky encoded format that it "types" as if it were a keyboard. For all intents, it IS a keyboard as the PS2 version we're using is installed in series with your existing (if you have one) keyboard.

For example, my copy of Neil Gaiman's excellent "Stardust" produces this output:


Which can be broken up into a series of tokens, some are one character and some are two. The periods are delimiters, so we'll toss them for now.

 C3 n Z C3 n Z C3 n Z E3 r 0 Ch r 3 CN n Y EN r 7 C3 n 1 C3 P W D3 r Y Cx z Y Ch n Z

The first part is the serial number of CueCat itself, which freaked a log of privacy folks out in the past. The scanned barcode is actually the last part after the third . delimiter:

EN r 7 C3 n 1 C3 P W D3 r Y Cx z Y Ch n Z

Each of these tokens is a key to a lookup table. The encoding is pretty lame, and very arbitrary, but it confounded folks for a few hours at least. There's dozens of implementations of this decoding to be found on the Web, although none in .NET, which is where we come in. Here's a resource page that includes several implementations in C, Perl and Python, but it hasn't been updated in at least six years. There's also some very old but interesting discussion here

The lookup table looks like this (a C# example):

static Decoder()


    decodingTable = new Dictionary<string, int>[3];

    decodingTable[0] = new Dictionary<string, int>();

    decodingTable[1] = new Dictionary<string, int>();

    decodingTable[2] = new Dictionary<string, int>();


    decodingTable[0]["Z"] = 0;

    decodingTable[0]["Y"] = 1;

    decodingTable[0]["X"] = 2;

    decodingTable[0]["W"] = 3;

    decodingTable[0]["3"] = 4;

    decodingTable[0]["2"] = 5;

    decodingTable[0]["1"] = 6;

    decodingTable[0]["0"] = 7;

    decodingTable[0]["7"] = 8;

    decodingTable[0]["6"] = 9;


    decodingTable[1]["C3"] = 0;

    decodingTable[1]["CN"] = 1;

    decodingTable[1]["Cx"] = 2;

    decodingTable[1]["Ch"] = 3;

    decodingTable[1]["D3"] = 4;

    decodingTable[1]["DN"] = 5;

    decodingTable[1]["Dx"] = 6;

    decodingTable[1]["Dh"] = 7;

    decodingTable[1]["E3"] = 8;

    decodingTable[1]["EN"] = 9;


    decodingTable[2]["n"] = 0;

    decodingTable[2]["j"] = 1;

    decodingTable[2]["f"] = 2;

    decodingTable[2]["b"] = 3;

    decodingTable[2]["D"] = 4;

    decodingTable[2]["z"] = 5;

    decodingTable[2]["v"] = 6;

    decodingTable[2]["r"] = 7;

    decodingTable[2]["T"] = 8;

    decodingTable[2]["P"] = 9;



private static Dictionary<string, int>[] decodingTable;

See how some tokens are two chars and some are one? We'll run through the tokens testing to see if they are in each dictionary and creating the result. For my Gaiman book, we end up with:


Now what do we do with it?


Universal Product Codes or UPCs are different from ISBNs. This page at the Book-Scanning Project gave me the algorithm I needed to convert a UPC code into an ISBN that I could use to talk to Most books have a bar code with 13 digits starting with "978." Turns out that the first 3 digits of a UPC are the country of origin, but "978" is "Bookland." Apparently the UPC number for a book is called the "Bookland EAN."

Here's the Javascript taken from

if (indexisbn.indexOf("978") == 0) {
   isbn = isbn.substr(3,9);
   var xsum = 0;
   var add = 0;
   var i = 0;
   for (i = 0; i < 9; i++) {
        add = isbn.substr(i,1);
        xsum += (10 - i) * add;
   xsum %= 11;
   xsum = 11 - xsum;
   if (xsum == 10) { xsum = "X"; }
   if (xsum == 11) { xsum = "0"; }
   isbn += xsum;

Now, converted into C#

public static string ConvertUPCtoISBN(string code)


    if (code.StartsWith("978") == false)


        throw new ArgumentOutOfRangeException("UPCs that might be books have length 13 and start with 978");


    code = code.Substring(3,9);

    int xsum = 0;

    for (int i = 0; i < 9; i++)


        xsum += (10 - i) * int.Parse(code[i].ToString());



    xsum %= 11;

    xsum = 11 - xsum;


    String val = xsum.ToString();


    switch (xsum)


        case 10: val = "X"; break;

        case 11: val = "0"; break;



    code += val;

    return code; //Now an ISBN


So, my Gaiman UPC of 978006093471251300 turns into an ISBN of 0060934719. This ISBN can be used to talk to Amazon. Note that the source code to this article includes both C# and VB.

Calling Amazon's REST Web Service has a rich Web Services platform that includes formal SOAP-based Web Services, but for our project, their HTTP GET-based system will work nicely. I visited the Amazon Web Services Home Page and applied for a free Amazon Web Service Developer Key. You'll need to do the same if you want to get the code to work. Amazon has some create documentation on their site that makes this really easy.

I'll make an HTTP GET call to Amazon like this (broken up for readability):

This HTTP GET will result in an XML document as seen in this screenshot.


Ah! Just the kind of information I was looking for.

A CueCatConsole

Before we integrate with Windows Live Writer, let's make a little test console to make sure this all works together. I put the CueCatDecoder into a small reusable assembly and called it from the Console Application. I also pull the Amazon Web Services key from the configuration file. Note that VS.NET 2005 creates a strongly typed accessor for the "AWSAccessKeyId" automatically.

I've removed the error handling in this listing for clarity.

CueCatDecoder.Product product = null;

product = CueCatDecoder.Decoder.Decode(input);

Console.WriteLine("Type: {0}.", product.Type.ToString());

string amazonType = "ASIN";

string amazonUrl = String.Format("





System.Net.WebClient web = new WebClient();

string amazonData = web.DownloadString(amazonUrl);

XmlDocument xmlDocument = new XmlDocument();

XmlNamespaceManager xnm = new XmlNamespaceManager(xmlDocument.NameTable);

xnm.AddNamespace("def", "");

xmlDocument.Load(new System.IO.StringReader(amazonData));

XmlNode itemNode = xmlDocument.SelectSingleNode("/def:ItemLookupResponse/def:Items/def:Item", xnm);

Console.WriteLine(String.Format("FOUND a {0} called {1} by {2}",

        itemNode.SelectSingleNode("//def:ProductGroup", xnm).InnerText,

        itemNode.SelectSingleNode("//def:Title", xnm).InnerText,

        itemNode.SelectSingleNode("//def:Author", xnm).InnerText));

Notice that since the Amazon XML includes a default namespace, we have to let SelectSingleNode know about that namespace by registering a namespace prefix - in this case "def:" - that we use later in our XPath. There are many ways to query XML within the .NET Base Class Library that are faster, but for a small application like this the XmlDocument is a reasonable choice when performance doesn't matter.

Here's the output from my CueCatConsole:

Coding4Fun: CueCatDecoder by Scott Hanselman @
Scan item with CueCat now or press Q then Enter to exit
Type: ISBN.
FOUND a Book called The Goal: A Process of Ongoing Improvement by Eliyahu M. Goldratt
Scan item with CueCat now or press Q then Enter to exit
Type: ISBN.
FOUND a Book called Programming Sudoku (Technology in Action) by Wei-Meng Lee
Scan item with CueCat now or press Q then Enter to exit
Type: ISBN.
FOUND a Book called Stardust by Neil Gaiman
Scan item with CueCat now or press Q then Enter to exit

Fantastic. It works. Let's integrate it with Windows Live Writer, the new Offline Blogging Editor in BETA (at the time of this writing) from

Integrating with Windows Live Writer

Windows Live Writer (download) is a new desktop application that folks with blogs can use to write their blog posts offline. I use DasBlog for my blog at, and since DasBlog supports the standard MetaWebLog API also supported by Live Writer, I was in business right away.

Windows Live Writer also has an SDK that supports "Content Source Plugins" to extend the capabilities of the application and let folks insert new kinds of data. That's exactly what I want to do! I'd like to click "Blog about Book" and have the book title and author appear linked with an image of the book cover. I'd also like have the URL to include my Amazon Associates ID so I could make a few cents if someone clicks my link and buys the book.

Writing a plugin for Windows Live Writer couldn't be easier. The SDK includes step-by-step instructions. I created a class that derived from WindowsLive.Writer.Api.ContentSource and overrode the CreateContent method, returning my new snippet of HTML in the newContent string variable.

Here's the gist of the source, again with error handling removed for clarity. VB is included in the download.

using System;

using System.Collections.Generic;

using System.Windows.Forms;

using WindowsLive.Writer.Api;

using CueCatDecoder;


namespace AmazonLiveWriterPlugin


    [WriterPlugin("605EEA63-B74B-4e9d-A290-F5E9E8229FC1", "Amazon Links with CueCat",

        ImagePath = "Images.CueCat.png",

        PublisherUrl = "",

        Description = "Amazon Links with a CueCat.")]

    [InsertableContentSource("Amazon Links")]

    public class Plugin : ContentSource


        const string AMAZONASSOCIATESID = "amazonassociatesid";

        const string AMAZONWEBSERVICESID = "amazonwebservicesid";


        public override System.Windows.Forms.DialogResult CreateContent(System.Windows.Forms.IWin32Window dialogOwner, ref string newContent)


            using(InsertForm form = new InsertForm())


                form.AmazonAssociatesID = this.Options[AMAZONASSOCIATESID];

                form.AmazonWebServicesID = this.Options[AMAZONWEBSERVICESID];

                DialogResult result = form.ShowDialog();

                if (result == DialogResult.OK)


                    this.Options[AMAZONASSOCIATESID] = form.AmazonAssociatesID;

                    this.Options[AMAZONWEBSERVICESID] = form.AmazonWebServicesID;

                    Product p = Decoder.Decode(form.CueCatData);

                    AmazonBook book = AmazonBookPopulator.CreateAmazonProduct(p, form.AmazonWebServicesID);

                    string associatesId = form.AmazonAssociatesID.Trim();

                    string builtAmazonUrl = "<a href=\"{0}&tag={1}&camp=1789&creative=9325\">{2} by {3}</a><a href=\"{0}&tag={1}&camp=1789&creative=9325\"><img border=\"0\" src=\"{0}.01._AA_SCMZZZZZZZ_.jpg\"></a><img src=\"{1}&l=as2&o=1&a={0}\" width=\"1\" height=\"1\" border=\"0\" alt=\"\" style=\"border:none !important; margin:0px !important;\" />";

                    newContent = string.Format(builtAmazonUrl, book.ID, associatesId, book.Title, book.Author);


                return result;





Notice the crazy URL. Most folks with blogs become Amazon Associates to make a little money to pay for hosting (you won't get rich doing this, believe me). The Amazon Associates site includes link builders that create these complex snippets of HTML. I selected the large image, basic HTML option, then inserted String.Format tokens like {0} in the appropriate places.

Installation is simple, just copy Coding4Fun.AmazonLiveWriterPlugin.dll and Coding4Fun.CueCatDecoder.dll to C:\Program Files\Windows Live Writer\Plugins and they will be automatically detected.

Our plugin appears automatically in the Windows Live Writer sidebar. Notice the text and the icon was picked up from the Plugin class attributes. My Amazon Web Services ID and Associates ID are both stored internally by an Options bag managed by Windows Live Writer, making management of preferences very easy for the plugin developer. Once the CueCat data is scanned, we decode it and make the HTTP GET Web Services call using our external CueCat assembly created earlier.



There's things that could be extended, added, and improved on with this project. Here are some ideas to get you started:

  • Include support for CDs and other products available on Amazon.
  • Add support for more web-based databases with UPC codes.
  • Support different Amazon link styles. 
  • Create a system to print out product tags for a Garage Sale.

Have fun and have no fear when faced with the words - Some Assembly Required!

File Attachment: Hanselman Coding4Fun (74 KB)

Scott Hanselman is the Chief Architect at the Corillian Corporation, an eFinance enabler. He has thirteen years experience developing software in C, C++, VB, COM, and most recently in VB.NET and C#. Scott is proud to be both a Microsoft RD and Architecture MVP. He is co-author of Professional ASP.NET 2.0 with Bill Evjen, available on and Amazon. His thoughts on the Zen of .NET, Programming and Web Services can be found on his blog at He thanks his wife and 9 month old Z for indulging him in these hobbies!

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

Hanselminutes Podcast 32 - Mock Objects

September 14, '06 Comments [8] Posted in Podcast | Tools
Sponsored By

My thirty-second Podcast is up. This episode is about Mock Objects - what they are, and should you care?

We're listed in the iTunes Podcast Directory, so I encourage you to subscribe with a single click (two in Firefox) with the button below. For those of you on slower connections there are lo-fi and torrent-based versions as well.

Subscribe: Feed-icon-16x16 Subscribe to my Podcast in iTunes

Links from the show are also always on the show site. Do also remember the archives are always up and they have PDF Transcripts, a little known feature that show up a few weeks after each show.

Links from the Show

RhinoMocks (i0t)
TypeMock (i5b)
Ayende Rahien (i5d)
EasyMock.NET (i57)
Example of using TypeMock (i5c)
IBM - Unit Testing with Mocks (i0p)
NMock2 (i58)
NUnit2 Mocks (i5e)
NMock vs. NMock2 Comparison (i59)
Roy Osherove on NMock2 (i5a)
We have a new sponsor this show, Aspose, the .NET and Java Component Publisher. They produce a wide variety of components with versions in both .NET and Java. Do check out their Aspose Demo Downloads as they have a huge catalog of tools to explore.

Our sponsors are Apose, CodeSmith Tools and the .NET Dev Journal. There's a $100 off CodeSmith coupon for Hanselminutes listeners - it's coupon code HM100. Spread the word, now's the time to buy.

As I've said before this show comes to you with the audio expertise and stewardship of Carl Franklin. The name comes from Travis Illig, but the goal of the show is simple. Avoid wasting the listener's time. (and make the commute less boring)

  • The basic MP3 feed is here, and the iPod friendly one is here. There's a number of other ways you can get it (streaming, straight download, etc) that are all up on the site just below the fold. I use iTunes, myself, to listen to most podcasts, but I also use FeedDemon and it's built in support.
  • Note that for now, because of bandwidth constraints, the feeds always have just the current show. If you want to get an old show (and because many Podcasting Clients aren't smart enough to not download the file more than once) you can always find them at
  • I have, and will, also include the enclosures to this feed you're reading, so if you're already subscribed to ComputerZen and you're not interested in cluttering your life with another feed, you have the choice to get the 'cast as well.
  • If there's a topic you'd like to hear, perhaps one that is better spoken than presented on a blog, or a great tool you can't live without, contact me and I'll get it in the queue!

Enjoy. Who knows what'll happen in the next show?

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

IE7 RC1 can't update Password Protected Feeds

September 13, '06 Comments [13] Posted in ASP.NET | Programming | Tools | Web Services
Sponsored By

UPDATE: Niall Kennedy blogs about accessing private feeds, but doesn't mention that IE7 and Office 2007 doesn't support it. Dare posts about Niall's post and has an interesting comment "At the end of the day, can Bank of America trust that RSS Bandit or Bloglines is doing a good job of adequately protecting the feed from spyware or malicious hackers?"

Of course they can't, just as BofA can't control that I might use any old HTTP stack to talk to their regular website. Angle brackets over HTTP are just that. RSS just makes them more regular and a little easier to parse. I would propose within the context of banking, keying off Dare's comment, that OFX and RSS are arguably the same thing with RSS just being more presentation focused. OFX being pulled into Microsoft Money and Yodlee is no different from RSS being pulled into RSS Bandit or Bloglines.

More on this topic at this post...

This is news that I'm apparently late to the party on:

Internet Explorer is unable to update password-protected feeds.

In IE7RC1, it let me subscribe happily with a password dialog and added my feed. Only when I returned a day later did I find my stale content wasn't updating.

That's going to make things like and other password protected feeds difficult to work with in IE7. I hope the get this handled for the release.

Does anyone else think this is a huge problem? Is this just IE7 or is this the whole RSS Platform? If it is the platform, I think this makes personalized RSS content considerably more difficult.

There's been some news on this before over at GlobeBlogger, who noted as I did with considerable shock, that Outlook 2007 isn't using the RSS Platform.

The RSS Team PM Sean Lyndersay responded here to Charlie Wood's email. He says (edited for length)

To be honest, it was simply a casualty of time/resources vs. demand. There aren't a lot of authenticated feeds out there (yet). When we looked at the cost of doing it, we decided that it was something that could wait until our next release.

Outlook 2007 doesn't use the RSS Platform for downloading feeds, but they made fundamentally the same decision as we did (weighing resources against demand), and they don't support authenticated feeds either.

In both cases (IE/RSS Platform, and Outlook 2007), we support what's called NTLM/Kerberos pass-through authentication — which means that in many corporate environments where NTLM/Kerberos authentication is used (typically with Windows domains), the credentials that the user used to log into the machine will be automatically used. This allows authenticated feeds to work in a lot of corporate environments.

Both IE/RSS Platform and Outlook 2007 do support SSL-encrypted feeds. We also have found that many people who ask for authenticated feeds really want personalized feeds (where the data is public, but the feed itself is personalized to a particular user) — in these cases, we recommend generating URLs with guids or another unique identifier for each user.

So, to summarize:

  • We don't support storing different credentials for different feeds.
  • We do support NTLM/Kerberos pass-through for using the users logged-in credentials
  • We do support SSL-encrypted feeds
  • We recommend using personalized feeds, where possible.
  • As for when we will have authenticated feed support: I don't have an answer for you on that. We haven't announced a date for our next release.

Hope this is helpful.


With all due respect to Sean and his team, I hope that they hear our concern about this huge omission and realize that truly authenticated feeds will allow RSS to realize it's full potential.

Dare Obasanjo realizes how HUGE this could be and what a HUGE GOOF it is to not include support out of the gate. Authenticated feeds could change the game entirely (emphasis mine):

No support for password protected feeds. The number of password protected feeds on the Web continues to grow, Web sites such as GMail and LiveJournal provide authenticated feeds for users today. As the usage of syndication technologies like RSS continues to grow, the need to support authentication by feed readers will also grow as well. I can imagine a day when I can subscribe to a password protected feed from my bank or credit card company. Not having support for this today is a non-starter.

Please, discuss, I'm interested in your thoughts, dear reader. If you agree that this is important for the future of the spec and the continued usefulness of Feed technology, do put pressure on them.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

DNRTV - Sysinternals Tools

September 11, '06 Comments [6] Posted in Podcast | Screencasts | Tools
Sponsored By

I recorded an episode of DNRTV, Carl's ".NET Rocks" Screencast recently. This episode is on exclusively on Sysinternals tools. While certainly no replacement for the Sysinternals Video Library, we did cover quite a big of ground in less than an hour. Check it out. You might recognize a number of the tools and tricks from the Developer Producitivity Tools Videos. Forgive my slowness in these videos as I was on Carl's machine over VNC and didn't have all my hotkeys and speedy goodness installed.

DotNetRocks TV - Show #35 | 9/10/2006

Scott Hanselman on Sysinternals Tools

Play Flash Version in the BrowserOSubscribe with PwopCatcher (read more below)ur good friend Scott Hanselman pays us a visit to show us the nitty gritty of  some of his favorite Sysinternals tools. 
Download zipped video Download Torrent to Zip

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

Active ASP.NET Blogging Engines

September 8, '06 Comments [16] Posted in DasBlog
Sponsored By

Dasblog_splashJust stumbled on this post from "The Rabid Paladin." I wanted to clarify to a few things that he brings up in the post.

The front-runners in the .NET space for blogging software appear to be SubText and DasBlog--both are branches from their progenitor .Text which appears to be defunct. Unfortunately, since .Text was originally ASP.NET 1.1, both SubText and DasBlog are rooted in that technology. They both support custom themes, but they had to hack ASP.NET 1.1 to do so--mostly with custom controls.

DasBlog is a ongoing fork from BlogX, not .Text. Neither SubText nor DasBlog are "rooted" in ASP.NET 1.1 (not sure how one would root in a particular version of ASP.NET), both run happily under 2.0 and both have 'more native' 2.0 versions in development. DasBlog's theming isn't based on custom controls, it's a Radio Userland-style macro language so Mort can write his or her own themes without coding. It's true that there's lots of ways to architect themes and skins, including, but not limited to, the built in ASP.NET 2.0 theming.

I was originally drawn more to DasBlog because I've become a fan of Scott Hanselman--first from his podcasts, Hanselminutes, but later to his blog (which actually uses DasBlog, kudos for eating the dinner you've made). He's one of those over-producers who seems to have his hand in on fifteen million things at a time and is able to simultaneously talk about it all.

However, DasBlog's main website is frequently down, and there doesn't appear to be a lot of action in the form of improvements, releases, news, or updates. Which makes me wonder if it isn't a dying product, suffering from Scott's hyper interests.

Thanks for the kind words about the podcast! Our DasBlog website has been down occasionally because it's run from the basement of a very kind volunteer, but it being down shouldn't necessarily reflect poorly on the hard work the team has done.

We do have two sites:

On the "not a lot of action" point, I'm a little surprised by that. Have you read my blog over the last 6 months? There's a lot of activity:

We're just releasing 1.9 soon, we've got daily builds every day, we've added literally dozens of (we think) cutting edge features ( and are working on the roadmap for the .NET Framework 3.0 version.

And I stress we - There's an active group of a dozen or so contributors who are continuing to make DasBlog a great platform. It's not just me.

Here's a post on how to contribute to a project like DasBlog. Since the 'how to patch' post, dozens of patches have been added, many bug fixed. We also ship with 23 themes to choose from and more are on the way. The team is more active now then it's ever been and we're looking forward to the future.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.