<?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:blogChannel="http://backend.userland.com/blogChannelModule" xmlns:dc="http://purl.org/dc/elements/1.1/" 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:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">
  <channel>
    <title>Try-Catch-FAIL</title>
    <description>Failure is inevitable.</description>
    <link>http://trycatchfail.com/blog/</link>
    <docs>http://www.rssboard.org/rss-specification</docs>
    <generator>BlogEngine.NET 1.4.0.0</generator>
<language>en-GB</language><blogChannel:blogRoll>http://trycatchfail.com/blog/opml.axd</blogChannel:blogRoll><blogChannel:blink>http://www.dotnetblogengine.net/syndication.axd</blogChannel:blink><dc:creator>Matt Honeycutt</dc:creator><dc:title>Try-Catch-FAIL</dc:title><creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/2.0/</creativeCommons:license><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/Try-catch-fail" type="application/rss+xml" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><item><title>Tree-Grid Module for liteGrid</title><description>&lt;p&gt;For those just jumping on, &lt;a href="http://trycatchfail.com/blog/post/2009/07/13/Introducing-liteGrid-a-lightweight-jQuery-grid-plug-in.aspx" target="_blank"&gt;liteGrid is a lightweight jQuery grid plug-in that’s based on an event-driven architecture&lt;/a&gt;.&amp;#160; The core does practically nothing, but through the power of events, add-on modules can extend it with additional behavior.&amp;#160; In this post, I’ll explain the idea behind the event-driven architecture and modules, and I’ll show you an example that brings nice tree-grid functionality (ala &lt;a href="http://www.trirand.com/blog" target="_blank"&gt;jqGrid&lt;/a&gt;) to liteGrid in a simple, easy-to-use manor.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Improvements Since Last Time&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Thanks to feedback from &lt;a href="http://robtechdiff.blogspot.com/" target="_blank"&gt;Rob&lt;/a&gt;, I was able to make a few minor change to the core to clean things up. The big thing is that row IDs are no longer classes but actual element IDs.&amp;#160; I have no clue what I was thinking when I made row-id a class instead of using the attribute that exists specifically for such things, but oh well. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;A Little About Events&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;While objects in the DOM fire a variety of standard events (onclick, onkeypress, etc), jQuery makes it possible to fire &lt;em&gt;custom&lt;/em&gt; events, making it easier to build loosely-coupled systems entirely in JavaScript.&amp;#160; For more about custom events, I highly recommend &lt;a href="http://fuelyourcoding.com/jquery-custom-events-they-will-rock-your-world" target="_blank"&gt;Douglas Neiner’s article&lt;/a&gt;.&amp;#160; It’s a doozy, but well worth the read.&lt;/p&gt;  &lt;p&gt;So, why did I choose an event-driven architecture for liteGrid?&amp;#160; I wanted something that was loosely-coupled and extremely flexible.&amp;#160; The nice thing about this approach is that any number of add-on modules can plug in to liteGrid’s events and perform whatever actions they want.&amp;#160; As you’ll see, this makes it possible to do some very cool things.&amp;#160; Further, add-on modules themselves can publish &lt;strong&gt;their own&lt;/strong&gt; events, which makes it possible to have add-ons for your add-ons. :)&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Making liteGrid a tree-grid: TreeGridModule&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;In the last post, I showed you a simple add-on module that would zebra stripe the rows in the grid.&amp;#160; That’s all well-and-good, but a little simplistic.&amp;#160; Oh, and for those wondering why the rows are restriped in batch like that, there’s actually a really good reason (as we’re about to see): rows can be inserted inside the grid. :)&lt;/p&gt;  &lt;p&gt;So, what’s a tree-grid?&amp;#160; Here’s a screenshot (snapped from jqGrid’s &lt;a href="http://trirand.com/jqgrid/jqgrid.html" target="_blank"&gt;demonstration page&lt;/a&gt;):&lt;/p&gt;  &lt;p&gt;&lt;a href="http://trycatchfail.com/blog/image.axd?picture=WindowsLiveWriter/TreeGridModuleforliteGrid_A735/treeGrid_2.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="treeGrid" border="0" alt="treeGrid" src="http://trycatchfail.com/blog/image.axd?picture=WindowsLiveWriter/TreeGridModuleforliteGrid_A735/treeGrid_thumb.png" width="244" height="87" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;The basic idea is that a row can have children.&amp;#160; When a parent is expanded, the child rows should be displayed immediately below it, and there should be some visual indication that the children belong to the parent.&amp;#160; A good tree-grid should support an arbitrary depth of nesting, though this can become a UI problem since indenting things (the most common way to denote parent-child relationships) eats up quite a bit of space. &lt;/p&gt;  &lt;p&gt;If that sounds like it is going to be a challenge, you’re right!&amp;#160; How can we bring this functionality to liteGrid?&amp;#160; Let’s look at the module at a high level:&lt;/p&gt;  &lt;pre class="brush: js;"&gt;function TreeGridModule() {
    var base = this;

    //Called by liteGrid, this initializes the module and ties it
    //into the liteGrid plumbing.  liteGrid is the actual liteGrid
    //reference.
    base.initialize = function(liteGrid, options) {
        ...
    }

    //Callback that is invoked whenever a row has been bound in the grid.
    base.rowBound = function(event, row, dataItem, index) {
        ...
    }

    //Callback that is invoked whenever a row is collapsed. 
    base.rowCollapsed = function(parentId) {
        ...
    }

    //Used to hide children without actually changing their collapsed status.
    base.recursiveHideChildren = function(parentId) {
        ...
    }

    //Used to show children recursively.  Their collapsed status is not changed, so
    //only children that are expanded are shown.
    base.recursiveShowChildren = function(parentId) {
        ...
    }

    //Callback that is invoked whenever the expando-link is clicked.
    base.rowExpanded = function(parentId) {
        ...
    }
}
TreeGridModule.prototype.defaultOptions = {
    paddingPerLevel: 5
};&lt;/pre&gt;

&lt;p&gt;All modules must define an initialize function.&amp;#160; This is called by the liteGrid core to initialize the module.&amp;#160; Next, we have a few event handlers.&amp;#160; The first will be tied to liteGrid’s rowBound event.&amp;#160; After that, we have two special event handler that handle the user collapsing and expanding rows.&amp;#160; After that, we have two helper functions that take care of recursively showing/hiding a row’s children (after all, if you collapse a row that has children, and those children have children, shouldn’t they be hidden, too?).&amp;#160; At the very end, we add an object for default options used by TreeGridModule.&amp;#160; By default, we want to add 5 pixels of padding as we indent children under their parents.&amp;#160; As you’ll see, this default can be overriden by specifying the paddingPerLevel property on the liteGrid options.&lt;/p&gt;

&lt;p&gt;Let’s dig in to the initialization:&lt;/p&gt;

&lt;pre class="brush: js;"&gt;base.initialize = function(liteGrid, options) {

    //Store a reference to the table, that way it can be accessed later, if needed.
    base.liteGrid = liteGrid;

    if (!(&amp;quot;getChildData&amp;quot; in options.dataProvider)) {
        alert(&amp;quot;Specified data provider is not compatible with TreeGridModule, aborting initialization.&amp;quot;);
        return;
    }

    base.dataProvider = options.dataProvider;

    //Add a column to hold the expander.
    options.columns.splice(0, 0, { field: &amp;quot;Expander&amp;quot;, header: &amp;quot;X&amp;quot; });

    //Initialize module-specific options
    base.options = $.extend({}, TreeGridModule.prototype.defaultOptions, options);

    //Register to receive rowBound events, that way we can insert the expander.
    liteGrid.$el.bind(&amp;quot;rowBound&amp;quot;, base.rowBound);
}&lt;/pre&gt;

&lt;p&gt;First, we grab a reference to the actual liteGrid class so that we can use it in the other functions.&amp;#160; Next, we inspect liteGrid’s configured data provider to make sure it is compatible with the TreeGridModule.&amp;#160; If the provider doesn’t support retrieving child rows, the module initialization is aborted, and liteGrid can go about its business sans-tree-grid.&amp;#160; For simplicities sake, we also store a reference to the configured provider.&amp;#160; Here’s where the magic beings.&amp;#160; First, a new column is added to liteGrid’s column definitions.&amp;#160; Recall that columns are completely decoupled from the underlying data model.&amp;#160; The only way we’ll have an issue is if the data model actually defines a property named “Expander”, in which case we may get strange behavior. Next, we combine TreeGridModule’s default options with liteGrid’s options.&amp;#160; This allows the paddingPerLevel setting to be overriden by specifying a different value when liteGrid is initialized.&amp;#160; Finally, we register for the one event we care about: rowBound. &lt;/p&gt;

&lt;p&gt;Recall that rowBound is fired whenever liteGrid has finished populating a row with data and is ready to insert it into the grid.&amp;#160; Here’s what we’re going to do when that happens:&lt;/p&gt;

&lt;pre class="brush: js;"&gt;base.rowBound = function(event, row, dataItem, index) {

    //Only add an expander if the row has children.
    if (dataItem.HasChildren === true) {

        //Add the expander
        var expanderCell = row.find(&amp;quot;td:first&amp;quot;);

        //This is a div because an img won't render without a src attribute.
        var expandImage = $(&amp;quot;&amp;lt;div class='expander closed' /&amp;gt;&amp;quot;)
                        .toggle(
                            function() { base.rowExpanded(dataItem[base.options.rowIdColumn]); },
                            function() { base.rowCollapsed(dataItem[base.options.rowIdColumn]); }
                        );

        expanderCell.append(expandImage);
    }
    //TODO: We might want to show a different icon if the row doesn't have children.
}&lt;/pre&gt;

