<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" 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:copyright="http://blogs.law.harvard.edu/tech/rss" xmlns:image="http://purl.org/rss/1.0/modules/image/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">
    <channel>
        <title>Starin' at the Wall 2.0</title>
        <link>http://jdconley.com/blog/Default.aspx</link>
        <description>.NET/AS3 development and then some</description>
        <language>en-US</language>
        <copyright>JD Conley</copyright>
        <managingEditor>jd@ittybittysoft.com</managingEditor>
        <generator>Subtext Version 1.9.5.176</generator>
        <image>
            <title>Starin' at the Wall 2.0</title>
            <url>http://jdconley.com/blog/images/RSS2Image.gif</url>
            <link>http://jdconley.com/blog/Default.aspx</link>
            <width>77</width>
            <height>60</height>
        </image>
        <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/StarinAtTheWall" /><feedburner:info uri="starinatthewall" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><feedburner:emailServiceId>StarinAtTheWall</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><item>
            <title>Angry Players Make Sunday More Interesting</title>
            <category>tuning</category>
            <category>asp.net</category>
            <link>http://feedproxy.google.com/~r/StarinAtTheWall/~3/-64okgVYvCM/angry-players-make-sunday-more-interesting.aspx</link>
            <description>&lt;p&gt;Youtopia has been growing quickly the last couple of weeks. It's fun to watch and the team is really excited about it. Of course, with the growth comes a lot of performance tuning with our code. Today we hit an issue I wasn't expecting at all. . .&lt;/p&gt;
&lt;p&gt;We've been running Windows 2008, IIS7, and ASP.NET 3.5 in production for a while now, but haven't had to do much of any performance tuning. It &lt;em&gt;just works&lt;/em&gt;, and is fast. Which is awesome!&lt;/p&gt;
&lt;p&gt;But today, Youtopia was running slowly and requests were hanging so I investigated. The databases were performing normally and not having any locking issues. The network looked good. The memcached cluster was healthy. The queueing service looked great. The ASP.NET performance counters even looked good at first glance.&lt;/p&gt;
&lt;p&gt;None of the diagnostic performance monitors I'd used in the past (such as Requests in Application Queue) showed the issue, but requests were absolutely being queued -- or otherwise not processed immediately. There were also plenty of free worker and IOCP threads. The only thing that clued me in was the Pipeline Instance Count and Requests Executing counters were exactly the same (96) on all the servers. So I started investigating from there.&lt;/p&gt;
&lt;p&gt;It turns out that &lt;a href="http://blogs.msdn.com/tmarq/archive/2007/07/21/asp-net-thread-usage-on-iis-7-0-and-6-0.aspx"&gt;due to the way IIS7 ASP.NET integrated mode threading model&lt;/a&gt; functions there is a (configurable) request limit of 12 per CPU. We hit this limit in Youtopia today because we hold open requests for asynchronous Comet-like communications and there were over 288 people online simultaneously. Our three eight core web servers each had 96 (8*12) people connected to them and weren't really serving any other requests. We aren't running into any thread configuration limits as the long running requests are asynchronous and not using ASP.NET worker threads.&lt;/p&gt;
&lt;p&gt;Here are a few great links that came out of my research.&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;a href="http://blogs.msdn.com/tmarq/archive/2007/07/21/asp-net-thread-usage-on-iis-7-0-and-6-0.aspx"&gt;http://blogs.msdn.com/tmarq/archive/2007/07/21/asp-net-thread-usage-on-iis-7-0-and-6-0.aspx&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="http://support.microsoft.com/kb/816995"&gt;http://support.microsoft.com/kb/816995&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ee377050(BTS.10).aspx"&gt;http://msdn.microsoft.com/en-us/library/ee377050(BTS.10).aspx&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="http://blogs.msdn.com/webtopics/archive/2009/02/13/asp-net-hang-in-iis-7-0.aspx"&gt;http://blogs.msdn.com/webtopics/archive/2009/02/13/asp-net-hang-in-iis-7-0.aspx&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With ASP.NET 3.5 SP1 it boils down to a simple configuration file change. Use something like this in the aspnet.config file (in x64 it's at C:\Windows\Microsoft.NET\Framework64\v2.0.50727\aspnet.config). This is the default. Adjust maxConcurrentRequestsPerCPU to suit your needs.&lt;/p&gt;
&lt;pre class="brush: xml"&gt;
    &amp;lt;system.web&amp;gt;
        &amp;lt;applicationPool maxConcurrentRequestsPerCPU="12" maxConcurrentThreadsPerCPU="0" requestQueueLimit="5000"/&amp;gt;
    &amp;lt;/system.web&amp;gt;
