<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>The Book of Ryan &#187; Web Design/Programming</title>
	<atom:link href="http://ryancannon.com/category/web-designprogramming/feed" rel="self" type="application/rss+xml" />
	<link>http://ryancannon.com</link>
	<description>Wordslinger, dissident, webwright</description>
	<lastBuildDate>Sun, 15 Jan 2012 04:33:31 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Parsing Your Character&#8217;s Loot</title>
		<link>http://ryancannon.com/2009/07/01/parsing-your-characters-loot</link>
		<comments>http://ryancannon.com/2009/07/01/parsing-your-characters-loot#comments</comments>
		<pubDate>Wed, 01 Jul 2009 16:05:41 +0000</pubDate>
		<dc:creator>Ryan</dc:creator>
				<category><![CDATA[D&D]]></category>
		<category><![CDATA[Web Design/Programming]]></category>
		<category><![CDATA[D&DI]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://ryancannon.com/?p=290</guid>
		<description><![CDATA[Here&#8217;s a quick teaser for a new project I&#8217;m working on, almost ready for public beta. def loot(character_sheet_file) @xml &#124;&#124;= Hpricot::XML(character_sheet_file.read) @loot &#124;&#124;= @xml.search("//LootTally/loot[@count!='0']").map do &#124;item&#124; res = item.search("//RulesElement") case res.size when 0: nil when 1: coder.decode(res.first.attributes["name"]) when 2: coder.decode(res.last.attributes["name"].sub(res.first.attributes["type"], res.first.attributes["name"])) else res.map { &#124;re&#124; coder.decode(re.attributes["name"]) }.join(" ") end end.compact end Character files from D&#38;DI [...]]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s a quick teaser for a new project I&#8217;m working on, almost ready for public beta.</p>

<pre style="font-size:80%"><code>def loot(character_sheet_file)
  @xml ||= Hpricot::XML(character_sheet_file.read)
  @loot ||= @xml.search("//LootTally/loot[@count!='0']").map do |item|
    res = item.search("//RulesElement")
    case res.size
      when 0: nil
      when 1: coder.decode(res.first.attributes["name"])
      when 2: coder.decode(res.last.attributes["name"].sub(res.first.attributes["type"], res.first.attributes["name"]))
      else    res.map { |re| coder.decode(re.attributes["name"]) }.join(" ")
    end
  end.compact
end</code></pre>

<p>Character files from <a href="http://wizards.com/default.asp?x=dnd/insider/characterbuilder" title="D&amp;D Character Builder">D&amp;DI Character Builder</a> store loot as a list, but the names of magic items are concatenated with names of their connected mundane items, so you have to mix them based on the magic item&#8217;s <code>@type</code>.</p>

<p>Also, the Character Builder stores <em>every item you&#8217;ve ever added,</em> even if you deleted it immediately, so you have to filter out items with a count of zero. You have no way to tell if this was an intentional item purchase, an item accidentally clicked on or a found item from a module, so items with <code>@count=0</code> are useless.</p>

<p>What could I possibly be building‽‽‽</p>
]]></content:encoded>
			<wfw:commentRss>http://ryancannon.com/2009/07/01/parsing-your-characters-loot/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Scope in ActionScript 3 is so fubared I can barely express it in words</title>
		<link>http://ryancannon.com/2008/10/19/scope-in-actionscript-3-is-so-fubared-i-can-barely-express-it-in-words</link>
		<comments>http://ryancannon.com/2008/10/19/scope-in-actionscript-3-is-so-fubared-i-can-barely-express-it-in-words#comments</comments>
		<pubDate>Mon, 20 Oct 2008 03:00:08 +0000</pubDate>
		<dc:creator>Ryan</dc:creator>
				<category><![CDATA[Web Design/Programming]]></category>

		<guid isPermaLink="false">http://ryancannon.com/?p=203</guid>
		<description><![CDATA[This looks wrong: package { public class ScopeFu { private static var var0:String = 'var 0'; public static var var1:String = 'var 1'; private var var2:string = 'var 2'; public var var3:String = 'var 3'; public function ScopeFu(var4:String = 'var 4') { var var5 = 'var 5'; trace(var0); trace(var1); trace(var2); trace(var3); trace(var4); trace(var5); } } [...]]]></description>
			<content:encoded><![CDATA[<p>This looks wrong:</p>

<p><span id="more-203"></span></p>

<pre><code>package {
  public class ScopeFu {

    private static var var0:String = 'var 0';
    public static var var1:String  = 'var 1';

    private var var2:string = 'var 2';
    public var var3:String = 'var 3';

    public function ScopeFu(var4:String = 'var 4') {
      var var5  = 'var 5';

      trace(var0);
      trace(var1);
      trace(var2);
      trace(var3);
      trace(var4);
      trace(var5);
    }
  }
}
</code></pre>

<p>And yet it works.</p>

<p>Compared to JavaScript:</p>

<pre><code>var ScopeFu;
(function() {
  var var0 = 'var 0';

  ScopeFu = function(var4) {
    this.var2  = 'var 2';
    this.var3  = 'var3';
    var4       = var4 || 'var 4';
    var var5   = 'var 5';

    console.log(var0);
    console.log(ScopeFu.var1);
    console.log(this.var2);
    console.log(this.var3);
    console.log(var4);
    console.log(var5);
  }
  ScopeFu.var1 = 'var 1';
})();
</code></pre>

<p>Still a mess. The JavaScript syntax is a little more cryptic and <code>var2</code> isn&#8217;t private, yet there are half as many scope collisions. The ones that do exist are only because JavaScript doesn&#8217;t really support private members; I&#8217;m using closures to fake it.</p>

<p>In either case, scope can become a nightmare in large applications when you&#8217;re trying to figure out where something is defined, especially when you&#8217;re jumping back and forth between the otherwise-similar languages. Underscores and access methods can help, so long as you are disciplined enough to be consistent:</p>

<table class="vibrant">
    <caption>Preferred prefixes and access methods for variable scope in ActionScript and JavaScript</caption>
    <thead>
    <tr>
        <th> Scope </th>
        <th> Prefix </th>
        <th> Access </th>
        <th> Example </th>
    </tr>
    </thead>
    <tbody>
    <tr>
        <th> Private Static </th>
        <td> Three Underscores </td>
        <td> local </td>
        <td> <code>___var0</code> </td>
    </tr>
    <tr>
        <th> Public Static </th>
        <td> none </td>
        <td> via class </td>
        <td> <code>ScopeFu.var1</code> </td>
    </tr>
    <tr>
        <th> Private Instance </th>
        <td> Two Underscores </td>
        <td> this (JavaScript only) </td>
        <td> <code>this.__var2</code> or <code>__var2</code> </td>
    </tr>
    <tr>
        <th> Public Instance </th>
        <td> none </td>
        <td> this </td>
        <td> <code>this.var3</code> </td>
    </tr>
    <tr>
        <th> Function Argument </th>
        <td> One Underscore </td>
        <td> local </td>
        <td> <code>_var4</code> </td>
    </tr>
    <tr>
        <th> Function Member </th>
        <td> none </td>
        <td> local </td>
        <td> <code>var5</code> </td>
    </tr>
    </tbody>
</table>

<p>Adopting these kinds of conventions may help keep scope sorted amongst a group of developers.</p>

<script type="text/javascript" src="http://ryancannon.com/wp-content/attic/js/vibrantTable.js"></script>
]]></content:encoded>
			<wfw:commentRss>http://ryancannon.com/2008/10/19/scope-in-actionscript-3-is-so-fubared-i-can-barely-express-it-in-words/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Speeding up Prototype&#8217;s document.viewport.getDimensions</title>
		<link>http://ryancannon.com/2008/10/04/speeding-up-prototypes-documentviewportgetdimensions</link>
		<comments>http://ryancannon.com/2008/10/04/speeding-up-prototypes-documentviewportgetdimensions#comments</comments>
		<pubDate>Sat, 04 Oct 2008 08:18:24 +0000</pubDate>
		<dc:creator>Ryan</dc:creator>
				<category><![CDATA[Web Design/Programming]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Opera]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[prototype]]></category>

		<guid isPermaLink="false">http://ryancannon.com/?p=195</guid>
		<description><![CDATA[JavaScript has a lot of haters. They gripe about its loose typing and semicolon insertion. They whine about it&#8217;s lack of inheritance and hardened classes. My guess os that many of these complaints come from programmers trying to write JavaScript as if it were Java, C or Objective-C. JavaScript, however, is a unique dynamic and [...]]]></description>
			<content:encoded><![CDATA[<p>JavaScript has a lot of haters. They gripe about its loose typing and semicolon insertion. They whine about it&#8217;s lack of inheritance and hardened classes. My guess os that many of these complaints come from programmers trying to write JavaScript as if it were Java, C or <a href="http://cappuccino.org/learn/tutorials/objective-j-tutorial.php" title="Cappuccino Web Framework - Objective-J Tutorial">Objective-C</a>. JavaScript, however, is a unique dynamic and expressive language, and this makes best suited for the Web.</p>

<p>Browsers are fickle beasts, and have some wildly different implementations of the same operations. At the same time, JavaScript applications are becoming more complex and the Internet is rapidly spreading to gaming consoles, mobile phones and linux-powered toasters. Performance optimization is an important tool to keep our applications running sprightly.</p>

<p><span id="more-195"></span></p>

<p>Prototype&#8217;s <code>document.viewport.getDimensions</code> is a great example of some easy optimization. The method, in the <a href="http://github.com/sstephenson/prototype/tree/master" title="sstephenson's prototype at master — GitHub">master</a>:</p>

<pre><code>document.viewport = {
  getDimensions: function() {
    var dimensions = { }, B = Prototype.Browser;
    $w('width height').each(function(d) {
      var D = d.capitalize();
      if (B.WebKit &amp;&amp; !document.evaluate) {
        // Safari &lt;3.0 needs self.innerWidth/Height
        dimensions[d] = self['inner' + D];
      } else if (B.Opera &amp;&amp; parseFloat(window.opera.version()) &lt; 9.5) {
        // Opera &lt;9.5 needs document.body.clientWidth/Height
        dimensions[d] = document.body['client' + D]
      } else {
        dimensions[d] = document.documentElement['client' + D];
      }
    });
    return dimensions;
  }
  /* other methods */
};
</code></pre>

<p>The function operation is quite simple:</p>

<ol>
<li>Create an object to hold your results</li>
<li>Create an array of possible properties</li>
<li>Loop through those properties, each time:</li>
<li>Figure out which method to use, based on which browser you have</li>
<li>Get the viewport width using that method</li>
<li>Figure out which method to use, based on which browser you have</li>
<li>Get the viewport width using that method</li>
<li>Return the object</li>
</ol>

<p>However, it&#8217;s very wasteful. Steps 2, 4 and 7 execute <em>every time</em> you run the method, even though their results will <strong>always be the same</strong>. This may not be a big deal, but if you&#8217;re using this method a lot—for example, along with the <code>window.onresize</code> event handler which can fire many times per second—every little bit can help.</p>

<p>The above method uses some Ruby paradigms—<code>$w()</code> and <code>self</code>—leveraging a style unique to JavaScript will help us save some complexity without changing underlying logic.</p>

<pre><code>document.viewport = {
  getDimensions: function() {
    var B, vpsizer;

    B = Prototype.Browser;

              // Safari &lt;3.0 needs self.innerWidth/Height
    vpsizer = (B.WebKit &amp;&amp; !document.evaluate) ?
      function (D) {
        return self['inner' + D];
      } :

      // Opera &lt;9.5 needs document.body.clientWidth/Height
      (B.Opera &amp;&amp; parseFloat(window.opera.version()) &lt; 9.5) ?
        function(D) {
          return document.body['client' + D];
        } :
        function(D) {
          return document.documentElement['client' + D];
        };

    function it(acc, value) {
      acc[value] = vpsizer(value.capitalize());
      return acc;
    }

    function f() {
      var r = {};
      it(r, 'height');
      it(r, 'width');
      return r;
    }

    return (document.viewport.getDimensions = f)();
  }
  /* other methods */
};
</code></pre>

<p>This might look a little alien at first, so let me walk through it.</p>

<ol>
<li>Remove the array of properties. It&#8217;s a waste to invoke all of Prototype&#8217;s Array mechanics for a two-member array that never changes. We still set the browser name because we&#8217;re doing the same checks as the previous function.</li>
<li>We set <code>vpsizer</code> to a different function based on the browser&#8217;s needs. While using the ternary operators and function literals together looks a little awkward, it&#8217;s the most concise way to so set a variable based on shifting conditions where you can&#8217;t use a <code>switch</code> statement. In my opinion it&#8217;s always best to minimize the amount of assignment operators you use, as it becomes easier to track down exactly where variables are set.</li>
<li>The two functions <code>it</code> (short for iterator) and <code>f</code> are our workhorses. Now that we&#8217;ve stored <code>vpsizer</code> in memory, we call it for <code>'width' and 'height'</code>.</li>
<li>In the last line we&#8217;re doing  three things in concert:

<ol>
<li>Assigning <code>document.viewport.getDimensions</code> (the current method) to our workhorse function <code>f</code>. This means that all of the logic we&#8217;ve done so far remains in memory and we <em>never have to do it again.</em></li>
<li>The assignment operator also returns the assigned value. By wrapping the assignment in parenthesis, we can then use the <code>()</code> operator to immediately call <code>f</code>.</li>
<li>We exit the function, returning the value of <code>f()</code>.</li>
</ol></li>
</ol>

<p>What have we done? After all, the function looks more complex now than before. However, running the following script will show the performance difference:</p>

<pre><code>alert(document.viewport.getDimensions);
document.viewport.getDimensions();
alert(document.viewport.getDimensions);
</code></pre>

<p>Note that second alert: <code>document.viewport.getDimensions</code> is now only <em>four lines of code</em>. We have, however, removed quite a bit of syntactical sugar. Much like putting a slinky on top of your stairs converts kinetic energy into <a href="http://en.wikipedia.org/wiki/Potential_energy" title="Potential energy - Wikipedia, the free encyclopedia">potential energy</a>, we&#8217;ve converted computational complexity into conceptual complexity.</p>

<p>I&#8217;m not a pro at testing performance, but a <a href="http://ryancannon.com/wp-content/attic/html/viewport/" title="document.viewport Test">rudimentary test</a> is showing performance gains of  averaging around <strong>40% or more</strong> over time. Re-setting <code>document.viewport</code> gave me gains of 15% or so, and removing the Array madness added 25%. Now a cynic might say that we&#8217;re only really shaving a handful of milliseconds off of execution, but remember: <em>checking the viewport size is not an intensive operation.</em> Using these techniques in your own code can come to <a id="ref-1" href="#note-1">surprising benefits</a>.</p>

<p>All that&#8217;s left, of course, is to commit the code. Problem. Prototype Rake to do unit tests, and I can&#8217;t for the life of me get Opera to pass any of the viewport tests. In fact, I can&#8217;t get <code>window.resizeTo()</code> to work in Opera at all unless the window I&#8217;m resizing is a pop-up I&#8217;ve created. I&#8217;ve tried setting and unsetting Opera&#8217;s JavaScript preferences in 9.5 and 9.2 multiple times. Any help would be appreciated.</p>

<h3>Notes</h3>

<ol>
<li><span id="note-1">One note, however: do not use this technique to cache DOM Objects, lest you invoke the feebleness of <a href="http://javascript.crockford.com/memory/leak.html" title="Memory Leaks">Internet Explorer</a>. <a class="return" href="#ref-solution">↩</a></span>  </li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://ryancannon.com/2008/10/04/speeding-up-prototypes-documentviewportgetdimensions/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>If it quacks like a duck</title>
		<link>http://ryancannon.com/2008/07/20/if-it-quacks-like-a-duck</link>
		<comments>http://ryancannon.com/2008/07/20/if-it-quacks-like-a-duck#comments</comments>
		<pubDate>Sun, 20 Jul 2008 22:12:56 +0000</pubDate>
		<dc:creator>Ryan</dc:creator>
				<category><![CDATA[Web Design/Programming]]></category>

		<guid isPermaLink="false">http://ryancannon.com/?p=186</guid>
		<description><![CDATA[I felt a bit elitist after posting about my desire that job candidates should have a low-level understanding of JavaScript. Today a bug I caught reinforced that belief. JavaScript and Ruby are dynamic or duck-typed languages, meaning that variable values are converted between types when your code requires, allowing you to do things like: "2" [...]]]></description>
			<content:encoded><![CDATA[<p>I felt a bit elitist after posting about my desire that <a href="http://ryancannon.com/2008/07/04/the-other-side-of-the-interview-table" title="The other side of the interview table">job candidates should have a low-level understanding of JavaScript</a>. Today a bug I caught reinforced that belief.</p>

<p><span id="more-186"></span></p>

<p>JavaScript and Ruby are dynamic or <a href="http://en.wikipedia.org/wiki/Duck_typing" title="Duck typing - Wikipedia, the free encyclopedia">duck-typed</a> languages, meaning that variable values are converted between types when your code requires, allowing you to do things like:</p>

<pre><code>"2" * 2 == 4 // true
</code></pre>

<p>Instead of having to manually convert between types. This allows some shortcuts for otherwise annoying code. For example, you never have to do</p>

<pre><code>if (typeof foo == 'undefined' ||
    foo === null ||
    foo === false ||
    foo === "0" ||
    foo === '') { doSomething();}
</code></pre>

<p>You can just do</p>

<pre><code>if (foo) { doSomething();}
</code></pre>

<p>In JavaScript you can also do some nifty type conversion:</p>

<pre><code>"4" * 1 // 4
4 + ""  // "4"
!! 4    // true
</code></pre>

<p>This can lead, however, to some odd bugs if you&#8217;re not careful. I was receiving a boolean flag via JSON, which came across the wire as zero or one. In my application I had something that was essentially</p>

<pre><code>if (flag) { makeTheMagicHappen();}
</code></pre>

<p>Unfortunately, <code>flag</code> was coming in as a string, <em>not</em> an integer. I want <code>flag</code> as a Boolean, but <code>"0"</code> evaluates to <code>true</code>, so my flag was coming up incorrectly. Worse, this was a pretty tough bug to spot. The <a id="ref-solution" href="#note-solution">solution</a>, of course, is:</p>

<pre><code>if (Boolean(Number(flag))) { makeTheMagicHappen();}
</code></pre>

<p>or</p>

<pre><code>if (!! (flag * 1)) { makeTheMagicHappen();}
</code></pre>

<p>Worse, type coercion varies between languages. Ruby converts all values except <code>nil</code> to <code>true</code>.</p>

<h3>Notes</h3>

<ol>
<li><span id="note-solution">Actually, the solution is to change the bad data, but for complicated reasons outside of this post&#8217;s scope, that&#8217;s not possible. <a class="return" href="#ref-solution">↩</a></span></li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://ryancannon.com/2008/07/20/if-it-quacks-like-a-duck/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Intriguing Interfaces: How to share private videos on YouTube</title>
		<link>http://ryancannon.com/2008/07/13/intriguing-interfaces-how-to-share-private-videos-on-youtube</link>
		<comments>http://ryancannon.com/2008/07/13/intriguing-interfaces-how-to-share-private-videos-on-youtube#comments</comments>
		<pubDate>Sun, 13 Jul 2008 19:30:45 +0000</pubDate>
		<dc:creator>Ryan</dc:creator>
				<category><![CDATA[Web Design/Programming]]></category>

		<guid isPermaLink="false">http://ryancannon.com/?p=185</guid>
		<description><![CDATA[Although they label it as &#8220;beta&#8221;, YouTube has done some re-working of their video management interfaces in quite an intriguing manner. With their interface changes, the Help Center Page is a little out of date. The comment mechanism on their blog doesn&#8217;t work (note all the double comments—mine didn&#8217;t even show up). I thought I&#8217;d [...]]]></description>
			<content:encoded><![CDATA[<p>Although <a href="http://www.youtube.com/blog?entry=U-vkkWJx-aI" title="New “My Videos” &amp; Subscription Center">they label it as &#8220;beta&#8221;</a>, YouTube has done some re-working of their video management interfaces in quite an intriguing manner. With their interface changes, the <a href="http://www.google.com/support/youtube/bin/answer.py?hl=en&amp;answer=92316" title="Help Center: How do I share private videos?">Help Center Page</a> is a little out of date. The comment mechanism on their blog doesn&#8217;t work (note all the double comments—mine didn&#8217;t even show up). I thought I&#8217;d post here instead.</p>

<p><span id="more-185"></span></p>

<p>You can share your private video by following the steps below:</p>

<ol>
<li>Sign into your account.</li>
<li>Enter the &#8220;My Videos&#8221; section. There are three ways to do this:

<ul>
<li>Click the &#8220;My Videos&#8221; link in the &#8220;Account&#8221; dropdown at the top of the page.</li>
<li>Click the &#8220;Account&#8221; link at the top of the page, then click the &#8220;Uploaded Videos&#8221; link in the &#8220;My Videos&#8221; section.</li>
<li>Click the &#8220;Account&#8221; link at the top of the page, then click the &#8220;Videos, Favorites &amp; Playlists&#8221; link in the &#8220;My Account&#8221; dropdown.</li>
</ul></li>
<li>Click the edit button next to the video you would like to share.</li>
<li>In the address bar of your Web browser, change the the text <code>my_videos_edit2</code> in the URL to <code>my_videos_edit</code>.</li>
<li>Under &#8220;Broadcast Options&#8221;, click &#8220;choose options&#8221;</li>
<li>Click the &#8220;Private&#8221; radio button &#8220;+&#8221; next to the label that contains the user you want to share with. If you do not have a Label set up, do the following:

<ol>
<li>Click the &#8220;edit contacts&#8221; link.</li>
<li>Click &#8220;New Label&#8221; either under the &#8220;Label&#8221; drop down or the &#8220;New&#8221; drop down.</li>
<li>Enter a name for the list, then click &#8220;Create&#8221;</li>
<li>Click on &#8220;All Contacts&#8221;</li>
<li>Click the name of your contact.</li>
<li>Click &#8220;Edit&#8221;</li>
<li>Check the check box next to the label to which you want to add the friend.</li>
<li>Click the &#8220;Save Changes&#8221;</li>
</ol></li>
<li>Click the &#8220;Update Video Info&#8221; button.</li>
</ol>

<p>And there it is: eight (or fifteen) simple steps to sharing a private video on YouTube.</p>
]]></content:encoded>
			<wfw:commentRss>http://ryancannon.com/2008/07/13/intriguing-interfaces-how-to-share-private-videos-on-youtube/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>The Mobile Dollar: Dipping a toe into device JavaScript</title>
		<link>http://ryancannon.com/2008/07/10/the-mobile-dollar-dipping-a-toe-in-device-javascript</link>
		<comments>http://ryancannon.com/2008/07/10/the-mobile-dollar-dipping-a-toe-in-device-javascript#comments</comments>
		<pubDate>Thu, 10 Jul 2008 07:45:37 +0000</pubDate>
		<dc:creator>Ryan</dc:creator>
				<category><![CDATA[Web Design/Programming]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Mobile]]></category>
		<category><![CDATA[Web Design]]></category>

		<guid isPermaLink="false">http://ryancannon.com/?p=183</guid>
		<description><![CDATA[I&#8217;ve been working on a (very) small side project that targets mobile Web Browsers. Testing for the mobile platform, however, is ludicrous: someone I met a SXSW told me that their mobile application had over four-hundred different builds. Simple applications, however, aren&#8217;t terribly difficult to make, so long as you keep your focus small. My [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been working on a (very) small side project that targets mobile Web Browsers. Testing for the mobile platform, however, is ludicrous: someone I met a SXSW told me that their mobile application had over four-hundred different builds. Simple applications, however, aren&#8217;t terribly difficult to make, so long as you keep your focus small.</p>

<p><span id="more-183"></span></p>

<p>My Web app works in IE Mobile 5 and 6, Opera Mobile 8.65, Opera Mini 4 and the iPhone Simulator. A proper iPhone version would require a slightly different UI and leverage the absurdly better layout engine of MobileSafari, but this will work while I wait for lines to thin this weekend.</p>

<p>Opera Mobile is very good and will handle almost anything you throw at it; Opera Mini is a mysterious beast, but seems to &#8220;just work&#8221;. IE Mobile, however, is a bizarre member of the device browser family, and like its desktop-sized predecessors, has some quirks:</p>

<ul>
<li>Both support more selectors, but far fewer CSS properties than IE 6. Luckily the <a href="http://msdn.microsoft.com/en-us/library/bb415428.aspx" title="Internet Explorer Mobile Reference">IE Mobile 6</a> and <a href="http://msdn.microsoft.com/en-us/library/ms853311.aspx" title="http://msdn.microsoft.com/en-us/library/ms879886.aspx">IE Mobile 5</a> documentation is well done, if hard to find.</li>
<li>Unobtrusive scripting is explicitly <em>not</em> supported. At all. If an element needs to listen for an event, it must use the <code>onevent=""</code> attribute in the HTML.</li>
<li>Transparent PNGs and GIFs cause visual static when used as background images.</li>
<li><code>HTMLElement#nodeName</code> is not supported; you have to use <code>HTMLElement#tagName</code>.</li>
<li>The <code>getElementsByTagName</code> method is supported only on the <code>document</code> object in IE Mobile 6 and <em>not at all</em> in IE Mobile 5. If you want to support that browser, element references <em>must</em> be done via IDs.</li>
</ul>

<p>In addition, feature detection and <code>document.getElementById</code> are <a href="http://blogs.msdn.com/iemobile/archive/2007/05/15/ie-mobile-standards-support.aspx" title="IEMobile Team Weblog : IE Mobile Standards Support">new features in IE Mobile 6</a>. Luckily, IE Mobile 5 populates the <code>window</code> Object with variables named identically to element IDs, as if it could do:</p>

<pre><code>var el, c = -1;
while (el = document.getElementsByTagName('*')[++c]) {
  if (el.id) {
    window[el.id] = el;
  }
}
</code></pre>

<p>Because IE Mobile 5 lacks feature detection, testing for this case requires some special work as well. Porting the <a href="http://www.dustindiaz.com/top-ten-javascript/" title="Top 10 custom JavaScript functions of all time">dollar function</a> to device JavaScript looks like the following:</p>

<pre><code>var $ = (function() {
  try {
    (! document.getElementById);
      return function(id) {
        return document.getElementById(id);
      };
  }
  catch(e) {
    return function(id) {
      return window[id];
    }
  }
})();
</code></pre>

<p>This simplified version accepts only a string argument. It&#8217;d be a good coding exercise to rework it into accepting a string, HTMLElement or Array. Good luck!</p>

<p>UPDATE: The application is a very simple means to track life in a game of Magic: The Gathering. Check out the <a href="http://ryancannon.com/mtg" title="Magic Game Tracker: Keep score on your mobile phone.">Magic Game Tracker</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://ryancannon.com/2008/07/10/the-mobile-dollar-dipping-a-toe-in-device-javascript/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>The other side of the interview table</title>
		<link>http://ryancannon.com/2008/07/04/the-other-side-of-the-interview-table</link>
		<comments>http://ryancannon.com/2008/07/04/the-other-side-of-the-interview-table#comments</comments>
		<pubDate>Fri, 04 Jul 2008 11:06:22 +0000</pubDate>
		<dc:creator>Ryan</dc:creator>
				<category><![CDATA[Web Design/Programming]]></category>
		<category><![CDATA[interviewing resumes jobs javascript css]]></category>

		<guid isPermaLink="false">http://ryancannon.com/?p=182</guid>
		<description><![CDATA[As I mentioned before, the NFL is expanding their Web staff, and that put me into a strange position: the interviewer. I&#8217;d spent the better part of three years interviewing, studying and networking trying to get a job, and suddenly I was being asked to evaluate candidates who were going to be&#8230;well&#8230;me. We went through [...]]]></description>
			<content:encoded><![CDATA[<p>As I <a href="http://ryancannon.com/2008/02/01/football-company-seeks-the-moderately-webby" title="Football company seeks the moderately webby">mentioned before</a>, the NFL is expanding their Web staff, and that put me into a strange position: the interview<em>er</em>. I&#8217;d spent the better part of three years interviewing, studying and networking trying to get a job, and suddenly I was being asked to evaluate candidates who were going to be&#8230;well&#8230;me.</p>

<p><span id="more-182"></span></p>

<p>We went through a ton of candidates. It amazed me the range of skills and knowledge people applying for a Web Developer position had. But in general, I ran a few common issues that soured me on many candidates.</p>

<h3>Know what you don&#8217;t know</h3>

<p>One of the first questions I ask candidates is how they rate themselves on a one-to-ten scale with HTML, CSS, JavaScript and Flash. Amazingly, <em>most</em> of the candidates rate themselves a nine or ten in HTML. Now I&#8217;m pretty sure only <a href="http://ln.hixie.ch/" title="Hixi's Natural Log">Ian Hickson</a>, and maybe <a href="http://annevankesteren.nl/" title="Anne's Weblog">Anne Van Kesteren</a> grok HTML in it&#8217;s fullness, but if you rate yourself a ten in HTML and cannot describe the differences between HTML and SGML, or the parsing irregularities between the four major browsers, it reflects poorly. Many candidates rated themselves a seven or higher, but could not describe the purpose of a <code>&lt;label&gt;</code> element.</p>

<h3>JavaScript is not just frameworks</h3>

<p>I wasn&#8217;t prepared for the number of people with little or no idea how to program professionally in JavaScript. While I don&#8217;t require an intimate knowledge of the various native objects or having the ECMA standard memorized, good Web Applications require understanding <em>why</em> framework makers have to work around quirks like the event model—not just that they do.</p>

<p>In addition, most self-taught programmers have little grasp of good programming patterns that save time and make self-documenting code. The best Web application in the world is useless to me if I have to re-write it form scratch a month later because it would take less time than learning how it works.</p>

<p>I had a number of candidates ask me how I came about my JavaScript knowledge, and I didn&#8217;t have much to offer them. I&#8217;ve never taken a JavaScript class, although my unsuccessful interview at Google could be considered one. I do, however, recommend two books: <a href="http://www.amazon.com/gp/redirect.html?ie=UTF8&amp;location=http%3A%2F%2Fwww.amazon.com%2Fppk-JavaScript-1-e-VOICES%2Fdp%2F0321423305%3Fie%3DUTF8%26s%3Dbooks%26qid%3D1215169247%26sr%3D8-1&amp;tag=ryancannondot-20&amp;linkCode=ur2&amp;camp=1789&amp;creative=9325" title="Amazon Page for PPK on JavaScript">PPK on JavaScript</a> by <a href="http://www.quirksmode.org/" title="QuirksMode: For all you Browser Quirks">Peter-Paul Koch</a> and <a href="http://www.amazon.com/JavaScript-Design-Patterns-Recipes-Problem-Solution/dp/159059908X/ref=pd_bbs_sr_1?ie=UTF8&amp;s=books&amp;qid=1215169405&amp;sr=1-1" title="Amazon Page for Pro JavaScript Design Patterns">Pro JavaScript Design Patterns</a> by <a href="http://dustindiaz.com/" title="./ With Imagination">Dustin Diaz</a> were invaluable resources. The first is a very low-level examination of the history of JavaScript, while the second is a high-level translation of classic programming methods to JavaScript.</p>

<h3>Play</h3>

<p>The people who stand out to me are the people who play with the discipline. If your resume is a Word Doc or PDF, you&#8217;re starting with a strike against you. Have interesting side projects and who show a curiosity in the medium. Own yourname.com or yourlameinternethandle.com and show me what interesting things you&#8217;re doing with the Web 2.0 API of the week. Even if it&#8217;s a horrible hack or you code is just plain bad, I&#8217;d rather have that than a code wizard on autopilot.</p>
]]></content:encoded>
			<wfw:commentRss>http://ryancannon.com/2008/07/04/the-other-side-of-the-interview-table/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Doublethinking version targeting</title>
		<link>http://ryancannon.com/2008/02/27/doublethinking-version-targeting</link>
		<comments>http://ryancannon.com/2008/02/27/doublethinking-version-targeting#comments</comments>
		<pubDate>Wed, 27 Feb 2008 12:04:41 +0000</pubDate>
		<dc:creator>Ryan</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[Web Design/Programming]]></category>

		<guid isPermaLink="false">http://ryancannon.com/2008/02/28/doublethinking-version-targeting</guid>
		<description><![CDATA[Microsoft&#8217;s version targeting proposal for IE8 is all the rage on the Internets. I&#8217;ve been reading the arguments for and against, and have settled on holding two contradictory beliefs in my mind and accepting them both. Version targeting is a terrible proposal, one that threatens the advancement of Web design as we know it, and [...]]]></description>
			<content:encoded><![CDATA[<p>Microsoft&#8217;s <a href="http://blogs.msdn.com/ie/archive/2008/01/21/compatibility-and-ie8.aspx" title="IEBlog : Compatibility and IE8">version targeting proposal</a> for IE8 is all the rage on the Internets. I&#8217;ve been reading the arguments for and against, and have settled on <a href="http://en.wikipedia.org/wiki/Doublethink" title="Doublethink - Wikipedia, the free encyclopedia">holding two contradictory beliefs in my mind and accepting them both</a>. Version targeting is a terrible proposal, one that threatens the advancement of Web design as we know it, and props up a monolithic company that hasn&#8217;t been too good to Web developers in the past. We need it.</p>

<p><span id="more-172"></span></p>

<p>Visionaries of <a href="http://zeldman.com/" title="Jeffrey Zeldman Presents">HTML</a>, <a href="http://meyerweb.com/" title="meyerweb.com">CSS</a> and <a href="http://www.quirksmode.com" title="QuirksMode - for all your browser quirks">JavaScript</a> have been promoting this change—which they knew about before the rest of the world—with an odd sort of fanfare. <a href="http://alistapart.com/articles/minorthreat" title="A List Apart: Articles: Version Targeting: Threat or Menace?">Says Zeldman</a>:</p>

<blockquote>
  <p>What’s really new is that by opting out of Microsoft’s version targeting &#8230;
  you get to skip testing in
  future versions of IE. If your site works in IE7 today, it will work in IE47, or
  so Microsoft has promised.</p>
</blockquote>

<p>It&#8217;s the <em>Microsoft has promised</em> line that raises my hackles. Microsoft is somehow going to port every rendering mode since IE 5.5 into future versions of IE. How long will the cost of backporting IE7&#8242;s bugs and quirks to the latest Windows version will be seen as benefiting Microsoft&#8217;s shareholders? Methinks it won&#8217;t be 40 versions. My guess is two. Tops.</p>

<p>By taking the onus of maintaining sites off of Web developers and onto a fairly untrustworthy party—especially one with a <a href="http://www.microsoft.com/silverlight/" title="Microsoft Silverlight: Light Up the Web">business case for stagnating standards-based development</a> and a <a href="http://blogs.wsj.com/deals/2008/02/27/yahoos-deteriorating-defenses-against-the-microsoft-bid/?mod=googlenews_wsj" title="Deal Journal - WSJ.com : Yahoo's Deteriorating Defenses Against the Microsoft Bid">means to force it into broad acceptance</a>—we are making a deal with the devil. Version targeting is bad for the Internet.</p>

<h3>Who are the unenlightened?</h3>

<p>Worse, however, than betting on Microsoft to save us is that Zeldman blames the situation on some theoretical group of unwashed masses that are making bad Web sites:</p>

<blockquote>
  <p>Zillions of people who don’t know any better do tailor sites to the
  quirks of IE6. That’s why an improved IE7 “broke” old sites. And it’s 
  why, in crafting a new switch, Microsoft must build its default to 
  protect unenlightened developers.</p>
</blockquote>

<p>PPK walks lock-step with Zeldman, <a href="http://www.quirksmode.org/blog/archives/2008/01/the_versioning_1.html" title="QuirksBlog: The versioning switch's default is correct">using the same rationale as colonial Europe when pillaging Africa</a>.</p>

<blockquote>
  <p><em>Noblesse oblige.</em> Since we know more and can do more and better things with web sites, more is expected of us. If our ways are so much better, we should shoulder more responsibilities than those whose ways are wrong. Our shoulders are fit to bear these burdens; [standards-unaware web developers] aren&#8217;t.</p>
</blockquote>

<p>Both of these articles assume that these unenlightened people are going to magically become enlightened, and not abuse this new property as they do the rest of HTML currently. What seems realistic to me is that these people will start new projects. They&#8217;ll want to use new IE features. They&#8217;ll use—because they&#8217;re not &#8220;enlightened&#8221;—<code>IE=edge</code>. And Microsoft will have to dream up some other scheme to prevent the Web from breaking, and this hubub will start all over.</p>

<p>We need to stop being elitist. The &#8220;problem sites&#8221; aren&#8217;t just being created by these <a id="ref-unenlightened" href="#note-unenlightened">&#8220;unenlightened&#8221; developers</a>; they were created by developers—enlightened or not—and have been left fallow. Our industry is flush with hit-and-run agencies and freelancers that throw up a site and then dump it on understaffed, underpaid and under-experienced teams to manage. It&#8217;s easy to see that <a href="http://www.happycog.com/about/zeldman/" title="Happy Cog Studios: About Jeffrey Zeldman">three</a> <a href="http://complexspiral.com/about/eric/" title="About Complex Spiral Consulting: Eric A. Meyer">agency</a> <a href="http://quirksmode.org/freelance/intro.html" title="Peter-Paul Koch - Freelancer">guys</a> might focus on sites created by novice Web developers or existing since the 20th century as the main problems, but I have a hard time believing every Happy Cog site would survive IE8 without <em>some</em> kinds of tweaks. Sites which are not actively maintained, but still have value to Internet users—these are the sites Microsoft is afraid of breaking. A fix is never simple if there is no one to do it.</p>

<p>My guess is that the IE7 update is not the one that fueled the version targeting decision: it was the rancor over Vista. A vast number of applications and device drivers would not function with Windows Vista&#8217;s new API&#8217;s, and as a result the operating system has had a fairly frosty reception. IE7&#8242;s release was a party in comparison. Apparently there exists a hearty core of people that desired to use applications and hardware <em>years</em> after they&#8217;ve stopped being maintained. The scripting and CSS updates alluded to with IE8 may bring similar Web sites down, and that&#8217;s ill will Microsoft can&#8217;t afford to engender.</p>

<p>In other words, updating IE without setting up version targeting to a <a id="ref-current" href="#note-current">current browser</a> will break an unknowable number of Web sites which may still contain valuable content but have no means to upgrade and stay current. We need it.</p>

<h3>Opting to opt out</h3>

<p>Somehow, I&#8217;ve got to reconcile this conflict. I&#8217;m glad that Microsoft created a way to improve the state of their browser without throwing away the old Internet. That said, I don&#8217;t have a very high opinion of that company and am loathe to contribute a spare byte of mindshare to their products by inserting IE crutches in my code. I&#8217;m going to let it break. Refusing to use IE&#8217;s meta tag will lock their browser to a predictable set of features and bugs—or as predictable as such things will ever be, and for the foreseeable future, IE7&#8242;s Web standards support is passable enough for most work, and we&#8217;re going to have to support IE7 (the browser, not just the rendering mode) anyway.</p>

<p>I&#8217;ve long believed that Web Developers have been, as a group, too milquetoast about dealing with IE&#8217;s problems. We tediously work around a  cranky browser and then, hypocritically, use buttons that read &#8220;this site requires flash,&#8221; and &#8220;download the PDF viewer.&#8221; For me no longer. Any site in beta, any site I develop for fun, and any site without a demonstrable need for IE8 features is going to stay in IE7 mode. At least, that is, <a href="http://ejohn.org/blog/html5-doctype/" title="John Resig - HTML5 DOCTYPE">until HTML5 is usable</a>.</p>

<h3>Notes</h3>

<ol>
<li><span id="note-unenlightened">Mr. Meyer does <a href="http://alistapart.com/articles/fromswitchestotargets" title="A List Apart: Articles: From Switches to Targets: A Standardista's Journey">cite</a> some Web research, but both studies do not prove anything about the current state of Web development. <a href="http://code.google.com/webstats/" title="Google Code: Web Authoring Statistics">Google&#8217;s statistics</a> surveys the entire Internet with no regard to <em>when</em> a page was developed, while <a href="http://www.markokarppinen.com/20020222.html" title="Marko Karppinen | State of the Validation 2002">Marko Karppinen&#8217;s study</a> assumes that validity has anything to do with standards-based design, <a href="http://www.mikeindustries.com/blog/archive/2004/06/march-to-your-own-standard" title="Mike Davidson  -  March to Your Own Standard">which it clearly does not</a>.</span> <a class="return" href="#ref-unenlightened">↩</a></li>
<li><span id="note-current">If the IE team truly wanted to preserve the Internet, they&#8217;d make version targeting default to IE6 rendering, and not IE7, as IE6 has been actively targeted by Web developers for almost ten years, IE7 a fraction of that. Admitting this, however, makes me die a little on the inside. <a class="return" href="#ref-current">↩</a></li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://ryancannon.com/2008/02/27/doublethinking-version-targeting/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>EVE on Rails &#8211; Creating an EVE in-game-optimised version of your Rails site</title>
		<link>http://ryancannon.com/2008/02/14/eve-on-rails-creating-an-eve-in-game-optimised-version-of-your-rails-site</link>
		<comments>http://ryancannon.com/2008/02/14/eve-on-rails-creating-an-eve-in-game-optimised-version-of-your-rails-site#comments</comments>
		<pubDate>Thu, 14 Feb 2008 10:15:39 +0000</pubDate>
		<dc:creator>Ryan</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[Web Design/Programming]]></category>

		<guid isPermaLink="false">http://ryancannon.com/2008/02/14/eve-on-rails-creating-an-eve-in-game-optimised-version-of-your-rails-site</guid>
		<description><![CDATA[One thing I love about being a Rails hobbyist is that I can continually think about the best way to do things. With no paycheck hinging on a deliverable, I can refactor continuously until I&#8217;m convinced I have the best code I can muster. Sure, I never get anything done, but the exercise makes me [...]]]></description>
			<content:encoded><![CDATA[<p>One thing I love about being a Rails hobbyist is that I can continually think about the best way to do things. With no paycheck hinging on a deliverable, I can refactor continuously until I&#8217;m convinced I have the best code I can muster. Sure, I never get anything done, but the exercise makes me a better programmer.</p>

<p><span id="more-171"></span>
I mentioned previously <a href="http://ryancannon.com/2008/02/06/setting-up-a-rails-application-for-eve-online">how to set up an EVE Online-focused rails site</a>. After reading through old <a href="http://weblog.rubyonrails.com/">Riding Rails</a> posts, I noticed this excellent post on <a href="http://www.slashdotdash.net/articles/2007/12/04/iphone-on-rails-creating-an-iphone-optimised-version-of-your-rails-site-using-iui-and-rails-2" title="iPhone on Rails - Creating an iPhone optimised version of your Rails site using iUI and Rails 2">iPhone-optimising your rails project</a>. This process is almost exactly the same for sharing views between EVE and a normal browser. In Rails 2.0 all you have to do is register the MIME Type.</p>

<pre><code>config/initializers/mime_types.rb:

Mime::Type.register_alias "text/html", :eve
</code></pre>

<p>Then, in your application controller, use a <code>before_filter</code> to adjust the format as necessary.</p>

<pre><code>app/controllers/application_controller.rb:

before_filter :isolate_eve_browser

private
  # EVE-specific data
  def isolate_eve_browser
    if eve?
      request.format = :eve
      request_trust unless trusted?
      end
    end
  end
</code></pre>

<p>Now everywhere you want to separate your EVE views from your standard browser views, simply use <code>respond_to</code>.</p>

<pre><code>app/controllers/home_controller.rb:

class HomeController &lt; ApplicationController
  def index
    respond_to do |format|
      format.html
      format.eve
    end
  end  
end
</code></pre>

<p>You can then use <code>app/views/home/index.html.erb</code> and <code>app/views/home/index.eve.erb</code> respectively. This means you can also request trust on the appliaction level instead of on the action level as I mentioned previously. Notice that <code>request_trust</code> method above? It should look something like:</p>

<pre><code>app/controllers/application_controller.rb:

private
  def request_trust
    response.headers["eve.trustme"] = (
      "http://#{request.env['HTTP_HOST']}/" +
      "::Your custom message begging for trust."
    )
    render :template =&gt; 'trust_me'
  end
</code></pre>

<p>The action is rounded out by creating <code>app/views/trustme.eve.erb</code>, which is the template rendered above when the user declines to trust you. Happy coding!</p>
]]></content:encoded>
			<wfw:commentRss>http://ryancannon.com/2008/02/14/eve-on-rails-creating-an-eve-in-game-optimised-version-of-your-rails-site/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Setting up A Rails Application for EVE Online</title>
		<link>http://ryancannon.com/2008/02/06/setting-up-a-rails-application-for-eve-online</link>
		<comments>http://ryancannon.com/2008/02/06/setting-up-a-rails-application-for-eve-online#comments</comments>
		<pubDate>Wed, 06 Feb 2008 09:54:39 +0000</pubDate>
		<dc:creator>Ryan</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[Web Design/Programming]]></category>
		<category><![CDATA[Web Tools]]></category>

		<guid isPermaLink="false">http://ryancannon.com/2008/02/06/setting-up-a-rails-application-for-eve-online</guid>
		<description><![CDATA[As I mentioned before, I&#8217;ve be having a lot of fun with EVE Online. The attraction, however, hasn&#8217;t been just to the ability to fly around in a ship and blast pirates (as if that weren&#8217;t enough!). EVE has a pretty excellent API, an browser that provides in-game information, and even dumps of art and [...]]]></description>
			<content:encoded><![CDATA[<p>As I <a href="http://ryancannon.com/2008/01/13/new-year-new-addiction" title="The Book of Ryan  » New Year, New Addiction">mentioned before</a>, I&#8217;ve be having a lot of fun with <a href="http://eve-online.com/" title="EVE Online - a massive multiplayer online roleplaying space game">EVE Online</a>. The attraction, however, hasn&#8217;t been just to the ability to fly around in a ship and blast pirates (as if that weren&#8217;t enough!). EVE has a pretty excellent <a href="http://myeve.eve-online.com/api/doc/" title="EVE API Documentation">API</a>, an browser that provides <a href="http://bughunters.addix.net/igbtest/IGB-commands.html" title="EVE Ingame (sic) Webbrowser (sic)">in-game information</a>, and even <a href="http://myeve.eve-online.com/ingameboard.asp?a=topic&amp;threadID=650828" title="Trinity 1.0 Static Data Export">dumps of art and data</a> for developers to <a id="ref-license" href="http://ryancannon.com/2008/02/06/setting-up-a-rails-application-for-eve-online#note-license">use</a>.</p>

<p>I&#8217;ve already got a few ideas on fun things to do with all of this data. The trick is trying to make opinionated Rails play nice with the browser, the API and the Data. To that end, here are the strategies I&#8217;m invoking. Comments are, of course, welcome.</p>

<p><span id="more-170"></span></p>

<h3>Dealing with Data</h3>

<p>I can&#8217;t even begin to wrap my brain around the cool things you can do with EVE data. A number of desktop applications exist for character tracking and skill planning, but that&#8217;s only a very shallow bit of what&#8217;s possible. Getting the data into manageable form, however, is a bit tricky.</p>

<p>I wanted to keep my EVE data separate from my game data. Presumably EVE&#8217;s data will change over time. Ideally a new dump will come out and I can just swap it with my current one&#8211;no fuss, no muss. I downloaded the <a href="http://dl.eve-files.com/media/0712/trinity_1.0_sqlite3.db.zip" title="A ZIP archive of the Trinity DB file">Trinity 1.0 SQLite3 dump</a>. And dropped it into <code>db/</code> of my Rails application. Then I had to make sure to point all EVE data to the correct database.</p>

<pre><code>config/datbase.yml:

eve_development:
  adapter: sqlite3
  database: db/trinity_1.0_sqlite3.db
  timeout: 5000
eve_test:
  adapter: sqlite3
  database: db/trinity_1.0_sqlite3.db
  timeout: 5000
eve_production
  adapter: mysql
  database: *******
  username: ********
  password: ********
  host: *******
</code></pre>

<p>and</p>

<pre><code>app/models/eve_data.rb:

class EveData &lt; ActiveRecord::Base
  establish_connection "eve_#{RAILS_ENV}"
end
</code></pre>

<p>Now any model that subclasses EveData will point to the correct database and key:</p>

<pre><code>app/models/race.rb:

class Race &lt; EveData
  set_table_name :chrRaces
  set_primary_key :raceID
  has_many :careers, :foreign_key =&gt; :raceID
end
</code></pre>

<p>The tedious part of this is setting up all of the associations, as EVE data does not conform to rails column naming conventions (although it&#8217;s not unimaginable that one could fix this with an elegant script).</p>

<p>One last note: if you generate any sub-classes of EveData using the built-in generators, be sure to remove <code>test/fixtures/&lt;subclass&gt;.yml</code> as it will cause you tests to die horrible deaths.</p>

<h3>API Wrangling</h3>

<p>Rails has a lot of built-in API magic, all of which is absolutely worthless with EVE. Consuming the EVE API requires a lot of anonymous XML parsing. Boooooring! Luckily, <a href="http://www.crudvision.com/" title="CrudVision">Lisa Seelye</a> has an excellent <a href="http://www.crudvision.com/reve-ruby-eve-online-api-library/" title="REVE - Ruby Eve Online API Library">wrapper module for the EVE API</a>. So long as you&#8217;re okay with her clear-as-mud license, Lisa&#8217;s work will be a great benefit.</p>

<h3>Managing the EVE Browser</h3>

<p><strong>Update:</strong> I&#8217;ve written up a slightly better way to <a href="http://ryancannon.com/2008/02/14/eve-on-rails-creating-an-eve-in-game-optimised-version-of-your-rails-site" title="EVE on Rails - Creating an EVE in-game-optimised version of your Rails site">target the EVE Browser in Rails 2.0</a>.</p>

<p>The EVE Online browser stinks. I got only halfway through the HTML 4.01 test suite before quitting out of frustration. I&#8217;m pretty sure it can&#8217;t even render GIF images. I&#8217;d love to see them bundle WebKit instead. One thing the browser does, however, is provide custom HTTP headers (without the required X- in front, of course) for in-game EVE data. Custom headers are available to the controller in the <code>request.env</code> collection. I made them available to all controllers and views with the following:</p>

<pre><code>app/controllers/application.rb:

class ApplicationController &lt; ActionController::Base
  ...
  # Provides access to views
  helper_method :eve?
  helper_method :trusted?
  helper_method :eve_data

  private
    def eve?
      !! request.env['HTTP_EVE.TRUSTED']
    end
    def trusted?
      request.env['HTTP_EVE.TRUSTED'] == "yes"
    end
    def eve_data
      if trusted?
        {
          "name" =&gt; request.env['HTTP_EVE.CHARNAME'],
          "id" =&gt;  request.env['HTTP_EVE.CHARID'],
          "alliance" =&gt; request.env['HTTP_EVE.ALLIANCENAME'],
          "region" =&gt; request.env['HTTP_EVE.REGIONNAME'],
          "constellation" =&gt; request.env['HTTP_EVE.CONSTELLATIONNAME'],
          "solar system" =&gt; request.env['HTTP_EVE.SOLARSYSTEMNAME'],
          "station" =&gt; request.env['HTTP_EVE.STATIONNAME'],
          "corporation" =&gt; request.env['HTTP_EVE.CORPNAME'],
          "role" =&gt; request.env['HTTP_EVE.CORPROLE']
        }
      end
    end
end
</code></pre>

<p>The <code>eve?</code> and <code>trusted?</code> methods return booleans and <code>eve_data</code> a hash of the character&#8217;s current location in-game. They allow me to write helpers such as</p>

<pre><code>app/helpers/application_helper.rb:

def character_image_tag(id, size, options = nil)
  if eve?
    o = { :src =&gt; "#{src}:#{id}", :size =&gt; "#{size}" }
    o.merge!(options) if options.is_a(Hash)
    tag(:img, o)
  else
    o = { :width =&gt; "#{size}", :height =&gt; "#{size}" }
    o.merge!(options) if options.is_a(Hash)
    image_tag("http://img.eve.is/serv.asp?s=#{size}&amp;c=#{id}", o)
  end
end
</code></pre>

<p>Guessing by the speed of the browser, using in-game resources instead of external will save the user a lot of time.</p>

<p>As players fly around EVE, the application has the ability to detect a location change and refresh the page, updating the location information. Applications could work in EVE from only one URL, even without JavaScript. In order to do so, however, the application must do some header-gymnastics as well. My take on this is something akin to:</p>

<pre><code>app/controllers/foo_controller.rb:

class FooController &lt; ApplicationController
  def index
    # Tell the client your content will change
    # Not necessary, but correct and future-proof
    response.headers["Vary"] = "eve.trustme"
    if ! eve?
      # Do something to the regular browser
      render :action =&gt; "external"
    elsif ! trusted?
      trust_me
      render :action =&gt; "trust_me"
    else
      lookup
      render :action =&gt; "lookup"
    end
  end

  def external
    ...
  end

  def trust_me
    # Send the trust header
    response.headers["eve.trustme"] = "http://#{request.env['HTTP_HOST']}/::Trust me."
    ...
  end

  def play
    # Send the auto-refresh header
    response.headers["refresh"] = "sessionchange;URL=#{url_for(:controller =&gt; 'foo')}"
    ...
  end

end
</code></pre>

<p>Each action will then have its own view file and its own logic, but the same URL. Be careful where you send the auto-refresh header: create, update and delete actions should not get them. Note too that the <code>trust_me</code> action <em>should</em> end with <code>render =&gt; :nothing</code> or similar. <em>This does not work.</em> The EVE browser requires a text/html file to trigger the trust prompt.</p>

<p>And that&#8217;s it! You&#8217;re on your way to a Rails-powered EVE application. Please send me any questions, critiques or issues. I&#8217;ll post more often with other quirks I pick up.</p>

<p>UPDATE: Modified the database set-up to use my database.yml for EVE data and connect EVE data to my environments. Also moved establish_connection into the model where it should be. I also added a note on fixtures that took me a silly amount of time to work around.</p>

<h3>Notes</h3>

<ol>
<li><span id="note-license"></span> I haven&#8217;t been able to find a license for this data. Although I&#8217;m guessing it&#8217;s Creative Commons Attribution-DontDoAnythingStupid. <a class="return" href="#ref-license">↩</a></li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://ryancannon.com/2008/02/06/setting-up-a-rails-application-for-eve-online/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

<!-- Dynamic Page Served (once) in 0.812 seconds -->