&lt;p&gt;TreeGridModule expects the data model to define a HasChildren property, though rows that don’t have children can simply omit the value altogether.&amp;#160; If the row being bound &lt;strong&gt;does&lt;/strong&gt; have children, we add an div (rendered as an image thanks to CSS) to the first cell in the row.&amp;#160; We use jQuery’s toggle event to bind to appropriate event handlers: the first click of the image expands the row, the second collapses it.&amp;#160; &lt;/p&gt;

&lt;p&gt;When the expander image for a row is clicked, the rowExpanded callback is invoked.&amp;#160; Get ready for a screenfull of code as this is the most complicated piece of the module!&lt;/p&gt;

&lt;pre class="brush: js;"&gt;//Callback that is invoked whenever the expando-link is clicked.
base.rowExpanded = function(parentId) {

    //Grab a reference to the parent, the first row we add goes after it.
    var parent = base.liteGrid.$el.find(&amp;quot;tr#row-id-&amp;quot; + parentId);

    //Change the expander image
    var parentExpander = parent.find(&amp;quot;td:first div&amp;quot;)
            .removeClass(&amp;quot;closed&amp;quot;).addClass(&amp;quot;opened&amp;quot;);

    //Determine if the children are already loaded. If they are, we don't need to re-retrieve them.
    if (parent.hasClass(&amp;quot;children-loaded&amp;quot;)) {

        //Mark the children as shown, they'll be toggled on through the recursive call.
        var children = base.liteGrid.$el.find(&amp;quot;tr.child-of-&amp;quot; + parentId).removeClass(&amp;quot;hidden&amp;quot;).addClass(&amp;quot;shown&amp;quot;);
        base.recursiveShowChildren(parentId);

        return;
    }

    //Otherwise, we have to load and show the children.

    //Get the padding of the parent, we need it in order to add padding to the children.
    var expanderPadding = parseInt(parentExpander.css(&amp;quot;margin-left&amp;quot;));

    //Grab the child data from the provider.
    var dataItems = base.dataProvider.getChildData(parentId);

    //This is the row we're adding the next row after.  
    var targetRow = parent;

    //Add the items to the table
    $(dataItems).each(function() {

        //We want to insert the items in order, so the target for the next
        //iteration is the newly inserted row.
        var newRow = base.liteGrid.insertRowAfter(this, targetRow);

        //Mark the row as a child of the parent
        newRow.addClass(&amp;quot;child-of-&amp;quot; + parentId).addClass(&amp;quot;shown&amp;quot;);

        //Adjust the padding of the child's expander.  It should be more than
        //it's parent.
        newRow.find(&amp;quot;td:first div&amp;quot;).css(&amp;quot;margin-left&amp;quot;, (expanderPadding + base.options.paddingPerLevel) + &amp;quot;px&amp;quot;);

        //Update target, we want the next row added to go under
        //the row that was just added.
        targetRow = newRow;
    });

    //Mark the parent's children as having been loaded.
    parent.addClass(&amp;quot;children-loaded&amp;quot;);
}&lt;/pre&gt;

&lt;p&gt;This handler receives the ID of the row that is being expanded.&amp;#160; First, we grab a reference to this row from the liteGrid reference.&amp;#160; Next, we change the class to indicate that it’s been expanded.&amp;#160; Through the magic of CSS, the image will be swapped to something more appropriate (see the example below).&amp;#160; So far, so simple, but here’s where things get tricky.&amp;#160; We might be &lt;strong&gt;re-&lt;/strong&gt;expanding the row.&amp;#160; The child rows might already be in the table, but hidden.&amp;#160; We check for the marker class “children-loaded” to determine whether we just need to show the children or retrieve them from the data provider.&amp;#160; If the children aren’t present yet, we invoke the provider to get the data items.&amp;#160; We want to insert rows for these items sequentially into the grid immediately after our parent row (that’s what “targetRow” is tracking).&amp;#160; For each item, we simply use liteGrid’s helper method insertRowAfter to add the row.&amp;#160; We mark it with a special class that enables us to find who the row belongs to quickly, and we adjust the padding on the row’s expander image so that it is slightly more indented than its parent was.&amp;#160; Finally, we mark the parent with the “children-loaded” marker class.&lt;/p&gt;

&lt;p&gt;What happens if the child rows are already there, but hidden?&amp;#160; We use the parentId value to find the rows children, mark them as shown, and then recursively decide which descendents to show:&lt;/p&gt;

&lt;pre class="brush: js;"&gt;//Used to show children recursively.  Their collapsed status is not changed, so
//only children that are expanded are shown.
base.recursiveShowChildren = function(parentId) {

    //Show the children that aren't hidden.
    var children = base.liteGrid.$el.find(&amp;quot;tr.shown.child-of-&amp;quot; + parentId).show();

    if (children.length &amp;gt; 0) {
        //Show *their* children recursively.
        children.each(function() {
            base.recursiveShowChildren($(this).data(&amp;quot;dataItem&amp;quot;)[base.options.rowIdColumn]);
        });
    }
}&lt;/pre&gt;

&lt;p&gt;The recursive method actually shows all children of the row we just expanded, but note that the selector is slightly more complex now: we’re only selecting children marked with the “shown” class.&amp;#160; This allows us to maintain the shown/hidden state of child rows recursively.&amp;#160; If we &lt;strong&gt;didn’t&lt;/strong&gt; do this, and you expanded/collapsed a top-level element that had expandable children, the expanded/collapsed state of the children would be lost.&amp;#160; Tracking state with classes makes it easy to persist state in nested parent/child scenarios.&amp;#160; &lt;/p&gt;

&lt;p&gt;Alright, so now we can expand rows, how do we collapse them?&amp;#160; Remember that our expander image has a toggle event handler, so the second time an expander is clicked, it will trigger the rowCollapsed callback:&lt;/p&gt;

&lt;pre class="brush: js;"&gt;//Callback that is invoked whenever a row is collapsed. 
base.rowCollapsed = function(parentId) {

    //Grab a reference to the parent, the first row we add goes after it.
    var parent = base.liteGrid.$el.find(&amp;quot;tr#row-id-&amp;quot; + parentId);

    //Change the expander image
    var parentExpander = parent.find(&amp;quot;td:first div&amp;quot;)
            .removeClass(&amp;quot;opened&amp;quot;).addClass(&amp;quot;closed&amp;quot;);

    //Hide the children, and mark them as collapsed. 
    var children = base.liteGrid.$el.find(&amp;quot;tr.child-of-&amp;quot; + parentId).removeClass(&amp;quot;shown&amp;quot;).addClass(&amp;quot;hidden&amp;quot;).hide();

    //Hide the children recursively.
    base.recursiveHideChildren(parentId);
}&lt;/pre&gt;

&lt;p&gt;Again, we grab a reference to the actual row being collapsed.&amp;#160; We toggle the class on the expander image (remember that we’re handling the image via CSS for the sake of minimal configuration).&amp;#160; Next, we mark the immediate children as collapsed and hide them, then we recursively hide children of the children:&lt;/p&gt;

&lt;pre class="brush: js;"&gt;//Used to hide children without actually changing their collapsed status.
base.recursiveHideChildren = function(parentId) {

    //Hide the children, but don't mark them as collapsed.
    var children = base.liteGrid.$el.find(&amp;quot;tr.child-of-&amp;quot; + parentId).hide();

    if (children.length &amp;gt; 0) {
        //Hide *their* children recursively.
        children.each(function() {
            base.recursiveHideChildren($(this).data(&amp;quot;dataItem&amp;quot;)[base.options.rowIdColumn]);
        });
    }
}&lt;/pre&gt;
Note that we’re hiding the children without altering their shown/hidden state (which is stored as a class).&amp;#160; This enables to restore them to the correct state when the parent is re-expanded.

&lt;p&gt;Put it all together, and you have a tree-grid.&amp;#160; Here’s how to use it:&lt;/p&gt;

&lt;pre class="brush: js;"&gt;//Turn #myTable into a rich table.
$(&amp;quot;#myTable&amp;quot;).inrad_liteGrid(
    {
        columns: [
            { field: &amp;quot;Name&amp;quot;, editable: true },
            { field: &amp;quot;Value&amp;quot;, header: &amp;quot;My Value&amp;quot;, editable: true },
            { field: &amp;quot;Cost&amp;quot;, editable: true, type: &amp;quot;currency&amp;quot; },
            { field: &amp;quot;Other&amp;quot;, editable: true }
        ],
        dataProvider: new MockDataProvider(),
        modules: [new TreeGridModule(), new StripifyModule()]
    });&lt;/pre&gt;

&lt;p&gt;And here’s what it looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://trycatchfail.com/blog/image.axd?picture=WindowsLiveWriter/TreeGridModuleforliteGrid_A735/liteGrid_2.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="liteGrid" border="0" alt="liteGrid" src="http://trycatchfail.com/blog/image.axd?picture=WindowsLiveWriter/TreeGridModuleforliteGrid_A735/liteGrid_thumb.png" width="244" height="134" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;I was extremely pleased with how easy it was to add this functionality on top of liteGrid.&amp;#160; The liteGrid core stays nice and light, and the module has a single responsibility: to make rows within the grid expandable.&amp;#160; In the next post, we’ll (probably) look at the inline-editing module that I’m working on now.&amp;#160; It’s more complex, but (so far) I’m very pleased with how clean and flexible it is.&amp;#160; &lt;/p&gt;

&lt;p&gt;As always, please let me know what you think!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/Try-catch-fail/~4/Y_pAZLCpHIU" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/Try-catch-fail/~3/Y_pAZLCpHIU/post.aspx</link><author>matt.nospam@nospam.trycatchfail.com (Matt)</author><comments>http://trycatchfail.com/blog/post/2009/07/15/Tree-Grid-Module-for-liteGrid.aspx#comment</comments><guid isPermaLink="false">http://trycatchfail.com/blog/post.aspx?id=5c786ea8-7643-41cf-9a05-6d7aa2eb3143</guid><pubDate>Wed, 15 Jul 2009 03:53:16 -1300</pubDate><category>jQuery</category><dc:publisher>Matt</dc:publisher><pingback:server>http://trycatchfail.com/blog/pingback.axd</pingback:server><pingback:target>http://trycatchfail.com/blog/post.aspx?id=5c786ea8-7643-41cf-9a05-6d7aa2eb3143</pingback:target><slash:comments>1</slash:comments><trackback:ping>http://trycatchfail.com/blog/trackback.axd?id=5c786ea8-7643-41cf-9a05-6d7aa2eb3143</trackback:ping><wfw:comment>http://trycatchfail.com/blog/post/2009/07/15/Tree-Grid-Module-for-liteGrid.aspx#comment</wfw:comment><wfw:commentRss>http://trycatchfail.com/blog/syndication.axd?post=5c786ea8-7643-41cf-9a05-6d7aa2eb3143</wfw:commentRss><feedburner:origLink>http://trycatchfail.com/blog/post.aspx?id=5c786ea8-7643-41cf-9a05-6d7aa2eb3143</feedburner:origLink></item><item><title>ActiveRecord 2.0 Beta 1 Ships!</title><description>&lt;p&gt;It’s very nice to see new releases coming out of the Castle Project finally.&amp;#160; Windsor has been updated, and now &lt;a href="http://www.castleproject.org" target="_blank"&gt;ActiveRecord&lt;/a&gt; is getting some love.&amp;#160; Highlights include built-in support for in-memory unit tests, LINQ support, and simplified integration with &lt;a href="http://lucene.apache.org/" target="_blank"&gt;Lucene&lt;/a&gt; via NHSearch. You can read more about it over at &lt;a href="http://mortslikeus.blogspot.com/2009/07/activerecord-beta-1-released.html" target="_blank"&gt;Morts Like Us&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/Try-catch-fail/~4/fkKGUSntDTQ" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/Try-catch-fail/~3/fkKGUSntDTQ/post.aspx</link><author>matt.nospam@nospam.trycatchfail.com (Matt)</author><comments>http://trycatchfail.com/blog/post/2009/07/15/ActiveRecord-20-Beta-1-Ships!.aspx#comment</comments><guid isPermaLink="false">http://trycatchfail.com/blog/post.aspx?id=0663417e-361a-4873-837e-94617cbb6f8b</guid><pubDate>Wed, 15 Jul 2009 01:31:15 -1300</pubDate><category>Castle Project</category><dc:publisher>Matt</dc:publisher><pingback:server>http://trycatchfail.com/blog/pingback.axd</pingback:server><pingback:target>http://trycatchfail.com/blog/post.aspx?id=0663417e-361a-4873-837e-94617cbb6f8b</pingback:target><slash:comments>1</slash:comments><trackback:ping>http://trycatchfail.com/blog/trackback.axd?id=0663417e-361a-4873-837e-94617cbb6f8b</trackback:ping><wfw:comment>http://trycatchfail.com/blog/post/2009/07/15/ActiveRecord-20-Beta-1-Ships!.aspx#comment</wfw:comment><wfw:commentRss>http://trycatchfail.com/blog/syndication.axd?post=0663417e-361a-4873-837e-94617cbb6f8b</wfw:commentRss><feedburner:origLink>http://trycatchfail.com/blog/post.aspx?id=0663417e-361a-4873-837e-94617cbb6f8b</feedburner:origLink></item><item><title>Comments disabled</title><description>&lt;p&gt;I have had to temporarily disable comments as my site has been overrun by some jerk’s spam bot the last 24 hours.&amp;#160; Comments are moderated, so they’re not gaining anything by spamming my site, but it’s annoying to wake up after 6 hours of sleep and have over 50 comments pending review.&amp;#160; I’ll re-enable comments after I find a CAPTCHA system that works with BlogEngine.NET.&amp;#160; &lt;/p&gt;  &lt;p&gt;&lt;em&gt;NOTE TO THE BLOGENGINE.NET DEVS: No, your simple JavaScript-based “captcha-like!” system does NOT work. &lt;/em&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;em&gt;UPDATE: Comments re-enabled.&amp;#160; I’ve implemented a hack that *might* stop the spam attacks.&amp;#160; For more information on what’s going on and how everyone with a BlogEngine.NET blog is affected, check out &lt;a href="http://blogengine.codeplex.com/Thread/View.aspx?ThreadId=62069" target="_blank"&gt;this thread&lt;/a&gt;. &lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/Try-catch-fail/~4/vjjglM-oRfM" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/Try-catch-fail/~3/vjjglM-oRfM/post.aspx</link><author>matt.nospam@nospam.trycatchfail.com (Matt)</author><comments>http://trycatchfail.com/blog/post/2009/07/13/Comments-disabled.aspx#comment</comments><guid isPermaLink="false">http://trycatchfail.com/blog/post.aspx?id=b062ce83-bf3f-4b66-a994-7d76ebee9761</guid><pubDate>Mon, 13 Jul 2009 23:13:22 -1300</pubDate><category>Misc</category><dc:publisher>Matt</dc:publisher><pingback:server>http://trycatchfail.com/blog/pingback.axd</pingback:server><pingback:target>http://trycatchfail.com/blog/post.aspx?id=b062ce83-bf3f-4b66-a994-7d76ebee9761</pingback:target><slash:comments>0</slash:comments><trackback:ping>http://trycatchfail.com/blog/trackback.axd?id=b062ce83-bf3f-4b66-a994-7d76ebee9761</trackback:ping><wfw:comment>http://trycatchfail.com/blog/post/2009/07/13/Comments-disabled.aspx#comment</wfw:comment><wfw:commentRss>http://trycatchfail.com/blog/syndication.axd?post=b062ce83-bf3f-4b66-a994-7d76ebee9761</wfw:commentRss><feedburner:origLink>http://trycatchfail.com/blog/post.aspx?id=b062ce83-bf3f-4b66-a994-7d76ebee9761</feedburner:origLink></item><item><title>Introducing liteGrid, a lightweight jQuery grid plug-in</title><description>&lt;p&gt;At my day job, we’re basically stuck re-implementing Excel in a web environment.&amp;#160; (&lt;em&gt;Sidenote: &lt;/em&gt;&lt;a href="http://robtechdiff.blogspot.com/" target="_blank"&gt;&lt;em&gt;Rob&lt;/em&gt;&lt;/a&gt;&lt;em&gt; tells me that this is absolutely the correct way to build applications and all web applications should try to mimic desktop applications as much as possible.&amp;#160; I don’t like it, but it’s the cards we’ve been dealt, and we have to make it work.)&lt;/em&gt;&amp;#160; Right now, we’re using &lt;a href="http://www.trirand.com/blog" target="_blank"&gt;jqGrid&lt;/a&gt; with &lt;a href="http://www.asp.net/mvc" target="_blank"&gt;ASP.NET MVC&lt;/a&gt;, and we’ve got things working at a rudimentary level. However, we’ve found ourselves tripping more and more over jqGrid bugs, limitations, and just plain *pain* when trying to extend it.&amp;#160; My take on jqGrid is that it’s too heavy to be flexible, plus it’s not a perfect match for what we’re trying to build in this application.&amp;#160; It’s actually becoming a barrier to progress.&amp;#160; Though there are alternatives, there is nothing that we’ve found that has all the functionality we need.&amp;#160; So, I have now been tasked with creating a new plug-in from scratch that is flexible enough to support our needs.&amp;#160; I have dubbed this effort liteGrid (the name sucks because there are 10,000 table plug-ins, and all the good names have been taken). &lt;/p&gt;  &lt;p&gt;First, here the requirements I laid out for myself as I built liteGrid.&amp;#160; Some of these are based on application needs, but many are just based on design principles that I felt were important:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Must support tree-grid functionality.&amp;#160; You should be able to expand and collapse rows. &lt;/li&gt;    &lt;li&gt;Must support &lt;strong&gt;flexible &lt;/strong&gt;editing.&amp;#160; Items in the grid should be editable, and it should be very clean and easy to customize &lt;strong&gt;how&lt;/strong&gt; things are edited. &lt;/li&gt;    &lt;li&gt;Easy to customize.&amp;#160; If you want to change something on the grid, it should be easy and straightforward. &lt;/li&gt;    &lt;li&gt;Easy to handle formatting.&amp;#160; You should have complete control over how values are rendered. &lt;/li&gt;    &lt;li&gt;Completely decoupled data model.&amp;#160; The underlying data model should be distinct from what’s rendered. &lt;/li&gt;    &lt;li&gt;AJAX support.&amp;#160; At a minimum, loading and saving data should be doable with AJAX. &lt;/li&gt;    &lt;li&gt;Simple.&amp;#160; The grid itself should contain very little code. &lt;/li&gt;    &lt;li&gt;Event-driven.&amp;#160; The grid should be loosely-coupled and use events to pass messages.&amp;#160; I was inspired by &lt;a href="http://fuelyourcoding.com/jquery-custom-events-they-will-rock-your-world" target="_blank"&gt;this article&lt;/a&gt; on custom events in jQuery. &lt;/li&gt;    &lt;li&gt;jQuery UI support.&amp;#160; I hate coming up with themes for anything as I have no artistic inclination (at all), so this is me passing the buck. I’m still not sure how feasible this is as I’m a complete newb on jQuery UI, but hopefully they have something I can leverage. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Before we go any further …&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;DISCLAIMER&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;I do not consider myself to be a JavaScript or jQuery guru (yet).&amp;#160; This is also a work in-progress. I fully expect it to undergo major changes as additional functionality is added.&amp;#160; I’m not claiming (yet) that it’s the best grid out there, just that I like the way it is shaping up.&amp;#160; Still, all feedback is welcomed at this point, so feel free to throw rocks at it.&amp;#160; Oh, and this may/may not eventually be released in final form.&amp;#160; It depends on how my employer wants to handle it.&amp;#160; This code is &lt;strong&gt;not&lt;/strong&gt; free and open-source yet, so read it at your own risk (though I really don’t think anyone is going to care).&amp;#160; &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Getting Started&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;There is a “right” way to build a jQuery plug-in.&amp;#160; And &lt;a href="http://starter.pixelgraphics.us/" target="_blank"&gt;this is it&lt;/a&gt;.&amp;#160; I used Starter to generate my skeleton plug-in, which saved me quite a bit of time.&amp;#160; From there, I modeled the core of liteGrid based loosely on how ASP.NET data grids work.&amp;#160; The grid raises events when certain things happen, which interested parties can then listen for and respond to.&amp;#160; I wanted to keep the core extremely simple and light, so I also built in support for pluggable modules that hook into the grid to provide additional functionality.&amp;#160; The tree-grid, which I’ll show in a future post, is implemented a liteGrid module.&amp;#160; Also, liteGrid supports a data provider model.&amp;#160; By default, it uses a null provider that returns no data, but you can drop in any objection you want to serve as the provider.&amp;#160; By default, liteGrid requires only a single provider method, but as you will see in future posts, liteGrid modules may add additional data provider requirements.&lt;/p&gt;  &lt;p&gt;Alright, so code time.&amp;#160; Let’s look at the plug-in as a whole before we dive in to the interesting methods:&lt;/p&gt;  &lt;pre class="brush: js;"&gt;(function($) {

    // Declare namespace if not already defined
    if (!$.inrad) {
        $.inrad = new Object();
    }

    //This is the actual liteGrid plug-in class.
    $.inrad.liteGrid = function(el, options) {
        // To avoid scope issues, use 'base' instead of 'this'
        // to reference this class from internal events and functions.
        var base = this;

        // Access to jQuery and DOM versions of element
        base.$el = $(el);
        base.el = el;

        // Add a reverse reference to the DOM object
        base.$el.data(&amp;quot;inrad.liteGrid&amp;quot;, base);

        //This actually performs the initialization.
        base.init = function() {
            ...
        }

        //Rendes the actual table.  This can be overriden by modules.
        base.render = function() {
            ...
        }

        //Renders the specified row.
        base.renderRow = function(dataItem, index) {
            ...
        }

        //Builds a row that can be inserted into the table.  columnBound
        //events are raised, and the formatter is used to format cell
        //values.
        base.buildRow = function(dataItem) {
            ...
        }

        //Inserts a row for a data item after the specified row
        //that's already in the table.
        base.insertRowAfter = function(dataItem, existingRow) {
            ...
        }

        base.init();
    }


    $.inrad.liteGrid.defaultOptions = {
        columns: [],
        dataProvider: new NullDataProvider(),
        modules: [],
        missingValue: &amp;quot;&amp;quot;,
        rowIdColumn: &amp;quot;ID&amp;quot;
    }


    // This is the actual plug-in function.  It creates and returns
    // a new instance of the plug-in.  
    $.fn.inrad_liteGrid = function(options) {
        return this.each(function() {
            (new $.inrad.liteGrid(this, options));
        });
    }

    // This function breaks the chain, but returns
    // the inrad.liteGrid if it has been attached to the object.
    $.fn.getinrad_liteGrid = function() {
        return this.data(&amp;quot;inrad.liteGrid&amp;quot;);
    }

})(jQuery);&lt;/pre&gt;

