<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:pingback="http://madskills.com/public/xml/rss/module/pingback/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
  <channel>
    <title>The Blog of Many Hats</title>
    <link>http://blog.slatner.com/</link>
    <description>.NET, Cigars, Food. You know, the good stuff.</description>
    <language>en-us</language>
    <copyright>Bryan E. Slatner</copyright>
    <lastBuildDate>Wed, 20 Jan 2010 05:50:08 GMT</lastBuildDate>
    <generator>newtelligence dasBlog 2.3.9074.18820</generator>
    <managingEditor>bryan@slatner.com</managingEditor>
    <webMaster>bryan@slatner.com</webMaster>
    <item>
      <trackback:ping>http://blog.slatner.com/Trackback.aspx?guid=52d379b4-4027-4bba-8a25-0a0e9c8049bc</trackback:ping>
      <pingback:server>http://blog.slatner.com/pingback.aspx</pingback:server>
      <pingback:target>http://blog.slatner.com/PermaLink,guid,52d379b4-4027-4bba-8a25-0a0e9c8049bc.aspx</pingback:target>
      <dc:creator>Bryan Slatner</dc:creator>
      <wfw:comment>http://blog.slatner.com/CommentView,guid,52d379b4-4027-4bba-8a25-0a0e9c8049bc.aspx</wfw:comment>
      <wfw:commentRss>http://blog.slatner.com/SyndicationService.asmx/GetEntryCommentsRss?guid=52d379b4-4027-4bba-8a25-0a0e9c8049bc</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
It’s fairly common to use hidden form fields to store a value that gets posted back
to your controller for the purposes of establishing context.
</p>
        <p>
For example, on an edit form, you might render a hidden field containing the ID of
the entity you’re editing. This is actually preferable to using route values because
it’s much easier to tamper with those than it is to tamper with form data.
</p>
        <p>
That said…it’s still pretty darn easy to tamper with form data. If you’re using <a href="http://getfirebug.com/" target="_blank">FireBug</a>,
you can view the current page’s DOM and fiddle with any value you please. This can
be catastrophically bad if, for example, an attacker views a form to edit an entity
they have access to, and then changes the entity ID field to the ID of an entity they
don’t have access to. Granted, your validation code should handle that case, but when
it comes to attacks, an ounce of prevention is worth a pound of cure.
</p>
        <p>
So, how to prevent an attacker from tampering with our hidden fields?
</p>
        <p>
One solution is to create a secure hash of the field in question and render that to
the client as well. Then, on postback, validate that the hash of the incoming value
matches the original hash. Here’s an example of the HTML for that:
</p>
        <pre class="brush: xml;">&lt;input id="productId" name="productId" type="hidden" value="1" /&gt;
&lt;input id="productId_sha1" name="productId_sha1" type="hidden" value="vMrgoclb/K+6EQ+6FK9K69V2vkQ=" /&gt;&lt;</pre>
        <p>
The second hidden field is the SHA1 hash of the productId value 1, plus a secret value
that makes tampering with the hash impossible.
</p>
        <p>
I’ve written an HTML helper that facilitates creating these hash fields. Here’s how
it’s used:
</p>
        <pre class="brush: xml;">&lt;% using(Html.BeginForm()) { %&gt;
    &lt;%=Html.SecuredHiddenField("productId", 1) %&gt;
    &lt;fieldset&gt;  
        &lt;p&gt;&lt;label for="Name"&gt;Product Name:&lt;/label&gt; &lt;%=Html.TextBox("productName") %&gt;&lt;/p&gt;
        &lt;button name="save" value="with"&gt;Save Product&lt;/button&gt;
    &lt;/fieldset&gt;
&lt;% } %&gt;</pre>
        <p>
And here’s the code for the HTML helper:
</p>
        <pre class="brush: csharp;">public static class SecuredValueHtmlHelper
{
    public static string SecuredHiddenField(this HtmlHelper htmlHelper, string name, object value)
    {
        var html = new StringBuilder();
        html.Append(htmlHelper.Hidden(name, value));
        html.Append(GetHashFieldHtml(htmlHelper, name, GetValueAsString(value)));
        return html.ToString();
    }

    public static string HashField(this HtmlHelper htmlHelper, string name, object value)
    {
        return GetHashFieldHtml(htmlHelper, name, GetValueAsString(value));
    }

    public static string MultipleFieldHashField(this HtmlHelper htmlHelper, string name, IEnumerable values)
    {
        var valueToHash = new StringBuilder();
        foreach (var v in values)
        {
            valueToHash.Append(v);
        }

        return HashField(htmlHelper, name, valueToHash);
    }

    private static string GetValueAsString(object value)
    {
        return Convert.ToString(value, CultureInfo.CurrentCulture);
    }

    private static string GetHashFieldHtml(HtmlHelper htmlHelper, string name, string value)
    {
        return htmlHelper.Hidden(SecuredValueFieldNameComputer.GetSecuredValueFieldName(name),
                                 SecuredValueHashComputer.GetHash(value));
    }
}</pre>
        <p>
The HTML helper uses a class called SecuredValueHashComputer to compute the SHA1 hash.
I’ve written it so that you can plug in any hash computer that you want (MD5, or say
SHA512 for the really paranoid):
</p>
        <pre class="brush: csharp;">public static class SecuredValueHashComputer
{
    public static string Secret { get; set; }
    public static IHashComputer HashComputer { get; set; }

    static SecuredValueHashComputer()
    {
        Secret = "zomg!";
        HashComputer = new SHA1HashComputer();
    }

    public static string GetHash(string value)
    {
        return HashComputer.GetBase64HashString(value, Secret);
    }
}</pre>
        <p>
In an ideal world, you’d load the value for “Secret” from your Web.config (preferably
from an encrypted section) and use an IoC container to instantiate the IHashComputer.
</p>
        <p>