&lt;/pre&gt;
&lt;p&gt;In addition, the application pool needs to be configured to allow more requests. By default it only allows 1000 concurrent requests. This is done under the Advanced Settings for the application pool in the IIS 7 manager. Set Queue Length to 5000 to match this system level configuration.&lt;/p&gt;&lt;img src="http://jdconley.com/blog/aggbug/67.aspx" width="1" height="1" /&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/StarinAtTheWall?a=-64okgVYvCM:5h6TgFqmY0o:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/StarinAtTheWall?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/StarinAtTheWall?a=-64okgVYvCM:5h6TgFqmY0o:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/StarinAtTheWall?i=-64okgVYvCM:5h6TgFqmY0o:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/StarinAtTheWall?a=-64okgVYvCM:5h6TgFqmY0o:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/StarinAtTheWall?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/StarinAtTheWall?a=-64okgVYvCM:5h6TgFqmY0o:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/StarinAtTheWall?i=-64okgVYvCM:5h6TgFqmY0o:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/StarinAtTheWall?a=-64okgVYvCM:5h6TgFqmY0o:XAVGb8Xj5zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/StarinAtTheWall?d=XAVGb8Xj5zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
            <dc:creator>JD Conley</dc:creator>
            <guid isPermaLink="false">http://jdconley.com/blog/archive/2009/11/22/angry-players-make-sunday-more-interesting.aspx</guid>
            <pubDate>Sun, 22 Nov 2009 23:48:06 GMT</pubDate>
            <wfw:comment>http://jdconley.com/blog/comments/67.aspx</wfw:comment>
            <comments>http://jdconley.com/blog/archive/2009/11/22/angry-players-make-sunday-more-interesting.aspx#feedback</comments>
            <slash:comments>96</slash:comments>
            <wfw:commentRss>http://jdconley.com/blog/comments/commentRss/67.aspx</wfw:commentRss>
            <trackback:ping>http://jdconley.com/blog/services/trackbacks/67.aspx</trackback:ping>
        <feedburner:origLink>http://jdconley.com/blog/archive/2009/11/22/angry-players-make-sunday-more-interesting.aspx</feedburner:origLink></item>
        <item>
            <title>Ditch Your Events (Part 1)</title>
            <category>.net</category>
            <category>tuning</category>
            <category>as3</category>
            <link>http://feedproxy.google.com/~r/StarinAtTheWall/~3/UHfy-eZwWBw/ditch-your-events-part-1.aspx</link>
            <description>&lt;p&gt;
    About four months ago Max, Hive7's &lt;a href="http://corp.hive7.com/about/"&gt;Lawful Evil
      CEO&lt;/a&gt;, decided we needed to take our games to the next level and build something
    fun and accessible that everyone who plays "those farming games" would want to play.
    We all brainstormed, pitched our ideas to the company, and everyone voted by comparing
    every idea against every other – I wish we had a digital photo of the giant
    matrix on the whiteboard. There were a bunch of great ideas, but in the end... I
    won! &lt;a href="http://apps.facebook.com/you-topia/landing?ref=jd"&gt;Youtopia&lt;/a&gt; was
    born.
  &lt;/p&gt;
  &lt;p&gt;
    Youtopia was released to the public about three months from its inception. Hats
    off to the dev and art team for pulling this one together. A new technology for
    the developers and fully animated objects for the art team led to much blood, sweat,
    and tears, but we got 'er done! Of course, we're still actively developing Youtopia,
    and there are lots of great things planned for the future! But, back to my tech
    article...
  &lt;/p&gt;
  &lt;p&gt;
    It's been a long time since I've stepped out of my comfort zone and learned a new
    (to me) technology. Don't get me wrong, I'm always experimenting with the lastest
    .NET based thingie-ma-bobbers out there, but I haven't used a completely foreign
    development environment since C#/.NET came out over eight years ago. But for this
    project I needed to learn Flash/AS3, and it needed to be done yesterday. Luckily
    for me nobody else on our dev team knew Flash so I could still pretend like I knew
    what I was talking about and make lots of (un)educated architectural decisions without
    anyone being the wiser!
  &lt;/p&gt;
  &lt;p&gt;
    One such recent decision was to use an event driven property binding system. Youtopia's
    engine is based on a great open source game engine, brought to you from some of
    the Dyamix/GarageGames people, called the &lt;a href="http://www.pushbuttonengine.com"&gt;
      PushButton Engine&lt;/a&gt; (or PBE). In PBE there is a class called PropertyReference.
    This class facilitates a late-bound approach for one component to read the value
    of a property (member variable or getter/setter) on another component. It's a pretty
    cool pattern, but requires you to poll the target component whenever you want to
    know if the property changed. This works fine when you're talking about 10's or
    100's of components. But in Youtopia we have thousands of entities in the scene
    at once. We needed this binding to be event-driven.
  &lt;/p&gt;
  &lt;p&gt;
    Of course, with my .NET background I immediately reached for the &lt;a href="http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx"&gt;
      INotifyPropertyChanged&lt;/a&gt; pattern used in .NET's data binding infrastructure.
    With INotifyPropertyChanged it is the responsibility of the object owning the property
    to raise an event whenever a property value changes. Any listeners will then immediately
    know they need to poll for the new value if they want it.
  &lt;/p&gt;
  &lt;p&gt;
    This works great in .NET and is very performant. But in Flash, events are a whole
    other story. They are an extremely feature-rich subsystem that I don't really want
    to get into. In the end, all the features and memory allocations when you raise
    an event lead to poorer performance than we needed for Youtopia. We need every bit
    of CPU power on that single Flash thread and really shouldn't be wasting it raising
    events.
  &lt;/p&gt;
  &lt;p&gt;
    So, I shamelessly copied the .NET patterns and brought them over to AS3. Let's start
    at the core. In order for things to perform their best, I &lt;a href="http://troygilbert.com/2009/09/events-vs-callbacks/"&gt;
      couldn't use&lt;/a&gt; the built-in Events. Though Troy did the benchmarking legwork,
    he didn't provide an implementation we could use to register callbacks and call
    multiple functions. So, I wrote a MulticastFunction that behaves a whole lot like
    the &lt;a href="http://msdn.microsoft.com/en-us/library/system.multicastdelegate.aspx"&gt;
      MulticastDelegate&lt;/a&gt; in .NET. Usage is really straightforward.
  &lt;/p&gt;
  &lt;pre class="brush: as3"&gt;
  var func:MulticastFunction = new MulticastFunction();
  
  //register my listener callback
  func.add(
    function():void 
    {
      //this callback does amazingly cool stuff
      trace("hello from the callback");
    });
  
  //calls all the callbacks that have been added, in the order they were added
  func.apply();
  &lt;/pre&gt;
  &lt;p&gt;
    As you can see, dealing with the MulticastFunction is a lot like the EventDispatcher,
    but each MulticastFunction is only designed to be used for a single event. So, to
    use it for events, create a public getter on your class named something reasonable
    and add your callbacks to it. Done!
  &lt;/p&gt;
  &lt;p&gt;
    Ok, I realize I keep talking about event dispatching speed, but haven't put my money
    where my mouth is. I wrote some benchmarks of my own and here is the output with
    a release build, in the latest standalone Flash 10 player. It does five test runs.
    &lt;a href="http://jdconley.com/blog/downloads/CSharpAS3.zip"&gt;Download the Source&lt;/a&gt;
  &lt;/p&gt;
  &lt;pre&gt;