&lt;p&gt;Aside from the JavaScript added by jQuery Starter, there’s not really much going on.&amp;#160; liteGrid is a simple object with only a few methods: init, render, renderRow, buildRow, and insertRowAfter.&amp;#160; I expect this list to grow a little bit as I find common functionality that feels like it belongs on the core object, but still, this is far from a complicated object.&amp;#160; &lt;/p&gt;

&lt;p&gt;Let’s look at the options that are supported right now: columns, dataProvider, modules, missingValue, and rowIdColumn.&amp;#160; Columns is simply an array of objects that defines the columns to be rendered.&amp;#160; Note that modules can modify this definition to add new columns as needed, as we’ll see in the tree-grid module.&amp;#160; Next is the data provider.&amp;#160; By default, this is a null provider that just returns an empty array.&amp;#160; Users of liteGrid should supply their own provider or use one of the available providers that will “ship” when this thing is finished (including an AJAX provider).&amp;#160; Next is the array of add-on modules for the grid.&amp;#160; These are initialized by liteGrid and can do all sorts of crazy things.&amp;#160; Next we have the value to substitute for rows that are missing a value for a column.&amp;#160; This may be a bit of &lt;a href="http://en.wikipedia.org/wiki/You_Ain%27t_Gonna_Need_It" target="_blank"&gt;YAGNI&lt;/a&gt; creeping in, so I might remove it later.&amp;#160; Finally, we have the name of the column (we’re talking data model column) that contains the unique identifier for the row.&amp;#160; This should probably renamed to “rowIdProperty” for clarity.&amp;#160; Basically, the underlying data objects that are returned by the grid’s data provider must expose a unique identifier, and this is the name of that identifier. &lt;/p&gt;