Finally, validate the data like so:
</p>
        <pre class="brush: csharp;">[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(int productId, string productName, string save, FormCollection formValues)
{
    if (save == "with")
    {
        SecuredValueValidator.ValidateValue(formValues, "productId");
    }

    ViewData["message"] = string.Format("Product ID {0} was saved!", productId);

    return View();
}</pre>
        <p>
The complete source code is available at <a href="http://blog.slatner.com/downloads/SecuredFormExample.zip">http://blog.slatner.com/downloads/SecuredFormExample.zip</a>.
</p>
        <img width="0" height="0" src="http://blog.slatner.com/aggbug.ashx?id=52d379b4-4027-4bba-8a25-0a0e9c8049bc" />
      </body>
      <title>Securing Form Values in ASP.NET MVC</title>
      <guid isPermaLink="false">http://blog.slatner.com/PermaLink,guid,52d379b4-4027-4bba-8a25-0a0e9c8049bc.aspx</guid>
      <link>http://blog.slatner.com/2010/01/20/SecuringFormValuesInASPNETMVC.aspx</link>
      <pubDate>Wed, 20 Jan 2010 05:50:08 GMT</pubDate>
      <description>&lt;p&gt;
It’s fairly common to use hidden form fields to store a value that gets posted back
to your controller for the purposes of establishing context.
&lt;/p&gt;
&lt;p&gt;
For example, on an edit form, you might render a hidden field containing the ID of
the entity you’re editing. This is actually preferable to using route values because
it’s much easier to tamper with those than it is to tamper with form data.
&lt;/p&gt;
&lt;p&gt;
That said…it’s still pretty darn easy to tamper with form data. If you’re using &lt;a href="http://getfirebug.com/" target="_blank"&gt;FireBug&lt;/a&gt;,
you can view the current page’s DOM and fiddle with any value you please. This can
be catastrophically bad if, for example, an attacker views a form to edit an entity
they have access to, and then changes the entity ID field to the ID of an entity they
don’t have access to. Granted, your validation code should handle that case, but when
it comes to attacks, an ounce of prevention is worth a pound of cure.
&lt;/p&gt;
&lt;p&gt;
So, how to prevent an attacker from tampering with our hidden fields?
&lt;/p&gt;
&lt;p&gt;
One solution is to create a secure hash of the field in question and render that to
the client as well. Then, on postback, validate that the hash of the incoming value
matches the original hash. Here’s an example of the HTML for that:
&lt;/p&gt;
&lt;pre class="brush: xml;"&gt;&amp;lt;input id=&amp;quot;productId&amp;quot; name=&amp;quot;productId&amp;quot; type=&amp;quot;hidden&amp;quot; value=&amp;quot;1&amp;quot; /&amp;gt;
&amp;lt;input id=&amp;quot;productId_sha1&amp;quot; name=&amp;quot;productId_sha1&amp;quot; type=&amp;quot;hidden&amp;quot; value=&amp;quot;vMrgoclb/K+6EQ+6FK9K69V2vkQ=&amp;quot; /&amp;gt;&amp;lt;&lt;/pre&gt;
&lt;p&gt;
The second hidden field is the SHA1 hash of the productId value 1, plus a secret value
that makes tampering with the hash impossible.
&lt;/p&gt;
&lt;p&gt;
I’ve written an HTML helper that facilitates creating these hash fields. Here’s how
it’s used:
&lt;/p&gt;
&lt;pre class="brush: xml;"&gt;&amp;lt;% using(Html.BeginForm()) { %&amp;gt;
    &amp;lt;%=Html.SecuredHiddenField(&amp;quot;productId&amp;quot;, 1) %&amp;gt;
    &amp;lt;fieldset&amp;gt;  
        &amp;lt;p&amp;gt;&amp;lt;label for=&amp;quot;Name&amp;quot;&amp;gt;Product Name:&amp;lt;/label&amp;gt; &amp;lt;%=Html.TextBox(&amp;quot;productName&amp;quot;) %&amp;gt;&amp;lt;/p&amp;gt;
        &amp;lt;button name=&amp;quot;save&amp;quot; value=&amp;quot;with&amp;quot;&amp;gt;Save Product&amp;lt;/button&amp;gt;
    &amp;lt;/fieldset&amp;gt;
&amp;lt;% } %&amp;gt;&lt;/pre&gt;
&lt;p&gt;
And here’s the code for the HTML helper:
&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;public static class SecuredValueHtmlHelper
{
    public static string SecuredHiddenField(this HtmlHelper htmlHelper, string name, object value)
    {
        var html = new StringBuilder();
        html.Append(htmlHelper.Hidden(name, value));
        html.Append(GetHashFieldHtml(htmlHelper, name, GetValueAsString(value)));
        return html.ToString();
    }

    public static string HashField(this HtmlHelper htmlHelper, string name, object value)
    {
        return GetHashFieldHtml(htmlHelper, name, GetValueAsString(value));
    }

    public static string MultipleFieldHashField(this HtmlHelper htmlHelper, string name, IEnumerable values)
    {
        var valueToHash = new StringBuilder();
        foreach (var v in values)
        {
            valueToHash.Append(v);
        }

        return HashField(htmlHelper, name, valueToHash);
    }

    private static string GetValueAsString(object value)
    {
        return Convert.ToString(value, CultureInfo.CurrentCulture);
    }

    private static string GetHashFieldHtml(HtmlHelper htmlHelper, string name, string value)
    {
        return htmlHelper.Hidden(SecuredValueFieldNameComputer.GetSecuredValueFieldName(name),
                                 SecuredValueHashComputer.GetHash(value));
    }
}&lt;/pre&gt;
&lt;p&gt;
The HTML helper uses a class called SecuredValueHashComputer to compute the SHA1 hash.
I’ve written it so that you can plug in any hash computer that you want (MD5, or say
SHA512 for the really paranoid):
&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;public static class SecuredValueHashComputer
{
    public static string Secret { get; set; }
    public static IHashComputer HashComputer { get; set; }

    static SecuredValueHashComputer()
    {
        Secret = &amp;quot;zomg!&amp;quot;;
        HashComputer = new SHA1HashComputer();
    }

    public static string GetHash(string value)
    {
        return HashComputer.GetBase64HashString(value, Secret);
    }
}&lt;/pre&gt;
&lt;p&gt;
In an ideal world, you’d load the value for “Secret” from your Web.config (preferably
from an encrypted section) and use an IoC container to instantiate the IHashComputer.
&lt;/p&gt;
&lt;p&gt;
Finally, validate the data like so:
&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(int productId, string productName, string save, FormCollection formValues)
{
    if (save == &amp;quot;with&amp;quot;)
    {
        SecuredValueValidator.ValidateValue(formValues, &amp;quot;productId&amp;quot;);
    }

    ViewData[&amp;quot;message&amp;quot;] = string.Format(&amp;quot;Product ID {0} was saved!&amp;quot;, productId);

    return View();
}&lt;/pre&gt;
&lt;p&gt;
The complete source code is available at &lt;a href="http://blog.slatner.com/downloads/SecuredFormExample.zip"&gt;http://blog.slatner.com/downloads/SecuredFormExample.zip&lt;/a&gt;.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://blog.slatner.com/aggbug.ashx?id=52d379b4-4027-4bba-8a25-0a0e9c8049bc" /&gt;</description>
      <comments>http://blog.slatner.com/CommentView,guid,52d379b4-4027-4bba-8a25-0a0e9c8049bc.aspx</comments>
      <category>The Geek</category>
    </item>
    <item>
      <trackback:ping>http://blog.slatner.com/Trackback.aspx?guid=454168c0-46ab-4e67-9b3b-e2e1860f502b</trackback:ping>
      <pingback:server>http://blog.slatner.com/pingback.aspx</pingback:server>
      <pingback:target>http://blog.slatner.com/PermaLink,guid,454168c0-46ab-4e67-9b3b-e2e1860f502b.aspx</pingback:target>
      <dc:creator>Bryan Slatner</dc:creator>
      <wfw:comment>http://blog.slatner.com/CommentView,guid,454168c0-46ab-4e67-9b3b-e2e1860f502b.aspx</wfw:comment>
      <wfw:commentRss>http://blog.slatner.com/SyndicationService.asmx/GetEntryCommentsRss?guid=454168c0-46ab-4e67-9b3b-e2e1860f502b</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Fought for an hour tonight to get syntax highlighting working in my preferred dasBlog
theme. Didn't happen. Finally switched themes and everything worked right.
</p>
        <p>
My thanks to <a href="http://alexgorbatchev.com/">Alex Gorbatchev</a> for such an
awesome <a href="http://alexgorbatchev.com/wiki/SyntaxHighlighter">tool</a>.<img width="0" height="0" src="http://blog.slatner.com/aggbug.ashx?id=454168c0-46ab-4e67-9b3b-e2e1860f502b" /></p>
      </body>
      <title>Syntax Highlighting</title>
      <guid isPermaLink="false">http://blog.slatner.com/PermaLink,guid,454168c0-46ab-4e67-9b3b-e2e1860f502b.aspx</guid>
      <link>http://blog.slatner.com/2010/01/20/SyntaxHighlighting.aspx</link>
      <pubDate>Wed, 20 Jan 2010 05:18:10 GMT</pubDate>
      <description>&lt;p&gt;
Fought for an hour tonight to get syntax highlighting working in my preferred dasBlog
theme. Didn't happen. Finally switched themes and everything worked right.
&lt;/p&gt;
&lt;p&gt;
My thanks to &lt;a href="http://alexgorbatchev.com/"&gt;Alex Gorbatchev&lt;/a&gt; for such an
awesome &lt;a href="http://alexgorbatchev.com/wiki/SyntaxHighlighter"&gt;tool&lt;/a&gt;.&lt;img width="0" height="0" src="http://blog.slatner.com/aggbug.ashx?id=454168c0-46ab-4e67-9b3b-e2e1860f502b" /&gt;</description>
      <comments>http://blog.slatner.com/CommentView,guid,454168c0-46ab-4e67-9b3b-e2e1860f502b.aspx</comments>
      <category>The Geek</category>
    </item>
    <item>
      <trackback:ping>http://blog.slatner.com/Trackback.aspx?guid=8447dc05-9034-496b-9e63-c5863e1c8905</trackback:ping>
      <pingback:server>http://blog.slatner.com/pingback.aspx</pingback:server>
      <pingback:target>http://blog.slatner.com/PermaLink,guid,8447dc05-9034-496b-9e63-c5863e1c8905.aspx</pingback:target>
      <dc:creator>Bryan Slatner</dc:creator>
      <wfw:comment>http://blog.slatner.com/CommentView,guid,8447dc05-9034-496b-9e63-c5863e1c8905.aspx</wfw:comment>
      <wfw:commentRss>http://blog.slatner.com/SyndicationService.asmx/GetEntryCommentsRss?guid=8447dc05-9034-496b-9e63-c5863e1c8905</wfw:commentRss>
      <slash:comments>1</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Ever since I heard about the concept of "code kata", I've been practicing them every
day.
</p>
        <p>
If you hadn't heard, code kata are lot like those in martial arts. They are an exercise
wherein you make the same decisions over and over again so that you are more likely
to make those same decisions again when under stress. Since TDD is a somewhat rigid
process where the same rules are followed over and over again it lends itself to this
concept of "kata".
</p>
        <p>
There are a couple of kata that I do. First, the "calculator kata" (thanks <a href="http://www.21apps.com/agile/tdd-kata-by-example-video/">Andrew
Woodward</a>), where you create a class with a method that sums all of that numbers
in a comma delimited string.
</p>
        <p>
Second, and more fun, is a kata where you write a method to return a list of all of
a number's prime factors. I first learned about this kata from <a href="http://blog.objectmentor.com/">Uncle
Bob Martin</a>. A few days ago he mentioned on Twitter that he was trying to get a
screencast of a "flawless" version of this kata. After about 30 attempts, I did not
achieve "flawless", but I think I achieved "pretty good".
</p>
        <p>
This first video shows the primary kata exercise. Using TDD, I steadily create a method
called Generate that lists the prime factors for an input integer. I also use Resharper
and its templating and refactoring features to make this process easier. As an aside,
if you are not presently using something like <a href="http://www.jetbrains.com/resharper/">Resharper</a> or <a href="http://msdn.microsoft.com/en-us/vcsharp/dd218053.aspx">CodeRush</a> to
help you as you code, you are definitely doing things the hard way.
</p>
        <p>
In the video, I try to rigidly adhere to the TDD method:
</p>
        <ol>
          <li>
Write a test first</li>
          <li>
Watch it fail</li>
          <li>
Write just enough code to make it pass</li>
          <li>
Verify the test passes</li>
          <li>
Refactor</li>
        </ol>
        <p>
On that note, I know it annoys people to no end when I hard-code return values when
I <b>know I'll be eliminating that code very shortly</b>. But it's neat to watch how
the algorithm transforms over the course of the kata, and you wouldn't see it if you
didn't follow the steps rigidly.
</p>
        <div class="screencast">
          <object id="csSWF" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version==8" height="823" width="1024">
            <param name="src" value="/screencasts/PrimesFactorsKata/PrimesFactorsKata_controller.swf#" />
            <param name="bgcolor" value="FFFFFF" />
            <param name="quality" value="best" />
            <param name="allowScriptAccess" value="always" />
            <param name="flashVars" value="csConfigFile=/screencasts/PrimesFactorsKata/PrimesFactorsKata_config.xml&amp;csColor=FFFFFF;autoplay=false;autoStart=false" />
            <embed name="csSWF" src="/screencasts/PrimesFactorsKata/PrimesFactorsKata_controller.swf" bgcolor="FFFFFF" quality="best" allowscriptaccess="always" flashvars="csConfigFile=/screencasts/PrimesFactorsKata/PrimesFactorsKata_config.xml&amp;csColor=FFFFFF;autoplay=false;autoStart=false" pluginspage="http://www.adobe.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash" height="823" width="1024">
            </embed>
          </object>
        </div>
        <p>
This second video is not part of the kata, but it's meant to show two things:
</p>
        <ul>
          <li>
Refactoring the code and using your existing tests to validate that you haven't broken
anything. I call this the "real coder" refactoring since it replaces the easy-to-read
while loops with not-so-easy-to-read for loops.</li>
          <li>
The use of MbUnit's "Row" tests that we can use the same test code to validate multiple
inputs to the validator.</li>
        </ul>
        <div class="screencast">
          <object id="csSWF" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version==8" height="823" width="1024">
            <param name="src" value="/screencasts/PrimeFactorsRefactorAndMoreTests/PrimeFactorsRefactorAndMoreTests_controller.swf#" />
            <param name="bgcolor" value="FFFFFF" />
            <param name="quality" value="best" />
            <param name="allowScriptAccess" value="always" />
            <param name="flashVars" value="csConfigFile=/screencasts/PrimeFactorsRefactorAndMoreTests/PrimeFactorsRefactorAndMoreTests_config.xml&amp;csColor=FFFFFF;autoPlay=false;autoStart=false" />
            <embed name="csSWF" src="/screencasts/PrimeFactorsRefactorAndMoreTests/PrimeFactorsRefactorAndMoreTests_controller.swf" bgcolor="FFFFFF" quality="best" allowscriptaccess="always" flashvars="csConfigFile=/screencasts/PrimeFactorsRefactorAndMoreTests/PrimeFactorsRefactorAndMoreTests_config.xml&amp;csColor=FFFFFF;autoPlay=false;autoStart=false" pluginspage="http://www.adobe.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash" height="823" width="1024">
            </embed>
          </object>
        </div>
        <img width="0" height="0" src="http://blog.slatner.com/aggbug.ashx?id=8447dc05-9034-496b-9e63-c5863e1c8905" />
      </body>
      <title>Prime Factors Kata in C#</title>
      <guid isPermaLink="false">http://blog.slatner.com/PermaLink,guid,8447dc05-9034-496b-9e63-c5863e1c8905.aspx</guid>
      <link>http://blog.slatner.com/2009/11/11/PrimeFactorsKataInC.aspx</link>
      <pubDate>Wed, 11 Nov 2009 16:56:07 GMT</pubDate>
      <description>&lt;p&gt;
Ever since I heard about the concept of "code kata", I've been practicing them every
day.
&lt;/p&gt;
&lt;p&gt;
If you hadn't heard, code kata are lot like those in martial arts. They are an exercise
wherein you make the same decisions over and over again so that you are more likely
to make those same decisions again when under stress. Since TDD is a somewhat rigid
process where the same rules are followed over and over again it lends itself to this
concept of "kata".
&lt;/p&gt;
&lt;p&gt;
There are a couple of kata that I do. First, the "calculator kata" (thanks &lt;a href="http://www.21apps.com/agile/tdd-kata-by-example-video/"&gt;Andrew
Woodward&lt;/a&gt;), where you create a class with a method that sums all of that numbers
in a comma delimited string.
&lt;/p&gt;
&lt;p&gt;
Second, and more fun, is a kata where you write a method to return a list of all of
a number's prime factors. I first learned about this kata from &lt;a href="http://blog.objectmentor.com/"&gt;Uncle
Bob Martin&lt;/a&gt;. A few days ago he mentioned on Twitter that he was trying to get a
screencast of a "flawless" version of this kata. After about 30 attempts, I did not
achieve "flawless", but I think I achieved "pretty good".
&lt;/p&gt;
&lt;p&gt;
This first video shows the primary kata exercise. Using TDD, I steadily create a method
called Generate that lists the prime factors for an input integer. I also use Resharper
and its templating and refactoring features to make this process easier. As an aside,
if you are not presently using something like &lt;a href="http://www.jetbrains.com/resharper/"&gt;Resharper&lt;/a&gt; or &lt;a href="http://msdn.microsoft.com/en-us/vcsharp/dd218053.aspx"&gt;CodeRush&lt;/a&gt; to
help you as you code, you are definitely doing things the hard way.
&lt;/p&gt;
&lt;p&gt;
In the video, I try to rigidly adhere to the TDD method:
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Write a test first&lt;/li&gt;
&lt;li&gt;
Watch it fail&lt;/li&gt;
&lt;li&gt;
Write just enough code to make it pass&lt;/li&gt;
&lt;li&gt;
Verify the test passes&lt;/li&gt;
&lt;li&gt;
Refactor&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
On that note, I know it annoys people to no end when I hard-code return values when
I &lt;b&gt;know I'll be eliminating that code very shortly&lt;/b&gt;. But it's neat to watch how
the algorithm transforms over the course of the kata, and you wouldn't see it if you
didn't follow the steps rigidly.
&lt;/p&gt;
&lt;div class="screencast"&gt;
&lt;object id="csSWF" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version==8" height="823" width="1024"&gt;
&lt;param name="src" value="/screencasts/PrimesFactorsKata/PrimesFactorsKata_controller.swf#"&gt;
&lt;param name="bgcolor" value="FFFFFF"&gt;
&lt;param name="quality" value="best"&gt;
&lt;param name="allowScriptAccess" value="always"&gt;
&lt;param name="flashVars" value="csConfigFile=/screencasts/PrimesFactorsKata/PrimesFactorsKata_config.xml&amp;amp;csColor=FFFFFF;autoplay=false;autoStart=false"&gt;
&lt;embed name="csSWF" src="/screencasts/PrimesFactorsKata/PrimesFactorsKata_controller.swf" bgcolor="FFFFFF" quality="best" allowscriptaccess="always" flashvars="csConfigFile=/screencasts/PrimesFactorsKata/PrimesFactorsKata_config.xml&amp;amp;csColor=FFFFFF;autoplay=false;autoStart=false" pluginspage="http://www.adobe.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash" height="823" width="1024"&gt; 
&lt;/object&gt;
&lt;/div&gt;
&lt;p&gt;
This second video is not part of the kata, but it's meant to show two things:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Refactoring the code and using your existing tests to validate that you haven't broken
anything. I call this the "real coder" refactoring since it replaces the easy-to-read
while loops with not-so-easy-to-read for loops.&lt;/li&gt;
&lt;li&gt;
The use of MbUnit's "Row" tests that we can use the same test code to validate multiple
inputs to the validator.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="screencast"&gt;
&lt;object id="csSWF" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version==8" height="823" width="1024"&gt;
&lt;param name="src" value="/screencasts/PrimeFactorsRefactorAndMoreTests/PrimeFactorsRefactorAndMoreTests_controller.swf#"&gt;
&lt;param name="bgcolor" value="FFFFFF"&gt;
&lt;param name="quality" value="best"&gt;
&lt;param name="allowScriptAccess" value="always"&gt;
&lt;param name="flashVars" value="csConfigFile=/screencasts/PrimeFactorsRefactorAndMoreTests/PrimeFactorsRefactorAndMoreTests_config.xml&amp;amp;csColor=FFFFFF;autoPlay=false;autoStart=false"&gt;
&lt;embed name="csSWF" src="/screencasts/PrimeFactorsRefactorAndMoreTests/PrimeFactorsRefactorAndMoreTests_controller.swf" bgcolor="FFFFFF" quality="best" allowscriptaccess="always" flashvars="csConfigFile=/screencasts/PrimeFactorsRefactorAndMoreTests/PrimeFactorsRefactorAndMoreTests_config.xml&amp;amp;csColor=FFFFFF;autoPlay=false;autoStart=false" pluginspage="http://www.adobe.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash" height="823" width="1024"&gt; 
&lt;/object&gt;
&lt;/div&gt;
&lt;img width="0" height="0" src="http://blog.slatner.com/aggbug.ashx?id=8447dc05-9034-496b-9e63-c5863e1c8905" /&gt;</description>
      <comments>http://blog.slatner.com/CommentView,guid,8447dc05-9034-496b-9e63-c5863e1c8905.aspx</comments>
      <category>The Geek</category>
    </item>
    <item>
      <trackback:ping>http://blog.slatner.com/Trackback.aspx?guid=10834d82-d377-4fbe-a30e-5859fc8fd820</trackback:ping>
      <pingback:server>http://blog.slatner.com/pingback.aspx</pingback:server>
      <pingback:target>http://blog.slatner.com/PermaLink,guid,10834d82-d377-4fbe-a30e-5859fc8fd820.aspx</pingback:target>
      <dc:creator>Bryan Slatner</dc:creator>
      <wfw:comment>http://blog.slatner.com/CommentView,guid,10834d82-d377-4fbe-a30e-5859fc8fd820.aspx</wfw:comment>
      <wfw:commentRss>http://blog.slatner.com/SyndicationService.asmx/GetEntryCommentsRss?guid=10834d82-d377-4fbe-a30e-5859fc8fd820</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
From <a href="http://www.losanjealous.com/nfc/perm.php?c=22&amp;q=69">The Nietzsche
Family Circus</a>:
</p>
        <p>
        </p>
        <p>
          <img src="http://blog.slatner.com/content/binary/NietcheFamilyCircus.png" border="0" />
        </p>
        <img width="0" height="0" src="http://blog.slatner.com/aggbug.ashx?id=10834d82-d377-4fbe-a30e-5859fc8fd820" />
      </body>
      <title>From The Nietzsche Family Circus</title>
      <guid isPermaLink="false">http://blog.slatner.com/PermaLink,guid,10834d82-d377-4fbe-a30e-5859fc8fd820.aspx</guid>
      <link>http://blog.slatner.com/2008/08/22/FromTheNietzscheFamilyCircus.aspx</link>
      <pubDate>Fri, 22 Aug 2008 18:58:10 GMT</pubDate>
      <description>&lt;p&gt;
From &lt;a href="http://www.losanjealous.com/nfc/perm.php?c=22&amp;amp;q=69"&gt;The Nietzsche
Family Circus&lt;/a&gt;:
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://blog.slatner.com/content/binary/NietcheFamilyCircus.png" border="0"&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://blog.slatner.com/aggbug.ashx?id=10834d82-d377-4fbe-a30e-5859fc8fd820" /&gt;</description>
      <comments>http://blog.slatner.com/CommentView,guid,10834d82-d377-4fbe-a30e-5859fc8fd820.aspx</comments>
      <category>The Jester</category>
    </item>
    <item>
      <trackback:ping>http://blog.slatner.com/Trackback.aspx?guid=470d563f-592e-49ec-a16d-ed089ad656c5</trackback:ping>
      <pingback:server>http://blog.slatner.com/pingback.aspx</pingback:server>
      <pingback:target>http://blog.slatner.com/PermaLink,guid,470d563f-592e-49ec-a16d-ed089ad656c5.aspx</pingback:target>
      <dc:creator>Bryan Slatner</dc:creator>
      <wfw:comment>http://blog.slatner.com/CommentView,guid,470d563f-592e-49ec-a16d-ed089ad656c5.aspx</wfw:comment>
      <wfw:commentRss>http://blog.slatner.com/SyndicationService.asmx/GetEntryCommentsRss?guid=470d563f-592e-49ec-a16d-ed089ad656c5</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I took my daughter out on a play date today. Really, this is the first time in 18
months that I've had her all to myself and been completely responsible for her out
of the house for more than an hour or two.
</p>
        <p>
Needless to say, I wanted it to go well. Needless for <i>Murphy</i> to say, things
didn't go as planned.
</p>
        <p>
The play date host had recently purchased a new pair of shoes. Large, white shoes.
They were sitting in the middle of the living room floor. My daughter, who is not
yet very coordinated, went careening through the house at full tilt, tripped over
the shoes, went airborne, and smashed her face into the wall of the living room.
</p>
        <p>
You can always tell the severity of a child's injury by the type of crying that commences
afterward. In this case, my daughter didn't move for a full five seconds, and then
commenced to wail at the top of her lungs. She still didn't move. She just lay there
with her face pressed against the wall.
</p>
        <p>
I ran over to her and picked her up, whereupon blood began running from her nose all
over our host's new white shoes and his carpet. I was completely paralyzed with indecision
for a moment. But the smartass side of me surveyed the situation and I said "Wow!
She fought the wall and the wall won!"
</p>
        <img width="0" height="0" src="http://blog.slatner.com/aggbug.ashx?id=470d563f-592e-49ec-a16d-ed089ad656c5" />
      </body>
      <title>An Epic Battle</title>
      <guid isPermaLink="false">http://blog.slatner.com/PermaLink,guid,470d563f-592e-49ec-a16d-ed089ad656c5.aspx</guid>
      <link>http://blog.slatner.com/2008/08/17/AnEpicBattle.aspx</link>
      <pubDate>Sun, 17 Aug 2008 04:15:50 GMT</pubDate>
      <description>&lt;p&gt;
I took my daughter out on a play date today. Really, this is the first time in 18
months that I've had her all to myself and been completely responsible for her out
of the house for more than an hour or two.
&lt;/p&gt;
&lt;p&gt;
Needless to say, I wanted it to go well. Needless for &lt;i&gt;Murphy&lt;/i&gt; to say, things
didn't go as planned.
&lt;/p&gt;
&lt;p&gt;
The play date host had recently purchased a new pair of shoes. Large, white shoes.
They were sitting in the middle of the living room floor. My daughter, who is not
yet very coordinated, went careening through the house at full tilt, tripped over
the shoes, went airborne, and smashed her face into the wall of the living room.
&lt;/p&gt;
&lt;p&gt;
You can always tell the severity of a child's injury by the type of crying that commences
afterward. In this case, my daughter didn't move for a full five seconds, and then
commenced to wail at the top of her lungs. She still didn't move. She just lay there
with her face pressed against the wall.
&lt;/p&gt;
&lt;p&gt;
I ran over to her and picked her up, whereupon blood began running from her nose all
over our host's new white shoes and his carpet. I was completely paralyzed with indecision
for a moment. But the smartass side of me surveyed the situation and I said "Wow!
She fought the wall and the wall won!"
&lt;/p&gt;
&lt;img width="0" height="0" src="http://blog.slatner.com/aggbug.ashx?id=470d563f-592e-49ec-a16d-ed089ad656c5" /&gt;</description>
      <comments>http://blog.slatner.com/CommentView,guid,470d563f-592e-49ec-a16d-ed089ad656c5.aspx</comments>
    </item>
    <item>
      <trackback:ping>http://blog.slatner.com/Trackback.aspx?guid=4531678a-0865-4177-b889-2b8edc8908e4</trackback:ping>
      <pingback:server>http://blog.slatner.com/pingback.aspx</pingback:server>
      <pingback:target>http://blog.slatner.com/PermaLink,guid,4531678a-0865-4177-b889-2b8edc8908e4.aspx</pingback:target>
      <dc:creator>Bryan Slatner</dc:creator>
      <wfw:comment>http://blog.slatner.com/CommentView,guid,4531678a-0865-4177-b889-2b8edc8908e4.aspx</wfw:comment>
      <wfw:commentRss>http://blog.slatner.com/SyndicationService.asmx/GetEntryCommentsRss?guid=4531678a-0865-4177-b889-2b8edc8908e4</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Well, it looks like <a href="http://www.amazon.com/gp/product/0061256684?ie=UTF8&amp;tag=iloveclicksco-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=0061256684">Waiter
Rant</a> has finally hit the shelves. I've been waiting for this book for a long time.
</p>
        <p>
I've been following the adventures of <a href="http://www.waiterrant.net">The Waiter</a> almost
since his blog began. It's one of my favorite reads.
</p>
        <p>
I'm kind of annoyed that the press has done their sleuthing and determined that Waiter's
restaurant, "The Bistro" is actually <a href="http://lanternausa.com/">Lanterna Tuscan
Bistro</a> in Nyack. I'm annoyed because I figured it out two years ago (in January
2006), but I kept my mouth shut because I knew Waiter didn't want it revealed.
</p>
        <p>