running tests...
Event dispatching took 848ms
MulticastFunction took 355ms

running tests...
Event dispatching took 846ms
MulticastFunction took 351ms

running tests...
Event dispatching took 834ms
MulticastFunction took 352ms

running tests...
Event dispatching took 836ms
MulticastFunction took 351ms

running tests...
Event dispatching took 823ms
MulticastFunction took 343ms  
  &lt;/pre&gt;
  &lt;p&gt;
    Yup, that's right. MulticastFunction is nearly 2.5x faster, and I haven't spent
    much time tuning it. For example, it's using an Array under the hood and doing more
    work than it needs to during the apply call. Events will also become less performant
    over time as you have to create (and potentially clone) Event objects for every
    dispatch, causing a lot of garbage collection pressure. Here's the MulticastFunction,
    with lots of comments or you can &lt;a href="http://jdconley.com/blog/downloads/CSharpAS3.zip"&gt;download the source&lt;/a&gt;
  &lt;/p&gt;
  &lt;pre class="brush: as3"&gt;
package com.jdconley
{
    /**
     * A wrapper that mimics the synchronous behavior of the MulticastDelegate used in .NET for events.
     * This doesn't support any of the async methods, as we don't have free threading here.
     * It also doesn't support return values.
     * See: http://msdn.microsoft.com/en-us/library/system.multicastdelegate.aspx
     */
    public class MulticastFunction
    {
        private var _functions:Array = [];
        private var _iterators:int = 0;

        /**
         * Adds a function to be called when apply is called.
         * If the function is already in the list it won't be added twice.
         * Returns true if the function was added.
         **/
        public function add(func:Function):Boolean
        {
            var i:int = _functions.indexOf(func);
            if (i &amp;gt; -1)
                return false;

            //add new functions to the end so they are picked up live during an apply
            _functions.push(func);
            return true;
        }

        /**
         * Removes a function to be called when apply is called.
         * Returns true if the function was removed.
         **/
        public function remove(func:Function):Boolean
        {
            var i:int = _functions.indexOf(func);
            if (i &amp;lt; 0)
                return false;

            if (_iterators == 0)
                _functions.splice(i, 1);
            else
                _functions[i] = null;

            return true;
        }

        /**
         * Synchronously applies all functions that have been added.
         * Functions can be safely added or removed during an apply and changes will take effect immediately.
         * Added functions will be called, and removed functions will not.
         **/
        public function apply(thisArg:*=null, argArray:*=null):void
        {
            _iterators++;
            var holes:Boolean = false;
            
            for (var i:int = 0; i &amp;lt; _functions.length; i++)
            {
                var f:Function = _functions[i];
                if (f == null)
                    holes = true;
                else
                    f.apply(thisArg, argArray);
            }

            //cleanup holes left by removing functions during this apply call.
            //if any of the function apply's throw an error the state of _iterators will be off.
            //but, we'll only leak array slot memory if functions are removed.
            //putting a try/finally or try/catch block here significantly decreases performance.
            if (--_iterators == 0 &amp;amp;&amp;amp; holes)
            {
                for (i = _functions.length - 1; i &amp;gt;= 0; i--)
                {
                    if (_functions[i] == null)
                        _functions.splice(i, 1);
                }            
            }
        }

        /**
         * Removes all functions from the list. Stops the current apply call, if there is one.
         **/
        public function clear():void
        {
            _functions = [];
        }
    }
}
  &lt;/pre&gt;
  &lt;p&gt;
    Although capture, bubble, weak references, and priority are handy features of the
    Flash eventing system, they're not always necessary and will hurt your performance
    when you might have thousands of them firing per frame.&lt;/p&gt;
  &lt;p&gt;
    In Part 2 we'll put this MulticastFunction to use in a more meaningful way with
    the INotifyPropertyChanged implementation.&lt;/p&gt;&lt;img src="http://jdconley.com/blog/aggbug/66.aspx" width="1" height="1" /&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/StarinAtTheWall?a=UHfy-eZwWBw:EVHuKLhLW5Q:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/StarinAtTheWall?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/StarinAtTheWall?a=UHfy-eZwWBw:EVHuKLhLW5Q:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/StarinAtTheWall?i=UHfy-eZwWBw:EVHuKLhLW5Q:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/StarinAtTheWall?a=UHfy-eZwWBw:EVHuKLhLW5Q:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/StarinAtTheWall?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/StarinAtTheWall?a=UHfy-eZwWBw:EVHuKLhLW5Q:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/StarinAtTheWall?i=UHfy-eZwWBw:EVHuKLhLW5Q:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/StarinAtTheWall?a=UHfy-eZwWBw:EVHuKLhLW5Q:XAVGb8Xj5zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/StarinAtTheWall?d=XAVGb8Xj5zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
            <dc:creator>JD Conley</dc:creator>
            <guid isPermaLink="false">http://jdconley.com/blog/archive/2009/11/16/ditch-your-events-part-1.aspx</guid>
            <pubDate>Mon, 16 Nov 2009 19:30:11 GMT</pubDate>
            <wfw:comment>http://jdconley.com/blog/comments/66.aspx</wfw:comment>
            <comments>http://jdconley.com/blog/archive/2009/11/16/ditch-your-events-part-1.aspx#feedback</comments>
            <slash:comments>75</slash:comments>
            <wfw:commentRss>http://jdconley.com/blog/comments/commentRss/66.aspx</wfw:commentRss>
            <trackback:ping>http://jdconley.com/blog/services/trackbacks/66.aspx</trackback:ping>
        <feedburner:origLink>http://jdconley.com/blog/archive/2009/11/16/ditch-your-events-part-1.aspx</feedburner:origLink><enclosure url="http://feedproxy.google.com/~r/StarinAtTheWall/~5/eojjqccPqU0/CSharpAS3.zip" length="13761" type="application/x-zip-compressed" /><feedburner:origEnclosureLink>http://jdconley.com/blog/downloads/CSharpAS3.zip</feedburner:origEnclosureLink></item>
        <item>
            <title>Anyone still out there?</title>
            <category>.net</category>
            <category>as3</category>
            <link>http://feedproxy.google.com/~r/StarinAtTheWall/~3/lh2JgLhu9mk/anyone-still-out-there.aspx</link>
            <description>&lt;p&gt;
    Wow, I haven't posted in a while. In recent months I've been focused intently on
    a few things.&lt;/p&gt;
  &lt;ol&gt;
    &lt;li&gt;Babies! My wife and I had twins in February.&lt;/li&gt;
    &lt;li&gt;Learning a new technology while shipping an &lt;a href="http://apps.facebook.com/you-topia/landing?ref=jd"&gt;
      amazing game&lt;/a&gt; at Hive7.&lt;/li&gt;
    &lt;li&gt;Working on a &lt;a href="http://www.pushbuttonengine.com"&gt;cool open source project&lt;/a&gt;.&lt;/li&gt;
  &lt;/ol&gt;
  &lt;p&gt;
    I won't bore all you geeks with the baby stuff. If you can find the link to my personal
    blog you can go look at lots of pictures.&lt;/p&gt;
  &lt;p&gt;
    You should all check out &lt;a href="http://apps.facebook.com/you-topia/landing?ref=jd"&gt;
      Youtopia&lt;/a&gt; (the new game we shipped). We're really proud of this one.&lt;/p&gt;
  &lt;p&gt;
    So, drumroll please... *in my most awesome announcer voice* And, the new technology
    is... Flash! That's right, this Microsoft fanboy is now in the Flash camp. I really
    wish I could be working with Silverlight, but well, you can't build a game that
    runs on Facebook and make people install something. It just won't work. Once Silverlight
    has a market share more like Flash Player, then we're in business.&lt;/p&gt;
  &lt;p&gt;
    What do I dislike most about Flash? The development environments (yes, plural) for Flash pale
    in comparison to Visual Studio. Compiling is slow. Stuff crashes a lot. Heck, I
    even got the compiler to throw a null pointer exception on a few occasions! Debugging
    is a pain. The garbage collector isn't very fast. You only have &lt;strong&gt;one&lt;/strong&gt;
    thread to work with. Hey Adobe is it still 1998?
  &lt;/p&gt;
  &lt;p&gt;
    All that being said, Flash (and more specifically Actionscript 3 and Flash Player)
    is actually really mature now and a decent piece of technology. It has most things
    a developer looks for in a language/runtime. And, well, it allows us to create a
    really rich and interactive experience that runs in your browser and doesn't require
    you to install anything. Obviously the business case here wins out over my whining.&lt;/p&gt;
  &lt;p&gt;
    I think I've spent enough time talking. Coming very soon, a useful post that contains
    lots of great technical info from the perspective of a C# junky diving head first
    into Flash.
  &lt;/p&gt;&lt;img src="http://jdconley.com/blog/aggbug/65.aspx" width="1" height="1" /&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/StarinAtTheWall?a=lh2JgLhu9mk:4LQ1a3b9l7c:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/StarinAtTheWall?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/StarinAtTheWall?a=lh2JgLhu9mk:4LQ1a3b9l7c:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/StarinAtTheWall?i=lh2JgLhu9mk:4LQ1a3b9l7c:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/StarinAtTheWall?a=lh2JgLhu9mk:4LQ1a3b9l7c:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/StarinAtTheWall?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/StarinAtTheWall?a=lh2JgLhu9mk:4LQ1a3b9l7c:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/StarinAtTheWall?i=lh2JgLhu9mk:4LQ1a3b9l7c:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/StarinAtTheWall?a=lh2JgLhu9mk:4LQ1a3b9l7c:XAVGb8Xj5zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/StarinAtTheWall?d=XAVGb8Xj5zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
            <dc:creator>JD Conley</dc:creator>
            <guid isPermaLink="false">http://jdconley.com/blog/archive/2009/11/13/anyone-still-out-there.aspx</guid>
            <pubDate>Fri, 13 Nov 2009 22:49:33 GMT</pubDate>
            <wfw:comment>http://jdconley.com/blog/comments/65.aspx</wfw:comment>
            <comments>http://jdconley.com/blog/archive/2009/11/13/anyone-still-out-there.aspx#feedback</comments>
            <slash:comments>66</slash:comments>
            <wfw:commentRss>http://jdconley.com/blog/comments/commentRss/65.aspx</wfw:commentRss>
            <trackback:ping>http://jdconley.com/blog/services/trackbacks/65.aspx</trackback:ping>
        <feedburner:origLink>http://jdconley.com/blog/archive/2009/11/13/anyone-still-out-there.aspx</feedburner:origLink></item>
        <item>
            <title>Functional Optimistic Concurrency in C#</title>
            <category>linq</category>
            <category>utility</category>
            <category>architecture</category>
            <link>http://feedproxy.google.com/~r/StarinAtTheWall/~3/WyYvHG7MFOI/functional-optimistic-concurrency-in-c.aspx</link>
            <description>&lt;p&gt;A few months ago Phil Haack wrote about how C# 3.0 is a  &lt;a href="http://haacked.com/archive/2009/02/15/the-functional-language-gateway-drug.aspx"&gt;gateway drug&lt;/a&gt;  to functional programming. (Yeah, that's how long ago I started writing this blog.)  I couldn't agree more. I find myself solving problems using functional rather than imperative programming quite often nowadays. It's much more elegant for many problem spaces.&lt;/p&gt;