&lt;p&gt;Alright, time for some code.&amp;#160; Let’s dig in to the init method first:&lt;/p&gt;

&lt;pre class="brush: js;"&gt;base.init = function() {

    base.options = $.extend({}, $.inrad.liteGrid.defaultOptions, options);

    //Initialize all modules!  Modules might, for example, add
    //new columns (such as the expander column), add decorators to
    //the providers, subscribe to events, or do other fun things.
    $(base.options.modules).each(function() {
        console.log(&amp;quot;Initializing %s...&amp;quot;, this.constructor.name);
        //TODO: Add error-handling!
        this.initialize(base, base.options);

        console.log(&amp;quot;Finished!&amp;quot;);
    });

    base.render();
    base.$el.trigger(&amp;quot;tableRendered&amp;quot;);
}&lt;/pre&gt;

&lt;p&gt;There is the standard jQuery stuff for handling options.&amp;#160; After that, all the modules are initialized.&amp;#160; This is done prior to *anything* else happening because modules can do whatever they want to the grid.&amp;#160; They can override methods, they can change options, they can register event handlers, whatever.&amp;#160; Next, we render the grid, and fire a custom event on the actual table element itself that signifies that rendering is complete.&amp;#160; Pretty simple!&lt;/p&gt;

&lt;p&gt;Next up is the render method:&lt;/p&gt;

&lt;pre class="brush: js;"&gt;//Rendes the actual table.  This can be overriden by modules.
base.render = function() {
    //Clear any existing table markup
    base.$el.html(&amp;quot;&amp;quot;);

    //Build the header.
    var headerRow = $(&amp;quot;&amp;lt;tr&amp;gt;&amp;lt;/tr&amp;gt;&amp;quot;);
    $(&amp;quot;&amp;lt;thead&amp;gt;&amp;lt;/thead&amp;gt;&amp;quot;).append(headerRow).appendTo(base.$el);

    $(base.options.columns).each(function() {
        headerRow.append(&amp;quot;&amp;lt;th&amp;gt;&amp;quot; + (this.header || this.field) + &amp;quot;&amp;lt;/th&amp;gt;&amp;quot;);
    });

    //Grab data and add the rows.
    var dataArray = base.options.dataProvider.getData();

    $(dataArray).each(function(index) {

        base.renderRow(this, index);
    });

    //The table has been rendered, so trigger the event.
    base.$el.trigger(&amp;quot;tableUpdated&amp;quot;, base);
}&lt;/pre&gt;

&lt;p&gt;This method does a lot, so it defers a lot of logic to helpers where it can.&amp;#160; First, it wipes out any existing HTML content, and builds a header row for the table based on the column definitions.&amp;#160; Next, the data items are retrieved from the configured provider, and a row is rendered for each table.&amp;#160; Finally, an event is raised to signify that the grid has changed in some way.&lt;/p&gt;

&lt;p&gt;Next is our helper to render a row.&amp;#160;&amp;#160; I’ll also throw in a related method that builds the actual row:&lt;/p&gt;

&lt;pre class="brush: js;"&gt;//Renders the specified row.
base.renderRow = function(dataItem, index) {

    var row = base.buildRow(dataItem);

    base.$el.append(row);
}

//Builds a row that can be inserted into the table.  columnBound
//events are raised, and the formatter is used to format cell
//values.
base.buildRow = function(dataItem) {

    //Spit out values for each of the columns
    var row = $(&amp;quot;&amp;lt;tr&amp;gt;&amp;lt;/tr&amp;gt;&amp;quot;);

    //Add a class containing the ID
    row.addClass(&amp;quot;row-id-&amp;quot; + dataItem[base.options.rowIdColumn]);

    //Bind the actual data item to the row so that we can get it later.
    row.data(&amp;quot;dataItem&amp;quot;, dataItem);

    $(base.options.columns).each(function() {
        var column = this;

        //Format the value.
        var value = (dataItem[column.field] || base.options.missingValue));

        var element = &amp;quot;&amp;lt;td&amp;gt;&amp;quot; + value + &amp;quot;&amp;lt;/td&amp;gt;&amp;quot;;
        element = $(element).appendTo(row);

        base.$el.trigger(&amp;quot;columnBound&amp;quot;, [column, element]);
    });

    //Raises the &amp;quot;rowBound&amp;quot; event on the table.
    //TODO: Can we hand the user the row's index?  Probably not...
    base.$el.trigger('rowBound', [row, dataItem]);

    return row;
}&lt;/pre&gt;

&lt;p&gt;renderRow simply calls buildRow to build up the DOM tree for the row, then appends it to the table.&amp;#160; buildRow is a little more complicated.&amp;#160; First, the new row is tagged with a special class that stores the row’s ID.&amp;#160; The jQuery data function is also used to store the raw dataItem with the row, making it easy to grab the raw data later.&amp;#160; Next, a cell is rendered for each column.&amp;#160; Note that the data item may define fields beyond the column specifications, it is completely flexible in this regard.&amp;#160; If the data item doesn’t define the column, the missing value is used instead.&amp;#160; When it’s all finished, an event is triggered, again on the table element, that allows interested parties to see what’s going on.&lt;/p&gt;