In case you were wondering how <b>you</b> could have figured it out yourself, here's
the long list of clues that Waiter dropped over the years:
</p>
        <ul>
          <li>
New York metro area</li>
          <li>
Italian Bistro</li>
          <li>
Owner with a stereotypical, Italian-sounding name ("Fluvio")</li>
          <li>
Owner offers occasional <a href="http://waiterrant.net/?p=152">cooking classes</a></li>
          <li>
Restaurant offers take-out</li>
          <li>
Restaurant has a web site</li>
          <li>
Take-out menu is posted online</li>
          <li>
Very close to a <a href="http://waiterrant.net/?p=189">Starbucks</a> (I know, they're
everywhere, but you'd be surprised how many possibilities this eliminates)</li>
          <li>
Close proximity to an Irish pub where you can get your <a href="http://waiterrant.net/?p=217">Bushmills,
neat</a>.<br /></li>
        </ul>
        <p>
All those clues made me 90% sure the restaurant had to be Lanterna. However, the final
clue for me was when Waiter posted that "The Bistro" had "<a href="http://waiterrant.net/?p=273">river
views</a>". As you can see from <a href="http://maps.google.com/maps?f=q&amp;hl=en&amp;q=3+south+broadway,+nyack,+ny&amp;ll=41.090783,-73.918146&amp;spn=0.078143,0.195007&amp;om=1">this
map</a>, Lanterna is right on a big 'ol river.
</p>
        <img width="0" height="0" src="http://blog.slatner.com/aggbug.ashx?id=4531678a-0865-4177-b889-2b8edc8908e4" />
      </body>
      <title>Waiter Revealed</title>
      <guid isPermaLink="false">http://blog.slatner.com/PermaLink,guid,4531678a-0865-4177-b889-2b8edc8908e4.aspx</guid>
      <link>http://blog.slatner.com/2008/08/02/WaiterRevealed.aspx</link>
      <pubDate>Sat, 02 Aug 2008 01:39:33 GMT</pubDate>
      <description>&lt;p&gt;
Well, it looks like &lt;a href="http://www.amazon.com/gp/product/0061256684?ie=UTF8&amp;amp;tag=iloveclicksco-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=0061256684"&gt;Waiter
Rant&lt;/a&gt; has finally hit the shelves. I've been waiting for this book for a long time.
&lt;/p&gt;
&lt;p&gt;
I've been following the adventures of &lt;a href="http://www.waiterrant.net"&gt;The Waiter&lt;/a&gt; almost
since his blog began. It's one of my favorite reads.
&lt;/p&gt;
&lt;p&gt;
I'm kind of annoyed that the press has done their sleuthing and determined that Waiter's
restaurant, "The Bistro" is actually &lt;a href="http://lanternausa.com/"&gt;Lanterna Tuscan
Bistro&lt;/a&gt; in Nyack. I'm annoyed because I figured it out two years ago (in January
2006), but I kept my mouth shut because I knew Waiter didn't want it revealed.
&lt;/p&gt;
&lt;p&gt;
In case you were wondering how &lt;b&gt;you&lt;/b&gt; could have figured it out yourself, here's
the long list of clues that Waiter dropped over the years:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
New York metro area&lt;/li&gt;
&lt;li&gt;
Italian Bistro&lt;/li&gt;
&lt;li&gt;
Owner with a stereotypical, Italian-sounding name ("Fluvio")&lt;/li&gt;
&lt;li&gt;
Owner offers occasional &lt;a href="http://waiterrant.net/?p=152"&gt;cooking classes&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
Restaurant offers take-out&lt;/li&gt;
&lt;li&gt;
Restaurant has a web site&lt;/li&gt;
&lt;li&gt;
Take-out menu is posted online&lt;/li&gt;
&lt;li&gt;
Very close to a &lt;a href="http://waiterrant.net/?p=189"&gt;Starbucks&lt;/a&gt; (I know, they're
everywhere, but you'd be surprised how many possibilities this eliminates)&lt;/li&gt;
&lt;li&gt;
Close proximity to an Irish pub where you can get your &lt;a href="http://waiterrant.net/?p=217"&gt;Bushmills,
neat&lt;/a&gt;.&lt;br&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
All those clues made me 90% sure the restaurant had to be Lanterna. However, the final
clue for me was when Waiter posted that "The Bistro" had "&lt;a href="http://waiterrant.net/?p=273"&gt;river
views&lt;/a&gt;". As you can see from &lt;a href="http://maps.google.com/maps?f=q&amp;amp;hl=en&amp;amp;q=3+south+broadway,+nyack,+ny&amp;amp;ll=41.090783,-73.918146&amp;amp;spn=0.078143,0.195007&amp;amp;om=1"&gt;this
map&lt;/a&gt;, Lanterna is right on a big 'ol river.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://blog.slatner.com/aggbug.ashx?id=4531678a-0865-4177-b889-2b8edc8908e4" /&gt;</description>
      <comments>http://blog.slatner.com/CommentView,guid,4531678a-0865-4177-b889-2b8edc8908e4.aspx</comments>
    </item>
    <item>
      <trackback:ping>http://blog.slatner.com/Trackback.aspx?guid=907c0df3-3f7c-4fbc-b43c-8f7f8e3fb9b0</trackback:ping>
      <pingback:server>http://blog.slatner.com/pingback.aspx</pingback:server>
      <pingback:target>http://blog.slatner.com/PermaLink,guid,907c0df3-3f7c-4fbc-b43c-8f7f8e3fb9b0.aspx</pingback:target>
      <dc:creator>Bryan Slatner</dc:creator>
      <wfw:comment>http://blog.slatner.com/CommentView,guid,907c0df3-3f7c-4fbc-b43c-8f7f8e3fb9b0.aspx</wfw:comment>
      <wfw:commentRss>http://blog.slatner.com/SyndicationService.asmx/GetEntryCommentsRss?guid=907c0df3-3f7c-4fbc-b43c-8f7f8e3fb9b0</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I recently ate at at <a href="http://www.cantina1511restaurant.com">Cantina 1511</a> and
was astonished at how yummy their margaritas were. They were honestly the best I've
ever tasted.
</p>
        <p>
First, there was not a ton of ice. They sell frozen margaritas, but the ones I had
came straight out of a pitcher and were served on the rocks.
</p>
        <p>
Second, it was obvious that it was made with fresh juices. Almost all the margaritas
you'll ever have -- unless you're at one of my parties -- are made with mixes. The
freshness of the stuff just made my day.
</p>
        <p>
So, I set about figuring out how to duplicate this margarita. I wasn't quite able
to duplicate the recipe, but what I ended up with was fan-fucking-tastic.
</p>
        <p>
As the owner of Cantina 1511 <a href="http://www.beveragenet.net/cheers/2005/0507_chrs/0507teq.asp">will
tell you</a>, variations in the sweetness of the fruit play a huge part here, so your
mileage may vary if you try this recipe.
</p>
        <p>
Also, you can use any kind of tequila you want, but the <a href="http://www.cabowabo.com">Cabo
Wabo Reposado</a> I used just took the flavors to a completely new level.
</p>
        <p>
Finally, an important note: though you have likely been led to believe that ripe limes
are green and overripe limes are yellow. This is <b>NOT TRUE</b>. Ripe limes are yellow.
Overripe limes are brown. Always get the ripest limes you can find.
</p>
        <h1>Bryan's Fresh Juice Margaritas
</h1>
        <p>
Yield: About 8 margaritas, depending on the size of your glasses.
</p>
        <h2>Ingredients
</h2>
        <p>
1 1/2 cups freshly squeezed lime juice<br />
1/2 cup freshly squeezed orange juice<br />
1 1/2 cups simple syrup<br />
Cabo Wabo Reposado Tequila
</p>
        <h2>Preparation
</h2>
        <p>
Strain the juices through a strainer into a pitcher. We don't want pulp in our margaritas.
Gently stir in the simple syrup.
</p>
        <p>
Optional: rim the margarita glass with kosher salt by rubbing a lime around the rim
and dipping the rim in salt.
</p>
        <p>
Pour the tequila into the bottom of the margarita glass. Margarita glasses have a
small well at the bottom that blossoms up into a large mouth. I fill the bottom well
in my glasses. Really, it depends on how much tequila you like and how fast you want
to get smashed.
</p>
        <p>
Add a handful of ice to the glass and pour juice mixture over the top until the glass
is full.
</p>
        <p>
Serve the result to a delighted audience.
</p>
        <img width="0" height="0" src="http://blog.slatner.com/aggbug.ashx?id=907c0df3-3f7c-4fbc-b43c-8f7f8e3fb9b0" />
      </body>
      <title>Fresh Juice Margaritas</title>
      <guid isPermaLink="false">http://blog.slatner.com/PermaLink,guid,907c0df3-3f7c-4fbc-b43c-8f7f8e3fb9b0.aspx</guid>
      <link>http://blog.slatner.com/2008/07/20/FreshJuiceMargaritas.aspx</link>
      <pubDate>Sun, 20 Jul 2008 19:43:49 GMT</pubDate>
      <description>&lt;p&gt;
I recently ate at at &lt;a href="http://www.cantina1511restaurant.com"&gt;Cantina 1511&lt;/a&gt; and
was astonished at how yummy their margaritas were. They were honestly the best I've
ever tasted.
&lt;/p&gt;
&lt;p&gt;
First, there was not a ton of ice. They sell frozen margaritas, but the ones I had
came straight out of a pitcher and were served on the rocks.
&lt;/p&gt;
&lt;p&gt;
Second, it was obvious that it was made with fresh juices. Almost all the margaritas
you'll ever have -- unless you're at one of my parties -- are made with mixes. The
freshness of the stuff just made my day.
&lt;/p&gt;
&lt;p&gt;
So, I set about figuring out how to duplicate this margarita. I wasn't quite able
to duplicate the recipe, but what I ended up with was fan-fucking-tastic.
&lt;/p&gt;
&lt;p&gt;
As the owner of Cantina 1511 &lt;a href="http://www.beveragenet.net/cheers/2005/0507_chrs/0507teq.asp"&gt;will
tell you&lt;/a&gt;, variations in the sweetness of the fruit play a huge part here, so your
mileage may vary if you try this recipe.
&lt;/p&gt;
&lt;p&gt;
Also, you can use any kind of tequila you want, but the &lt;a href="http://www.cabowabo.com"&gt;Cabo
Wabo Reposado&lt;/a&gt; I used just took the flavors to a completely new level.
&lt;/p&gt;
&lt;p&gt;
Finally, an important note: though you have likely been led to believe that ripe limes
are green and overripe limes are yellow. This is &lt;b&gt;NOT TRUE&lt;/b&gt;. Ripe limes are yellow.
Overripe limes are brown. Always get the ripest limes you can find.
&lt;/p&gt;
&lt;h1&gt;Bryan's Fresh Juice Margaritas
&lt;/h1&gt;
&lt;p&gt;
Yield: About 8 margaritas, depending on the size of your glasses.
&lt;/p&gt;
&lt;h2&gt;Ingredients
&lt;/h2&gt;
&lt;p&gt;
1 1/2 cups freshly squeezed lime juice&lt;br&gt;
1/2 cup freshly squeezed orange juice&lt;br&gt;
1 1/2 cups simple syrup&lt;br&gt;
Cabo Wabo Reposado Tequila
&lt;/p&gt;
&lt;h2&gt;Preparation
&lt;/h2&gt;
&lt;p&gt;
Strain the juices through a strainer into a pitcher. We don't want pulp in our margaritas.
Gently stir in the simple syrup.
&lt;/p&gt;
&lt;p&gt;
Optional: rim the margarita glass with kosher salt by rubbing a lime around the rim
and dipping the rim in salt.
&lt;/p&gt;
&lt;p&gt;
Pour the tequila into the bottom of the margarita glass. Margarita glasses have a
small well at the bottom that blossoms up into a large mouth. I fill the bottom well
in my glasses. Really, it depends on how much tequila you like and how fast you want
to get smashed.
&lt;/p&gt;
&lt;p&gt;
Add a handful of ice to the glass and pour juice mixture over the top until the glass
is full.
&lt;/p&gt;
&lt;p&gt;
Serve the result to a delighted audience.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://blog.slatner.com/aggbug.ashx?id=907c0df3-3f7c-4fbc-b43c-8f7f8e3fb9b0" /&gt;</description>
      <comments>http://blog.slatner.com/CommentView,guid,907c0df3-3f7c-4fbc-b43c-8f7f8e3fb9b0.aspx</comments>
      <category>The Chef</category>
    </item>
    <item>
      <trackback:ping>http://blog.slatner.com/Trackback.aspx?guid=c40d8f17-6979-4d1a-85b2-a8a38a0c6b3e</trackback:ping>
      <pingback:server>http://blog.slatner.com/pingback.aspx</pingback:server>
      <pingback:target>http://blog.slatner.com/PermaLink,guid,c40d8f17-6979-4d1a-85b2-a8a38a0c6b3e.aspx</pingback:target>
      <dc:creator>Bryan Slatner</dc:creator>
      <wfw:comment>http://blog.slatner.com/CommentView,guid,c40d8f17-6979-4d1a-85b2-a8a38a0c6b3e.aspx</wfw:comment>
      <wfw:commentRss>http://blog.slatner.com/SyndicationService.asmx/GetEntryCommentsRss?guid=c40d8f17-6979-4d1a-85b2-a8a38a0c6b3e</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I just made this recipe up tonight. It makes up for the fact that my mahi-mahi was
not fresh and was actually pretty gross. This slaw rocked my world when I bit into
it:
</p>
        <h1>Bryan's Pepper and Mango Slaw
</h1>
        <h2>Ingredients
</h2>
        <p>
1 mango, julienned<br />
1 red bell pepper, julienned<br />
1 yellow or orange bell pepper, julienned<br />
1 granny smith apple, julienned<br />
1/2 red onion, julienned<br />
1 jalapeño pepper, minced<br />
Red wine or apple cider vinegar<br />
Salt and pepper to taste
</p>
        <h2>Preparation
</h2>
        <p>
Put everything in a bowl and toss to combine everything evenly. Add salt and pepper,
using a little more pepper than salt. You just need enough salt to give it a little
oomph. Add a couple tablespoons of vinegar and toss again. Taste the slaw and add
seasoning and vinegar until it's to your liking.
</p>
        <img width="0" height="0" src="http://blog.slatner.com/aggbug.ashx?id=c40d8f17-6979-4d1a-85b2-a8a38a0c6b3e" />
      </body>
      <title>Way cool recipe I just invented</title>
      <guid isPermaLink="false">http://blog.slatner.com/PermaLink,guid,c40d8f17-6979-4d1a-85b2-a8a38a0c6b3e.aspx</guid>
      <link>http://blog.slatner.com/2008/04/16/WayCoolRecipeIJustInvented.aspx</link>
      <pubDate>Wed, 16 Apr 2008 01:39:49 GMT</pubDate>
      <description>&lt;p&gt;
I just made this recipe up tonight. It makes up for the fact that my mahi-mahi was
not fresh and was actually pretty gross. This slaw rocked my world when I bit into
it:
&lt;/p&gt;
&lt;h1&gt;Bryan's Pepper and Mango Slaw
&lt;/h1&gt;
&lt;h2&gt;Ingredients
&lt;/h2&gt;
&lt;p&gt;
1 mango, julienned&lt;br&gt;
1 red bell pepper, julienned&lt;br&gt;
1 yellow or orange bell pepper, julienned&lt;br&gt;
1 granny smith apple, julienned&lt;br&gt;
1/2 red onion, julienned&lt;br&gt;
1 jalapeño pepper, minced&lt;br&gt;
Red wine or apple cider vinegar&lt;br&gt;
Salt and pepper to taste
&lt;/p&gt;
&lt;h2&gt;Preparation
&lt;/h2&gt;
&lt;p&gt;
Put everything in a bowl and toss to combine everything evenly. Add salt and pepper,
using a little more pepper than salt. You just need enough salt to give it a little
oomph. Add a couple tablespoons of vinegar and toss again. Taste the slaw and add
seasoning and vinegar until it's to your liking.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://blog.slatner.com/aggbug.ashx?id=c40d8f17-6979-4d1a-85b2-a8a38a0c6b3e" /&gt;</description>
      <comments>http://blog.slatner.com/CommentView,guid,c40d8f17-6979-4d1a-85b2-a8a38a0c6b3e.aspx</comments>
      <category>The Chef</category>
    </item>
    <item>
      <trackback:ping>http://blog.slatner.com/Trackback.aspx?guid=3b61046f-1757-4914-aac3-0376703f910c</trackback:ping>
      <pingback:server>http://blog.slatner.com/pingback.aspx</pingback:server>
      <pingback:target>http://blog.slatner.com/PermaLink,guid,3b61046f-1757-4914-aac3-0376703f910c.aspx</pingback:target>
      <dc:creator>Bryan Slatner</dc:creator>
      <wfw:comment>http://blog.slatner.com/CommentView,guid,3b61046f-1757-4914-aac3-0376703f910c.aspx</wfw:comment>
      <wfw:commentRss>http://blog.slatner.com/SyndicationService.asmx/GetEntryCommentsRss?guid=3b61046f-1757-4914-aac3-0376703f910c</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
My wife, bless her, usually handles all of the late-night baby issues. She is well
within her rights to wake my lazy ass up and make me do it, but she either loves me
or knows that it would be easier to just deal with it than to way me up. I'm not sure
which.
</p>
        <p>
As a result, I'm a little untrained on how to deal with 2:00am baby issues, which
is how the following conversation came to take place:
</p>
        <p>
          <b>Baby:</b> Waaaaaaaaahhhhh!
</p>
        <p>
          <b>Cecilia:</b> Okay, Bryan, I'm completely exhausted so you are going to go give
the baby her pacifier. You will not make eye contact. You will not speak. You will
not make any noise at all. You will not engage the baby in anyway. You will simply
grab the pacifier, insert it into her mouth, make sure she has a firm grasp on the
stuffed elephant, tuck her in, and return to bed. Do you understand?
</p>
        <p>
          <b>Me:</b> Sir, yes sir!
</p>
        <img width="0" height="0" src="http://blog.slatner.com/aggbug.ashx?id=3b61046f-1757-4914-aac3-0376703f910c" />
      </body>
      <title>A 2:00am Conversation with My Wife</title>
      <guid isPermaLink="false">http://blog.slatner.com/PermaLink,guid,3b61046f-1757-4914-aac3-0376703f910c.aspx</guid>
      <link>http://blog.slatner.com/2007/12/06/A200amConversationWithMyWife.aspx</link>
      <pubDate>Thu, 06 Dec 2007 01:21:58 GMT</pubDate>
      <description>&lt;p&gt;
My wife, bless her, usually handles all of the late-night baby issues. She is well
within her rights to wake my lazy ass up and make me do it, but she either loves me
or knows that it would be easier to just deal with it than to way me up. I'm not sure
which.
&lt;/p&gt;
&lt;p&gt;
As a result, I'm a little untrained on how to deal with 2:00am baby issues, which
is how the following conversation came to take place:
&lt;/p&gt;
&lt;p&gt;
&lt;b&gt;Baby:&lt;/b&gt; Waaaaaaaaahhhhh!
&lt;/p&gt;
&lt;p&gt;
&lt;b&gt;Cecilia:&lt;/b&gt; Okay, Bryan, I'm completely exhausted so you are going to go give
the baby her pacifier. You will not make eye contact. You will not speak. You will
not make any noise at all. You will not engage the baby in anyway. You will simply
grab the pacifier, insert it into her mouth, make sure she has a firm grasp on the
stuffed elephant, tuck her in, and return to bed. Do you understand?
&lt;/p&gt;
&lt;p&gt;
&lt;b&gt;Me:&lt;/b&gt; Sir, yes sir!
&lt;/p&gt;
&lt;img width="0" height="0" src="http://blog.slatner.com/aggbug.ashx?id=3b61046f-1757-4914-aac3-0376703f910c" /&gt;</description>
      <comments>http://blog.slatner.com/CommentView,guid,3b61046f-1757-4914-aac3-0376703f910c.aspx</comments>
      <category>The Jester</category>
    </item>
    <item>
      <trackback:ping>http://blog.slatner.com/Trackback.aspx?guid=d70ac21e-7c13-40fa-8ca8-9b5247aab583</trackback:ping>
      <pingback:server>http://blog.slatner.com/pingback.aspx</pingback:server>
      <pingback:target>http://blog.slatner.com/PermaLink,guid,d70ac21e-7c13-40fa-8ca8-9b5247aab583.aspx</pingback:target>
      <dc:creator>Bryan Slatner</dc:creator>
      <wfw:comment>http://blog.slatner.com/CommentView,guid,d70ac21e-7c13-40fa-8ca8-9b5247aab583.aspx</wfw:comment>
      <wfw:commentRss>http://blog.slatner.com/SyndicationService.asmx/GetEntryCommentsRss?guid=d70ac21e-7c13-40fa-8ca8-9b5247aab583</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
As I've mentioned <a href="http://blog.slatner.com/2007/01/22/CigarReviewCAOMX2.aspx" target="_new">before</a>,
I have a lot of CAO cigars in my humidor.
</p>
        <p>
I generally like CAO's product line. They are not the <b>best</b> cigars in my humidor,
but they are pretty darn close. And some of their cigars, I really love (current CAO
fave: the <b>Criollo</b>).
</p>
        <p>
Every now and again, even knowing how good their cigars are, I get a nice surprise.
</p>
        <p>
Last night, I opened up the "Miscellaneous CAO" drawer in my humidor and my eyes were
drawn to the humble <b>CAO Maduro</b>. It ain't pretty, the wrapper is nothing fancy,
it's just a plain-old maduro cigar.
</p>
        <p>
I suddenly recalled that I'd smoked one of these before, as part of a sampler pack,
and that I'd really enjoyed it. Really <b>really</b> enjoyed it.
</p>
        <p>
"Why haven't I had one of these in a while?" I wondered. The one in the drawer had
been there at least six months. It seemed strange that something I liked so much would
be left to linger for so long, so I decided to end the wait cycle and took the CAO
Maduro out for a spin.
</p>
        <p>
To make a long story short, everything I remembered about the CAO Maduro was accurate.
</p>
        <p>
With the first puffs, I began to experience that classic maduro flavor. You know the
one I mean: that taste of slightly bitter berries that fills up your sinuses and gives
you a full-head cigar sensation.
</p>
        <p>
Next, came my favorite thing about CAO cigars: they consistently delivery big mouthfuls
of smoke. When I'm smoking a cigar, the last thing in the world I want is wimpy smoke
output. I want the smoke to enter my mouth and coat everything, so I can really taste
it, send some out my nose to smell it, and still have plenty left over to do a group
of smoke rings (if I'm so inclined). This "big smoke" characteristic is typical of
the CAO brands, which is one reason I keep coming back to them.
</p>
        <p>
The flavor kept on building as I smoked. And it kept getting better and better, adding
richness and complexity with each puff. Usually, I read while I smoke, but the flavor
of this cigar was good enough that I found it hard to concentrate on my book.
</p>
        <p>
If there is one complaint to make about this particular cigar, it's that about 2/3
of the way through, it started drawing poorly and wouldn't stay lit. But that self-corrected
after about 10 minutes.
</p>
        <p>
Overall, it was a thoroughly enjoyable smoke, and I found myself wondering "Why don't
I have more of these?"
</p>
        <p>
That's a good question. One that I'll have to answer next time I'm at the tobacco
store.
</p>
        <img width="0" height="0" src="http://blog.slatner.com/aggbug.ashx?id=d70ac21e-7c13-40fa-8ca8-9b5247aab583" />
      </body>
      <title>Cigar Review: CAO Maduro</title>
      <guid isPermaLink="false">http://blog.slatner.com/PermaLink,guid,d70ac21e-7c13-40fa-8ca8-9b5247aab583.aspx</guid>
      <link>http://blog.slatner.com/2007/05/25/CigarReviewCAOMaduro.aspx</link>
      <pubDate>Fri, 25 May 2007 16:28:44 GMT</pubDate>
      <description>&lt;p&gt;
As I've mentioned &lt;a href="http://blog.slatner.com/2007/01/22/CigarReviewCAOMX2.aspx" target="_new"&gt;before&lt;/a&gt;,
I have a lot of CAO cigars in my humidor.
&lt;/p&gt;
&lt;p&gt;
I generally like CAO's product line. They are not the &lt;b&gt;best&lt;/b&gt; cigars in my humidor,
but they are pretty darn close. And some of their cigars, I really love (current CAO
fave: the &lt;b&gt;Criollo&lt;/b&gt;).
&lt;/p&gt;
&lt;p&gt;
Every now and again, even knowing how good their cigars are, I get a nice surprise.
&lt;/p&gt;
&lt;p&gt;
Last night, I opened up the "Miscellaneous CAO" drawer in my humidor and my eyes were
drawn to the humble &lt;b&gt;CAO Maduro&lt;/b&gt;. It ain't pretty, the wrapper is nothing fancy,
it's just a plain-old maduro cigar.
&lt;/p&gt;
&lt;p&gt;
I suddenly recalled that I'd smoked one of these before, as part of a sampler pack,
and that I'd really enjoyed it. Really &lt;b&gt;really&lt;/b&gt; enjoyed it.
&lt;/p&gt;
&lt;p&gt;
"Why haven't I had one of these in a while?" I wondered. The one in the drawer had
been there at least six months. It seemed strange that something I liked so much would
be left to linger for so long, so I decided to end the wait cycle and took the CAO
Maduro out for a spin.
&lt;/p&gt;
&lt;p&gt;
To make a long story short, everything I remembered about the CAO Maduro was accurate.
&lt;/p&gt;
&lt;p&gt;
With the first puffs, I began to experience that classic maduro flavor. You know the
one I mean: that taste of slightly bitter berries that fills up your sinuses and gives
you a full-head cigar sensation.
&lt;/p&gt;
&lt;p&gt;
Next, came my favorite thing about CAO cigars: they consistently delivery big mouthfuls
of smoke. When I'm smoking a cigar, the last thing in the world I want is wimpy smoke
output. I want the smoke to enter my mouth and coat everything, so I can really taste
it, send some out my nose to smell it, and still have plenty left over to do a group
of smoke rings (if I'm so inclined). This "big smoke" characteristic is typical of
the CAO brands, which is one reason I keep coming back to them.
&lt;/p&gt;
&lt;p&gt;
The flavor kept on building as I smoked. And it kept getting better and better, adding
richness and complexity with each puff. Usually, I read while I smoke, but the flavor
of this cigar was good enough that I found it hard to concentrate on my book.
&lt;/p&gt;
&lt;p&gt;
If there is one complaint to make about this particular cigar, it's that about 2/3
of the way through, it started drawing poorly and wouldn't stay lit. But that self-corrected
after about 10 minutes.
&lt;/p&gt;
&lt;p&gt;
Overall, it was a thoroughly enjoyable smoke, and I found myself wondering "Why don't
I have more of these?"
&lt;/p&gt;
&lt;p&gt;
That's a good question. One that I'll have to answer next time I'm at the tobacco
store.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://blog.slatner.com/aggbug.ashx?id=d70ac21e-7c13-40fa-8ca8-9b5247aab583" /&gt;</description>
      <comments>http://blog.slatner.com/CommentView,guid,d70ac21e-7c13-40fa-8ca8-9b5247aab583.aspx</comments>
      <category>The Epicurean</category>
    </item>
    <item>
      <trackback:ping>http://blog.slatner.com/Trackback.aspx?guid=64769cf4-a113-43fe-aa08-0be0f4026a52</trackback:ping>
      <pingback:server>http://blog.slatner.com/pingback.aspx</pingback:server>
      <pingback:target>http://blog.slatner.com/PermaLink,guid,64769cf4-a113-43fe-aa08-0be0f4026a52.aspx</pingback:target>
      <dc:creator>Bryan Slatner</dc:creator>
      <wfw:comment>http://blog.slatner.com/CommentView,guid,64769cf4-a113-43fe-aa08-0be0f4026a52.aspx</wfw:comment>
      <wfw:commentRss>http://blog.slatner.com/SyndicationService.asmx/GetEntryCommentsRss?guid=64769cf4-a113-43fe-aa08-0be0f4026a52</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
          <a href="http://www.waiterrant.net/" target="new">Waiter Rant</a> has been out of
commission for several days now.
</p>
        <p>
For anyone wondering what happened, the good folks at <a href="http://www.soundque.com/" target="_new">SoundQue</a> --
who host his site -- have confirmed that the WordPress software Waiter uses was hacked.
</p>
        <p>
I suspected a hacker when, on the first day I began to get suspicious, I looked at
the HTML source and saw that there was a hidden &lt;iframe&gt; tag that was downloading
content from http://www.allddos.biz. None of that sounded good to me.
</p>
        <p>
In any event, I'm assured that Waiter will be back on the air in a couple of days.
</p>
        <img width="0" height="0" src="http://blog.slatner.com/aggbug.ashx?id=64769cf4-a113-43fe-aa08-0be0f4026a52" />
      </body>
      <title>Whither Waiter?</title>
      <guid isPermaLink="false">http://blog.slatner.com/PermaLink,guid,64769cf4-a113-43fe-aa08-0be0f4026a52.aspx</guid>
      <link>http://blog.slatner.com/2007/05/24/WhitherWaiter.aspx</link>
      <pubDate>Thu, 24 May 2007 19:19:45 GMT</pubDate>
      <description>&lt;p&gt;
&lt;a href="http://www.waiterrant.net/" target="new"&gt;Waiter Rant&lt;/a&gt; has been out of
commission for several days now.
&lt;/p&gt;
&lt;p&gt;
For anyone wondering what happened, the good folks at &lt;a href="http://www.soundque.com/" target="_new"&gt;SoundQue&lt;/a&gt; --
who host his site -- have confirmed that the WordPress software Waiter uses was hacked.
&lt;/p&gt;
&lt;p&gt;
I suspected a hacker when, on the first day I began to get suspicious, I looked at
the HTML source and saw that there was a hidden &amp;lt;iframe&amp;gt; tag that was downloading
content from http://www.allddos.biz. None of that sounded good to me.
&lt;/p&gt;
&lt;p&gt;
In any event, I'm assured that Waiter will be back on the air in a couple of days.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://blog.slatner.com/aggbug.ashx?id=64769cf4-a113-43fe-aa08-0be0f4026a52" /&gt;</description>
      <comments>http://blog.slatner.com/CommentView,guid,64769cf4-a113-43fe-aa08-0be0f4026a52.aspx</comments>
      <category>Everything Else</category>
      <category>The Geek</category>
    </item>
    <item>
      <trackback:ping>http://blog.slatner.com/Trackback.aspx?guid=915e85ce-4567-4df2-8853-08e90a51888c</trackback:ping>
      <pingback:server>http://blog.slatner.com/pingback.aspx</pingback:server>
      <pingback:target>http://blog.slatner.com/PermaLink,guid,915e85ce-4567-4df2-8853-08e90a51888c.aspx</pingback:target>
      <dc:creator>Bryan Slatner</dc:creator>
      <wfw:comment>http://blog.slatner.com/CommentView,guid,915e85ce-4567-4df2-8853-08e90a51888c.aspx</wfw:comment>
      <wfw:commentRss>http://blog.slatner.com/SyndicationService.asmx/GetEntryCommentsRss?guid=915e85ce-4567-4df2-8853-08e90a51888c</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Where I work, everyone's e-mail address is first initial, last initial, at vgei.com.
So if you are Pomerania Elbergort, your e-mail address is pe<img src="http://blog.slatner.com/content/binary/atsign.gif" align="middle" border="0" />vgei<img src="http://blog.slatner.com/content/binary/period.gif" align="middle" border="0" />com.
</p>
        <p>
My e-mail, naturally, is bs<img src="http://blog.slatner.com/content/binary/atsign.gif" align="middle" border="0" />vgei<img src="http://blog.slatner.com/content/binary/period.gif" align="middle" border="0" />com.
</p>
        <p>
Do you have any idea how <b>maddening</b> it is to give that address out to somebody
over the phone? This is what I usually wind up saying:
</p>
        <p>
"Yes, that's 'B'-as-in-'boy', 'S'-like-'Sam', no, not 'F', 'S'! 'S'-like-'Sam'! at
'V'-like-'Victor', 'G'-like-'Gary', 'E'-like-'Edward', I dot com."
</p>
        <p>
It makes me want to shoot myself in the head every time I have to say it.
</p>
        <img width="0" height="0" src="http://blog.slatner.com/aggbug.ashx?id=915e85ce-4567-4df2-8853-08e90a51888c" />
      </body>
      <title>My Work E-mail Address Sucks</title>
      <guid isPermaLink="false">http://blog.slatner.com/PermaLink,guid,915e85ce-4567-4df2-8853-08e90a51888c.aspx</guid>
      <link>http://blog.slatner.com/2007/05/24/MyWorkEmailAddressSucks.aspx</link>
      <pubDate>Thu, 24 May 2007 15:51:33 GMT</pubDate>
      <description>&lt;p&gt;
Where I work, everyone's e-mail address is first initial, last initial, at vgei.com.
So if you are Pomerania Elbergort, your e-mail address is pe&lt;img src="http://blog.slatner.com/content/binary/atsign.gif" align="middle" border="0"&gt;vgei&lt;img src="http://blog.slatner.com/content/binary/period.gif" align="middle" border="0"&gt;com.
&lt;/p&gt;
&lt;p&gt;
My e-mail, naturally, is bs&lt;img src="http://blog.slatner.com/content/binary/atsign.gif" align="middle" border="0"&gt;vgei&lt;img src="http://blog.slatner.com/content/binary/period.gif" align="middle" border="0"&gt;com.
&lt;/p&gt;
&lt;p&gt;
Do you have any idea how &lt;b&gt;maddening&lt;/b&gt; it is to give that address out to somebody
over the phone? This is what I usually wind up saying:
&lt;/p&gt;
&lt;p&gt;
"Yes, that's 'B'-as-in-'boy', 'S'-like-'Sam', no, not 'F', 'S'! 'S'-like-'Sam'! at
'V'-like-'Victor', 'G'-like-'Gary', 'E'-like-'Edward', I dot com."
&lt;/p&gt;
&lt;p&gt;
It makes me want to shoot myself in the head every time I have to say it.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://blog.slatner.com/aggbug.ashx?id=915e85ce-4567-4df2-8853-08e90a51888c" /&gt;</description>
      <comments>http://blog.slatner.com/CommentView,guid,915e85ce-4567-4df2-8853-08e90a51888c.aspx</comments>
      <category>The Jester</category>
    </item>
  </channel>
</rss>