&lt;p&gt;Before we go any further, here's the sample app used for this article. Even if you don't like my writing, you should play with it. Yeah, you! &lt;a href="http://jdconley.com/blog/downloads/optimistic-concurrency.zip"&gt;optimistic-concurrency.zip&lt;/a&gt;&lt;/p&gt;
&lt;p&gt; One problem space that fits very well with functional patterns is in developing apps that have to use &lt;a href="http://jdconley.com/blog/archive/2009/01/20/concurrency.-its-like-doing-the-dishes.aspx"&gt;optimistic concurrency&lt;/a&gt;  to maintain data consistency at scale. Here at Hive7 we build PvP games. In such games, multiple  people and background  processes are often affecting the same entity at the same time. We can't use coarse grained locks or high isolation levels in MS-SQL, or the whole game would come to a halt. Here's a common scenario in a game like &lt;a href="http://corp.hive7.com/games/knighthood/"&gt;Knighthood&lt;/a&gt;: &lt;/p&gt;
&lt;blockquote style="height: 175px;"&gt;
&lt;p&gt;&lt;img style="border: 0pt none ; float: left;" src="http://knight.fb.hive7.com/res/img/area/wall.png?63356112540" alt="" /&gt; Multiple rival lords are attacking my Kingdom at once trying to steal my most prized vassal, my wife! My wall is staffed with a heavy defense, and my hospital has a strong set of medics healing my kingdom over time. But to keep a handle on  the attack I also have to continuously spend gold to heal my defensive army.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt; In this common use case there are a number of subtleties. First, multiple people are attacking me at once. That  means they're doing damage to my defenses in real time, and at the same time. My hospital is healing my vassals over time. This occurs in a background process once every few minutes. And I'm triggering an instant heal to my defensive vassals using my gold supply. My Marketplace is also generating gold for me over time in another background process. To top it all off, this is happening across a cluster of  application servers that are certain to be processing multiple requests simultaneously. Phew! &lt;/p&gt;
&lt;p&gt; So what does all that mean? Well, basically, there are a lot of possibilities for change conflicts. And we have to  deal with those conflicts to both keep a consistent data model and perform well.  &lt;/p&gt;
&lt;p&gt; There are a a number of potential strategies for managing these change conflicts in the persistent store – a few beefy Microsoft  SQL Server databases in our case. We chose to go with optimistic concurrency and an abort on conflict transaction strategy. That basically means when we write data to the database we make sure we are always writing the most recent version of a row. If an application attempts to write an old version of the row, the data access layer throws an exception and aborts the transaction. Knighthood uses &lt;a href="http://www.hibernate.org"&gt;NHibernate&lt;/a&gt; so the validation is done for us automatically using a  simple version number on the row. The basic algorithm is: &lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;Read data and serialize into objects (done by NHibernate)&lt;/li&gt;
    &lt;li&gt;Modify objects in code&lt;/li&gt;
    &lt;li&gt;Tell NHibernate to persist the changes, which does the following
    &lt;ol&gt;
        &lt;li&gt;Increments the version number&lt;/li&gt;
        &lt;li&gt;Finds all the changes and batches up insert/update calls&lt;/li&gt;
        &lt;li&gt;Uses the version number in the WHERE clause of updates like: "UPDATE Table SET Col1='blah' WHERE Version=36"&lt;/li&gt;
        &lt;li&gt;Checks the rows modified reported by SQL server and throws an exception if it's an unexpected number&lt;/li&gt;
    &lt;/ol&gt;
    &lt;/li&gt;