&lt;p&gt;The last method our grid exposes is a helper for modules to use.&amp;#160; It inserts a row after an existing row in the table:&lt;/p&gt;

&lt;pre class="brush: js;"&gt;base.insertRowAfter = function(dataItem, existingRow) {

    //Create the row.
    var row = base.buildRow(dataItem);

    //Insert it.
    row.insertAfter(existingRow);

    //The table has been changed, so fire the event.
    //TODO: Do we *really* want to fire this after every insert?  Would
    //it be better to have a way to supress the event being fired, and
    //allow modules to trigger the event?
    base.$el.trigger(&amp;quot;tableUpdated&amp;quot;, base);

    return row;
}&lt;/pre&gt;

&lt;p&gt;It uses the buildRow function, insuring that all our events are fired, adds it to the DOM, and triggers an event indicating that the table has changed. &lt;/p&gt;

&lt;p&gt;And that’s all there is to it!&amp;#160; How do we put this grid into action?&amp;#160; Here’s a simple example:&lt;/p&gt;

&lt;pre class="brush: js;"&gt;$(function() {
    //Subscribes to events just to make sure they work.
    $(&amp;quot;#myTable&amp;quot;).bind(&amp;quot;rowBound&amp;quot;, function() {
        //alert(&amp;quot;Received rowBound event!&amp;quot;);
    })
    .bind(&amp;quot;columnBound&amp;quot;, function(event, column, element) {
        //element.html(column.field + &amp;quot;: &amp;quot; + element.html());
    })
    .bind(&amp;quot;tableRendered&amp;quot;, function(event) {
        //Do some table-specific processing?
    });

    //Turn #myTable into a rich table.
    $(&amp;quot;#myTable&amp;quot;).inrad_liteGrid(
        {
            columns: [
                { field: &amp;quot;Name&amp;quot; },
                { field: &amp;quot;Value&amp;quot;, header: &amp;quot;My Value&amp;quot; },
                { field: &amp;quot;Other&amp;quot; }
            ],
            dataProvider: new MockDataProvider(),
            modules: [new TreeGridModule(), new StripifyModule()]
        });
}
);&lt;/pre&gt;

&lt;p&gt;This tells the plug-in to convert the table with ID #myTable to a liteGrid.&amp;#160; We are passing in a custom data provider for testing:&lt;/p&gt;

&lt;pre class="brush: js;"&gt;function MockDataProvider() {
    this.getData = function() { 
        return [
            {ID:1, Name:&amp;quot;Name1&amp;quot;, Value:&amp;quot;Value1&amp;quot;, Cost:1234, HasChildren:true},
            {ID:2, Name:&amp;quot;Name2&amp;quot;, Value:&amp;quot;Value2&amp;quot;, Cost:12345, HasChildren:true}
        ];
    };
    
    //Gets child data from the server.
    this.getChildData = function(parentId) {
        if (parentId == 1) {
            return [
                { ID: 3, Name: &amp;quot;Child1&amp;quot;, Value: &amp;quot;Value3&amp;quot;, Cost: 1234, HasChildren:true },
                { ID: 4, Name: &amp;quot;Child2&amp;quot;, Value: &amp;quot;Value4&amp;quot;, Cost: 1234, HasChildren:false }
            ];
        }
        else if (parentId == 2) {
            return [
                { ID: 5, Name: &amp;quot;Child1&amp;quot;, Value: &amp;quot;Value3&amp;quot;, Cost: 1234 },
                { ID: 6, Name: &amp;quot;Child2&amp;quot;, Value: &amp;quot;Value4&amp;quot;, Cost: 1234 }
            ];
        }
        else if (parentId == 3) {
            return [
                { ID: 7, Name: &amp;quot;Child1&amp;quot;, Value: &amp;quot;Value3&amp;quot;, Cost: 1234 },
                { ID: 8, Name: &amp;quot;Child2&amp;quot;, Value: &amp;quot;Value4&amp;quot;, Cost: 1234 }
            ];
        }
        else { 
            return [];
        }
    }
}&lt;/pre&gt;

&lt;p&gt;Note that this provider actually has a few things that are required by the tree-grid module, which I’ll show in the next post, but liteGrid doesn’t care.&amp;#160; It simply looks for matches between your column definitions and the fields on your data items, and skips anything that doesn’t match.&lt;/p&gt;

&lt;p&gt;There you have it, liteGrid.&amp;#160; Before I end this post, let’s look at a simple module that stripes the rows in the table:&lt;/p&gt;

&lt;pre class="brush: js;"&gt;function StripifyModule() {
    var base = this;
    
    //Registers for events that signal that the table needs to be 
    //re-stripified.
    base.initialize = function(liteGrid, options) {

        //Register for the events we care about.
        liteGrid.$el.bind(&amp;quot;tableUpdated&amp;quot;, function(event, table) {

            //Remove even/odd classes from everything
            table.$el.find(&amp;quot;tbody tr&amp;quot;).removeClass(&amp;quot;even odd&amp;quot;);

            table.$el.find(&amp;quot;tbody tr:even&amp;quot;).addClass(&amp;quot;even&amp;quot;);
            table.$el.find(&amp;quot;tbody tr:odd&amp;quot;).addClass(&amp;quot;odd&amp;quot;);
        });
    }
}&lt;/pre&gt;

&lt;p&gt;By simply subscribing to events, this module can now apply stripes to the table anytime a row is added or removed.&amp;#160; This is a very simple example, and the true power of this functionality won’t really be obvious until the next post, when I show the TreeGridModule.&lt;/p&gt;

