<?xml version="1.0" ?>
<rss version="2.0" 
	xmlns:dc="http://purl.org/dc/elements/1.1/" 
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:georss="http://www.georss.org/georss/">
	<channel>
		<title>Code on the Road - The Expat Software blog</title>
		<link>http://www.expatsoftware.com/articles/</link>
		<description>A laptop, some ideas, and a one-way ticket.</description>
		<dc:language>en-US</dc:language>
		<dc:creator></dc:creator>
		<copyright>Copyright © 2013, Expat Software</copyright>
		<sy:updatePeriod>daily</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
		<sy:updateBase>1</sy:updateBase>
		
				<item>
					<title><![CDATA[A/B Split Testing for ASP.NET]]></title>
					<description><![CDATA[Common knowledge:  You need to do A/B testing on your site.
<p/>
Why?  Because it will make you more money.
<p/>
Cool, but why?  Because if your business sells things on the web or otherwise makes you money as a result of people doing stuff on your website, you want to maximize the percentage of people doing stuff.  That's where A/B testing comes in.
<p/>
<h2>
What is it?
</h2>
<p/>
Basically, if you <b>test one version of your website against another version</b>, you can <b>measure which one better compels users to do something.</b>
So, for example, you might try testing your normal "Buy Now" button against a double-sized, bright red shiny button. You'd show one version to half your visitors, the other version to the other half. Pay attention to who saw which version, and whether they actually bought your thing.
<p/>
After a week or so collecting data, you can see that, for example, 4.8% of visitors seeing your old button clicked it, whereas 6.6% of those who saw the big red one clicked it. That's valuable. As in, <b>measurable in dollars</b> valuable, so you need to be doing it.
<p/>

<h2>
How to do it
</h2>
<p/>

To do A/B testing right, you need to run it from the web server.  There are tools out there that give you javascript code that Marketing will try to convince you to paste into your site, but don't do it.  It would take an entire article just to explain all the ways that's a bad idea.
<p/>

It's not too hard to code something up yourself, but there are some good libraries out there that you can simply drop in.  I'm writing this post to tell you about the one I wrote for ASP.NET and ASP.NET MVC:
<p/>

<a href="http://www.fairtutor.com/fairlycertain/">FairlyCertain - A/B Split Testing for ASP.NET</a>
<p/>
I've been using this for the past 6 months for <a href="http://www.s3stat.com">S3stat</a> and <a href="http://www.fairtutor.com">FairTutor</a>, with some pretty impressive results. Now that it's good and stable, I finally motivated myself to package it up and release it as Open Source.
<p/>
It's essentially a simplified version of Rails' <a href="http://www.bingocardcreator.com/abingo">A/Bingo</a>, with one major departure in that participation data is stored in the users' browser rather than a local database. That helps it scale out better and means that you can pretty much just drop the code into your project and have it start working without having to configure anything.
<p/>
Check it out and let me know if you find it useful.
<p/>
<div style="border:solid 1px #ccc;background-color:#f0f0f0;padding:5px;font-size:90%;">
<img src="http://cdn.fairtutor.com/images/girl_on_tan.gif" border=0 style="border:none;float:right;margin-left:20px;"/>
<a href="http://www.fairtutor.com/">FairTutor</a> is our latest project here at Expat.  It's a website that connects Spanish teachers in South America with students in the US and lets them hold <a href="http://www.fairtutor.com/">live Spanish classes online</a>.  
<p/>
We'll be starting Beta classes soon, so if you want to score some free Spanish lessons, you might want to go <a href="http://www.fairtutor.com/Setup/RequestInvite.aspx">sign up for the waiting list</a>!
</div>

]]></description>
					<author><![CDATA[Jason Kester]]></author>
					<pubDate>Tue, 07 Dec 2010 05:33:46 GMT</pubDate> 
					<link>http://www.expatsoftware.com/Articles/ab-split-testing-for-asp-net</link>
					<guid isPermaLink="true">http://www.expatsoftware.com/Articles/ab-split-testing-for-asp-net</guid> 
					<slash:comments>0</slash:comments>
				</item>
			
				<item>
					<title><![CDATA[Cloudfront Streaming Analytics from S3stat]]></title>
					<description><![CDATA[We're happy to announce that S3stat now offers support for CloudFront Streaming distributions. We've offered <a href="http://www.s3stat.com/">S3 and CloudFront Analytics</a> for quite a while, so it was an easy decision to extend the service to include Streaming . 
<p/>
Basically, we'll handle all the setup and configuration needed to get Logging enabled on your CloudFront distribution, and each night we'll download and process those logfiles, and deliver reports back to your S3 bucket. 
<p/>
<a href="http://www.s3stat.com/" title="Web Log Analysis and Statistics for Cloudfront and Amazon S3" style="display:block;float:right;margin-left:20px;font-style:normal;text-align:center;font-size:80%;"><img src="http://www.s3stat.com/images/logo_low_short.gif" border="0" style="border-width:0px!important;" alt="Web Log Analysis and Statistics for Cloudfront and Amazon S3"/><br>Web Stats for Cloudfront & Amazon S3</a> 
This feature has been out of Beta for about a week, so go ahead and give it a try when you get a chance. I'd love to hear your feedback. 
]]></description>
					<author><![CDATA[Jason Kester]]></author>
					<pubDate>Tue, 15 Jun 2010 06:49:21 GMT</pubDate> 
					<link>http://www.expatsoftware.com/Articles/2010/06/cloudfront-streaming-analytics-from-s3stat</link>
					<guid isPermaLink="true">http://www.expatsoftware.com/Articles/2010/06/cloudfront-streaming-analytics-from-s3stat</guid> 
					<slash:comments>0</slash:comments>
				</item>
			
				<item>
					<title><![CDATA[Care and feeding of Happy Spammers (the joys of running a Zero-Spam public blog host in 2010)]]></title>
					<description><![CDATA[<style>
   .purple
   {
font-weight:bold;
    color:#a200db;
   }
   .green,.filtered
   {
font-weight:bold;
    color:#00e800;
   }
   .blue,.retro
   {
font-weight:bold;
    color:#00a8ff;
   }
   .red,.known
   {
font-weight:bold;
    color:#f5302f;
   }
   .gold,.notick
   {
font-weight:bold;
    color:#f4b34b;
   }
</style>   
I remember the day I got my first Spam post at <a href="http://www.blogabond.com/">Blogabond</a>, back in 2005.  It was actually kind of flattering, since the site had only been live for a few months.  I deleted it by hand and moved on.
<p/>
<img src="http://img.expatsoftware.com/blog/spam-chart-320.gif" width="320" style="float:right;margin-left:10px;"/>
Things have progressed substantially since then.  Automated Spam Bots gave way to armies of cheap workers posting by hand, and now we've reached a point where roughly 90% of new blog entries on the site are attempted spam.  The sheer volume of posts coming in is enough to sneak some of them past the <a href="http://www.expatsoftware.com/articles/2008/02/naive-bayesian-spam-filter-for-c.html">Bayesian Filtering</a> we have in place, so we're lucky to have some extra measures in place to make sure that the general public never sees any spam on Blogabond.
<p/>
I've learned a lot about Blog Spam over the years, so I thought I'd share some advice for anybody building their own user-generated-content site.  Presuming, of course, that you don't want to be overrun with spam.
<p/>

<h3>Collect Everything</h3>
<p/>
<b>Never throw spam away</b>.  It's valuable.  You need tons of spam to train your Bayesian filters, and you need to use real spam from your own site to get the filtering results you want.  Our filters, for example, can differentiate between a post written by a <a href="http://www.blogabond.com/guatemala">backpacker traveling through Guatemala</a> and a resort offering package vacations there.
<p/>
Mark posts as spam and ensure that nobody can see them, but keep them around.  They're handy!
<p/>

<h3>Classify your Users</h3>
<p/>
At Blogabond, we have the concept of a "Trusted User", whose posts we're comfortable showing on our front page, in RSS feeds, sitemaps, location searches, etc.  The only way to become Trusted is to have a moderator flip you there by hand after reading enough of your posts.  Everybody else is either a Known Spammer or simply Unknown.  
<p/>
These classifications are the main reason that the average person will never see any spam on Blogabond.  All publicly browsable content is from Trusted Users, so the only way to see something from an Unknown user is to go to the URL directly.  That means that you can start a new blog today and send out a link that people can use to see what you've written, but until you've convinced us you're trustworthy we're not going to let people off the street stumble across your stuff.
<p/>
 
<h3>Never Give Feedback</h3>
<p/>
The last thing you want to tell a Spammer is that his post was rejected as spam.  Never tell him that his account has been disabled.  Let him figure these things out on his own, hopefully after a lot of wasted time and effort.  
<p/>
Pages with spam content return a 404 (Not Found) to anybody accessing it from outside the author's IP block.  That way, the author can (mistakenly) verify that it's live, while the rest of the world and Google never get to see it. 
<p/>

<h3>Never Show Untrusted Content to Google</h3>
<p/>
The whole point of blog spam is SEO.  Once Google gets ahold of a post, the game is over and the spammer has won.  The worst thing you can do is blindly trust your spam filters to keep spam off your site and out of Google's index.
<p/>
Assuming you're categorizing your users, this is simple.  If it's from a Trusted User, it goes to places that Google can see it.  If not, it doesn't.  Sorted.
<p/>

<h3>Maximize Collateral Damage</h3>
<p/>
Stack the deck so that every action a Spammer takes increases the odds that he'll undo all his previous work.
<p/>
When we flag something as spam, we also go back and flag everything in the past that came from that User and from his IP Address Block (as well as poisoning that IPBlock and User in the future).  So while he may get lucky and sneak a post through the filter on his first try, chances he'll end up retroactively flagging that post as spam if he presses his luck.
<p/>
We can actually watch as new messages drop onto the "Maybe Ham" pile, then mysteriously disappear a few minutes later.  In essence, the spammer is cleaning up his own mess.

<p/>
<h3>Automate Everything</h3>
<p/>
You're going to get a lot of spam, so you need tools to make it really easy to moderate it if you want to stay happy.   Our Spam Dashboard has a view showing snippets from every recent post that lets us flag an item with a single click (in a speedy, AJAX fashion).  I'll spend maybe a minute a day running down that list turning Maybe's into Spam, and occasionally marking a new user as Trusted.
<p/>
We also have a pretty view of everything that's been marked as spam recently, along with reasons why and daily stats to see how well we're doing:
<p/>
<a href="http://img.expatsoftware.com/blog/spam-dashboard-1-1024.gif">
<img src="http://img.expatsoftware.com/blog/spam-dashboard-1-520.gif" width="520" style="border:solid 1px #ccc;padding:0px;"/></a>
<p/>

That's a screenshot from our Spam Dashboard this morning.  As you can see, we're doing pretty well.
<p/>
<span class="green">GREEN</span> items are ones recently caught by the filter, <span class="red">RED</span> items are attempts by a Known Spammer to post something, and items that have been retroactively flagged (from the spammer pushing his luck too far) are shown in <span class="blue">BLUE</span>.  <span class="purple">PURPLE</span> items (none shown) are ones that we had to flag by hand because they made it past the filter.
<p/>
In this shot, you can see a busy spammer creating new accounts, posting enough blog entries to trip the filter and undo all his efforts, then creating a new account and trying again.
<p/>

<h3>Filter Ruthlessly</h3>
<p/>
There are two categories of people using your site:  Real Users and Spammers.  When you first start out, you tend to see it less as two distinct groups and more as a broad spectrum with some people falling in between.  The longer you run a site, the more you come to realize that no, there are no Real Users with "good intentions" who are mistakenly posting commercial links on your site.  Those people are spammers.
So don't hesitate to flag anything that looks even a little bit fishy.  Woman talking about her fabulous Caribbean Cruise out of the blue?  Spam.  Random person posting poetry in China?  Spam.  Guy from India who really wants to tell you about his hometown?  Spam.
<p/>
And how do you know you were right?  Because you will never hear complaints from any of those people.  We've labeled thousands and thousands of "bloggers" as Spammers over the years, and so far I've heard back from exactly one of them.  Spammers know that what they're doing is Bad Behavior.  When you shut down their account, they'll know why.
<p/>

<h3>Make the Spammers feel successful</h3>
<p/>
Spammers will put in a surprising amount of effort to get their posts past your spam filter.  The harder you fight back, the harder they'll try.  Once they've found something that works, however, they'll sit back and watch the posts flow.  That's the place you want them, happily sending post after post into your Spam corpus and training your Bayesian filters.
<p/>
A happy spammer is a spammer who's not going to spend any more time trying to work your system.  A happy spammer is reporting success to his boss and costing the bad guys money.  A happy spammer is constantly teaching your filter about new trends in the spam world so that it can do its job better.
<p/>
You want to cultivate a community of happy spammers on your site.]]></description>
					<author><![CDATA[Jason Kester]]></author>
					<pubDate>Fri, 12 Mar 2010 14:56:00 GMT</pubDate> 
					<link>http://www.expatsoftware.com/Articles/2010/03/care-and-feeding-of-happy-spammer</link>
					<guid isPermaLink="true">http://www.expatsoftware.com/Articles/2010/03/care-and-feeding-of-happy-spammer</guid> 
					<slash:comments>0</slash:comments>
				</item>
			
				<item>
					<title><![CDATA[Why Internationalization is Hopelessly Broken in ASP.NET]]></title>
					<description><![CDATA[I wrote an <a href="http://www.expatsoftware.com/articles/2010/03/fixing-internationalization-in-aspnet.html">article last week</a> describing ASP.NET's Internationalization (i18n) scheme in less than favorable terms, and it occurs to me that I should probably offer up a proper justification if I'm going to start throwing terms like 'Hopelessly Broken' around.
<p/>
As several members of the ASP.NET community <a href="http://blogs.ipona.com/davids/archive/2010/03/02/fixing-internationalisation-in-asp.net.aspx">so eloquently pointed out</a> in response to that article, ASP.NET does in fact offer a way to translate web sites from one language to another, and it does indeed work perfectly fine, thank you very much.  That fact, I omitted to mention last week, is not in dispute and I apologize for implying as much.
<p/>
To clarify, I don't mean to say that ASP.NET i18n is Hopelessly Broken to the point where it's not possible to do it, but rather that ASP.NET handles i18n in a fashion that is demonstrably worse than the accepted industry standard way of doing things which, incidentally, pre-dates ASP.NET.
<p/>
<h2>Here's why.</h2>
<p/>
First, let me give a quick rundown on the industry standard way of localizing websites: <a href="http://www.gnu.org/software/gettext/">gettext</a>.  It's a set of tools from the GNU folks that can be used to translate text in computer programs.  The ever-humble GNU crowd have a <a href="http://www.gnu.org/software/gettext/manual/gettext.html#Why">lot of documentation</a> you can read about these tools explaining why they're so well suited for i18n and how they're a milestone in the history of computer science and incidentally how much smarter the GNU folks are than, say, you. And why you should be using emacs.  
<p/>
But anyway, to demonstrate why the gettext way of doing things makes so much more sense than the Microsoft way, let me run down a short list of the things you need to do to translate a website.  For each task, I'll give an indication of how ASP.NET would have you do it, along with how you'd do it using hacky fixes I've put in place for the <a href="http://www.fairtutor.com/fairlylocal">FairlyLocal library</a> I discussed at length last week.  Also, if there's a difference, I'll talk briefly about how "Everybody Else" (meaning gettext, which is in fact used by Everybody Else in the world to localize text) does it.
<p/>
<div class="comparison">
<h4>Identifying strings that should be marked for translation</h4>
<b>ASP.NET</b>: Find them by hand
<br/>
<b>FairlyLocal</b>: Find them by hand 
<br/>
<b>Everybody Else</b>: Find them by hand, (unless you're using a language that supports the emacs gettext commands for finding text and wrapping them automatically)
<p/>
<h4>Marking text for translation in code</h4>
<b>ASP.NET</b>: Ensure that they're wrapped in some form of runat="server" control
<br/>
<b>FairlyLocal</b>: Wrap with _() 
<br/>
<b>Everybody Else</b>: Wrap with _()
<p/>
ASP.NET actually does offer one advantage here, in that many of the text messages in need of translation will already be surrounded by a runat="server" control of some description.  Unfortunately, that advantage is compensated for by the sheer amount of typing (or copy/pasting or Regex Replacing) involved in surrounding all the static text in your application with "&lt;asp:literal runat="server">&lt;/asp:literal>", and by the computational overhead involved in instantiating Control objects for every one of those text fragments.
<p/>
Everybody Else gets to suffer through the steady-state habit of surrounding all their text with _(""), or with a long copy/paste or Regex Replace session similar to the ASP.NET experience.  It's still not all that much fun, but at least it's less typing.
<p/>

<h4>Compiling a list of text fragments for use in translation</h4>
<b>ASP.NET</b>: Pull up each file in Design View, right click and select Create Local Resources
<br/>
<b>FairlyLocal</b>: Build the project (thus running xgettext automatically)
<br/>
<b>Everybody Else</b>: run xgettext
<p/>
ASP.NET uses a proprietary XML file format called .resx, which is incomprehensible to humans in its raw form, but has an editor in Visual Studio.NET.  Everybody Else uses .po files, which is a text format that's simple enough to be read and edited by non-technical translators, but there are also a variety of good standalone editors available.
<p/>




<h4>Updating that list of text fragments as code changes</h4>
<b>ASP.NET</b>: Pull up each file in Design View (again), right click and select Create Local Resources (again)
<br/>
<b>FairlyLocal</b>: Build the project (thus running xgettext automatically (again))
<br/>
<b>Everybody Else</b>: run xgettext again

<h4>Specifying languages for translation:</h4>
<b>ASP.NET</b>: Copy the .resx file for each page on your site to a language-specific version, such as .es-ES.resx.
<br/>
<b>FairlyLocal</b> and <b>Everybody Else</b>: create a language-specific folder under /locale and copy a single .po file there.
<p/>
Surely there must be a tool to copy and rename the hundreds of locale-specific .resx files that ASP.NET needs for every single language, but I haven't found it yet.  Please ASP.NET camp, point me in the right direction here so I don't need to go off on a rant about this one…
<p/>

<h4>Translating strings from one language to another</h4>
<b>ASP.NET</b>: Translator opens the project in Visual Studio.NET (seriously!) so that he can use the .resx editor there to edit the cryptic XML files containing the text.  
<br/>
<b>FairlyLocal</b> & <b>Everybody Else</b>: Give your translator a .po file and have him edit it as text or with a 3rd party tool such as <a href="http://www.poedit.net/">POedit</a>
<p/>


<h4>Identifying the language preference of the end user</h4>
Everybody: Automatically happens behind the scenes, but you can specify language preference too.
<p/>


<h4>Referencing Translated Text (by using):</h4>
<b>ASP.NET</b>: Uniquely named Resource Keys
<br/>
<b>FairlyLocal</b>: The text itself
<br/>
<b>Everybody Else</b>: The text itself
<p/>
When Visual Studio.NET does its magic, every  runat="server" control will get a new attribute called meta:resourceKey containing a unique key with a helpful name such as "Literal26" or "HyperLink7" that is used to relate the text in the .resx file back to the control that uses it.  
<p/>
This is not actually as unhelpful as it seems, since translators will still see the Original Text in the .resx file alongside that meaningless key, so they will in fact know what text they're translating.  Just not its context.  Further, as ASP.NET developers we've learned to put up with a certain amount of VS.NET's autogenerated metagarbage, so we can generally gloss over these strange XML attributes that suddenly appear in our source.
<p/>
Everybody else simply uses the text itself as the lookup key.
<p/>



<h4>Displaying text to the end user in his preferred language</h4>
<b>ASP.NET</b>: Automagic.  Can also ask for text directly from AppLocalResources
<br/>
<b>FairlyLocal</b>: Automagic.  Can also ask for translated text directly.
<br/>
<b>Everybody Else</b>: Automagic.  Can also ask for translated text directly.
<p/>
In ASP.NET, you can add keys to your .resx file by hand if there are any messages you need that didn't get sniffed from the source.  Other technologies don't need to bother with this step as often, since any text appearing in the source code will be marked for translation, whether it's associated with a control or not.
</div>
<p/>
<h2>Wrapping Up</h2>
<p/>
<div class="aside">
<b>A short interlude...</b>
<p/>
I'm a believer in <a href="http://en.wikipedia.org/wiki/Sturgeon's_Law">Sturgeon's Law</a>, which states that "<b>90% of everything is crap.</b>"  Even ASP.NET, which I feel is still miles ahead of every other web development framework is not immune.  
<p/>
We've learned to avoid using pretty much all of the "Rich" controls and Designer Mode garbage that shipped with 1.1 and has plagued .NET ever since, and every new release brings a few things with it (including, alas, System.Globalization) that are best avoided.  
<p/>
In my opinion, that's fine, since the rest of the framework is so ridiculously productive.  Don't worry though, any honest Django or Rails veteran will tell you that their frameworks also have bits that are best left alone.  And hey, the <a href="http://www.php.net/">most popular platform</a> in the world for building web apps is 100% crap, so we're still miles ahead of the game here in the land of MS. 
</div>
Anybody still following along will notice that while ASP.NET offers workable solutions to every stage of the i18n process, it's generally not quite as straightforward or convenient as the alternative way of doing things.  ASP.NET also tends to pollute your codebase with a lot of extraneous noise in the form of meta:resourceKey attributes (why couldn't they have at least shortened that to "key" and made it part of the Control class so you could easily add it to anything) and .resx file collections for every single page in your site, and it leaves you a little short in the Tools department when it comes time to translate those files.
<p/>
So while it's certainly possible to localize a website the way that ASP.NET recommends, it is definitely a lot of work, and it tends to be quite confusing.  Doing it in another technology, say Django for instance, just doesn't seem like that big a deal.  That's the sort of experience that I'm trying to bring to ASP.NET with the <a href="http://www.fairtutor.com/fairlylocal">FairlyLocal library</a>, and I hope it's at least a good first step.  
<p/>
If you have any suggestions (or better still, code contributions) to make it better, I look forward to hearing from you.

<style>
.comparison
{
font-size:80%;
border:dashed 1px #ccc;
padding:5px;
}
.comparison h4
{
margin-bottom:0px;
}

.aside
{
width:45%;
margin-left:20px;
padding:5px;
border:solid 1px #ccc;
background-color:#f0f0f0;
float:right;
font: 12px/18px Arial, sans-serif;
}
</style>]]></description>
					<author><![CDATA[Jason Kester]]></author>
					<pubDate>Wed, 10 Mar 2010 18:54:00 GMT</pubDate> 
					<link>http://www.expatsoftware.com/Articles/2010/03/why-internationalization-is-hopelessly</link>
					<guid isPermaLink="true">http://www.expatsoftware.com/Articles/2010/03/why-internationalization-is-hopelessly</guid> 
					<slash:comments>0</slash:comments>
				</item>
			
				<item>
					<title><![CDATA[Fixing Internationalization in ASP.NET]]></title>
					<description><![CDATA[<p/>
I've been building websites with ASP.NET for a little over 10 years now, and I have a dirty little secret to confess:  I've never Internationalized a single one of them.
<p/>

It's not from lack of trying, I can tell you.  I've got a good dozen false starts under my belt, and plenty of hours spent studying the code from other people's sites that implement Internationalization (abbreviated as i18n for us lazy typists) the way that Microsoft wants you to do it.  And my conclusion is that it's just plain not worth the effort.
<p/>
I18n is hopelessly broken in ASP.NET.  Let's look at this nice snippet of sample code to see why:
<p/>
<code class="prettyprint" style="margin-bottom:0px;">&lt;!-- STEP ONE, in MyPage.aspx: Create Runat="Server" Literal Control: -->
&lt;asp:Literal ID="lblPages" 
 runat="server" 
 meta:resourcekey="lblPagesResource1" 
 Text="Pages"/>

&lt;!-- STEP TWO, in MyPage.es-ES.resx: Create Message Key/Value: -->
&lt;data name="lblPagesResource1.Text" xml:space="preserve">
 &lt;value>Browse&lt;/value>
&lt;/data>
</code>
<b>...and that's for EVERY piece of text in your whole site!</b>
<p/>
Notice that you need to make every single piece of localized text into a runat="server" control.  And that you then need to add this crazy long attribute (that Intellisense doesn't know about, so you have to type out in full) to each one of those controls so that ASP.NET can find them in one of the Resource files that you need to generate <b>by hand</b> for  every text fragment in your entire website.  
<p/>
If it sounds like a ridiculous amount of work for your developers, you're probably being charitable.  In practice, it's <b>so much</b> extra work that nobody actually does it.  That, my friends, is the reason you hardly ever see any multi-language websites written with ASP.NET.
<p/>
Recently, however, my hand was truly forced.  We're getting pretty close to launching <a href="http://www.fairtutor.com/">FairTutor</a> to the public, and since it has target audiences in both the United States and Latin America it pretty much needs to work in Spanish as well as English.  This is the part where I start wistfully looking back to a couple Django projects we did not too long ago, and the absolute breeze it was localizing those sites.  If only the rest of Django wasn't so crap, we could just port this project across and…  Hang on a sec.  Port.  Yeah, how about we simply port that amazing Django i18n stuff over to ASP.NET instead.  
<p/>
That was a week ago.
<p/>
Today, I'm releasing some code that I hope will single-handedly fix i18n in ASP.NET.  It's based on the way that everybody else does it.  Let's pause a minute to let that sink in, since many of my fellow .NET devs might not have been aware of this fact:  There's another way of doing i18n, and it's so simple and straightforward that <b>every</b> other web framework uses it in some form or another to do multi-language websites.   
<p/>
In Django, PHP, Java, Rails, and pretty much everything else out there, you simply call a function called gettext() to localize text.  Usually, you alias that function to _(), so you're looking at like 5 keystrokes (including quotes) to mark a piece of text for internationalization.  That's simple enough that even lazy developers like me can be convinced to do it.
<p/>
Better still, frameworks that use this gettext() library (it's actually a chunk of open source code from the GNU folks), also tend to come with a program that will sift through your source and automagically generate translation files for you (in .PO format, which is basic enough to be edited in notepad by non-tech-savvy translators, but is popular enough that there are several existing editors built just for it), containing every text fragment that was marked for i18n.
 
<p/>
The whole process is so simple and straightforward that you're left to wonder why Microsoft felt compelled to spend so much time and effort reinventing it all to be worse.
<p/>

<h2>Introducing FairlyLocal</h2>
<p/>

I really want ASP.NET to stop forcing people to monkey with XML files and jump through hoops just to show web pages in Spanish, so I'm going to package up all this code and release it as Open Source:
<p/>
<a href="http://www.fairtutor.com/fairlylocal/">FairlyLocal - Gettext Internationalization for ASP.NET</a>
<p/>
At the moment, there's not a whole lot to it.  It'll find where you're using the FairlyLocal.GetText() (or its _() alias) and generate .PO files for you.  And it'll suck in various language versions of those files and translate text on your website.  Not much there, eh?  But then that's the whole point:  i18n is supposed to be simple and straightforward.  Hopefully, FairlyLocal will make that an actuality for the ASP.NET community.
<p/>
I look forward to hearing your feedback.
<p/>

<div style="border:solid 1px #ccc;background-color:#f0f0f0;padding:5px;font-size:90%;">
<img src="http://cdn.fairtutor.com/images/girl_on_tan.gif" border=0 style="border:none;float:right;margin-left:20px;"/>
<a href="http://www.fairtutor.com/">FairTutor</a> is our latest project here at Expat.  It's a website that connects Spanish teachers in South America with students in the US and lets them hold <a href="http://www.fairtutor.com/">live online Spanish lessons</a>.  
<p/>
We'll be starting Beta classes soon, so if you want to score some free Spanish lessons, you might want to go <a href="http://www.fairtutor.com/Setup/RequestInvite.aspx">sign up for the waiting list</a>!
</div>]]></description>
					<author><![CDATA[Jason Kester]]></author>
					<pubDate>Mon, 01 Mar 2010 14:01:00 GMT</pubDate> 
					<link>http://www.expatsoftware.com/Articles/2010/03/fixing-internationalization-in-aspnet</link>
					<guid isPermaLink="true">http://www.expatsoftware.com/Articles/2010/03/fixing-internationalization-in-aspnet</guid> 
					<slash:comments>0</slash:comments>
				</item>
			
				<item>
					<title><![CDATA[S3stat announces Self-Managed mode]]></title>
					<description><![CDATA[About twice a week, I'll get an email from somebody asking "why does <a href="http://www.s3stat.com/">S3stat</a> need my AWS Credentials???", followed by an explanation that this individual would be happy to set everything up at his end so that he wouldn't have to hand over sensitive information.
<p/>
Ok, fine. Enough asking already!  <a href="http://www.s3stat.com/web-stats/self-managed.ashx">You can do that now</a>.  
<p/>
A little background for those of you who couldn't parse a single word of that.  S3stat is a service we built that provides <a href="http://www.s3stat.com/">Amazon S3 and Cloudfront Analytics</a>.  For five bucks a month, we'll set up logging on your cloud stuff, and every night we'll process those logs into nice shiny reports and graphs.  It's pretty cool.  You should go sign up for it!
<p/>
But here's the deal.  To do all that, we pretty much have to pretend we're you.  We need you to trust us with your Amazon Web Services credentials so that we can make those changes and process those logs.  Most people are fine with that (just like we're fine with handing out our credit card number to buy shoes online), but some organizations simply can't afford to take the risk, regardless of how trustworthy our company is or how nice a guy I seem.
<p/>
That's fine.  But it used to lose us a bit of business.
<p/>
So now, we're proud to announce "<a href="http://www.s3stat.com/web-stats/self-managed.ashx">S3stat Self Managed Mode</a>", where you exchange an hour's worth of fiddling around with <a href="http://developer.amazonwebservices.com/connect/entry.jspa?externalID=128">s3curl</a> for the peace of mind that nobody will be using your bucket to store their vacation photos.
<p/>
Try it out and let us know what you think!]]></description>
					<author><![CDATA[Jason Kester]]></author>
					<pubDate>Fri, 14 Aug 2009 16:55:00 GMT</pubDate> 
					<link>http://www.expatsoftware.com/Articles/2009/08/s3stat-announces-self-managed-mode</link>
					<guid isPermaLink="true">http://www.expatsoftware.com/Articles/2009/08/s3stat-announces-self-managed-mode</guid> 
					<slash:comments>0</slash:comments>
				</item>
			
				<item>
					<title><![CDATA[Cloudfront Analytics from S3stat]]></title>
					<description><![CDATA[We're happy to announce that S3stat is now offering <a href="http://www.s3stat.com/">Web Stats for Amazon Cloudfront</a>.  
<p/>
It's actually pretty cool, if we do say so ourselves.  When you sign up for the service, we'll set up your Cloudfront Distributions so that they generate the necessary logfiles.  Each night, we'll download, translate and process those logs into useful reports.  You'll get web stats for your Cloudfront usage without having to do any work.  Sorted.
<p/>
<a href="http://www.s3stat.com/" title="Web Log Analysis and Statistics for Cloudfront and Amazon S3" style="display:block;float:right;margin-left:20px;font-style:normal;text-align:center;font-size:80%;"><img src="http://www.s3stat.com/images/logo_low_short.gif" border="0" style="border-width:0px!important;" alt="Web Log Analysis and Statistics for Cloudfront and Amazon S3"/><br>Web Stats for Cloudfront & Amazon S3</a> 
We also still do <a href="http://www.s3stat.com/">S3 Analytics</a>, just like always.  Check it out when you get a chance, and be sure to let us know what you think!]]></description>
					<author><![CDATA[Jason Kester]]></author>
					<pubDate>Sat, 13 Jun 2009 12:30:00 GMT</pubDate> 
					<link>http://www.expatsoftware.com/Articles/2009/06/cloudfront-analytics-from-s3stat</link>
					<guid isPermaLink="true">http://www.expatsoftware.com/Articles/2009/06/cloudfront-analytics-from-s3stat</guid> 
					<slash:comments>0</slash:comments>
				</item>
			
				<item>
					<title><![CDATA[Travel Map theme for Wordpress]]></title>
					<description><![CDATA[A few months back, I spent a few hours putting together a 
<a href="http://www.blogabond.com/Promo/BloggerTemplate.aspx">travel map template for Blogger</a>, and mentioned it here.  Much to my surprise, people started downloading and using it.  Doing a quick search today, I see almost 500 sites running that theme now.
<p/>
Cool!
<p/>
So I figured I'd do the same for <a href="http://www.wordpress.org">Wordpress</a> users.  Here is a screenshot of the Theme in action:
<p/>
<a href="http://www.blogabond.com/Promo/Wordpress-Travel-Blog-Template.aspx" title="Travel Blog theme for Wordpress"><img src="http://www.blogabond.com/images/press/wordpress_template_600.jpg" alt="Travel Blog template for Blogger" border="0" width="450" /></a>
<p/>
As you can see, it's a pretty clean look, with a Map up top that you can customize to show where you've been and where you're going.  Try it out and let me know what you think!
<p/>
<a href="http://www.blogabond.com/Promo/Wordpress-Travel-Blog-Template.aspx">Get a free Travel Map theme for Wordpress</a> from Blogabond.com!]]></description>
					<author><![CDATA[Jason Kester]]></author>
					<pubDate>Fri, 30 Jan 2009 00:54:00 GMT</pubDate> 
					<link>http://www.expatsoftware.com/Articles/2009/01/travel-map-theme-for-wordpress</link>
					<guid isPermaLink="true">http://www.expatsoftware.com/Articles/2009/01/travel-map-theme-for-wordpress</guid> 
					<slash:comments>0</slash:comments>
				</item>
			
				<item>
					<title><![CDATA[Google Adsense Serving Malware?]]></title>
					<description><![CDATA[Last night, I noticed some strange behavior from one of my sites that uses AdSense.  In Internet Explorer, the site started asking me to install some plugins from google-adservice.com.  Naturally, I declined, but the install message came right back.  Eventually I had to kill the process to close the browser.
<p/>
This morning, I opened the same site in Chrome, and was immediately greeted with this:
<p/>
<a href="http://img.expatsoftware.com.s3.amazonaws.com/blog/google_malware_800.gif">
<img src="http://img.expatsoftware.com.s3.amazonaws.com/blog/google_malware_450.gif" border=0></a>
<p/>
<div style="font-size:8px;color:#999;border:solid 1px #ccc;padding:10px;">
"Warning: Visiting this site may harm your computer!
The website at oracle-dev.appspot.com contains elements from the site google-adservice.com, which appears to host malware – software that can hurt your computer or otherwise operate without your consent. Just visiting a site that contains malware can infect your computer.
For detailed information about the problems with these elements, visit the Google Safe Browsing diagnostic page for google-adservice.com.
Learn more about how to protect yourself from harmful software online.
 I understand that visiting this site may harm my computer.  "
</div>
<p/>

My first suspiction was that something else was running on that page and impersonating AdSense, but no.  There's only one script include on that page, and it points to pagead2.googlesyndication.com.  It seems that somebody has found a way to push out some arbitrary script through AdSense.
<p/>
I did some digging around to see who else has been having this problem, and what Google was doing about it.  Nothing, it seems.  In fact, I only found one thread about it.  But 
<a href="http://www.google.com/support/forum/p/AdSense/thread?tid=40ce71d66721b826&hl=en&fid=40ce71d66721b82600046102d76d9fc3">
that one thread</a> is filled with real people that are seeing the same thing.
<p/>
I suspect this is an actual exploit.
<p/>
<b>EDIT: </b>Here is <a href="http://www.quartertothree.com/game-talk/showthread.php?t=49982">another thread</a> discussing the issue.]]></description>
					<author><![CDATA[Jason Kester]]></author>
					<pubDate>Wed, 21 Jan 2009 19:12:00 GMT</pubDate> 
					<link>http://www.expatsoftware.com/Articles/2009/01/google-adsense-serving-malware</link>
					<guid isPermaLink="true">http://www.expatsoftware.com/Articles/2009/01/google-adsense-serving-malware</guid> 
					<slash:comments>0</slash:comments>
				</item>
			
				<item>
					<title><![CDATA[CloudFront costs compared to S3]]></title>
					<description><![CDATA[A little over a month ago, I did a quick writeup
<a href="http://www.expatsoftware.com/articles/2008/11/cloudfront-performance-numbers.html">comparing Amazon's CloudFront CDN performance</a> with that of Amazon S3 on its own.  The results weren't all that surprising.  CloudFront kicked the stuffing out of its older sibling in terms of latency.  Just like it was designed to do.
<p/>
That silly article kicked off 
<a href="http://news.ycombinator.com/item?id=369366">quite a bit</a> of <a href="http://www.reddit.com/r/programming/comments/7ebgl/amazon_cloudfront_performance_numbers/">discussion</a>, most of which was speculation about how much more expensive CloudFront was when compared with S3 on its own, and how its costs stacked up to other Content Delivery Networks.
<p/>
Well, keeping in the style of that last article, here is one statistically insignificant datapoint from which I'll draw a conclusion.  Namely, my Amazon Web Services bill for two months.  The following tables represent the costs of hosting imagery for <a href="http://www.blogabond.com">Blogabond</a>, a medium sized blog hosting platform that sees traffic of around 100,000 unique visitors per month and a little over a million pageviews:

<p/>
October - Amazon S3 alone<br/>
<a href="http://img.expatsoftware.com/blog/s3_200810.gif">
<img src="http://img.expatsoftware.com./blog/s3_200810_450.gif" border=0 /></a><br/>
<b>$8.12 Total</b>
<p/>

December - Amazon S3 + CloudFront:<br/>
<a href="http://img.expatsoftware.com.s3.amazonaws.com/blog/s3_200812.gif">
<img src="http://img.expatsoftware.com.s3.amazonaws.com/blog/s3_200812_450.gif" border=0 /></a><br/>

<a href="http://img.expatsoftware.com/blog/cloudfront_200812.gif">
<img src="http://img.expatsoftware.com/blog/cloudfront_200812_450.gif" border=0 /></a><br/>
$6.09 + $6.28 = <b>$12.37 Total</b>
<p/>

So there you have it:  It's a little less than twice as expensive to host the same content on CloudFront as compared to S3 alone.  And it's still dirt cheap at twice the price!  I don't know about you, but I'm going to stick with it.
<p/>


<i>
DISCLAIMER:  This is not intended to be a thorough, or even fair, comparison of every available CDN on the planet.  So if you happen to be a sales rep for, say, 
<a href="http://www.reddit.com/r/programming/comments/7ebgl/amazon_cloudfront_performance_numbers/">Akamai, and you've got your feelings all hurt because of this post</a>, please remember that it was not directed at you.
I'm sure your thing is really really great, but we're not talking about it here.
</i>]]></description>
					<author><![CDATA[Jason Kester]]></author>
					<pubDate>Wed, 14 Jan 2009 21:30:00 GMT</pubDate> 
					<link>http://www.expatsoftware.com/Articles/2009/01/cloudfront-costs-compared-to-s3</link>
					<guid isPermaLink="true">http://www.expatsoftware.com/Articles/2009/01/cloudfront-costs-compared-to-s3</guid> 
					<slash:comments>0</slash:comments>
				</item>
			
				<item>
					<title><![CDATA[CloudFront Performance Numbers]]></title>
					<description><![CDATA[Yesterday, Amazon finally released the Content Delivery Network (CDN) they had been promising for several months.  They're calling it 
<a href="http://aws.amazon.com/cloudfront/">CloudFront</a>, and so far it seems to be living up to expectations.
<p/>
It's dead simple to set up if you're already using S3 to store your content.  Both 
<a href="http://www.bucketexplorer.com/documentation/cloudfront--amazon-cloudfront.html">Bucket Explorer</a>
and <a href="https://addons.mozilla.org/en-US/firefox/addon/3247">S3fox</a>
have already integrated CloudFront support, so you don't even need to write any new code.  Just configure a few settings, switch the CNAME records in your DNS, and suddenly your content is serving a lot faster.
<p/>
How much faster?  Lots.  Here are my numbers for serving a one pixel .gif file to my development machine here in the North of England (I've given URLs that are guaranteed to point to the right places, even after my CNAME changes propagate):
<p/>
Amazon S3:<br/>
<a href="http://img.twiddla.com.s3.amazonaws.com/images/pixel.gif">
http://img.twiddla.com.s3.amazonaws.com/images/pixel.gif</a><br/>
<b>300ms - 800ms latency</b>, ~0s download time
<p/>
CloudFront:<br/>
<a href="http://d2livl246cusvi.cloudfront.net/images/pixel.gif">
http://d2livl246cusvi.cloudfront.net/images/pixel.gif</a><br/>
<b>46ms latency</b>, ~0s download time
<p/>
S3 performance is all over the map.  As expected.  Amazon never intended S3 to be used as a direct web host, so it's no surprise that it performs like a big dumb file storage system.  
<p/>
CloudFront, however, is amazingly well tuned.  That 46ms time remained constant within 2ms every single time I loaded that file.  In other words, CloudFront is so much faster and more consistent that there is simply no reason not to use it for all your S3 content hosting starting today.]]></description>
					<author><![CDATA[Jason Kester]]></author>
					<pubDate>Wed, 19 Nov 2008 10:35:00 GMT</pubDate> 
					<link>http://www.expatsoftware.com/Articles/2008/11/cloudfront-performance-numbers</link>
					<guid isPermaLink="true">http://www.expatsoftware.com/Articles/2008/11/cloudfront-performance-numbers</guid> 
					<slash:comments>0</slash:comments>
				</item>
			
				<item>
					<title><![CDATA[How close to Zero Friction is your signup process?]]></title>
					<description><![CDATA[<a href="http://stackoverflow.com">StackOverflow.com</a>
just launched this last week, and it looks pretty cool.  It seems like it might be our best shot at getting back to the sort of useful discussion that we used to have on the Usenet back in the 90's.  Lots of signal, hardly any noise, and even the occasional correct answer.  Sign me up!
<p/>
Uh... wait a sec...  I can't sign up.
<p/>
StackOverflow has made the inexplicable blunder of requiring its users to sign in via <a href="http://openid.net">OpenID</a>.  That means you can't simply pick a username and password, but must instead go away and find yourself an OpenID provider, sign up for that, and bring it back to StackOverflow.  It's like 14 steps, depending on which provider you choose.  Observe:

<p/>
<img src="http://img.expatsoftware.com.s3.amazonaws.com/blog/stackoverflow-logo-250.png" border="0" style="border:none;" alt="StackOverflow"/>

<p/>
<ul>
<li>Click login
<li>Read a ton of instructions
<li>Locate and click the "get one" link
<li>Dismiss the javascript error popup from <a href="http://openid.net">openid.net</a>
<li>Read a bunch more instructions
<li>Find and click the "<a href="http://www.claimid.com/">ClaimID</a>" link (it's the first one on the list of providers)
<li>Click "Create a new account"
<li>Type in your information
<li>Open your email, find their email, click the link
<li>Go back to StackOverflow, click login again
<li>Paste in that giant URL that is now your OpenID 
<li>Type in your Username & Password
<li>Type in a bunch of Personal Info
<li>... and you're in!  Easy as that!
</ul>
<p/>
Now, for sake of comparison, let's take a look at the steps required to start using 
<a href="http://www.twiddla.com/">
Twiddla
</a>
 (the web meeting playground that we've been working on these last several months here at Expat):
<p/>
<img src="http://www.twiddla.com/images/press/logo_100.png" border="0" alt="Twiddla" style="border:none;float:left;margin-right:20px;"/>
<br/>
<ul>
<li>Click the "<a href="http://www.twiddla.com/NewMeeting.aspx">New Meeting</a>" button
</ul>
<br/>
<p/>
Can you spot the difference?
<p/>
Look, it's not just me saying this.  Talk to any Usability expert you like, and they'll tell you that every barrier that you put in front of your users will cause a certain percentage of them to leave and not come back.  For most sites, even stopping to ask for a Username & Password is too intrusive.  That's why we built Twiddla the way we did.  
<p/>
Our stated goal with Twiddla is to get the hell out of your way so that you can get some work done.  We've taken that idea so far that most of our users will never see a login screen of any description.  Some might not ever know they've used Twiddla at all, since we keep our Logo hidden away in the corner where it's not in your way.
<p/>
Can we say the same about StackOverflow's new registration system?   Unfortunately not.  For me, it was 10 minutes of grumbling "StackOverflow", "F'ng StackOverflow" under my breath while stumbling through the painful OpenID signup process.  Complete usability failure.  I can only hope they'll come to their senses and put in a reasonable username/password login like everybody else.]]></description>
					<author><![CDATA[Jason Kester]]></author>
					<pubDate>Mon, 13 Oct 2008 14:19:00 GMT</pubDate> 
					<link>http://www.expatsoftware.com/Articles/2008/10/how-close-to-zero-friction-is-your</link>
					<guid isPermaLink="true">http://www.expatsoftware.com/Articles/2008/10/how-close-to-zero-friction-is-your</guid> 
					<slash:comments>0</slash:comments>
				</item>
			
				<item>
					<title><![CDATA[Canvas Rendering Issue in Google Chrome]]></title>
					<description><![CDATA[Pop Quiz.  What's wrong with this picture?
<p/>
<a href="http://www.twiddla.com/test/ChromeCanvas.html" title="Google Chrome misrendering a Canvas element">
<img src="http://www.twiddla.com/test/canvas_chrome.gif" alt="Google Chrome misrendering a Canvas element"/>
</a>
<p/>
That's what you'll see if you use Google Chrome to draw a rounded box in a 
<a href="http://www.twiddla.com/">Twiddla meeting</a> today, and it highlights a minor cosmetic issue in Chrome's Canvas rendering engine.  Oops.
<p/>
If you think about how you would draw a rounded box on a canvas (straight line, curve, straight line, curve...), you can quickly see what's going on in that picture.  We've told it to "turn right 90 degrees", and it though we meant "270 degrees".  Or, in math terms, π/2 vs. -π/2, which is the same as 3π/2, since it ends you up in the same place.
<p/>
<a href="http://www.twiddla.com/test/ChromeCanvas.html">
Here is a Test Page that reproduces the Issue.  
</a>
Try it in a few browsers and see it for yourself.
<p/>
The strange thing here is that Chrome is supposed to be using WebKit's Canvas engine.  WebKit runs Safari, and Safari draws that box just fine.  Funky.
<p/>
As far as I'm concerned, Chrome is a great browser.  With this one minor exception, it ran <a href="http://www.twiddla.com/">Twiddla</a> perfectly right out of the box, which is certainly more than I can say for FireFox 3 (but that's another post...), and it's rendering engine is a bit faster than Safari (but not quite as fast as Internet Explorer.  Go figure.) 
<p/>
Keep up the good work!
<p/>
<br/>
<i>
UPDATE:  Google fixed this issue on December 11, 2008.  Here'a a link to <a href="http://code.google.com/p/chromium/issues/detail?id=3620">their bug report</a> on the issue.
</i>]]></description>
					<author><![CDATA[Jason Kester]]></author>
					<pubDate>Thu, 11 Sep 2008 11:33:00 GMT</pubDate> 
					<link>http://www.expatsoftware.com/Articles/2008/09/canvas-rendering-issue-in-google-chrome</link>
					<guid isPermaLink="true">http://www.expatsoftware.com/Articles/2008/09/canvas-rendering-issue-in-google-chrome</guid> 
					<slash:comments>0</slash:comments>
				</item>
			
				<item>
					<title><![CDATA[Windows Search gets worse!]]></title>
					<description><![CDATA[I have no idea how they  pulled it off, but Microsoft has somehow made it even harder to find files on your computer.  
<p/>
I'm already wistful for the good old days, when hitting "Search" from windows explorer would pull up an annoying dialog asking a 
<a href="http://secretgeek.net/ms_search.asp">bunch of stupid questions </a>
about what you wanted to search for.
<p/>
The one thing that old dialog had going for it, and I'm afraid that I never gave it its due credit, 
is that when you hit the Search button, it would actually, you know, 
<b>search your hard drive for files</b>.
<p/>
Well, that's all gone with the new & improved Search dialog.  Now, you get a bunch of even stupider questions to look at, but when you hit the Search button it immediately comes up with this:
<p/>
<div class='borderedPhoto' ><a href='http://www.blogabond.com/Photos/PhotoView.aspx?imageID=31493' class='photoLink' title='Nothing found for query "manage.py" because the folder F:\ is not indexed.' ><img src='http://www.blogabond.com/UserPhotos/1/580/windows-search.jpg' border=0 width=480 alt='Nothing found for query "manage.py" because the folder F:\ is not indexed.'></a>
</div>
<i>Nothing found for query "manage.py" because the folder F:\ is not indexed.</i>
<p/>
Roughly translated:  "I didn't find anything because I didn't actually look."
<p/>
Now, being a reasonably computer-savvy guy, I figured it should be a simple matter of hitting the "Index this folder" button somewhere on that screen.
Uhh... maybe it's in a dropdown someplace...  in a menu maybe???

Nope.  It's nowhere.  To this day, I have no idea where to even look for the tool that might be responsible for indexing that folder.
It just became impossible to search for files anywhere except for my C drive.
<p/>
So here is my advice for anybody on the Microsoft Search team that might be reading this.
In the case where your clever little index of "Things on this drive" doesn't know about the 
file I'm searching for, or maybe if your clever little index doesn't actually 
<b><i>know</i></b>
anything about the hard drive in the first place,
maybe you should fall back to, you know, 
<b><i>searching the hard drive</i></b>.

It would make my life a little easier.
<p/>
As it is, I'm back to DOS, pulling out commands I haven't used in 15 years.

Thanks Microsoft!
<p/>

<div style="border:solid 1px #ccc;background-color:#f0f0f0;padding:5px;font-size:90%;">
<b>UPDATE: 
LazyWeb™ to the rescue!  
</b><p/>
This got picked up by Reddit, and 20,000 people have since written comments explaining how to actually convince Windows Search to index new content.
Since this page is now the #1 Google result for that annoying message, I figured it might help if I actually explained how to turn indexing on.   
<p/>
You've got three basic choices:
<ul>
<li>
Go to My Computer, right click F:\, Properties, check "Allow Indexing Service to index this disk for fast file searching."
</li>
<li>
or, click the <b>text</b> of that helpful error message (not the help icon), which will pop up a help page.  Read through the longwinded description of how Indexing works and how it's making your life better, and eventually you'll find some form of link that sends you to a control panel that should let you turn it on.  Somehow. 
</li>
<li>
or, of cource, the obvious solution that anybody who's not a complete idiot (according to Reddit) would immediately know:
<b>Click the Dog!</b>
</li>
</ul>
</div>]]></description>
					<author><![CDATA[Jason Kester]]></author>
					<pubDate>Thu, 21 Aug 2008 18:11:00 GMT</pubDate> 
					<link>http://www.expatsoftware.com/Articles/2008/08/windows-search-gets-worse</link>
					<guid isPermaLink="true">http://www.expatsoftware.com/Articles/2008/08/windows-search-gets-worse</guid> 
					<slash:comments>0</slash:comments>
				</item>
			
				<item>
					<title><![CDATA[Travel Map template for  Blogger]]></title>
					<description><![CDATA[<a href="http://www.blogabond.com/">Blogabond</a> has been growing steadily this year, and one thing that has really taken off is the <a href="http://www.blogabond.com/Promo/GetABlogMap.aspx">Travel Map Widget</a> that lets you embed an itinerary map into your blog.
<p/>
At first, it might seem strange that a blogging site like Blogabond should offer tools to help people blogging elsewhere.  After all, why not just force people to migrate their stuff over to Blogabond if they want to get a little map up on top of their blog?  
<p/>
But there's the rub.  Forcing people to do things is <b>BAD</b>.  People <b>hate</b> being told what to do.  In this case, they've got a perfectly good blog going already, thank you very much, and all they want is a stinking map to put on it.  Personally, I'll take a little goodwill over a new user any day, so it makes a lot of sense to just give these little freebies away.
<p/>
In that spirit, you can now <a href="http://www.blogabond.com/Promo/BloggerTemplate.aspx">download an entire Blogger template</a> that will give you the best of all possible worlds.  Here's what it will look like if you install it on your blog:
<p/>
<a href="http://blogabondtest.blogspot.com/" title="Travel Blog template for Blogger"><img src="http://www.blogabond.com/images/press/blogger_template_400.gif" alt="Travel Blog template for Blogger" border="0" /></a>
<p/>
So yeah, go nuts and try it out for yourself.
<p/>
<a href="http://www.blogabond.com/Promo/BloggerTemplate.aspx">Get a free Travel Map template for Blogger</a> from Blogabond.com!]]></description>
					<author><![CDATA[Jason Kester]]></author>
					<pubDate>Wed, 28 May 2008 12:02:00 GMT</pubDate> 
					<link>http://www.expatsoftware.com/Articles/2008/05/travel-map-template-for-blogger</link>
					<guid isPermaLink="true">http://www.expatsoftware.com/Articles/2008/05/travel-map-template-for-blogger</guid> 
					<slash:comments>0</slash:comments>
				</item>
			
				<item>
					<title><![CDATA[The One Rule of DHTML Programming]]></title>
					<description><![CDATA[I just don't get it.
<p/>
How can so many smart people be so collectively bad at something as simple as Javascript on a web page?
<p/>
It's just not that hard.  And yet, not an hour goes by when I'm not stopped in my tracks by at least one javascript error.  And it's especially sad because many of these errors are coming from well known sites, with huge development budgets and plenty of good talent that really should know better.  Observe:
<p/>
<img src='http://img.twiddla.com/blog/error_aws.png' style='padding:5px;border:solid 1px #ccc;'/>
<img src='http://img.twiddla.com/blog/error_tc.png' style='padding:5px;border:solid 1px #ccc;'/>
<img src='http://img.twiddla.com/blog/error_mash.png' style='padding:5px;border:solid 1px #ccc;'/>
<img src='http://img.twiddla.com/blog/error_oreilly.png' style='padding:5px;border:solid 1px #ccc;'/>
<img src='http://img.twiddla.com/blog/error_scoble.jpg' style='padding:5px;border:solid 1px #ccc;'/>
<p/>
That was just a ten minute sample of browsing today.  
<p/>
<h2>The One Rule of DHTML Programming</h2>
<p/>
Look, it's not that hard to do this stuff right.  In fact, here is everything you'll ever need to know about Dynamic HTML Programming with Javascript:
<p/>
<div align='center' style='font-size:150%;font-weight:bold;border:solid 1px #ccc;padding:10px;'>
Test EVERYTHING before you reference it.
</div>
<p/>
That's it.  Simple.  Every little scrap of code you write needs to live inside its own little IF block that tests to make sure that the things it's expecting to interact with really exist.  Here's how:
<p/>
<table border=1 style='border-collapse:collapse'>
  <tr valign='top'>
    <td width='50%' style='font-size:10px;'>
      <b>BAD:</b>
      <pre>gbN2Loaded.style.display='none';</pre>
    </td>
    <td width='50%' style='font-size:10px;'>
      <b>Good:</b>
      <pre>if (window.gbN2Loaded)
{
  gbN2Loaded.style.display='none';
}</pre>
    </td>
  </tr>
  <tr valign='top'>
    <td width='50%' style='font-size:10px;'>
      <b>BAD:</b>
      <pre>document.getElementById('myDiv').innerHTML
     = 'stuff';</pre>
    </td>
    <td width='50%' style='font-size:10px;'>
      <b>Good:</b>
      <pre>if (document.getElementById('myDiv'))
{
  document.getElementById('myDiv').innerHTML
       = 'stuff';
}</pre>
    </td>
  </tr>
</table>

<p/>
I don't care that <a href="http://code.google.com/apis/maps/documentation/">Google's API Reference</a> told you to put <code>&lt;body onunload='GUnload()'></code> into all your pages.  That's just example code, and it's <a href="http://www.expatsoftware.com/articles/2007/03/examplecode-productioncode.html">not intended to be used in the real world</a>.  
<p/>
Real World Javascript will need to survive in dozens of strange browser environments that do things in strange unexpected ways, and as soon as you get it working right, Junior Dev Jimmy will accidently include it on every single page on your site and suddenly it won't be able to find the things it needs to live.  When that happens, it needs to quietly stop trying to do stuff instead of throwing error messages all over the place.
<p/>
<h2>What you need to do about it</h2>
<p/>
Ok, cool, you've fixed everything, but you're not done yet.  There's one more thing you need to do right this second.  You need to turn on those annoying Script Error popups in both Internet Explorer and Firefox, and you need to keep them on from here on out.  Don't just do it for your own machine, but for every computer owned by every employee of your company.  
<p/>
Yes, I know that you turned them off on purpose because they make the internet basically unsurfable, but most casual users of your site will have them on by default.  That means that most casual users will see every single little script error that your site throws at them, and they won't like it.  Those errors are pissing off real people right this minute, and you need to know about it.  If you arrange it so that they start pissing off you and your co-workers too, you just might find the incentive to get rid of them once and for all.]]></description>
					<author><![CDATA[Jason Kester]]></author>
					<pubDate>Tue, 27 May 2008 17:54:00 GMT</pubDate> 
					<link>http://www.expatsoftware.com/Articles/2008/05/one-rule-of-dhtml-programming</link>
					<guid isPermaLink="true">http://www.expatsoftware.com/Articles/2008/05/one-rule-of-dhtml-programming</guid> 
					<slash:comments>0</slash:comments>
				</item>
			
				<item>
					<title><![CDATA[Laid off?  The one thing you absolutely need to do on the first day]]></title>
					<description><![CDATA[You're in IT, right?  So chances are you've been laid off at least once from some crappy company and it's going to happen again.  Here is my one piece of advice to you.  The single most important thing to do as soon as you make it back to your house with that box full of stuff:
<p/>
<div style='font-size:200%;font-weight:bold;text-align:center;border:solid 1px #ccc;padding:10px;'>Book a flight</div>
<p/>
Seriously.  Do it now, before the initial shock wears off and that logical side of your brain starts coming up with lame excuses.  You will never have a better chance to get out and see the world than right now.  You have a pile of saving and a severance package.  You've got 6 months to a year before your skills start getting rusty.  There is absolutely no reason to start looking for work immediately, and every reason to take that round-the-world trip you've always dreamed about.  Right.  Now.
<p/>
Trust me, your career will be just fine.  
<p/>
<h3>Where to go</h3>
This is the easiest question to answer:  
<a href="http://www.blogabond.com/Thailand/Bangkok">Bangkok</a>.  Seriously, the mere fact that you had to ask the question indicates that you're probably not a seasoned traveler and therefore should be going to Thailand first.  I know you always wanted to do Europe, but it's crazy expensive and frankly, it's just not relaxed enough for you right now.  You're going to need some serious chilling to recover from a layoff.  Southeast Asia has that in Spades.
<p/>
Make your way to Khao San Road, find a room, grab a Beer Chang and talk to a few other travelers.  Your trip will plan itself from there.
<p/>
<h4>Where to go if it's May</h4>
Ok, one modification to the above.  Thailand is thoroughly uninhabitable for a few months between May and July.  In that case, you're going to Africa.  Book a flight to Cape Town instead.  Follow <a href="http://www.blogabond.com/TripView.aspx?tripID=6">this itinerary</a> up through Zambia, Malawi and Tanzania.  Everybody there speaks English and you can get a room for $0.75.  You'll do fine.
<p/>
<h3>How long to go for</h3>
You're going to want to stay gone for 6-9 months.  Less than that and it you'll be kicking yourself for not leaving enough time, and you'll be rushing through entire countries just to keep up with your itinerary.  I know that this seems silly now, but somewhere along the way somebody will ask how long you've been in Vietnam for and you'll answer "Only one month."  Timescales work differently on the road.
<p/>
In my experience (did I mention that I take about 9 months vacation a year and spend most of that traveling in the developing world?), I tend to start missing work after about 6 months away.  By 9 months, I'm pretty much ready to commit to a real job in a real office just so that I can start using my brain again.  Talking to other software guys on the road, it seems that this is pretty common.  You're going to want to come back eventually, so be sure to keep a few good contacts back home.
<p/>
Regardless of how long you plan to be gone, <a href="http://www.blogabond.com/CommentView.aspx?CommentID=8226">try to book your flight one-way</a>.  It will give you unlimited flexibility with your travel plans and let you pick your return date later when you know what you actually want to do.  As a last resort, pick the return date furthest in the future, since it's a lot easier to move it forward than to push it back.
<p/>
<h3>How much will it cost?</h3>
I budget about $1,000 a month when I'm traveling in Southeast Asia, Central America, Africa or the Middle East.  I seldom go through that much if I'm sticking to ground transport, but over the course of a year if you consider flights into the calculations, $1,000 a month is about right.  <b>Stay away from the developed world</b> at all costs though, or you'll quickly triple that figure!
<p/>
<h3>How do I get another job when I get back?</h3>
The nice thing about a 6 month timeframe is that it gives all of your ex-coworkers time to entrench themselves in other hopeless software companies.  Email them and notice how everything around them seems to be on fire.  They need you to start tomorrow.  Line up a good offer based on one of their recommendations and book a flight home.
<p/>
<h3>Three Lame Excuses and why they're not valid:</h3>

<h4>But I don't have any money saved...</h4>
You can't possibly be serious.  Are you saying that you've been working in IT for all these years and haven't put away a lousy ten grand??? Shame on you. Get a book on life skills and open a bank account fer cryin' out loud.
<p/>
<h4>But nobody will hire me after six months away...</h4>
Not true.  Nobody will hire you if you're bad at what you do and have terrible interviewing skills.  Those things won't change over the course of six months, but you might possibly wind up more relaxed (and with some good stories to tell) and that's actually a benefit when it comes to interviewing.  
<p/>
Regardless of what you may have heard, <a href="http://www.expatsoftware.com/articles/2007/02/two-weeks-vacation-is-only.html">skilled developers are very hard to find</a>.  If you fit that category, there's very little that you can do to poison your resume.  Certainly, heading off on your once-in-a-lifetime trip won't leave you unemployable. 
<p/>
<h4>But I'm married with a family and a house...</h4>
Ok, you win.  You're screwed, but that's the life you chose for yourself so you're going to have to live it.  It's worth noting, however, that most Europeans wouldn't consider that a reason not to travel.  Right this second, there is a German couple pushing a stroller down a remote beach in Thailand, and they're not going home for another month.  What's your excuse again?
<p/>
<h3>Why you're not actually going to do it</h3>
When you get right down to it, you'll probably find a way to talk yourself out of taking that dream trip.  You'll come up with some pretty believable excuses, but really it will come down to the fact that you're scared.
<p/>
That's cool.  Travel is pretty scary when you look at it from the outside. But here's the thing.  It stops being scary the moment your feet hit the pavement on Khao San Road in Bangkok.  You're going to get blasted by 100 degree heat, power-wafted by smells of the most amazing street food one minute and an open sewer the next, assaulted with music from a thousand bars, and crammed into a tiny room overlooking it all with a fan that doesn't work.  And you won't be able to wipe the silly grin off your face.
<p/>
Book the flight today, because every day you delay it is one more day wasted on the couch, and one more day to come up with lame excuses for why you shouldn't go.
<p/>
It is all good here.  Get your ass on a plane.
<p/>]]></description>
					<author><![CDATA[Jason Kester]]></author>
					<pubDate>Thu, 08 May 2008 18:33:00 GMT</pubDate> 
					<link>http://www.expatsoftware.com/Articles/2008/05/laid-off-one-thing-you-absolutely-need</link>
					<guid isPermaLink="true">http://www.expatsoftware.com/Articles/2008/05/laid-off-one-thing-you-absolutely-need</guid> 
					<slash:comments>0</slash:comments>
				</item>
			
				<item>
					<title><![CDATA[No Magic]]></title>
					<description><![CDATA[PHP used to have a cool little feature where it would automatically detect single quotes in text strings and escape them for you whenever they needed to be.  It was called Magic_quotes_runtime.  Maybe you've heard of it.  <a href="http://www.google.com/search?q=magic_quotes_runtime+bug">It was a disaster</a>.
<p/>
Countless developer hours were spent trying to chase down mysterious runtime errors where single quotes were either introduced, doubled up, or removed, causing disastrous crashes, data corruption and so much untold havoc that the feature was deprecated and eventually <a href="http://es.php.net/manual/en/info.configuration.php#ini.magic-quotes-runtime">removed from PHP entirely</a>.
<p/>
You would think that people would have learned their lesson.
<p/>
People are, by and large, dumb.  We make the same dumb mistakes over and over again because we didn't bother to do any research or read about the last time that somebody tried whatever stupid idea we just re-invented.  As a result, we have development frameworks and tools like <a href="http://www.google.com/search?hl=en&q=java+hibernate+bug">Hibernate</a>, ASP.NET's <a href="http://www.google.com/search?hl=en&q=smartnavigation+bug">SmartNav</a>, and Rails' <a href="http://www.google.com/search?hl=en&q=rails+activerecord+bug">ActiveRecord</a>, all trying to magically solve problems that weren't very hard in the first place, and silently making a lot of people's lives a lot harder without them even realizing it.  
<p/>
The big problem with Magic tools is that they work fine the first time you try them.  "Wow!", you say, " It posted the page back and scrolled my browser back down to the Submit button!"  So you turn that feature on for all your pages and start to trust it.  You get used to it.  You take it for granted.  You forget you're even using it.  Then suddenly something weird starts happening with one of your pages and you can't figure out why.  
<p/>
Examples of this sort of side effect abound, but nobody yet has taken a stand and done something about it.  How many developer hours have been lost trying to figure out what magical SQL statement was running behind the scenes and only “Hibernating” half of an object?  How many CPU cycles have been squandered (and slanderous blog entries written) because some poor developer didn’t realize that ActiveRecord was hitting the database three times for every single row in that recordset?  Are we really so scared of Outer Joins that we allow ourselves to be subject to this torment?
<p/>
I’ll leave you with an axiom that I’ve been telling developers for years without much success.  Call it Kester’s Caution:
<p/>
<div style="border:solid 1px #cccccc;padding:5px;margin:5px;background:#f0f0f0">

<b>Never use any language feature that describes itself as "Smart" or "Magic."</b>
Such features will invariably be trying to abstract
out some behavior that is not that hard to deal with anyway, and will
make any number of incorrect assumptions about your application that
will result in strange behavior cropping up that could possibly be
described as "Magic", but certainly would never be labeled "Smart".
</div>]]></description>
					<author><![CDATA[Jason Kester]]></author>
					<pubDate>Sat, 03 May 2008 16:43:00 GMT</pubDate> 
					<link>http://www.expatsoftware.com/Articles/2008/05/no-magic</link>
					<guid isPermaLink="true">http://www.expatsoftware.com/Articles/2008/05/no-magic</guid> 
					<slash:comments>0</slash:comments>
				</item>
			
				<item>
					<title><![CDATA[6 million hits a day.  Time to think scale!]]></title>
					<description><![CDATA[<a href="http://twiddla.blogspot.com/2008/03/oh-yeah-we-won.html" style="float:right"><img src="http://img.twiddla.com/blog/2008_web_awards.jpg" border=0></a>
<a href="http://www.twiddla.com/">Twiddla</a> has been getting a ton of attention this week.  We picked up the <a href="http://2008.sxsw.com/interactive/web_awards/winners/">Technical Achievement award at SXSW Interactive</a>, and have been getting a bunch of good press ever since.  25,000 people have signed up for the service since the award was mentioned, with 7,500 of those signups happening in a single day.  It's about to get good.
<p/>
For me though, it's been even better.  We're finally getting enough traffic to start thinking about scaling issues. You might remember an article that I wrote a few months back, where I told people
<a href="http://www.expatsoftware.com/articles/2007/06/getting-your-priorities-straight.html">not to sweat Performance and Scaling issues too much</a>, but rather to focus on Readability, Debugability, Maintainability, and Development Pace.  The idea was that getting your product to market quickly and being able to move fast if necessary are more important than having the Perfect Dream System that takes forever to build.  Of course, the implied point was that when and if that Big Day came, you'd be able to move fast enough to deal with Scalability and Performance concerns as they appeared.
<p/>
On March 12th, 2008, I got to see first hand whether I was talking out my arse…
<p/>
<h2>3/11/2008 7:00pm: 150 signups/hr, 50 hits/sec, 0-5% CPU</h2>
It's the day after the awards, and the first brief announcements are out.  Traffic has been building steadily all day, but we've seen worse.  The only crisis at the moment is that we don't yet have a <a href="http://www.twiddla.com/wiki/about-us.ashx">Press Kit</a>, so we're seeing writeups with the old logo and screenshots from the old UI.  D'oh!
<p/>
<h2>3/11/2008 11:00pm: 350 signups/hr, 120 hits/sec, 1-9% CPU</h2>
Japan wakes up.  The Asian press really liked us, so we saw a big spike in users from China and Japan the first few days.  <a href="http://www.twiddla.com/Demo/Sandbox.aspx">The sandbox</a> is pretty clogged, and with 30 people drawing simultaneously it's starting to tax people's browsers.  Every once in a while, somebody navigates the sandbox over to a porn site, and people write our support line to complain.  We're wiping the sandbox every 5 minutes, but it's still not acceptable.  Gotta get a handle on that.
<p/>
<a href="http://jas9.blogspot.com/2008/03/twiddla.html"><img src="http://img.twiddla.com/blog/twiddla_mr_sparkle.png" border=0></a>
<p/>
<h2>3/12/2008 9:00am: 300 signups/hr, 100 hits/sec, 1-6% CPU</h2>
The sandbox is completely overloaded.  There are 100 people in there, which is too many people communicating at once for any medium to really handle.  Imagine 100 people drawing on a real whiteboard at the same time, or 100 people talking over each other on a conference call.  It just doesn't work.  To bring a little order into the picture, I fire up the Visual Studio.NET and add a little switcher that will direct traffic to any one of 5 sandboxes, each one holding 8 users.  Throw that live, and now there are 5 overloaded sandboxes. 
<p/><h2>
3/12/2008 9:30am: 500 signups/hr, 300 hits/sec, 3-15% CPU</h2>
I bump up the sandbox count to 10.  Then think better of it and bump it up to 20 before pushing.  Then think better of THAT and add a new page to show users in case all 20 of those sandboxes fill up.  Push that live.
<p/><h2>
3/12/2008 9:41am</h2>
Testing out the above changes, I am immediately redirected to a page saying "Sorry, all the Sandboxes are full."  Let me restate that:  From the time I pushed those changes live to the time I could test them out, 160 people had beaten me into the sandboxes.  Wow.
<p/><h2>
3/12/2008 10:00am: 700 signups/hr, 500 hits/sec, 5-20% CPU</h2>
Looking through the error logs, I'm starting to see our first concurrency issues.  These are the little one-in-a-million things that you'd never find in test, but that happen every ten minutes under load.  They're mostly low-hanging fruit, so I spend the next hour patching and re-deploying until the error logs go silent.  
<p/><h2>
3/12/2008 12:00pm: 600 signups/hr, 400 hits/sec, 5-17% CPU</h2>
I'd been doing all of this from my sister's house up in Ft. Worth, who I had supposedly been visiting for a couple days, but whose house I had been mostly using for an office (thanks Lisa for tolerating that, and I promise to get out and visit sometime when I'm not trying to launch a new website!)  Now I had to hop in the car and drive back to Austin to fly home.  Our trusty server will be on its own for the next 12 hours, taking the beating of its life.  I won't even know if it goes down.
<p/><h2>
3/13/2008 4000 signups/day, 100 hits/sec, 3-10% CPU</h2>
<a href="http://img.twiddla.com/blog/twiddla_art_1_800.jpg" style="float:right"><img src="http://img.twiddla.com/blog/twiddla_art_1.jpg" border=0><br>Twiddla Art</a>Back in a stable place, and ready to deal with the flood of feedback emails we've been getting.  This part is fun, since most people have nice things to say, and it becomes readily apparent what features everybody wants to see.  Nothing has broken, so I actually have some time to put a few minor features live.  The "Wite-out" button was added this day, I think, and I re-did the way we handle snapshots and image exporting.
<p/><h2>
3/14/2008 3000 signups/day, 100 hits/sec, 2-5% CPU</h2>
I implemented a fix for the last little concurrency bug that we'd been seeing.  Then, while profiling that fix on the server, I noticed that TwiddleBot was flipping out.  TwiddleBot is the little service that runs the Guided Tour feature, and is also responsible for clearing out the sandboxes from time to time.  Turns out, he was also pounding the database 20 times a second, asking for instructions.  Hmm…  Chill, TwiddleBot.  Pushed a fix for that, and suddenly CPU usage dropped to zero.  Like, ZERO!  Every 5 seconds, it would spike up to 1%.  Cool.  I think we're gonna be able to scale this thing…
<p/><h2>
One week later, ~1000 signups per day, 50 hits/sec, 0% CPU</h2>
In the end, we came through our first little scaling event rather well.  We were actually a bit over-prepared.  Our colocation facility (<a href="http://www.easystreet.com/">Easystreet</a> in Beaverton, Oregon) had a couple extra boxes waiting to go for us, and I had taken the time a week earlier to write up and test a little software load balancer to allocate whiteboard sessions to various boxes when needed.  In the end, we didn't get to try any of that out.  Hell, we never spiked the processor on our one server over 50%.  I'd love to congratulate myself for the design choices I made all those months back when I wrote that article, but I think it's still too early in the game to conclude that we'll really scale when we ramp up to the next level.
<p/>
Still, it's worth noting that everything in Twiddla was built using the simple, Readable, Debuggable backend that we've been using on our more pedestrian sites for years, and it held up just fine under traffic.  When it turned out that parts of that backend needed refactoring to handle the kind of concurrency we saw last week, it was a simple 5 minute task to crack open the code, find what needed to change, and change it.  
<p/>
Readable, Debuggable, Maintainable.  That's the plan.  Thus far, that has enabled us to keep on top of any Performance and Scalability issues that have come along.  With luck, things will continue to work that way!]]></description>
					<author><![CDATA[Jason Kester]]></author>
					<pubDate>Fri, 21 Mar 2008 20:34:00 GMT</pubDate> 
					<link>http://www.expatsoftware.com/Articles/2008/03/6-million-hits-day-time-to-think-scale</link>
					<guid isPermaLink="true">http://www.expatsoftware.com/Articles/2008/03/6-million-hits-day-time-to-think-scale</guid> 
					<slash:comments>0</slash:comments>
				</item>
			
				<item>
					<title><![CDATA[Amazon goes down.  Everybody flips out.]]></title>
					<description><![CDATA[Everybody in the world is talking about the <a href="http://www.techcrunch.com/2008/02/15/amazon-web-services-goes-down-takes-many-startup-sites-with-it/">Big Amazon Outage</a> yesterday.  It hit us pretty hard.  A few of our sites were serving broken image links for several hours yesterday, and a service we run that relies on SQS was completely dead in the water.
<p/>
You know what though?  It's just not that big a deal.  I think about how reliable my stuff was before I put it up on Amazon's machines, and really it wasn't any better.  The only difference here is that I couldn't jump onto the server and do the hotfixing myself.  I didn't get to spend all day writing a patch to some low-level shared thing that suddenly started misbehaving system wide.
<p/>
Hey, wait a minute.  Scratch that.
<p/>
I didn't HAVE to do anything at all.  It was somebody else getting that page at 3AM and scrambling to get my site back up.  This is actually better from my perspective.
<p/>
So yeah, my sites still see the rare hour-long down window.  But now it's not my problem anymore.
<p/>
Cool.]]></description>
					<author><![CDATA[Jason Kester]]></author>
					<pubDate>Sat, 16 Feb 2008 11:16:00 GMT</pubDate> 
					<link>http://www.expatsoftware.com/Articles/2008/02/amazon-goes-down-everybody-flips-out</link>
					<guid isPermaLink="true">http://www.expatsoftware.com/Articles/2008/02/amazon-goes-down-everybody-flips-out</guid> 
					<slash:comments>0</slash:comments>
				</item>
			
	</channel>
</rss>