&lt;/ol&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;p&gt; As you can imagine, this fails regularly in a high concurrency scenario, but it succeeds orders of magnitude more often than not. It's also pretty standard for any web app nowadays. &lt;/p&gt;
&lt;p&gt; The only problem is, to preserve consistency, an exception is thrown and the transaction is aborted when change conflicts occur.  That means whatever request the application or user issued fails. We could show the user a friendly error message, but that would be a  frustrating experience. Nobody likes seeing errors for non-obvious reasons. And in the case of headless software running in the  background the error would just be in a log somewhere. If it's something important that needs to happen, then we have to make sure it gets done! So us imperative programmers devise a retry scheme and write a loop with an exception trap around our code.  Maybe you get clever and create a class that does this which raises an event any time you need to execute your retry-able code.  But, this gets pretty cumbersome. Enter functional programming! &lt;/p&gt;
&lt;p&gt; We have a little class named DataActions that is used to simplify and consolidate this retry process and make it painless to use. I'm going to use LINQ to SQL as the example here. Here's some usage code: &lt;/p&gt;
&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;pre class="csharpcode"&gt;DataActions.ExecuteOptimisticSubmitChanges&amp;lt;GameDataContext&amp;gt;(&lt;br /&gt;    dc =&amp;gt;&lt;br /&gt;    {&lt;br /&gt;        var playerToMod = dc.Players.Where(p =&amp;gt; p.ID == playerId).Single();&lt;br /&gt;        SetRandomGold(playerToMod);&lt;br /&gt;    });&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;p&gt; As you can see it's really straight forward. Notice all the goodness going on there. We don't have to instantiate our own DataContext, manually submit the changes, or worry at all about transactions. It's all handled by the wrapper. And, you just have to provide some  code to execute once the DataContext has been instantiated. &lt;/p&gt;
&lt;p&gt; The ExecuteOptimisticSubmitChanges helper method itself is pretty simple as well: &lt;/p&gt;
&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; &lt;br /&gt;ExecuteOptimisticSubmitChanges&amp;lt;TDataContext&amp;gt;(Action&amp;lt;TDataContext&amp;gt; action)&lt;br /&gt;    &lt;span class="kwrd"&gt;where&lt;/span&gt; TDataContext : DataContext, &lt;span class="kwrd"&gt;new&lt;/span&gt;()&lt;br /&gt;{&lt;br /&gt;    Retry(() =&amp;gt;&lt;br /&gt;&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="kwrd"&gt;using&lt;/span&gt; (var ts = &lt;span class="kwrd"&gt;new&lt;/span&gt; TransactionScope())&lt;br /&gt;            {&lt;br /&gt;                &lt;span class="kwrd"&gt;using&lt;/span&gt; (var dc = &lt;span class="kwrd"&gt;new&lt;/span&gt; TDataContext())&lt;br /&gt;                {&lt;br /&gt;                    action(dc);&lt;br /&gt;                    dc.SubmitChanges();&lt;br /&gt;                    ts.Complete();&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        });&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;p&gt;  And, finally, we have the Retry method: &lt;/p&gt;
&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Retry(Action a)&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;const&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; retries = 5;&lt;br /&gt;    &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i = 0; i &amp;lt; retries; i++)&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;try&lt;/span&gt;          {             a();             &lt;span class="kwrd"&gt;break&lt;/span&gt;;&lt;br /&gt;        }&lt;br /&gt;        &lt;span class="kwrd"&gt;catch&lt;/span&gt;         {             &lt;span class="kwrd"&gt;if&lt;/span&gt; (i == retries - 1) &lt;span class="kwrd"&gt;throw&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;            &lt;span class="rem"&gt;//exponential/random retry back-off.&lt;/span&gt;             var rand = &lt;span class="kwrd"&gt;new&lt;/span&gt; Random(Guid.NewGuid().GetHashCode());&lt;br /&gt;            &lt;span class="kwrd"&gt;int&lt;/span&gt; nextTry = rand.Next(&lt;br /&gt;              (&lt;span class="kwrd"&gt;int&lt;/span&gt;)Math.Pow(i, 2), (&lt;span class="kwrd"&gt;int&lt;/span&gt;)Math.Pow(i + 1, 2) + 1);&lt;br /&gt;&lt;br /&gt;            Thread.Sleep(nextTry);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;p&gt; When you string all this together you get pseudo-stacks that look like: &lt;/p&gt;
&lt;pre&gt;MyCode&lt;br /&gt;  ExecuteOptimisticSubmitChanges&lt;br /&gt;    Retry&lt;br /&gt;      ExecuteOptimisticSubmitChanges&lt;br /&gt;        MyCode&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt; So, why should you care? The calling code is really easy to read, and you get a number of other benefits with this code. In addition to handling exceptions caused by concurrency errors, you also get retries on deadlocks, and more common Sql Connection errors. &lt;/p&gt;
&lt;p&gt; I put together a little sample application you can play with. It uses these helpers and has a SQL Database with it. The sample simulates really high concurrency and you can watch it deal gracefully with deadlocks. Then you can change  line 29 of Program.cs and execute the same concurrent code without retries enabled. It ouputs the number of failed transactions and a bunch of other interesting stuff to the console. Here's some example output: &lt;/p&gt;
&lt;pre&gt; ...  Retrying after iteration 0 in 1ms Retrying after iteration 0 in 0ms Thread finished with 0 failures. Concurrency at 3&lt;br /&gt;Retrying after iteration 1 in 3ms&lt;br /&gt;Retrying after iteration 1 in 4ms&lt;br /&gt;Thread finished with 0 failures. Concurrency at 2&lt;br /&gt;Retrying after iteration 2 in 5ms&lt;br /&gt;Thread finished with 0 failures. Concurrency at 1&lt;br /&gt;Retrying after iteration 3 in 15ms&lt;br /&gt;Thread finished with 0 failures. Concurrency at 0&lt;br /&gt;&lt;br /&gt;0 total failures and 7 total retries.&lt;br /&gt;All done. Hit enter to exit.&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt; And the same test run with retries disabled: &lt;/p&gt;
&lt;pre&gt; ...  Starting worker. Concurrency at 8&lt;br /&gt;Thread finished with 0 failures. Concurrency at 7&lt;br /&gt;Thread finished with 0 failures. Concurrency at 6&lt;br /&gt;Thread finished with 1 failures. Concurrency at 5&lt;br /&gt;Thread finished with 1 failures. Concurrency at 4&lt;br /&gt;Thread finished with 1 failures. Concurrency at 2&lt;br /&gt;Thread finished with 2 failures. Concurrency at 3&lt;br /&gt;Thread finished with 0 failures. Concurrency at 1&lt;br /&gt;Thread finished with 2 failures. Concurrency at 0&lt;br /&gt;&lt;br /&gt;7 total failures and 0 total retries.&lt;br /&gt;All done. Hit enter to exit.&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;p&gt;Here's the download link again: &lt;a href="http://jdconley.com/blog/downloads/optimistic-concurrency.zip"&gt;optimistic-concurrency.zip&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Let me know if you have any questions.&lt;/p&gt;&lt;img src="http://jdconley.com/blog/aggbug/64.aspx" width="1" height="1" /&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/StarinAtTheWall?a=WyYvHG7MFOI:rpOUoMcUUTw:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/StarinAtTheWall?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/StarinAtTheWall?a=WyYvHG7MFOI:rpOUoMcUUTw:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/StarinAtTheWall?i=WyYvHG7MFOI:rpOUoMcUUTw:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/StarinAtTheWall?a=WyYvHG7MFOI:rpOUoMcUUTw:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/StarinAtTheWall?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/StarinAtTheWall?a=WyYvHG7MFOI:rpOUoMcUUTw:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/StarinAtTheWall?i=WyYvHG7MFOI:rpOUoMcUUTw:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/StarinAtTheWall?a=WyYvHG7MFOI:rpOUoMcUUTw:XAVGb8Xj5zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/StarinAtTheWall?d=XAVGb8Xj5zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
            <dc:creator>JD Conley</dc:creator>
            <guid isPermaLink="false">http://jdconley.com/blog/archive/2009/06/26/functional-optimistic-concurrency-in-c.aspx</guid>
            <pubDate>Fri, 26 Jun 2009 07:00:00 GMT</pubDate>
            <wfw:comment>http://jdconley.com/blog/comments/64.aspx</wfw:comment>
            <comments>http://jdconley.com/blog/archive/2009/06/26/functional-optimistic-concurrency-in-c.aspx#feedback</comments>
            <slash:comments>98</slash:comments>
            <wfw:commentRss>http://jdconley.com/blog/comments/commentRss/64.aspx</wfw:commentRss>
            <trackback:ping>http://jdconley.com/blog/services/trackbacks/64.aspx</trackback:ping>
        <feedburner:origLink>http://jdconley.com/blog/archive/2009/06/26/functional-optimistic-concurrency-in-c.aspx</feedburner:origLink><enclosure url="http://feedproxy.google.com/~r/StarinAtTheWall/~5/THR4uP_pExU/optimistic-concurrency.zip" length="174544" type="application/x-zip-compressed" /><feedburner:origEnclosureLink>http://jdconley.com/blog/downloads/optimistic-concurrency.zip</feedburner:origEnclosureLink></item>
        <item>
            <title>A new basket for my eggs</title>
            <category>business</category>
            <category>facebook</category>
            <category>azure</category>
            <link>http://feedproxy.google.com/~r/StarinAtTheWall/~3/sD5tM0zfhEA/a-new-basket-for-my-eggs.aspx</link>
            <description>&lt;p&gt;Hopefully after reading that title you're thinking of the old adage "Don't put all your eggs in one basket" and not something crude. Ok, I admit, either way it works for me. You're still reading.&lt;/p&gt;
&lt;p&gt;Let me preface by saying I love what's going on at Hive7, but a guy's gotta have a side project. In fact I wrote about &lt;a href="http://jdconley.com/blog/archive/2009/01/19/dont-hire-a-programmer-if-they-dont-code-for-fun.aspx"&gt;this phenomenon&lt;/a&gt; a while back. And, in my mind, that side project might as well make me some lunch money.&lt;/p&gt;
&lt;p&gt;For the last two years or so I've been really interested in digital photos and the untapped markets that lie within. In fact, I got introduced to Hive7 while trying to sell myself to an investor to get some angel funding in the space. I'm not a pro photographer wannabe or anything like that. I just think digital photos are a great medium for sharing life with friends and family. I have built &lt;a href="http://www.facebook.com/apps/application.php?id=2466327790"&gt;Friend Photosaver&lt;/a&gt; for Facebook (a screen saver using Facebook photos), &lt;a href="http://www.facebook.com/apps/application.php?id=7515202213"&gt;Photo Feeds&lt;/a&gt; for Facebook (automatic photo RSS creator for Facebook), and &lt;a href="http://www.facebook.com/apps/application.php?id=5577408502"&gt;Photozap&lt;/a&gt; (a tool to download Facebook photos as a zip file).&lt;/p&gt;
&lt;p&gt;Those applications are all pretty cool, but didn't really strike me (or anyone else) as especially compelling. But, they did lead me down the path of building something that I think is pretty interesting.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Everyone&lt;/strong&gt; has a digital camera or cell phone camera. When you go to a social gathering of any sort there are usually tens to hundreds of photos taken. Think of weddings, birthdays, graduations, family bbq's, night clubs. . . . What happens to these photos? Someone copies them to their computer, or uploads them to a photo sharing web site. They send out links or maybe share the photos through a social network's tagging or posting features or some such. That's all fine and good, but I think there's more to be had.&lt;/p&gt;
&lt;p&gt;Enter &lt;a href="http://www.pixur.me"&gt;pixur.me&lt;/a&gt;. Quoting the about page:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Pixur.me is a different kind of online photo sharing service. Our mission is to focus on the person receiving photos, rather than the one taking them. There are a lot of great services where you can organize your own photos and share them with people, but we think that's only half of the equation.&lt;/p&gt;
&lt;p&gt;Can you find all the cute pictures of your kids from your last family vacation? Or how about all the photos from your wedding that your guests took? Could your mother find those same photos?&lt;/p&gt;
&lt;p&gt;You could if your family was using pixur.me! What if all the photos that everyone took at that last vacation or your wedding were in one spot? Even though Aunt Sue uses Flickr, and you use Facebook, and your mother uses Picasa. That's pixur.me. Create a Stream and see for yourself! Once your stream is created anyone can add photos to it, regardless of where they are stored online.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That's it. Another basket awaiting some eggs. &lt;a href="http://www.pixur.me"&gt;Give it a spin&lt;/a&gt; and let me know what you think. Of course, it's not very interesting if you just use it by yourself. Create a stream and give out the link at your next gathering. Or maybe start a stream that your extended family can add photos to so grandma can see them all in one spot.&lt;/p&gt;
&lt;p&gt;Oh yeah, I almost forgot this is a technical blog. This project started out as a technology experiment so it's built on Windows Azure and ASP.NET MVC. Very cool stuff. I'll have to write more about them later...&lt;/p&gt;&lt;img src="http://jdconley.com/blog/aggbug/63.aspx" width="1" height="1" /&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/StarinAtTheWall?a=sD5tM0zfhEA:W7cQ4h5WJVY:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/StarinAtTheWall?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/StarinAtTheWall?a=sD5tM0zfhEA:W7cQ4h5WJVY:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/StarinAtTheWall?i=sD5tM0zfhEA:W7cQ4h5WJVY:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/StarinAtTheWall?a=sD5tM0zfhEA:W7cQ4h5WJVY:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/StarinAtTheWall?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/StarinAtTheWall?a=sD5tM0zfhEA:W7cQ4h5WJVY:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/StarinAtTheWall?i=sD5tM0zfhEA:W7cQ4h5WJVY:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/StarinAtTheWall?a=sD5tM0zfhEA:W7cQ4h5WJVY:XAVGb8Xj5zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/StarinAtTheWall?d=XAVGb8Xj5zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
            <dc:creator>JD Conley</dc:creator>
            <guid isPermaLink="false">http://jdconley.com/blog/archive/2009/06/02/a-new-basket-for-my-eggs.aspx</guid>
            <pubDate>Wed, 03 Jun 2009 06:46:58 GMT</pubDate>
            <wfw:comment>http://jdconley.com/blog/comments/63.aspx</wfw:comment>
            <comments>http://jdconley.com/blog/archive/2009/06/02/a-new-basket-for-my-eggs.aspx#feedback</comments>
            <slash:comments>74</slash:comments>
            <wfw:commentRss>http://jdconley.com/blog/comments/commentRss/63.aspx</wfw:commentRss>
            <trackback:ping>http://jdconley.com/blog/services/trackbacks/63.aspx</trackback:ping>
        <feedburner:origLink>http://jdconley.com/blog/archive/2009/06/02/a-new-basket-for-my-eggs.aspx</feedburner:origLink></item>
    </channel>
</rss>