&lt;p&gt;Alright, so, comment away.&amp;#160; What do you think?&amp;#160; Any suggestions for improving things? &lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/Try-catch-fail/~4/oMK3gEM8dEk" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/Try-catch-fail/~3/oMK3gEM8dEk/post.aspx</link><author>matt.nospam@nospam.trycatchfail.com (Matt)</author><comments>http://trycatchfail.com/blog/post/2009/07/13/Introducing-liteGrid-a-lightweight-jQuery-grid-plug-in.aspx#comment</comments><guid isPermaLink="false">http://trycatchfail.com/blog/post.aspx?id=08e4cf8b-3cbf-4181-9fea-661da835a990</guid><pubDate>Mon, 13 Jul 2009 04:49:38 -1300</pubDate><category>JavaScript</category><category>jQuery</category><dc:publisher>Matt</dc:publisher><pingback:server>http://trycatchfail.com/blog/pingback.axd</pingback:server><pingback:target>http://trycatchfail.com/blog/post.aspx?id=08e4cf8b-3cbf-4181-9fea-661da835a990</pingback:target><slash:comments>1</slash:comments><trackback:ping>http://trycatchfail.com/blog/trackback.axd?id=08e4cf8b-3cbf-4181-9fea-661da835a990</trackback:ping><wfw:comment>http://trycatchfail.com/blog/post/2009/07/13/Introducing-liteGrid-a-lightweight-jQuery-grid-plug-in.aspx#comment</wfw:comment><wfw:commentRss>http://trycatchfail.com/blog/syndication.axd?post=08e4cf8b-3cbf-4181-9fea-661da835a990</wfw:commentRss><feedburner:origLink>http://trycatchfail.com/blog/post.aspx?id=08e4cf8b-3cbf-4181-9fea-661da835a990</feedburner:origLink></item><item><title>What makes a developer &amp;ldquo;great&amp;rdquo;?</title><description>&lt;p&gt;I’ve been thinking recently about how to define the skills and traits that make for a “great” developer.&amp;#160; I’m certainly not an authority on the subject, but I consider myself to be a pretty solid developer.&amp;#160; I’ve worked with some truly stellar people, too, so I know what a great developer looks like.&amp;#160; But as I’ve tried to come up with a description, I’ve found that &lt;em&gt;defining&lt;/em&gt; a great developer is a lot harder than recognizing one.&amp;#160; Here are a few traits that I think great developers &lt;strong&gt;usually&lt;/strong&gt; have.&amp;#160; &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Strong problem-solving skills&lt;/strong&gt; – Software development is mainly about solving problems, particularly new problems (or variations on existing problems).&amp;#160; Let’s face it, if this wasn’t true, there would be no need for developers, since monkeys would be able to take off-the-shelf components, slap them together, and successfully meet all the customer requirements.&amp;#160; In reality though, any solution requires at least some customization and novel thinking; if not, the customer would be much better off using the existing solution.&amp;#160; So being able to solve problems is very important, but what makes a developer “great” is an ability to quickly come up with &lt;strong&gt;elegant &lt;/strong&gt;solutions to problems.&amp;#160; A “great” developer doesn’t reinvent the wheel, either, he recognizes and utilizes existing solutions whenever possible.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;A passion to learn&lt;/strong&gt; – Software development is not a skill that you pick-up in school then coast on for the rest of your career.&amp;#160; “Great” developers recognize this and make both a professional and personal commitment to advance their knowledge.&amp;#160; They constantly explore new things, acquire new skills, and seek knowledge from those that are more knowledgeable than they are.&amp;#160; A “great” developer is not content and always seeks to improve themselves.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;An ability to craft elegant solutions &lt;/strong&gt;– A “great” developer will solve a problem using a solution that is both readable and efficient.&amp;#160; It will contain exactly as much code as is needed and no more.&amp;#160; A “great” developer will &lt;strong&gt;not&lt;/strong&gt; hammer a problem with more and more code until it “works”.&amp;#160; A “great” developer dies a little inside every time he sees that happen.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;A willingness to teach&lt;/strong&gt; - “Great” developers are not greedy with their knowledge.&amp;#160; They’re happy to share it; they &lt;strong&gt;want&lt;/strong&gt; to help their fellow developers learn.&amp;#160; They may not want to hand-hold constantly, but a “great” developer will be more than willing to provide feedback and guidance when asked.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;An understanding of the differences between “developer” and “programmer”&lt;/strong&gt; – While every developer is a programmer, not every programmer is a developer.&amp;#160; A “great” developer not only understands this, but they embrace it.&amp;#160; They know that development doesn’t just mean writing code, it means &lt;em&gt;understanding&lt;/em&gt; the business and the users.&amp;#160; It means &lt;em&gt;testing&lt;/em&gt; code, not just flinging it at the screen.&amp;#160; It means &lt;em&gt;documenting&lt;/em&gt; code so that solutions aren’t write-only.&amp;#160; It means &lt;em&gt;designing&lt;/em&gt; solutions, not just hacking at it until it works.&amp;#160; A “great” developer understands that the majority of their time will be spent &lt;strong&gt;not &lt;/strong&gt;writing code.&amp;#160; &lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;That’s certainly not an all-inclusive list, and if I sat here longer, I’d probably think of other things.&amp;#160; What do &lt;strong&gt;you&lt;/strong&gt; think are some key traits that separate a great developer from an average one?&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/Try-catch-fail/~4/1TvKKvsj6_I" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/Try-catch-fail/~3/1TvKKvsj6_I/post.aspx</link><author>matt.nospam@nospam.trycatchfail.com (Matt)</author><comments>http://trycatchfail.com/blog/post/2009/06/09/What-makes-a-developer-ldquo3bgreatrdquo3b.aspx#comment</comments><guid isPermaLink="false">http://trycatchfail.com/blog/post.aspx?id=0a495211-4c68-4841-8b31-f15eda26da7a</guid><pubDate>Tue, 09 Jun 2009 06:46:27 -1300</pubDate><category>Misc</category><dc:publisher>Matt</dc:publisher><pingback:server>http://trycatchfail.com/blog/pingback.axd</pingback:server><pingback:target>http://trycatchfail.com/blog/post.aspx?id=0a495211-4c68-4841-8b31-f15eda26da7a</pingback:target><slash:comments>3</slash:comments><trackback:ping>http://trycatchfail.com/blog/trackback.axd?id=0a495211-4c68-4841-8b31-f15eda26da7a</trackback:ping><wfw:comment>http://trycatchfail.com/blog/post/2009/06/09/What-makes-a-developer-ldquo3bgreatrdquo3b.aspx#comment</wfw:comment><wfw:commentRss>http://trycatchfail.com/blog/syndication.axd?post=0a495211-4c68-4841-8b31-f15eda26da7a</wfw:commentRss><feedburner:origLink>http://trycatchfail.com/blog/post.aspx?id=0a495211-4c68-4841-8b31-f15eda26da7a</feedburner:origLink></item><item><title>Thesis defense complete!</title><description>&lt;p&gt;The reason I suddenly went dark (again) was due to an unexpected change in the timing of my thesis defense.&amp;#160; Originally my deadline was July 9th, but I found out at the end of May that I actually had to defend by Friday, June 5th, because some of my committee members were going to be taking extended trips during the summer.&amp;#160; Last week, the schedule was again accelerated, as my defense was moved from June 5th to June 2nd (yesterday).&amp;#160; Fortunately, many late nights and lots of Red Bull were all it took to wrap things up, and I am now all clear to graduate in August.&amp;#160; I have the usual edits to make and a few things to clean up, but I’m mostly finished now.&amp;#160; &lt;/p&gt;  &lt;p&gt;I probably won’t be posting much this week as I try to finalize my thesis and catch up on all the things that have fallen by the wayside, but I &lt;strong&gt;will&lt;/strong&gt; start blogging again.&amp;#160; I still have lots of things I want to cover: deep-web crawling (and the public release of DeepCrawler.NET), my &lt;a href="http://en.wikipedia.org/wiki/Machine_learning" target="_blank"&gt;machine learning&lt;/a&gt; library for .NET, &lt;a href="http://lucene.apache.org/" target="_blank"&gt;&lt;a href="http://incubator.apache.org/lucene.net/" target="_blank"&gt;Lucene.NET&lt;/a&gt;,&lt;/a&gt; object databases, and more.&amp;#160; &lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/Try-catch-fail/~4/4ltX7l-xW8s" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/Try-catch-fail/~3/4ltX7l-xW8s/post.aspx</link><author>matt.nospam@nospam.trycatchfail.com (Matt)</author><comments>http://trycatchfail.com/blog/post/2009/06/03/Thesis-defense-complete!.aspx#comment</comments><guid isPermaLink="false">http://trycatchfail.com/blog/post.aspx?id=71733545-8bfa-4132-a2a9-6ff478f57626</guid><pubDate>Wed, 03 Jun 2009 01:22:54 -1300</pubDate><category>Misc</category><dc:publisher>Matt</dc:publisher><pingback:server>http://trycatchfail.com/blog/pingback.axd</pingback:server><pingback:target>http://trycatchfail.com/blog/post.aspx?id=71733545-8bfa-4132-a2a9-6ff478f57626</pingback:target><slash:comments>2</slash:comments><trackback:ping>http://trycatchfail.com/blog/trackback.axd?id=71733545-8bfa-4132-a2a9-6ff478f57626</trackback:ping><wfw:comment>http://trycatchfail.com/blog/post/2009/06/03/Thesis-defense-complete!.aspx#comment</wfw:comment><wfw:commentRss>http://trycatchfail.com/blog/syndication.axd?post=71733545-8bfa-4132-a2a9-6ff478f57626</wfw:commentRss><feedburner:origLink>http://trycatchfail.com/blog/post.aspx?id=71733545-8bfa-4132-a2a9-6ff478f57626</feedburner:origLink></item><item><title>ASP.NET MVC HtmlHelper for Uploadify, Take One</title><description>&lt;p&gt;As I’ve mentioned before, I really, really hate the way most people seem to be creating reusable UI “controls” with &lt;a href="http://www.asp.net/mvc" target="_blank"&gt;ASP.NET MVC&lt;/a&gt;.&amp;#160; I do not like emitting JavaScript, HTML, etc. from within C# code.&amp;#160; It’s cumbersome to create, difficult to really test, and just a real PITA in general.&lt;/p&gt;  &lt;p&gt;Based on feedback I received from &lt;a href="http://robtechdiff.blogspot.com/" target="_blank"&gt;Rob&lt;/a&gt; after my attempts at creating a helper for &lt;a href="http://www.trirand.com/blog" target="_blank"&gt;jqGrid&lt;/a&gt;, I decided to take a completely different approach when it was time to wrap another jQuery plug-in: &lt;a href="http://www.uploadify.com" target="_blank"&gt;Uploadify&lt;/a&gt;.&amp;#160; My goal was to minimize the amount of tag-soup embedded in my C# code while still maintaining the ease-of-use of the jqGrid helper, which required only a single HtmlHelper call to go from nothing to full grid.&lt;/p&gt;  &lt;p&gt;Well, one painful afternoon later, I think I’ve arrived at something that makes some sense.&amp;#160; First, I couldn’t completely eliminate the tag soup, but I did minimize it (I think) while still keeping the thing extremely simple to use and (hopefully) maintain.&amp;#160; Let’s start with how you would use it:&lt;/p&gt;  &lt;pre class="brush: xml;"&gt;&amp;lt;asp:Content ContentPlaceHolderID=&amp;quot;HeadContent&amp;quot; runat=&amp;quot;server&amp;quot;&amp;gt;
    &amp;lt;%=Html.Uploadify(&amp;quot;fileInput&amp;quot;, 
        new UploadifyOptions
           {
               UploadUrl = Html.BuildUrlFromExpression&amp;lt;SandboxController&amp;gt;(c =&amp;gt; c.HandleUpload(null)),
            FileExtensions = &amp;quot;*.xls;*.xlsx&amp;quot;,
            FileDescription = &amp;quot;Excel Files&amp;quot;,
            AuthenticationToken = Request.Cookies[FormsAuthentication.FormsCookieName] == null ?
                string.Empty :
                Request.Cookies[FormsAuthentication.FormsCookieName].Value,
            ErrorFunction = &amp;quot;onError&amp;quot;,
            CompleteFunction = &amp;quot;onComplete&amp;quot;
           }) %&amp;gt;
           
    &amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;
        function onError() {
            alert('Something went wrong.');
        }
        function onComplete() {
            alert('File saved!');
        }
    &amp;lt;/script&amp;gt;                                                   
&amp;lt;/asp:Content&amp;gt;&lt;/pre&gt;

&lt;p&gt;The first parameter is the name of the input control to convert to an uploadify control, the second contains all the optional settings you can customize.&amp;#160; I prefer to use an options class like this rather than provide 50,000 overloads.&amp;#160; By using a dedicated options class, I can add new settings without breaking existing code or having to create new overloads.&amp;#160; The options should be fairly self explanatory, but here they are:&lt;/p&gt;

&lt;pre class="brush: csharp;"&gt;/// &amp;lt;summary&amp;gt;
/// Defines all options for &amp;lt;see cref=&amp;quot;HtmlHelperExtensions.Uploadify&amp;quot;/&amp;gt;.
/// &amp;lt;/summary&amp;gt;
public class UploadifyOptions
{
    #region Public Properties

    /// &amp;lt;summary&amp;gt;
    /// The URL to the action that will process uploaded files.
    /// &amp;lt;/summary&amp;gt;
    public string UploadUrl { get; set; }

    /// &amp;lt;summary&amp;gt;
    /// The file extensions to accept.
    /// &amp;lt;/summary&amp;gt;
    public string FileExtensions { get; set; }

    /// &amp;lt;summary&amp;gt;
    /// Description corresponding to &amp;lt;see cref=&amp;quot;FileExtensions&amp;quot;/&amp;gt;.
    /// &amp;lt;/summary&amp;gt;
    public string FileDescription { get; set; }

    /// &amp;lt;summary&amp;gt;
    /// The ASP.NET forms authentication token.
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;example&amp;gt;
    /// You can get this in a view using:
    /// &amp;lt;code&amp;gt;
    /// Request.Cookies[FormsAuthentication.FormsCookieName].Value
    /// &amp;lt;/code&amp;gt;
    /// You should check for the existence of the cookie before accessing
    /// its value.
    /// &amp;lt;/example&amp;gt;
    public string AuthenticationToken { get; set; }

    /// &amp;lt;summary&amp;gt;
    /// The name of a JavaScript function to call if an error occurs
    /// during the upload.
    /// &amp;lt;/summary&amp;gt;
    public string ErrorFunction { get; set; }

    /// &amp;lt;summary&amp;gt;
    /// The name of a JavaScript function to call when an upload
    /// completes successfully. 
    /// &amp;lt;/summary&amp;gt;
    public string CompleteFunction { get; set; }

    #endregion
}&lt;/pre&gt;

&lt;p&gt;Next, we have the actual HtmlHelper extension method:&lt;/p&gt;

&lt;pre class="brush: csharp;"&gt;/// &amp;lt;summary&amp;gt;
/// Renders JavaScript to turn the specified file input control into an 
/// Uploadify upload control.
/// &amp;lt;/summary&amp;gt;
/// &amp;lt;param name=&amp;quot;helper&amp;quot;&amp;gt;&amp;lt;/param&amp;gt;
/// &amp;lt;param name=&amp;quot;name&amp;quot;&amp;gt;&amp;lt;/param&amp;gt;
/// &amp;lt;param name=&amp;quot;options&amp;quot;&amp;gt;&amp;lt;/param&amp;gt;
/// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;
public static string Uploadify(this HtmlHelper helper, string name, UploadifyOptions options)
{
    string scriptPath = helper.ResolveUrl(&amp;quot;~/Content/jqueryPlugins/uploadify/&amp;quot;);

    StringBuilder sb = new StringBuilder();
    //Include the JS file.
    sb.Append(helper.ScriptInclude(&amp;quot;~/Content/jqueryPlugins/uploadify/jquery.uploadify.js&amp;quot;));
    sb.Append(helper.ScriptInclude(&amp;quot;~/Content/jqueryPlugins/uploadify/jquery.uploadify.init.js&amp;quot;));

    //Dump the script to initialze Uploadify
    sb.AppendLine(&amp;quot;&amp;lt;script type=\&amp;quot;text/javascript\&amp;quot;&amp;gt;&amp;quot;);
    sb.AppendLine(&amp;quot;$(document).ready(function() {&amp;quot;);
    sb.AppendFormat(&amp;quot;initUploadify($('#{0}'),'{1}','{2}','{3}','{4}','{5}',{6},{7});&amp;quot;, name, options.UploadUrl,
                    scriptPath, options.FileExtensions, options.FileDescription, options.AuthenticationToken,
                    options.ErrorFunction ?? &amp;quot;null&amp;quot;, options.CompleteFunction ?? &amp;quot;null&amp;quot;);
    sb.AppendLine();
    sb.AppendLine(&amp;quot;});&amp;quot;);
    sb.AppendLine(&amp;quot;&amp;lt;/script&amp;quot;);

    return sb.ToString();
}&lt;/pre&gt;

&lt;p&gt;The helper uses a StringBuilder (yeah, I hate them, and I’m open to suggestions) to include two JavaScript files.&amp;#160; The first is the standard uploadify script, but the second is something custom, which I’ll get to in just a second.&amp;#160;&amp;#160;&amp;#160; Finally, the helper outputs a call to &lt;em&gt;initUploadify&lt;/em&gt; inside of the page load event, passing in all the options that were specified. &lt;/p&gt;

&lt;p&gt;And that brings us to that second JavaScript include:&lt;/p&gt;

&lt;pre class="brush: js;"&gt;//This is used in conjunction with the HtmlHelper.Uploadify extension method.
function initUploadify(control, uploadUrl, baseUrl, fileExtensions, fileDescription, authenticationToken, errorFunction, completeFunction) {
    var options = {};

    options.script = uploadUrl;
    options.uploader = baseUrl + 'uploader.swf';
    options.cancelImg = baseUrl + 'cancel.png';
    //TODO: Make this an option?
    options.auto = true;
    options.scriptData = { AuthenticationToken: authenticationToken };
    options.fileExt = fileExtensions;
    options.fileDesc = fileDescription;

    if (errorFunction != null) {
        options.onError = errorFunction;
    }

    if (completeFunction != null) {
        options.onComplete = completeFunction;
    }

    control.fileUpload(options);
}&lt;/pre&gt;

&lt;p&gt;In here, I’ve created a simple JavaScript function that actually calls the uploadify JavaScript plug-in.&amp;#160; By using this method instead of using C# to emit the configuration code directly, I’m cutting out a fair amount of tag soup, and I’m wrapping things up in a way that will be easier to change in the future.&amp;#160; Hopefully.&amp;#160; The down side to this approach is that you have to create a new JavaScript method and include for every plug-in you want to use, but combining the scripts and correctly setting cache headers should reduce the request overhead.&lt;/p&gt;

&lt;p&gt;I’m not claiming that this is the best way to do this.&amp;#160; In fact, I really hope it isn’t, because I still don’t like it.&amp;#160; But I &lt;strong&gt;think &lt;/strong&gt;that I like it better than the approach I took for jqGrid.&amp;#160; If you have any suggestions or feedback, please share.&amp;#160; Feel free to tell me that I’m doing things completely wrong.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/Try-catch-fail/~4/42K4E4Z9-Dk" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/Try-catch-fail/~3/42K4E4Z9-Dk/post.aspx</link><author>matt.nospam@nospam.trycatchfail.com (Matt)</author><comments>http://trycatchfail.com/blog/post/2009/05/13/ASPNET-MVC-HtmlHelper-for-Uploadify-Take-One.aspx#comment</comments><guid isPermaLink="false">http://trycatchfail.com/blog/post.aspx?id=32689eb5-c734-4b43-8109-de5bf3af8a7f</guid><pubDate>Wed, 13 May 2009 06:56:16 -1300</pubDate><category>ASP.NET</category><category>MVC</category><category>JavaScript</category><dc:publisher>Matt</dc:publisher><pingback:server>http://trycatchfail.com/blog/pingback.axd</pingback:server><pingback:target>http://trycatchfail.com/blog/post.aspx?id=32689eb5-c734-4b43-8109-de5bf3af8a7f</pingback:target><slash:comments>12</slash:comments><trackback:ping>http://trycatchfail.com/blog/trackback.axd?id=32689eb5-c734-4b43-8109-de5bf3af8a7f</trackback:ping><wfw:comment>http://trycatchfail.com/blog/post/2009/05/13/ASPNET-MVC-HtmlHelper-for-Uploadify-Take-One.aspx#comment</wfw:comment><wfw:commentRss>http://trycatchfail.com/blog/syndication.axd?post=32689eb5-c734-4b43-8109-de5bf3af8a7f</wfw:commentRss><feedburner:origLink>http://trycatchfail.com/blog/post.aspx?id=32689eb5-c734-4b43-8109-de5bf3af8a7f</feedburner:origLink></item><item><title>Using Flash with ASP.NET MVC and Authentication</title><description>&lt;p&gt;There is a well-known bug in Flash that causes it to completely ignore the browser’s session state when it makes a request.&amp;#160; Instead, it either pulls cookies from Internet Explorer or just starts a new session with no cookies.&amp;#160; GOOD CALL, ADOBE.&amp;#160; And when I say this bug is well-known, I mean it was reported in Flash 8.&amp;#160; It’s still sitting in the Adobe bug tracker.&amp;#160; It has been triaged, it &lt;strong&gt;seems&lt;/strong&gt; to have high priority, yet it remains unfixed.&amp;#160; Again, GREAT job, Adobe.&amp;#160; &lt;/p&gt;  &lt;p&gt;Anyway, why should you care?&amp;#160; Well, if you want to use Flash for anything, even something simple like AJAX file uploads with &lt;a href="http://www.uploadify.com" target="_blank"&gt;Uploadify&lt;/a&gt;, you better hope you don’t need authorization and authentication.&amp;#160; But really, why would you want to authenticate users before letting them upload stuff to your site, anyway?&amp;#160; There’s no possible way that could ever be exploited, right?&lt;/p&gt;  &lt;p&gt;If you do decide that security is important (HINT: IT IS), there are some well-known hacks to work around it.&amp;#160; None of them fit well with &lt;a href="http://www.asp.net/mvc" target="_blank"&gt;ASP.NET MVC&lt;/a&gt; though.&amp;#160; Just when all seemed lost, I found &lt;a href="http://geekswithblogs.net/apopovsky/archive/2009/05/06/working-around-flash-cookie-bug-in-asp.net-mvc.aspx" target="_blank"&gt;this post&lt;/a&gt; from Ariel Popovsky that saved the day.&amp;#160; I have wrapped his solution up in an easy-to-apply custom AuthorizationAttribute that you can tag to a controller or action method.&amp;#160; Here’s the code:&lt;/p&gt;  &lt;pre class="brush: csharp;"&gt;/// &amp;lt;summary&amp;gt;
/// A custom version of the &amp;lt;see cref=&amp;quot;AuthorizeAttribute&amp;quot;/&amp;gt; that supports working
/// around a cookie/session bug in Flash.  
/// &amp;lt;/summary&amp;gt;
/// &amp;lt;remarks&amp;gt;
/// Details of the bug and workaround can be found on this blog:
/// http://geekswithblogs.net/apopovsky/archive/2009/05/06/working-around-flash-cookie-bug-in-asp.net-mvc.aspx
/// &amp;lt;/remarks&amp;gt;
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class FlashCompatibleAuthorizeAttribute : AuthorizeAttribute
{
    /// &amp;lt;summary&amp;gt;
    /// The key to the authentication token that should be submitted somewhere in the request.
    /// &amp;lt;/summary&amp;gt;
    private const string TOKEN_KEY = &amp;quot;AuthenticationToken&amp;quot;;

    /// &amp;lt;summary&amp;gt;
    /// This changes the behavior of AuthorizeCore so that it will only authorize
    /// users if a valid token is submitted with the request.
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;param name=&amp;quot;httpContext&amp;quot;&amp;gt;&amp;lt;/param&amp;gt;
    /// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;
    protected override bool AuthorizeCore(System.Web.HttpContextBase httpContext)
    {
        string token = httpContext.Request.Params[TOKEN_KEY];

        if (token != null)
        {
            FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(token);

            if (ticket != null)
            {
                FormsIdentity identity = new FormsIdentity(ticket);
                string[] roles = System.Web.Security.Roles.GetRolesForUser(identity.Name);
                GenericPrincipal principal = new GenericPrincipal(identity, roles);
                httpContext.User = principal;
            }
        }

        return base.AuthorizeCore(httpContext);
    }
}&lt;/pre&gt;

&lt;p&gt;The filter checks the request to see if the authentication ticket was submitted.&amp;#160; If so, it tries to decrypt it, then recreates the IPrincipal that is needed by the base AuthorizationAttribute to do its work.&amp;#160; Just apply it to your controller, make sure Flash is submitted the value of the Forms Authentication cookie, and BAM, everything works. &lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/Try-catch-fail/~4/pxe1Jd7cXks" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/Try-catch-fail/~3/pxe1Jd7cXks/post.aspx</link><author>matt.nospam@nospam.trycatchfail.com (Matt)</author><comments>http://trycatchfail.com/blog/post/2009/05/13/Using-Flash-with-ASPNET-MVC-and-Authentication.aspx#comment</comments><guid isPermaLink="false">http://trycatchfail.com/blog/post.aspx?id=26c1381f-07c1-41dd-8d46-9c0c23f96abd</guid><pubDate>Wed, 13 May 2009 01:47:57 -1300</pubDate><category>ASP.NET</category><category>MVC</category><dc:publisher>Matt</dc:publisher><pingback:server>http://trycatchfail.com/blog/pingback.axd</pingback:server><pingback:target>http://trycatchfail.com/blog/post.aspx?id=26c1381f-07c1-41dd-8d46-9c0c23f96abd</pingback:target><slash:comments>7</slash:comments><trackback:ping>http://trycatchfail.com/blog/trackback.axd?id=26c1381f-07c1-41dd-8d46-9c0c23f96abd</trackback:ping><wfw:comment>http://trycatchfail.com/blog/post/2009/05/13/Using-Flash-with-ASPNET-MVC-and-Authentication.aspx#comment</wfw:comment><wfw:commentRss>http://trycatchfail.com/blog/syndication.axd?post=26c1381f-07c1-41dd-8d46-9c0c23f96abd</wfw:commentRss><feedburner:origLink>http://trycatchfail.com/blog/post.aspx?id=26c1381f-07c1-41dd-8d46-9c0c23f96abd</feedburner:origLink></item><item><title>Testing SyntaxHighlighter</title><description>&lt;p&gt;This is a test post to see how &lt;a href="http://alexgorbatchev.com/wiki/SyntaxHighlighter" target="_blank"&gt;SyntaxHighlighter&lt;/a&gt; works with Windows Live Writer.&amp;#160; I’m using the &lt;a href="http://www.codeplex.com/precode" target="_blank"&gt;PreCode&lt;/a&gt; plug-in. So, C#:&lt;/p&gt;  &lt;pre class="brush: csharp;"&gt;public class Testing
{
    public Id { get; private set; }
    public void Method(string parameter)
    {
        Console.WriteLine(&amp;quot;Testing!&amp;quot;);
    }
}&lt;/pre&gt;

&lt;p&gt;And JavaScript:&lt;/p&gt;

&lt;pre class="brush: js;"&gt;function(x,y)
{
    alert('X is:' + x + &amp;quot; and Y is: &amp;quot; + y);
}&lt;/pre&gt;

&lt;p&gt;And SQL:&lt;/p&gt;

&lt;pre class="brush: sql;"&gt;SELECT * FROM Table
WHERE Col1='Test' 
AND 1=0&lt;/pre&gt;

&lt;p&gt;HTML:&lt;/p&gt;

&lt;pre class="brush: xml;"&gt;&amp;lt;div&amp;gt;
    &amp;lt;h1&amp;gt;Something!&amp;lt;/h1&amp;gt;
    &amp;lt;p&amp;gt;Something else!&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;&lt;/pre&gt;&lt;img src="http://feeds.feedburner.com/~r/Try-catch-fail/~4/Z7xJ5Xae_PY" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/Try-catch-fail/~3/Z7xJ5Xae_PY/post.aspx</link><author>matt.nospam@nospam.trycatchfail.com (Matt)</author><comments>http://trycatchfail.com/blog/post/2009/05/13/Testing-SyntaxHighlighter.aspx#comment</comments><guid isPermaLink="false">http://trycatchfail.com/blog/post.aspx?id=622ab261-f811-421e-bde9-97dcd52947cf</guid><pubDate>Wed, 13 May 2009 00:53:11 -1300</pubDate><dc:publisher>Matt</dc:publisher><pingback:server>http://trycatchfail.com/blog/pingback.axd</pingback:server><pingback:target>http://trycatchfail.com/blog/post.aspx?id=622ab261-f811-421e-bde9-97dcd52947cf</pingback:target><slash:comments>0</slash:comments><trackback:ping>http://trycatchfail.com/blog/trackback.axd?id=622ab261-f811-421e-bde9-97dcd52947cf</trackback:ping><wfw:comment>http://trycatchfail.com/blog/post/2009/05/13/Testing-SyntaxHighlighter.aspx#comment</wfw:comment><wfw:commentRss>http://trycatchfail.com/blog/syndication.axd?post=622ab261-f811-421e-bde9-97dcd52947cf</wfw:commentRss><feedburner:origLink>http://trycatchfail.com/blog/post.aspx?id=622ab261-f811-421e-bde9-97dcd52947cf</feedburner:origLink></item><item><title>&amp;ldquo;Hi, we&amp;rsquo;re Square Enix, and we are totally LAME!&amp;rdquo;</title><description>&lt;p&gt;This isn’t directly development-related, but it is noteworthy.&amp;#160; On May 8th, Square Enix, makers of Final Fantasy, Chrono Trigger, etc, hit &lt;a href="http://www.chronocompendium.com/" target="_blank"&gt;Chrono Compendium&lt;/a&gt; with a cease-and-desist related to ROM hacking and modifications, particularly as it relates to the &lt;a href="http://www.crimsonechoes.com/" target="_blank"&gt;Crimson Echoes&lt;/a&gt; fan project.&amp;#160; Square Enix has sent C&amp;amp;D projects in the Chrono community before, but they were always to people that were recreating Chrono in a new engine/platform/whatever, not to groups that were creating ROM hacks.&amp;#160; ROM hacks are essentially nothing more than mods, which are standard fare these days.&amp;#160; Instead of being appreciative of a community that has thrived despite being largely abandoned for the better part of a decade, Square Enix decided to be LAME and resort to legal threats.&amp;#160; &lt;/p&gt;  &lt;p&gt;I was actually look forward to playing Crimson Echoes, and I’m very sad to see it go.&amp;#160; This is a great example of how screwed up intellectual properties are… anyway, if you have a blog and were/are a fan of the Chrono series, spread the word.&amp;#160; I highly recommend *NOT* buying things with the Square Enix label since they are unoriginal dicks who are surviving mostly on name and rehashes of old IP.&amp;#160; Good job, Square!&amp;#160; &lt;a href="http://digg.com/nintendo/Chrono_Trigger_sequel_98_comlete_C_Ded_before_release" target="_blank"&gt;Digg the story here&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/Try-catch-fail/~4/YJmKytwAxck" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/Try-catch-fail/~3/YJmKytwAxck/post.aspx</link><author>matt.nospam@nospam.trycatchfail.com (Matt)</author><comments>http://trycatchfail.com/blog/post/2009/05/11/ldquo3bHi-wersquo3bre-Square-Enix-and-we-are-totally-LAME!rdquo3b.aspx#comment</comments><guid isPermaLink="false">http://trycatchfail.com/blog/post.aspx?id=c38f62ca-1d79-4dfc-8330-ad22c34a6e4c</guid><pubDate>Mon, 11 May 2009 07:47:31 -1300</pubDate><category>Misc</category><dc:publisher>Matt</dc:publisher><pingback:server>http://trycatchfail.com/blog/pingback.axd</pingback:server><pingback:target>http://trycatchfail.com/blog/post.aspx?id=c38f62ca-1d79-4dfc-8330-ad22c34a6e4c</pingback:target><slash:comments>0</slash:comments><trackback:ping>http://trycatchfail.com/blog/trackback.axd?id=c38f62ca-1d79-4dfc-8330-ad22c34a6e4c</trackback:ping><wfw:comment>http://trycatchfail.com/blog/post/2009/05/11/ldquo3bHi-wersquo3bre-Square-Enix-and-we-are-totally-LAME!rdquo3b.aspx#comment</wfw:comment><wfw:commentRss>http://trycatchfail.com/blog/syndication.axd?post=c38f62ca-1d79-4dfc-8330-ad22c34a6e4c</wfw:commentRss><feedburner:origLink>http://trycatchfail.com/blog/post.aspx?id=c38f62ca-1d79-4dfc-8330-ad22c34a6e4c</feedburner:origLink></item></channel>
</rss>
