<?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: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/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>timgittos</title>
	
	<link>http://www.timgittos.com</link>
	<description>professional bit pusher</description>
	<lastBuildDate>Fri, 13 Aug 2010 07:17:44 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/TimGittos" /><feedburner:info uri="timgittos" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>Evaluating JSON in Safari</title>
		<link>http://feedproxy.google.com/~r/TimGittos/~3/JR4Mtmn3ZXQ/evaluating-json-in-safari</link>
		<comments>http://www.timgittos.com/evaluating-json-in-safari#comments</comments>
		<pubDate>Fri, 13 Aug 2010 07:17:44 +0000</pubDate>
		<dc:creator>Tim</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.timgittos.com/?p=560</guid>
		<description><![CDATA[Just a quickie on parsing JSON strings in Safari. I&#8217;m in the middle of a project developing a timesheet/rostering application, which uses a lot of Javascript. I have a series of web services that interact with jQuery. For reasons beyond the scope of this post, the web service returns a JSON string, which needs to [...]]]></description>
			<content:encoded><![CDATA[<p>Just a quickie on parsing JSON strings in Safari.</p>
<p>I&#8217;m in the middle of a project developing a timesheet/rostering application, which uses a lot of Javascript. I have a series of web services that interact with jQuery. For reasons beyond the scope of this post, the web service returns a JSON string, which needs to be parsed into a JSON object, and then further processing is done on the object.</p>
<p>I had a bug where Safari was choking on the JSON string returned by my webservice, yet Firefox and IE were happy parsing it. As it turns out, my JSON string had a Javascript keyword in it; &#8216;break&#8217;.</p>
<p>Here is my JSON string (well, an example):</p>
<pre class="brush: text">
{employee: &#039;Joe&#039;, worked: true, periods: [{start: &#039;09:00 AM&#039;, finish: &#039;17:00 PM&#039;}], break: {paid: true, hours: &#039;1&#039;}}
</pre>
<p>Safari was choking on the <code>break</code> in the above JSON string.</p>
<p>When I wrapped the attribute in single quotes, like so:</p>
<pre class="brush: text">
{employee: &#039;Joe&#039;, worked: true, periods: [{start: &#039;09:00 AM&#039;, finish: &#039;17:00 PM&#039;}], &#039;break&#039;: {paid: true, hours: &#039;1&#039;}}
</pre>
<p>it was happy.</p>
<p>You can replicate this by using the below code snippet to parse out your JSON string quickly in Safari&#8217;s debug window:</p>
<pre class="brush: javascript">
var json = &quot;{employee: &#039;Joe&#039;, worked: true, periods: [{start: &#039;09:00 AM&#039;, finish: &#039;17:00 PM&#039;}], break: {paid: true, hours: &#039;1&#039;}}&quot;;
var obj = (new Function(&quot;return &quot; + json))();
</pre>
<p>which should fail. If you add the single quotes around <code>break</code> though, it should work just fine.</p>
<p>This also fails for other Javascript keywords:</p>
<pre class="brush: javascript">
(new Function(&quot;return &quot; + &quot;{if: true}&quot;))();
</pre>
<p>fails. If you wrap <code>if</code> in single quotes, it works.</p>
<p>I think the take away lesson is to always wrap your object attributes in a JSON string in single quotes, otherwise Safari will choke on it.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/TimGittos?a=JR4Mtmn3ZXQ:AQSBlBrjuJg:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TimGittos?a=JR4Mtmn3ZXQ:AQSBlBrjuJg:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/TimGittos?i=JR4Mtmn3ZXQ:AQSBlBrjuJg:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TimGittos?a=JR4Mtmn3ZXQ:AQSBlBrjuJg:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/TimGittos?i=JR4Mtmn3ZXQ:AQSBlBrjuJg:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TimGittos?a=JR4Mtmn3ZXQ:AQSBlBrjuJg:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/TimGittos?i=JR4Mtmn3ZXQ:AQSBlBrjuJg:V_sGLiPBpWU" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/TimGittos/~4/JR4Mtmn3ZXQ" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.timgittos.com/evaluating-json-in-safari/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.timgittos.com/evaluating-json-in-safari?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=evaluating-json-in-safari</feedburner:origLink></item>
		<item>
		<title>ASP.NET GridView with an ObjectDataSource</title>
		<link>http://feedproxy.google.com/~r/TimGittos/~3/UerJoooyQms/asp-net-gridview-with-an-objectdatasource</link>
		<comments>http://www.timgittos.com/asp-net-gridview-with-an-objectdatasource#comments</comments>
		<pubDate>Mon, 26 Oct 2009 07:21:38 +0000</pubDate>
		<dc:creator>Tim</dc:creator>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[Languages]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[asp.net]]></category>
		<category><![CDATA[quick]]></category>
		<category><![CDATA[tip]]></category>

		<guid isPermaLink="false">http://www.timgittos.com/?p=526</guid>
		<description><![CDATA[Just a quick tip: I got the following exception today: If a data source does not return ICollection and cannot return the total row count, it cannot be used by the GridView to implement server-side paging. If you&#8217;re trying to return an IEnumerable from your select method, try changing it to a List or an [...]]]></description>
			<content:encoded><![CDATA[<p>Just a quick tip:</p>
<p>I got the following exception today:</p>
<pre class="brush: text">
If a data source does not return ICollection and cannot return the total row count, it cannot be used by the GridView to implement server-side paging.
</pre>
<p>If you&#8217;re trying to return an IEnumerable from your select method, try changing it to a List or an array. That should clear the problem right up.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/TimGittos?a=UerJoooyQms:oKrmK1duyUM:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TimGittos?a=UerJoooyQms:oKrmK1duyUM:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/TimGittos?i=UerJoooyQms:oKrmK1duyUM:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TimGittos?a=UerJoooyQms:oKrmK1duyUM:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/TimGittos?i=UerJoooyQms:oKrmK1duyUM:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TimGittos?a=UerJoooyQms:oKrmK1duyUM:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/TimGittos?i=UerJoooyQms:oKrmK1duyUM:V_sGLiPBpWU" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/TimGittos/~4/UerJoooyQms" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.timgittos.com/asp-net-gridview-with-an-objectdatasource/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.timgittos.com/asp-net-gridview-with-an-objectdatasource?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=asp-net-gridview-with-an-objectdatasource</feedburner:origLink></item>
		<item>
		<title>Going Dark</title>
		<link>http://feedproxy.google.com/~r/TimGittos/~3/LqjikFzG9B0/going-dark</link>
		<comments>http://www.timgittos.com/going-dark#comments</comments>
		<pubDate>Tue, 13 Oct 2009 19:17:33 +0000</pubDate>
		<dc:creator>Tim</dc:creator>
				<category><![CDATA[Editorials]]></category>
		<category><![CDATA[Personal]]></category>

		<guid isPermaLink="false">http://www.timgittos.com/?p=522</guid>
		<description><![CDATA[Nearly 12 months on from the start of my blog (the first post went up at the end of November 2008), I&#8217;m finding less and less time to do the quality kind of writing I have set out to do. I feel that, as I change, so too does my website need to change. As [...]]]></description>
			<content:encoded><![CDATA[<p>Nearly 12 months on from the start of my blog (the first post went up at the end of November 2008), I&#8217;m finding less and less time to do the quality kind of writing I have set out to do. I feel that, as I change, so too does my website need to change.</p>
<p>As much as this site is currently a programming blog, it&#8217;s also my electronic representation. The website shares my name, and is representative of me. There&#8217;s more to me than just programming. For a while I&#8217;ve tried blogging or writing about non-programming related topics on another domain, however I don&#8217;t feel this is fair to myself.</p>
<p>I guess the best way to describe myself is an <a href="http://en.wikipedia.org/wiki/Polymath">aspiring polymath</a>. I have an interest in a broad range of topics, notably programming/computer science, mathematics and art. This website doesn&#8217;t really represent that. I can&#8217;t maintain multiple websites to separate various areas of my life &#8211; I&#8217;m a single person with multiple facets, and I should have a single website, with multiple facets.</p>
<p>Additionally, I find myself with less and less time to devote to this kind of writing, as it slowly makes it&#8217;s way down to the bottom of my priority list. Currently I&#8217;m trying to rekindle my math education by going back to basics, learn Punjabi so I can impress the fiance&#8217;s parents, do several programming projects at once and get back into doing art regularly, and writing is a very far last. </p>
<p>So, all that lead up to say that I&#8217;m going dark, and will be overhauling the site sometime in the future. I&#8217;m going to change the format of the site so that it more accurately represents me as a whole, is better organised and has a nice format that allows me to post quick, smaller posts that can be filtered out when subscribing to RSS feed. I may or may not stick with WordPress &#8211; I think I&#8217;ll probably start hacking away at <a href="http://www.enkiblog.com/">Enki</a> and do some funky stuff with wildcard subdomains or something.</p>
<p>All older posts will remain, as a few of my posts are rather popular (by more than 50% compared to the rest of the site) and I suspect they&#8217;re really helping people out.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/TimGittos?a=LqjikFzG9B0:PetIwhgEmoE:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TimGittos?a=LqjikFzG9B0:PetIwhgEmoE:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/TimGittos?i=LqjikFzG9B0:PetIwhgEmoE:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TimGittos?a=LqjikFzG9B0:PetIwhgEmoE:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/TimGittos?i=LqjikFzG9B0:PetIwhgEmoE:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TimGittos?a=LqjikFzG9B0:PetIwhgEmoE:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/TimGittos?i=LqjikFzG9B0:PetIwhgEmoE:V_sGLiPBpWU" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/TimGittos/~4/LqjikFzG9B0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.timgittos.com/going-dark/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.timgittos.com/going-dark?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=going-dark</feedburner:origLink></item>
		<item>
		<title>Mario AI Competition 2009 – Getting Started</title>
		<link>http://feedproxy.google.com/~r/TimGittos/~3/rDD8jNRN9IA/mario-ai-competition-2009-getting-started</link>
		<comments>http://www.timgittos.com/mario-ai-competition-2009-getting-started#comments</comments>
		<pubDate>Tue, 25 Aug 2009 22:35:09 +0000</pubDate>
		<dc:creator>Tim</dc:creator>
				<category><![CDATA[Artificial Intelligence]]></category>
		<category><![CDATA[Contests]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[competition]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[marioai]]></category>

		<guid isPermaLink="false">http://www.timgittos.com/?p=466</guid>
		<description><![CDATA[Programming is fun. That&#8217;s why I decided it would be a good career for me. I love solving puzzles, and I love the concept of making computers, these mysterious boxes of my childhood, do things. However, when you finally get to working as a professional programmer, the types of projects you get to work on [...]]]></description>
			<content:encoded><![CDATA[<p>Programming is fun. That&#8217;s why I decided it would be a good career for me. I love solving puzzles, and I love the concept of making computers, these mysterious boxes of my childhood, do things. However, when you finally get to working as a professional programmer, the types of projects you get to work on are often not as interesting as you&#8217;d like. This is why I am interested in AI. AI presents new and unique challenges, and techniques of approaching these challenges. I said in a previous post that AI was more commonplace than you&#8217;d think, but didn&#8217;t really follow it up with suggestions of where you can work on AI related programs.</p>
<p>I&#8217;ve recently stumbled on an interesting AI competition (before it got big with the video &#8211; I&#8217;ve been writing this post for about a month), based off of an open source Java project called Inifine Mario, called <a href="http://julian.togelius.com/mariocompetition2009/">Mario AI Competition 2009</a>. The competition is to create an AI agent that can navigate randomly generated Mario levels, pitting each agent against each other. The first round of this competition has already closed, however there is another round that closes September 3.</p>
<p>I won&#8217;t be attending the conferences nor will I be submitting agents to the competition. I will however work on a few agents, as this is probably the most fun application of AI that I&#8217;ve seen in a while, and it&#8217;s a small enough environment to enable me to get very familiar with it very quickly, and hence get into making solutions very quickly.</p>
<p>On the surface, this seems a trivial, niche problem. An agent that can navigate a video game level doesn&#8217;t really have a lot of diverse applications. However, it&#8217;s a great way to begin practicing some fundamental concepts of AI. The parameters of the competition don&#8217;t limit the techniques you can use to create the agent. In the video below, <a href="http://www.doc.ic.ac.uk/~rb1006/projects:marioai">Robin Baumgarten</a> is using A* path finding techniques. </p>
<p><object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/DlkMs4ZHHr8&#038;color1=0xb1b1b1&#038;color2=0xcfcfcf&#038;feature=player_embedded&#038;fs=1"></param><param name="allowFullScreen" value="true"></param><param name="allowScriptAccess" value="always"></param><embed src="http://www.youtube.com/v/DlkMs4ZHHr8&#038;color1=0xb1b1b1&#038;color2=0xcfcfcf&#038;feature=player_embedded&#038;fs=1" type="application/x-shockwave-flash" allowfullscreen="true" allowScriptAccess="always" width="425" height="344"></embed></object></p>
<p>However, A* is just the start, and is a fairly basic approach (though it works pretty well by the demos), and there are many more options, including machine learning and neural networks. Unfortunately, I won&#8217;t be covering any of that yet. The goal of this post is to get myself, and anyone else interested, up to speed on the environment, and the basics of creating an agent. I will be creating a very simple reactive agent that has no planning, and is quite flawed. However, you should be able to walk away with a firm grasp of how the environment works and what tools you have at your disposal.</p>
<p>Before I go on, a disclaimer is necessary: I haven&#8217;t worked with Java since my university days, so about 6 years or so. I will post some code, and that code will probably suck. You have been warned.</p>
<h3>The Game Environment</h3>
<p>The details on the code available from the competition website are fairly vague, so I&#8217;m posting this to perhaps help some people who are interested in getting into it, and also for my reference to help while working on it. Firstly, obviously, you&#8217;re going to have to download the code available on the competition website. The code is relatively stable at this point, however it was constantly being updated with fixes for bugs posted on the <a href="http://groups.google.com/group/mariocompetition">Google Group</a> for the competition. These changes would be posted on the group, so I&#8217;d check it regularly, or grab it from <a href="http://code.google.com/p/marioai/">Google Code</a> with svn, and just update your repo regularly. Once you&#8217;ve downloaded it, open it in your IDE/editor of choice, and roll up your sleeves.</p>
<p>Firstly, I&#8217;m going to reference classes by their fully qualified class names; ie: ch.idsia.scenarios.Play, which references Play.java located in the src/ch/idsia/scenarios folder. This way you can play along at home.</p>
<p>According to the online documentation, you can fire up a run by typing</p>
<pre class="brush: text">
java ch.idsia.scenarios.Play
</pre>
<p>from within the &#8220;classes&#8221; directory. This will start a copy of the Infinite Mario game with a human player. To start with a pre written agent, type</p>
<pre class="brush: text">
java ch.idsia.scenarios.Play ch.idsia.ai.agents.ai.ForwardJumpingAgent
</pre>
<p>to start with an agent that will run forward and jump as soon as it can.</p>
<p>The ch.idsia.scenarios.Play class is a simple class that sets up the agent, whether it&#8217;s human controlled or automated, and then it sets some play environment variables and runs the application. If an argument is supplied, it will attempt to instantiate an instance of the class and pass it through to the play environment. </p>
<p>I won&#8217;t be covering the the details of the simulation code, as it&#8217;s all pretty logically separated and you don&#8217;t really need to know how to do that. Information is passed through to the agent through an implementation of the interface ch.idsia.mario.environments.Environment. This argument to the <code>getAction</code> function provides the agent with a serialised view of the terrain and the location of enemies, along with information about Mario. Basically, any information you can get by looking at the scene.</p>
<p>This information is provided in the form of a byte matrix, through several functions. <code>observation.getLevelSceneObservation()</code> will return a matrix with details of the terrain. It will also tell you what the type of the terrain is, such as a pipe or a one way platform. This detail is found in <code>ch.idsia.mario.engine.LevelScene</code>. You can see the number codes for the different types of terrain. It&#8217;s broken down into gaps, hard borders, half borders and flower pots. </p>
<p>The <code>observation.getEnemiesObservation()</code> is very similar to <code>observation.getLevelSceneObservation()</code>, except it addresses enemy locations. Again, you&#8217;ll also get the type of the enemy from the matrix in the form of an integer code, which you can find in <code>ch.idsia.mario.engine.sprites.Sprite</code>.</p>
<p>I&#8217;ve written a debugging function that will output both the enemy and terrain matricies to give you a code view of what&#8217;s going on. It&#8217;s interesting and enlightening to watch the code view of the simulation next to the simulation itself, and it will help us write code to fit our design. The function is as follows:</p>
<pre class="brush: java">
byte[][] levelState = observation.getLevelSceneObservation();
byte[][] enemyState = observation.getEnemiesObservation();

//Debug information
for (int y = 0; y &lt; 22; y++)
{
    for (int x = 0; x &lt; 22; x++)
    {
        //Check for enemies first
        if (enemyState[y][x] &gt; 0)
        {
            String enemyValue = Integer.toString(enemyState[y][x]);
            int padding = 3 - enemyValue.length();
            if (enemyState[y][x] == 1)
                System.out.print(&quot;mmm&quot;);
            else if (padding == 2)
                System.out.print(&quot; &quot; + enemyValue + &quot; &quot;);
            else if (padding == 1)
                System.out.print(&quot; &quot; + enemyValue);
            else
                System.out.print(enemyValue);
        }
        else
        {
            //Check for terrain next
            String terrainValue = Integer.toString(levelState[y][x]);
            int padding = 3 - terrainValue.length();
            if (padding == 2)
                System.out.print(&quot; &quot; + terrainValue + &quot; &quot;);
            else if (padding == 1)
                System.out.print(&quot; &quot; + terrainValue);
            else
                System.out.print(terrainValue);
        }
        System.out.print(&quot;|&quot;);
    }
    System.out.print(&quot;\n&quot;);
}
System.out.print(&quot;---------------\n&quot;);
</pre>
<p>I put the above code into a function in the agent itself, and called the function from the <code>getAction</code> function of the agent, purely because I know this is going to get called once per tick. You can put it wherever you want to put it.</p>
<h3>Creating a Dumb Agent</h3>
<p>As I mentioned at the start of this post, I&#8217;m just going to start with creating a very simple, dumb agent that will attempt to traverse the level, and even then not get it right all the time for reasons I will cover. On the surface, Mario&#8217;s tasks for navigating a stage without enemies is pretty straightforward. All he needs to do is to get himself around the level and jump over pits. </p>
<p>However, sometimes Mario can find himself falling into a gap, or over-jumping his mark and jumping into a hole. So basically, we need to check if there&#8217;s something in Mario&#8217;s path that needs to be jumped over, or if there&#8217;s a gap that we need to jump over. But, we can&#8217;t just jump &#8211; we also need to check if jumping is going to put is into a gap and kill Mario, and if Mario runs off of where ever he is, he might fall into a hole.</p>
<p>This would be fairly straight forward if we had a robust method of predicting where Mario&#8217;s jumps will take him, but unfortunately we don&#8217;t officially get this information.<br />
There is a movement algorithm in <code>ch.idsia.mario.engine.sprites.Mario</code>, which starts at the <code>move</code> method, however, not only is this not in the spirit of the competition, but more importantly, it&#8217;s very hard to figure out, for me at least. I&#8217;ve not been able to reliably modify the movement code to act as a predictor of Mario&#8217;s path if you plug-in how long to hold each key for.</p>
<p>Hence, at this stage, we&#8217;ll just be making Mario go right and try and jump over obstacles. Seems fairly simple.</p>
<p>You&#8217;ll see in the provided agents that the function <code>getAction</code> is the heart of the agent, and an instance of the Environment interface discussed before. This function is the work horse of your agent, as it will tell the simulation what the agent is going to do.</p>
<p>Although the <code>observation.getLevelSceneObservation()</code> and <code>observation.getEnemiesObservation()</code> methods return the full view of the level, all the features are jumbled together. Later on, we&#8217;ll need to know what&#8217;s a cannon and what&#8217;s a pipe, and what&#8217;s raised ground, and maybe even what&#8217;s a block we can punch. We&#8217;ll need to know this because cannons shoot Bullet Bills and enemy flowers live in pipes, and these can appear at any time, and if Mario is near by, he&#8217;s going to get hurt.</p>
<p>I&#8217;ve created the following function to categorize the environment into pipes, cannons and pits:</p>
<pre class="brush: java">
private Boolean[] pits;
private Vector cannons;
private Vector pipes;
private void processTerrain(byte[][] state)
{
    //Init features
    pits = new boolean[22];
    cannons = new Vector();
    pipes = new Vector();

    //Init pits
    for (int i = 0; i &lt; 22; i++)
    {
        pits[i] = true;
    }

    for (int y = 21; y &gt;= 0; y--)
    {
        for (int x = 0; x &lt; 22; x++)
        {
            //Look for gaps
            pits[x] = pits[x] &amp;&amp; state[y][x] == 0;

            //Look for cannons and pipes
            if (state[y][x] == 20)
            {
                boolean pipeFound = false;
                //Check if x,y is in pipes
                int pipeLength = pipes.size();
                for (int pi = 0; pi &lt; pipeLength; pi++)
                {
                    int[] coords = (int[])pipes.elementAt(pi);
                    if (coords != null &amp;&amp; coords[0] == x &amp;&amp; coords[1] == y)
                    {
                        //Pipe found, skip it
                        pipeFound = true;
                    }
                }
                if (!pipeFound)
                {
                    //Peek ahead to determine if it&#039;s a pipe or a cannon
                    if(x &lt; 21 &amp;&amp; state[y][x + 1] == 20)
                    {
                        //It&#039;s a pipe, add it and the next one to the pipe array
                        pipes.add(new int[]{x + 1, y});
                    }
                    else
                    {
                        //It&#039;s a cannon
                        cannons.add(new int[]{x, y});
                    }
                }
            }
        }
    }
}
</pre>
<p>The three variables are defined as private members of the agent, and calling this function will populate them with tile locations in the case of pipes and cannons, and tile columns in the case of pits. You don&#8217;t have to do this with such a simple agent &#8211; you can simply use similar techniques to parse over the whole level state.</p>
<p>I use this information to determine how far away obstacles are. At first I was going to make the distance between obstacles affect the jumping distance and height, however without an accurate way to determine where jumps are going to land, this can actually cause more harm than good. So I ignore it, and just use a fairly blunt approach.</p>
<p>Firstly, another helper function:</p>
<pre class="brush: java">
private int setDeltaForObstacles(Vector tiles)
{
    int length = tiles.size();
    int buffer = 0;
    int localDeltaX = 0;
    //Loop through every tile
    for (int counter = 0; counter &lt; length; counter++)
    {
        //Get coords of tile
        int[] coords = (int[])tiles.elementAt(counter);
        //Calculate the delta, then check to see if it&#039;s good enough
        localDeltaX = coords[0] - 11;
        if (action[Mario.KEY_RIGHT] &amp;&amp; coords[0] &gt; 11)
        {
            //If the tile is after mario, and we&#039;re heading right, delta is good
            break;
        }
        else if (action[Mario.KEY_LEFT] &amp;&amp; coords[0] &lt; 11)
        {
            //If the tile is before mario and we&#039;re heading left, add to buffer
            if (coords[0] &gt; buffer)
                buffer = coords[0];
        }
        else if (action[Mario.KEY_LEFT])
        {
            //If the tile is after mario, but we&#039;re heading left, get the last tile loc from the buffer
            localDeltaX = buffer - 11;
            break;
        }
    }
    return localDeltaX;
}
</pre>
<p>This function takes a Vector and will return the closes tile to Mario, depending on his direction. It&#8217;s a very coarse way to determine the closes obstacle to Mario. Bear in mind that it doesn&#8217;t recognise when obstacles are put close together, thus doesn&#8217;t optimise Mario&#8217;s jumping.</p>
<p>The goal of the agent is to jump over the closest obstacle. That&#8217;s it. Considering our obstacles are now in three different datastructures (cannons in one, pipes in another, and pits and raised terrain in the original byte array), we need to store the delta (distance between Mario and the closes obstacle) and update it only when we&#8217;ve found a smaller delta. Also, I want to keep the delta of any pits separate, as I&#8217;m going to have different rules for pits than other obstacles (because pits are the only thing that can kill Mario at this stage).</p>
<p>To this end, I create two integer variables at the top of the <code>getAction</code> method. They are intitialized to 11 because this is where Mario is:</p>
<pre class="brush: java">
int deltaX = 11;
int deltaJump = 11;
</pre>
<p>Here is the code to extract the delta of the nearest obstacle, and the delta of the nearest pit. Note that <code>levelState</code> is the results from a call to <code>observation.getLevelSceneObservation</code>:</p>
<pre class="brush: java">
//Analyse pipes
int pipeDelta = setDeltaForObstacles(pipes);
if (pipeDelta &lt; deltaX &amp;&amp; pipeDelta &gt; 0)
    deltaX = pipeDelta;
//Analyse cannons
int cannonDelta = setDeltaForObstacles(cannons);
if (cannonDelta &lt; deltaX &amp;&amp; cannonDelta &gt; 0)
    deltaX = cannonDelta;

//Analyse the gaps
boolean gap = false;
for(int y = 0; y &lt; 22; y++)
{
    if (pits[y])
    {
        if (action[Mario.KEY_RIGHT] &amp;&amp; y &gt; 11)
        {
            int localDelta = y - 11;
            if (localDelta &lt; deltaJump)
                deltaJump = localDelta;
        }
        else if (action[Mario.KEY_LEFT] &amp;&amp; y &lt; 11)
        {
            int localDelta = 11 - y;
            if (localDelta &lt; deltaJump)
                deltaJump = localDelta;
        }
        gap = true;
    }
}

//Analyse ground above Mario
boolean raisedGround = false;
if (action[Mario.KEY_RIGHT])
{
    for (int x = 12; x &lt; 22; x++)
    {
        for (int y = 12; y &gt;= 0; y--)
        {
            if (levelState[y][x] == -10)
            {
                int localDelta = x - 11;
                if (localDelta &lt; deltaX)
                    deltaX = localDelta;
                raisedGround = true;
                break;
            }
        }
        if (raisedGround)
            break;
    }
}
</pre>
<p>Once we have the deltas, we can use this information to decide what to do. I mentioned above treating obstacle deltas different from jump deltas. This is an attempt to make Mario take smaller jumps when he can see a pit is after an obstacle. This is controlled by two instance members that keep track of jump height and jump length, called <code>jumpHeight</code> and <code>jumpLength</code> respectively. This is very hit and miss. Notice that Mario does not respond to anything more than 4 tiles away, and tiles that are behind him. This is to prevent him from going jump crazy:</p>
<pre class="brush: java">
jumpHeight = 7;
jumpLength = 14;// * (deltaX / 11);
if (((pipes.size() &gt; 0 || cannons.size() &gt; 0 || raisedGround) &amp;&amp; deltaX &gt;= 0 &amp;&amp; deltaX &lt; 5))
{
    if (observation.mayMarioJump() &amp;&amp; !action[Mario.KEY_JUMP])
        action[Mario.KEY_JUMP] = true;
}

//If mario is jumping, there must be an obstacle in the way
if (action[Mario.KEY_JUMP])
{
    if (gap &amp;&amp; deltaJump &gt;= 3)
    {
        jumpHeight = 7;
        jumpLength = 1;
    }
}
//No obstacles, but there is a gap
else if (gap &amp;&amp; deltaJump &gt;= 0 &amp;&amp; deltaJump &lt;= 3)
{
    if (observation.mayMarioJump() &amp;&amp; !action[Mario.KEY_JUMP])
        action[Mario.KEY_JUMP] = true;
}
maintainJump();
</pre>
<p>Finally, the <code>maintainJump</code> method is to ensure we&#8217;re holding down the jump key for the optimal amount of time. It is also coded to provide rudimentary control over jump height and length, however this isn&#8217;t being taken advantage of.</p>
<pre class="brush: java">
private void maintainJump()
{
    if(action[Mario.KEY_JUMP] &amp;&amp; (jumpCount &gt; jumpHeight))
    {
        action[Mario.KEY_JUMP] = false;
        jumpCount = 0;
    }
    // otherwise you&#039;re in the middle of jump, increment jumpCount
    else if (action[Mario.KEY_JUMP])
    {
        jumpCount++;
    }
    if (jumping)
    {
        if (action[Mario.KEY_RIGHT] &amp;&amp; (rightCount &gt; jumpLength))
        {
            action[Mario.KEY_RIGHT] = false;
            rightCount = 0;
        }
        else if (action[Mario.KEY_RIGHT])
        }
    }
}
</pre>
<p>The complete agent is at the bottom of this post for you to download and include in your project. Simply put it in the path <code>src/timgittos</code>, configure the <code>ch.idsia.scenarios.Play</code> class to have no enemies, with <code>options.setPauseWorld(true)</code>, and run any level you want (passable result with difficulty 3). Then build the project and run it with <code>java ch.idsia.scenarios.Play timgittos.BlogAgent</code>.</p>
<p>As you will observe, the agent will make Mario go towards the right as fast as possible, jumping over obstacles as it meets them.  For the most part, it works well enough. However, there are quite a few fatal flaws, and I will explain why it fails in this way.</p>
<p>Most obviously, the agent frequently falls down gaps. It doesn&#8217;t fall down all gaps &#8211; which would indicate that it&#8217;s not a failure in the gap detection, but rather something else. In fact, what&#8217;s going on is that the gaps that Mario tends to fall down are those that enter his field of consideration (4 tiles ahead of him) while he&#8217;s in the air. The agent makes no effort to check whether it&#8217;s jump will land Mario in a pit (since it can&#8217;t predict where Mario will land), and my previous efforts at trying to make the agent force Mario to the left when it detects he&#8217;s going to go down a pit have failed.</p>
<p>Mario will also fall down pits if there are multiple pits in a row. Again, this is because the agent doesn&#8217;t exert much control over the size and length of Mario&#8217;s jumps ,and so can&#8217;t pin point that it wants to land in the middle of the two pits, so it tends to overshoot the jump and fall down the second pit.</p>
<p>Most annoyingly, the agent will sometimes get stuck. If it reaches an obstacle, such as a cannon or a bit of wall or a pipe and jumps at the wrong angle, it will enter a weird wall jump loop, where it jumps, gets stuck on the obstacle, jumps off, jumps again, and gets stuck again. This will loop until there is no time. This is a side effect of the environment allowing wall jumps, which is cool when you can get the agent to make Mario jump out of a pit he&#8217;s falling into, but annoying when he gets stuck.</p>
<p>In any case, this agent is far from complete, and just serves to demonstrate how the simulation environment works, and how to interact with it. Once you&#8217;re clear how to work with the simulation, you can concentrate on building a useful agent, either by starting from scratch (like you would if you were going to use a machine learning approach), or by building on top of this base (for a determinate approach like A*).</p>
<p><strong>Download: <a href='http://www.timgittos.com/wordpress/wp-content/uploads/2009/08/BlogAgent.java'>Mario AI Blog agent (.java)</a></strong></p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/TimGittos?a=rDD8jNRN9IA:1gFQXm3wpnY:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TimGittos?a=rDD8jNRN9IA:1gFQXm3wpnY:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/TimGittos?i=rDD8jNRN9IA:1gFQXm3wpnY:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TimGittos?a=rDD8jNRN9IA:1gFQXm3wpnY:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/TimGittos?i=rDD8jNRN9IA:1gFQXm3wpnY:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TimGittos?a=rDD8jNRN9IA:1gFQXm3wpnY:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/TimGittos?i=rDD8jNRN9IA:1gFQXm3wpnY:V_sGLiPBpWU" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/TimGittos/~4/rDD8jNRN9IA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.timgittos.com/mario-ai-competition-2009-getting-started/feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		<feedburner:origLink>http://www.timgittos.com/mario-ai-competition-2009-getting-started?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=mario-ai-competition-2009-getting-started</feedburner:origLink></item>
		<item>
		<title>Configuring webHttpBinding When Using WCF with JQuery</title>
		<link>http://feedproxy.google.com/~r/TimGittos/~3/1F0Fm3r7dOA/configuring-webhttpbinding-when-using-wcf-with-jquery</link>
		<comments>http://www.timgittos.com/configuring-webhttpbinding-when-using-wcf-with-jquery#comments</comments>
		<pubDate>Wed, 24 Jun 2009 15:39:32 +0000</pubDate>
		<dc:creator>Tim</dc:creator>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[asp.net]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[wcf]]></category>

		<guid isPermaLink="false">http://www.timgittos.com/?p=448</guid>
		<description><![CDATA[Firstly, a disclaimer: I don&#8217;t have a lot of experience working with AJAX enabled WCF services, and from reading some of Rick Strahl&#8217;s posts on using JQuery with ASP.NET, I&#8217;m doing things in a really hackish and terrible manner. Hopefully my mistakes won&#8217;t impact the usefulness of this short tip. When working with JQuery and [...]]]></description>
			<content:encoded><![CDATA[<p>Firstly, a disclaimer: I don&#8217;t have a lot of experience working with AJAX enabled WCF services, and from reading some of <a href="http://www.west-wind.com/presentations/jQuery/default.aspx">Rick Strahl&#8217;s posts on using JQuery with ASP.NET</a>, I&#8217;m doing things in a really hackish and terrible manner. Hopefully my mistakes won&#8217;t impact the usefulness of this short tip.</p>
<p>When working with JQuery and AJAX enabled WCF services, I recently encountered the following error, through Firebug and Fiddler:</p>
<pre>
The maximum string content length quota (8192) has been exceeded while reading XML data.
This quota may be increased by changing the
MaxStringContentLength property on the XmlDictionaryReaderQuotas
object used when creating the XML reader.
</pre>
<p>This is caused by WCF webHttpBinding default having fairly draconion limitations on XML message length and depth. <a href="http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/6ad1bf1c-e340-44ae-8ba5-91428d6e78a7">This thread on MSDN</a> helped diagnose the problem, however it didn&#8217;t do much to help me solve my particular problem. Ultimately, I stumbled upon the solution quite accidentally.</p>
<p>Firstly, as per the MSDN thread, you need to add the custom binding configuration underneath the <system.serviceModel> configuration section:</p>
<pre class="brush: xml">
&lt;system.serviceModel&gt;
  &lt;bindings&gt;
    &lt;webHttpBinding&gt;
      &lt;binding name=&quot;bindingConfiguration&quot;&gt;
        &lt;readerQuotas maxDepth=&quot;32&quot; maxStringContentLength=&quot;2048000&quot; maxArrayLength=&quot;16384&quot; maxBytesPerRead=&quot;4096&quot; maxNameTableCharCount=&quot;16384&quot; /&gt;
      &lt;/binding&gt;
    &lt;/webHttpBinding&gt;
  &lt;/bindings&gt;
  ..
&lt;/system.serviceModel&gt;
</pre>
<p>At first I thought this was a custom binding, and tried to replace the service endpoint binding to the custom binding defined above, however this was causing an &#8220;System.ServiceModel.ServiceActivationException&#8221; exception.</p>
<p>The above binding declaration is actually a configuration for the webHttpBinding. As such, you need to add the BindingConfiguration property onto your service endpoint, along side your binding declaration. This is as follows:</p>
<pre class="brush: xml">
&lt;service behaviorConfiguration=&quot;Your.Service.Behavior&quot;
      name=&quot;Your.Service.Name&quot;&gt;
    &lt;endpoint address=&quot;&quot; behaviorConfiguration=&quot;Your.Behavior.Configuration&quot;
     binding=&quot;webHttpBinding&quot; bindingConfiguration=&quot;bindingConfiguration&quot; contract=&quot;Your.Service.Contract&quot; /&gt;
&lt;/service&gt;
</pre>
<p>This will allow you to send larger messages to your WCF services via AJAX, and get on with creating applications.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/TimGittos?a=1F0Fm3r7dOA:fh0J5GJwIHQ:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TimGittos?a=1F0Fm3r7dOA:fh0J5GJwIHQ:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/TimGittos?i=1F0Fm3r7dOA:fh0J5GJwIHQ:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TimGittos?a=1F0Fm3r7dOA:fh0J5GJwIHQ:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/TimGittos?i=1F0Fm3r7dOA:fh0J5GJwIHQ:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TimGittos?a=1F0Fm3r7dOA:fh0J5GJwIHQ:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/TimGittos?i=1F0Fm3r7dOA:fh0J5GJwIHQ:V_sGLiPBpWU" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/TimGittos/~4/1F0Fm3r7dOA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.timgittos.com/configuring-webhttpbinding-when-using-wcf-with-jquery/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.timgittos.com/configuring-webhttpbinding-when-using-wcf-with-jquery?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=configuring-webhttpbinding-when-using-wcf-with-jquery</feedburner:origLink></item>
		<item>
		<title>Going Camping with CouchDB On OS X Tiger</title>
		<link>http://feedproxy.google.com/~r/TimGittos/~3/2GPbQ1-64cA/going-camping-with-couchdb-on-os-x-tiger</link>
		<comments>http://www.timgittos.com/going-camping-with-couchdb-on-os-x-tiger#comments</comments>
		<pubDate>Fri, 12 Jun 2009 20:11:59 +0000</pubDate>
		<dc:creator>Tim</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[camping]]></category>
		<category><![CDATA[couchdb]]></category>

		<guid isPermaLink="false">http://www.timgittos.com/?p=421</guid>
		<description><![CDATA[With Snow Leopard being released at the end of September this year, Tiger is definitely starting to show it&#8217;s age. I&#8217;ve been putting off upgrading to Leopard for quite some time, not being able to justify the down time associated with upgrading an OS. This has had an unpleasant side effect of not being able [...]]]></description>
			<content:encoded><![CDATA[<p>With <a href="http://www.engadget.com/2009/06/08/apple-shipping-snow-leopard-in-september-29-upgrade/">Snow Leopard being released at the end of September this year</a>, Tiger is definitely starting to show it&#8217;s age. I&#8217;ve been putting off upgrading to Leopard for quite some time, not being able to justify the down time associated with upgrading an OS. This has had an unpleasant side effect of not being able to do things quite as easily as I want, and finding information is hard.</p>
<p>Due to the <a href="http://www.timgittos.com/a-cms-in-ruby-and-why-i-stopped">recommendations in the comments of my Ruby CMS article</a>, I have decided to start playing with the <a href="http://camping.rubyforge.org/files/README.html">Camping Ruby microframework</a> backed by <a href="http://couchdb.apache.org/">CouchDB</a>. Getting Camping up and running was easy enough, and I managed to get some trivial functionality going. Camping uses SQLite for it&#8217;s database, which is fine if I wanted to massage my data into a relational form. However, I have models with optional attributes, and rather than making nullable database types, I want to leverage CouchDB&#8217;s schema-less, RESTful document storage. Each persisted object in my application will be available on a unique url, so CouchDB is a nice fit for what I want to do.</p>
<h3>The Great Installation</h3>
<p>I found this <a href="http://knuthellan.wordpress.com/2009/03/08/camping-with-couchdb/">great article</a> about getting Camping talking to CouchDB, and it seemed easy enough, so I decided to try it. Since I already had Camping working, all I needed was to get CouchDB installed on my Macbook. As much as I&#8217;m not scared of compiling applications from source, I&#8217;ve had issues in the past with OS X and compiling, so I decide to find a simple package or disk image to install. I found <a href="http://janl.github.com/couchdbx/">CouchDBX</a>, however checking the requirements showed that it supports Leopard only.</p>
<p>With a little more research, I found out I had to use <a href="http://www.macports.org/">Macports</a> to install CouchDB. Macports relies on XCode Tools which come available on the DVDs that came with OS X. If you haven&#8217;t previously installed XCode Tools, then you should install them before you install Macports. Something that is buried in a <a href="http://trac.macports.org/ticket/18282">support ticket</a>, however, is that Macports targets XCode tools 2.5. My XCode tools was something like 2.4.8. While I did manage to get Macports installed, the installation for CouchDB fails when it tries to build tk. If you, like me, have an older XCode Tools than 2.5, you&#8217;ll need to download 2.5, which you can find <a href="http://connect.apple.com/cgi-bin/WebObjects/MemberSite.woa/wa/getSoftware?bundleID=19907">deep inside the Apple website</a>. This does require an Apple Developer Connection account to get, so if you don&#8217;t have one, you&#8217;ll need to create one.</p>
<p>Installing CouchDB is as simple as issuing</p>
<pre class="brush: bash">
sudo port install couchdb
</pre>
<p>and Macports will take care of the rest. CouchDB lists it&#8217;s dependencies as Spidermonkey, Erlang and a few others, however each of those has dependencies, and each of those dependencies has dependencies, and it ends up taking quite a long time and downloading a fair few packages. The upside is that if you didn&#8217;t have Erlang previously installed, you do now. Erlang is something I&#8217;ve been wanting to take a look at.</p>
<h3>Start The Server Before You Leap</h3>
<p>While the article I linked to above about getting Camping and CouchDB talking is good, it&#8217;s not exactly the most verbose explanation especially if you haven&#8217;t read the documentation for CouchDB and prefer to just dive in. For those who are still a little unsure like I was about how exactly to do this, I&#8217;ll outline my approach below.</p>
<p>Before you get started writing any code at all, you need to start your CouchDB server. This is something that escaped me for the longest time, and when I finally twigged, it gave me a bit of grief. To start CouchDB, issue the following command:</p>
<pre class="brush: bash">
sudo couchdb
</pre>
<p>If you try this without escalating privilege, it will return an error &#8220;{&#8220;init terminating in do_boot&#8221;,{{badmatch,{error,shutdown}},[{couch_server_sup,start_server,1},{erl_eval,do_apply,5},{erl_eval,exprs,5}, {init,start_it,1},{init,start_em,1}]}}&#8221;, which searching for will bring you to the <a href="http://wiki.apache.org/couchdb/Error_messages">CouchDB</a> wiki page for error messages. This page will tell you the problem is an unavailable port. For me, at least, this is not true. CouchDB runs on port 5984 which as far as I know is not used for any system services or other software. The reason I was getting this error was that I wasn&#8217;t running it with enough privilege.</p>
<p>Once you get CouchDB started, you&#8217;ll notice it blocks the terminal. I don&#8217;t like to have too many windows open at once, so I&#8217;d prefer to have it run as a background process. Fortunately CouchDB will let you do that with a command line switch option, along with changing the location of the pid file. I&#8217;ll leave figuring out how you want to start it up to you.</p>
<p>Once you have CouchDB started, you&#8217;ll have access to a web-based administration panel called Futon. Futon is available to you at <code>http://localhost:5984/_utils/</code>, assuming you&#8217;re running CouchDB on your local host. The Futon utility will allow you to create databases and insert documents in preparation to test your connectivity with Camping.</p>
<h3>Camping Time</h3>
<p>There were two Ruby gems I had considered when deciding how to connect Ruby to CouchDB. I should point out that due to the RESTful nature of CouchDB, you strictly don&#8217;t need any Ruby gems and could roll your own fairly easily, if you wanted to. I didn&#8217;t want that level of control, personally. The two gems I considered were <a href="http://github.com/jchris/couchrest/tree/master">CouchRest</a> and <a href="http://github.com/paulcarey/relaxdb/tree/master">RelaxDB</a>. CouchRest is a simple Ruby wrapper around the CouchDB REST API, whereas RelaxDB is more abstracted, bringing ActiveRecord-like functionality to CouchDB. While before I would have chosen RelaxDB, I&#8217;m intentionally trying to work a little closer to the raw APIs here, so I chose CouchRest.</p>
<p>You can install CouchRest through RubyGems:</p>
<pre class="brush: bash">
sudo gem install couchrest
</pre>
<p>however I found that the gem version wouldn&#8217;t work and kept throwing errors when I started my Camping application. To overcome this, I just cloned it from the GitHun repository and placed it in my Camping app directory and referenced it that way.</p>
<p>The first thing to do would be to create a normal Camping sample application, if you haven&#8217;t done already. For the purposes of this post, I&#8217;m going to use the &#8220;<a href="http://camping.rubyforge.org/files/README.html">skeletal Camping blog</a>&#8221; application used in the documentation, and edit that to work with CouchDB. I figure this will give everyone a relatively common base from which to start. Import CouchRest just below where the application imports Camping:</p>
<pre class="brush: ruby">
require &#039;camping&#039;
require &#039;couchrest&#039; # or &#039;couchrest/couchrest&#039; or similar if you&#039;ve cloned from Github
</pre>
<p>Given that the purpose of this article is to demonstrate connecting to CouchDB, and not the design of a framework around it, we can safely ignore defining a model for now, and rely on CouchDB as our model. So if you&#8217;re following along from the example application, you can safely delete the classes from Blog::Models module. We&#8217;re not going to delete the whole module, because of the <code>create</code> method.</p>
<p>The Camping <a href="http://camping.rubyforge.org/classes/Camping.html">create</a> method that is run when the server starts up your Camping app. From the documentation, &#8220;This is a good place to check for database tables and create those tables to save users of your application from needing to manually set them up.&#8221; Instead, we&#8217;re going to use this method to set up CouchRest in our application:</p>
<pre class="brush: ruby">
module Blog::Models
  def Blog.create
    db_url = &#039;http://localhost:5984/&#039;
    storage = CouchRest.database(&quot;#{db_url}blog&quot;)
    Blog::Controllers::Index.set_storage(storage)
  end
end
</pre>
<p>Next, because we&#8217;re now calling a new method on the controller class, we need to modify that. Change the Blog::Controllers::Index class to the following:</p>
<pre class="brush: ruby">
module Blog::Controllers
  class Index &lt; R &#039;/(\w+)&#039;
    def Index.set_storage(storage)
      @@storage = storage
    end
    def get(id)
      @post = @@storage.get(&#039;posts/&#039; + id)
      render :index
    end
  end
end
</pre>
<p>What I&#8217;ve done here is given the controller class a static reference to my CouchDB database (from the <code>create</code> method). Then the controller was changed to respond to a regex, which is passed into the get method. We use the id passed in to retrieve a document from CouchDB, which we assign as an instance variable.</p>
<p>Lastly, we need to modify the Index function view to pull data from the CouchDB database:</p>
<pre class="brush: ruby">
def index
  h1 @post[:title]
end
</pre>
<p>This will output the title of the test document created at the start of the article.</p>
<p>If you haven&#8217;t already, start up Futon and create a database for the purposes of this demo. Call the database &#8220;blog&#8221;, and fill it with a test document with the id of &#8220;posts/test&#8221;, and at least a &#8220;title&#8221; property with the value &#8220;Test Post&#8221;, and any other properties you wish.</p>
<p>Start the Camping application with <code>camping blog.rb</code>, and point a browser to <code>http://localhost:3301/test</code>, and you should see &#8220;Test Post&#8221; in a header tag, rendered out to the browser, which means that Camping has successfully communicated with CouchDB.</p>
<p>I didn&#8217;t cover putting data into CouchDB, however you would do it in a similar vein, writing a <code>post</code> method inside your routes to create data and save it to CouchDB. From here, personally, I&#8217;m going to create some wrapper classes for requests and models and build up something which is a little DRYer, however as far as a demo, this is good enough.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/TimGittos?a=2GPbQ1-64cA:5MxOI0wFv3s:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TimGittos?a=2GPbQ1-64cA:5MxOI0wFv3s:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/TimGittos?i=2GPbQ1-64cA:5MxOI0wFv3s:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TimGittos?a=2GPbQ1-64cA:5MxOI0wFv3s:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/TimGittos?i=2GPbQ1-64cA:5MxOI0wFv3s:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TimGittos?a=2GPbQ1-64cA:5MxOI0wFv3s:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/TimGittos?i=2GPbQ1-64cA:5MxOI0wFv3s:V_sGLiPBpWU" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/TimGittos/~4/2GPbQ1-64cA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.timgittos.com/going-camping-with-couchdb-on-os-x-tiger/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.timgittos.com/going-camping-with-couchdb-on-os-x-tiger?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=going-camping-with-couchdb-on-os-x-tiger</feedburner:origLink></item>
		<item>
		<title>My Best Guesses About Wolfram Alpha</title>
		<link>http://feedproxy.google.com/~r/TimGittos/~3/S4t3_vAr-YM/my-best-guesses-about-wolfram-alpha</link>
		<comments>http://www.timgittos.com/my-best-guesses-about-wolfram-alpha#comments</comments>
		<pubDate>Tue, 19 May 2009 15:57:11 +0000</pubDate>
		<dc:creator>Tim</dc:creator>
				<category><![CDATA[Artificial Intelligence]]></category>
		<category><![CDATA[Mathematics]]></category>
		<category><![CDATA[knowledgebases]]></category>
		<category><![CDATA[searching]]></category>
		<category><![CDATA[wolframalpha]]></category>

		<guid isPermaLink="false">http://www.timgittos.com/?p=382</guid>
		<description><![CDATA[Following the &#8220;soft launch&#8221; of Wolfram Alpha a few days ago, I&#8217;ve been wondering exactly how Wolfram Alpha works. From the description of all the hype leading up to it, it seemed like a question answering application that is specialized in answering questions, as opposed to say Google, which is more into finding and presenting [...]]]></description>
			<content:encoded><![CDATA[<p>Following the &#8220;soft launch&#8221; of Wolfram Alpha a few days ago, I&#8217;ve been wondering exactly how Wolfram Alpha works. From the description of all the hype leading up to it, it seemed like a question answering application that is specialized in answering questions, as opposed to say Google, which is more into finding and presenting data, leaving the interpretation to humans. Now that it&#8217;s here, we can have a play around and see what it can do.</p>
<p>Firstly, I tried to <a href="http://www.wolframalpha.com/input/?i=how+does+wolfram+alpha+work" title="How does Wolfram Alpha work - Wolfram Alpha">ask Wolfram Alpha how it worked</a>, and it just gave me a puzzled look. So I can only guess, and guess I shall.</p>
<p>The <a href="http://www.wolframalpha.com/about.html">Wolfram Alpha website lays it all out on the table</a>, with regards to what it&#8217;s all about. Wolfram Alpha&#8217;s goal &#8220;is to accept completely free-form input, and to serve as a knowledge engine&#8221; to answer search queries entered. From the very limited playing I&#8217;ve done, it seems pretty cool. </p>
<p>Following my move from Perth to Texas, I typed in &#8220;<a href="http://www.wolframalpha.com/input/?i=austin+to+perth">Austin to Perth</a>&#8221; into Wolfram Alpha just to see what it told me. I got back map, with a line drawn between the cities. I got the distance in miles between the two and the flight time. I got a side by side comparison of the local times, populations and approximate elevations.</p>
<p><a href="http://www.google.com/search?q=austin+to+perth">Google however, delivered me what I was actually looking for, sort of.</a> Maybe that&#8217;s just a difference in expectations and thinking.<sup>1</sup></p>
<p>It&#8217;s clear that Wolfram Alpha is pretty cool, and will do some awesome things with the data before it returns it back to you, but it doesn&#8217;t really help me figure out how it works. My thoughts are that Wolfram Alpha combines a large database of indexed knowledge in the form of a knowledge base and a powerful logical language, the language being Stephen Wolfram&#8217;s own <a href="http://en.wikipedia.org/wiki/Mathematica" title="Mathematica on Wikipedia">Mathematica</a>, naturally. As he describes it, Wolfram Alpha is the &#8220;killer-app&#8221; for Mathematica.</p>
<p>First, lets discuss the vast store of data available to Wolfram Alpha, most likely in the form of a knowledge base. A knowledge base is an information representation scheme designed to allow information to be operated on using logic. Information is stored in &#8220;sentences&#8221; in a knowledge representation language. The knowledge base allows logical agents, in this case the Wolfram Alpha application, to receive queries, and then search and analyse the knowledge base, performing logical inferences and information compounding, then collating it and returning the results. The logical agent does all the heavy lifting, but the very structure of the knowledge base helps the agent.</p>
<p>The heart of the logical agent is it&#8217;s knowledge representation language. It allows the agent to &#8220;reason&#8221; through sentences and make inferences in order to derive new facts. Proposition logic and First-order logic are both knowledge representation languages. Knowledge representation languages use syntax and semantics to define knowledge, where syntax outlines the structure of a language, and the semantics are the meaning.</p>
<p>Logic is a very mathematical concept, and mathematics can be seen as a kind of logic that operates on numbers. Mathematics has a syntax, that defines the infix notation of logical operators on operands, and the semantics are what those operators do. 1 + 1 = 2 is an example of a complex logical language, where the syntax defines that the + operator acts on each 1, and the = operator defines the result of the previous operation. The semantics define that the value of 1 + 1 is 2.</p>
<p><a href="http://blog.wolframalpha.com/2009/05/01/the-secret-behind-the-computational-engine-in-wolframalpha/" title="The Secret Behind the Computational Engine in Wolfram Alpha">Mathematica, the heart of Wolfram Alpha</a>, is a computational language, according to it&#8217;s Wikipedia page. It&#8217;s built on top of the <a href="http://en.wikipedia.org/wiki/Symbolic_Manipulation_Program" title="Symbolic Manipulation Program - Wikipedia">Symbolic Manipulation Program</a>, designed by both Chris A. Cole and Stephen Wolfram. The Symbolic Manipulation Program is a &#8220;computer algebra system&#8221;, which facilitates symbolic computation,  allowing computers to operate on symbols and manipulate expressions instead of operating on their values, which sounds a heck of a lot like something that could be used to create a logic that can operate on a knowledge base. </p>
<p>Going back to logical agents and knowledge bases, there are a number of ways logical agents can extract and infer information from knowledge bases. The topic of knowledge based logical agents is a pretty vast one, and I couldn&#8217;t possibly explain it completely in a single post, even if I knew more than just a fraction of it, which I don&#8217;t. But I can summarize what I do understand, and how it applies to Wolfram Alpha.</p>
<p>As referred to often in the post so far, inference or <em>entailment</em> plays a large part of how a logical agent can extract &#8220;new&#8221; information from a knowledge base. <a href="http://en.wikipedia.org/wiki/Inference" title="Inference - Wikipedia">Inference</a> is deeply rooted in formal logic, and techniques have been developed to allow automated software processes to apply it to a knowledge base. </p>
<p>Logical entailment is the idea that a sentence &#8220;logically follows&#8221; another sentence. If a given sentence <strong>a</strong> is true, and the truth of sentence <strong>b</strong> depends on the truth of <strong>a</strong>, then <strong>b</strong> must be true, and also that if <strong>b</strong> is true, then logically <strong>a</strong> must also be true. This is useful if the knowledge base doesn&#8217;t contain the fact that one of <strong>a</strong> or <strong>b</strong> is true, but it does contain definition that the truth of <strong>b</strong> depends on the truth of <strong>a</strong>.</p>
<p>The knowledge base is designed to be a model of reality, and holds sentences about the world intended to describe it to a level of detail. Sentences can be as atomic as facts, such as &#8220;the sky is blue&#8221;, or can be logical sentences such as &#8220;if the sun is in the sky, it is not night&#8221;, which of course has exceptions (such as in certain seasons in the polar regions), which also need to be modeled in the knowledge base.</p>
<p>This is relevant because, with a finite model represented by the knowledge base, there are a finite number of entailment and inferences that can be made on the model, which means that a logical agent such as Wolfram Alpha can reduce the world to a finite search space, and can run a search over this space looking for information that follows on from the set of facts in the knowledge base.</p>
<p>Search techniques for searching the knowledge base are similar as search techniques in other AI based problems, such as constraint satisfaction problems and touring problems. These searching algorithms include backtracking and local search methods, such as hill climbing.</p>
<p>When searching this knowledge base, the logical agent needs to abide by a series of rules, known as inference rules, in order to guarantee the the knowledge it entails and infers is valid. </p>
<p>Firstly, the logical agent needs to be aware of the equivalence of two logical sentences. If two sentences are both true under the same model, such as the Wolfram Alpha knowledge base, then they are logically equivalent, and can be used to format facts in a different way to aid inference.</p>
<p>Secondly, the logical agent needs to be aware of the concept of validity. A sentence is valid if it is true in every model, which essentially means it&#8217;s a tautology and is always true. These tautologies are useful because they aid in validating inferences, where <strong>a</strong> infers <strong>b</strong> if a implies <strong>b</strong> is a tautology, where implication is such that <strong>b</strong> is true if and only if <strong>a</strong> is true. This can get a little confusing, and if you can, I&#8217;d suggest you read Chapter 7 in <a href="http://www.amazon.com/gp/product/0137903952?ie=UTF8&#038;tag=gebloftigi-20&#038;linkCode=as2&#038;camp=1789&#038;creative=9325&#038;creativeASIN=0137903952">AI:AMA</a><br />
.</p>
<p>Thirdly, it needs to ensure the sentence is satisfiable, which means it&#8217;s true in at least one model, which is basically just searching for inferences and determining that, for a given search space state, the inference being suggested is true.</p>
<p>The logical agent and inference/entailment from a knowledge base can be observed in Wolfram Alpha with a fairly simple query: &#8220;<a href="http://www.wolframalpha.com/input/?i=red+%2B+yellow">red + yellow</a>&#8220;. In this query, the logical agent would probably hit the knowledge base and tell it that both red and yellow are true, meaning that we want to find information about those. It would then search for all sentences that are entailed or logical structures that mention the fact red or yellow, such as a sentence &#8220;orange is a mix of red and yellow&#8221;. It would then tell the knowledge base that this fact had been entailed, and tell it that orange is true. Then, when it finds the sentence &#8220;blue is complementary to orange&#8221;, it can add that to the record set. Obviously there will be other sentences in the knowledge base, and the agent will have to use a filtering algorithm to determine which sentences and facts are relevant to the query, otherwise it might return results that the user is not interested in.</p>
<p>To successfully parse the search query, it would also need a measure of natural language processing, so that it can convert a human-readable query into a machine readable query. This, combined with a large, extensive knowledge base, a fast logical language such as Mathematica and AI techniques for inference and entailment of knowledge mean that Wolfram Alpha can answer a wide range of questions that a simple indexed and categorised search engine couldn&#8217;t.</p>
<p>However that&#8217;s just my best guess. And keep in mind who I am: I&#8217;m just a young web developer with an interest in AI. I don&#8217;t actively participate in AI research, and I have no formal training. My guesses and musings are probably widely off the mark, and if anyone has any other ideas or corrections, clarifications or discussions, I&#8217;d love to hear them in the comments.</p>
<hr />
<sub></p>
<ol>
<li>If you mistype a search query into Wolfram Alpha, curiously it won&#8217;t suggest a correction. Considering how relatively easy this task is (<a href="http://en.wikipedia.org/wiki/Levenshtein_distance">just use it&#8217;s Levenshtein Distance</a>), I find it odd that it doesn&#8217;t support this.
</li>
</ol>
<p></sub></p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/TimGittos?a=S4t3_vAr-YM:vVdL6ptywss:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TimGittos?a=S4t3_vAr-YM:vVdL6ptywss:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/TimGittos?i=S4t3_vAr-YM:vVdL6ptywss:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TimGittos?a=S4t3_vAr-YM:vVdL6ptywss:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/TimGittos?i=S4t3_vAr-YM:vVdL6ptywss:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TimGittos?a=S4t3_vAr-YM:vVdL6ptywss:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/TimGittos?i=S4t3_vAr-YM:vVdL6ptywss:V_sGLiPBpWU" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/TimGittos/~4/S4t3_vAr-YM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.timgittos.com/my-best-guesses-about-wolfram-alpha/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		<feedburner:origLink>http://www.timgittos.com/my-best-guesses-about-wolfram-alpha?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=my-best-guesses-about-wolfram-alpha</feedburner:origLink></item>
		<item>
		<title>Now Appearing In Austin, Texas</title>
		<link>http://feedproxy.google.com/~r/TimGittos/~3/p87XlQDPV-Y/now-appearing-in-austin-texas</link>
		<comments>http://www.timgittos.com/now-appearing-in-austin-texas#comments</comments>
		<pubDate>Mon, 27 Apr 2009 03:02:46 +0000</pubDate>
		<dc:creator>Tim</dc:creator>
				<category><![CDATA[Editorials]]></category>
		<category><![CDATA[Personal]]></category>
		<category><![CDATA[austin]]></category>
		<category><![CDATA[texas]]></category>
		<category><![CDATA[trip]]></category>
		<category><![CDATA[usa]]></category>

		<guid isPermaLink="false">http://www.timgittos.com/?p=362</guid>
		<description><![CDATA[This blog has gone dark over the last two or so weeks, but for a very good reason. On the 21st of April, I flew from Perth, Western Australia to Austin, Texas, where I will be staying for the next 6 months. For those not acquainted with the trip, it&#8217;s half a world away at [...]]]></description>
			<content:encoded><![CDATA[<p>This blog has gone dark over the last two or so weeks, but for a very good reason. On the 21<sup>st</sup> of April, I flew from Perth, Western Australia to Austin, Texas, where I will be staying for the next 6 months. For those not acquainted with the trip, it&#8217;s half a world away at over 13,000km, for a total flying time of 29 hours not including layovers (for my trip, anyway).</p>
<p>I&#8217;ve been spending the last week settling down here in Austin, and the week before that preparing for the trip. I&#8217;m still suffering from some jet lag, and catching up on the last 8 months with my girlfriend, who I hadn&#8217;t seen since August 2008. I haven&#8217;t had the time nor the concentration required to write a blog post, and I haven&#8217;t touched my Google Reader account, which I can see has over 1,600 unread articles.</p>
<p>However, I do have some interesting posts coming up. I&#8217;m planning a response to an AI article that was linked to me in a comment, a more in depth look at the importance of searching by solving the 8-Queens problems in Python using some different search techniques, and a look at creating some graceful degradation control adapters for ASP.NET server controls that don&#8217;t work without Javascript.</p>
<p>So, don&#8217;t unsubscribe from my feed in your readers, the blog isn&#8217;t abandoned, life has just taken priority over it. When things settle down, I&#8217;ll start writing articles again.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/TimGittos?a=p87XlQDPV-Y:Ug34uJ4J5P8:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TimGittos?a=p87XlQDPV-Y:Ug34uJ4J5P8:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/TimGittos?i=p87XlQDPV-Y:Ug34uJ4J5P8:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TimGittos?a=p87XlQDPV-Y:Ug34uJ4J5P8:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/TimGittos?i=p87XlQDPV-Y:Ug34uJ4J5P8:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TimGittos?a=p87XlQDPV-Y:Ug34uJ4J5P8:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/TimGittos?i=p87XlQDPV-Y:Ug34uJ4J5P8:V_sGLiPBpWU" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/TimGittos/~4/p87XlQDPV-Y" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.timgittos.com/now-appearing-in-austin-texas/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.timgittos.com/now-appearing-in-austin-texas?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=now-appearing-in-austin-texas</feedburner:origLink></item>
		<item>
		<title>Where Do We Draw The Line On Complexity?</title>
		<link>http://feedproxy.google.com/~r/TimGittos/~3/d0kuQvoB8Cc/where-do-we-draw-the-line-on-complexity</link>
		<comments>http://www.timgittos.com/where-do-we-draw-the-line-on-complexity#comments</comments>
		<pubDate>Thu, 16 Apr 2009 01:58:15 +0000</pubDate>
		<dc:creator>Tim</dc:creator>
				<category><![CDATA[Editorials]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[complexity]]></category>

		<guid isPermaLink="false">http://www.timgittos.com/?p=357</guid>
		<description><![CDATA[I&#8217;ve got a few posts planned about AI and HCI, however these require a lot of time to research and write code for, time that I don&#8217;t have given I&#8217;m flying to the US on the 21st of April. So I apologise to people who saw my last AI article on Hacker News and Reddit [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve got a few posts planned about AI and HCI, however these require a lot of time to research and write code for, time that I don&#8217;t have given I&#8217;m flying to the US on the 21<sup>st</sup> of April. So I apologise to people who saw my last AI article on Hacker News and Reddit and subscribed to my feed expecting more of the same. There will be more, I promise. I just need more time. For now, just some musings.</p>
<p>I&#8217;ve been thinking a lot lately about solving problems. I read a number of programming aggregators and startup blogs, and the term &#8220;solve a problem&#8221; keeps nagging at me. To be successful, at programming and business, you need to solve a problem. I&#8217;d love to eventually run a development company, but I don&#8217;t know what problem to solve. So, I consider the problem my current employer is solving.</p>
<p>I currently work for a web development company that is doing fairly well. We have a suite of products that we sell to our clients, and sell services related to those products. They&#8217;re doing well, so obviously, they must be solving a problem. So, from &#8220;client&#8221; point of view, the problem we solve is that of letting people who don&#8217;t know anything about websites build and run complex websites.</p>
<p>We have a CMS product that allows non web geeks manage websites. This includes writing new pages and editing content on existing pages, publishing news items, distributing these to an email list, managing uploaded files and inserting modules of dynamic content to their hearts desire. The modules we offer include contact forms, random image rotators, resume upload controls, auto-generating bread crumbs and menus, and so on. These modules aim to reduce the complexity of managing dynamic sites, so that ordinary people can do it.</p>
<p>On top of that, we do custom applications built on top of that CMS site. Clients have a site they run themselves with the CMS, but some also have dedicated applications with a separate interface. These are separate because they&#8217;re custom jobs. They provide functionality that is not available in the CMS (yet), or functionality that would be too complex to maintain using the CMS. So again, we&#8217;re reducing the complexity of running a custom application.</p>
<p>So, on first looks, we build websites and applications that non-geeks can use. But looking further, we manage complexity. We reduce the complexity for the client, so that the client can do difficult things with ease, and don&#8217;t have to know <em>how</em> it&#8217;s done, only that they can do it.</p>
<p>On the other hand, good programming is about managing complexity. That is, trying to keep your code as free from complexity as you can get away with while still doing the job. Complex code is buggy and unmaintainable.</p>
<p>Complexity exists, and it is immutable. Once you&#8217;ve simplified a task to the point that the only steps involved are those that accomplish that task, and that task cannot be accomplished without those steps, you have your complexity, and it isn&#8217;t going anywhere. The task cannot be made more simple, because to do that we&#8217;d have to leave out steps, which would not accomplish the task.</p>
<p>What we do from then on is delegate complexity, shift it around and make it other people&#8217;s problem. Take for example, the task of creating and publishing a blog post. Our software has tagging, categories, post titles and post content. Creating a post involves writing a post, giving it a title, adding tags, selecting categories and publishing it.</p>
<p>Breaking it down, we need to create a body, create a title, create all categories, create all tags, link the tags to the post, link the post to the categories and publish it. Each link has a display name and a URL slug, and each category has a display name and a URL slug. URL slugs cannot contain certain characters, however their display names can.</p>
<p>Now, we can delegate this complexity to the user, which will result in simple code. The user will be responsible for creating tags and categories, and giving them URL slugs that fit our rules, while the application will just take the data and store it, and retrieve it when asked. The user will be responsible for assigning tags to the post and the categories, and the application just stores it. This is obviously an unacceptable level of complexity for the user.</p>
<p>We could also delegate all the complexity to the application, making the user experience simple. The user just types in the tags they want, picks the categories, and the application will link the tags if they exist, create them if they don&#8217;t, automatically strip unwanted characters from URL slugs and hide a lot of the complexity. In more complicated cases, this will result in very complex code that will be bug prone.</p>
<p>So the question is, where do we draw the line? What balance of code complexity and user interface complexity is successful? I guess you could say &#8220;make it 50/50&#8243; and think that&#8217;s good enough, but I don&#8217;t agree. I think the balance is very contextual, and often leans in favour of code complexity. In simple examples like above, taking on all the complexity of the task in the code is a trivial thing and easily done. For nuclear reactor control software, things might not be straight forward.</p>
<p>This is the key to a successful software product/business, I think. Finding the right balance between complexity. If you put too much complexity on the user, user&#8217;s won&#8217;t be able to use it, and your software won&#8217;t sell, and the whole thing will bomb. If you put too much complexity on the software, it will be buggy and difficult to maintain, and will eat up development time and money, and possibly even end up costing more than it earns, and then it will bomb. That&#8217;s not even including the more personal aspects of programmer job satisfaction and sanity.</p>
<p>Success is finding the sweet spot when balancing complexity.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/TimGittos?a=d0kuQvoB8Cc:xhbOvlXLh0E:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TimGittos?a=d0kuQvoB8Cc:xhbOvlXLh0E:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/TimGittos?i=d0kuQvoB8Cc:xhbOvlXLh0E:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TimGittos?a=d0kuQvoB8Cc:xhbOvlXLh0E:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/TimGittos?i=d0kuQvoB8Cc:xhbOvlXLh0E:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TimGittos?a=d0kuQvoB8Cc:xhbOvlXLh0E:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/TimGittos?i=d0kuQvoB8Cc:xhbOvlXLh0E:V_sGLiPBpWU" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/TimGittos/~4/d0kuQvoB8Cc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.timgittos.com/where-do-we-draw-the-line-on-complexity/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.timgittos.com/where-do-we-draw-the-line-on-complexity?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=where-do-we-draw-the-line-on-complexity</feedburner:origLink></item>
		<item>
		<title>jQuery Context Menu Unbind Click Fix</title>
		<link>http://feedproxy.google.com/~r/TimGittos/~3/rsEJ1NERJ9E/jquery-context-menu-unbind-click-fix</link>
		<comments>http://www.timgittos.com/jquery-context-menu-unbind-click-fix#comments</comments>
		<pubDate>Thu, 09 Apr 2009 06:36:13 +0000</pubDate>
		<dc:creator>Tim</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[bugfix]]></category>
		<category><![CDATA[contextmenu]]></category>
		<category><![CDATA[jquery]]></category>

		<guid isPermaLink="false">http://www.timgittos.com/?p=347</guid>
		<description><![CDATA[Updated on May 28, 2009, due to partial fix. The fix should now be a complete fix. &#8211; Apologies for the somewhat confusing title. I&#8217;ve been doing a lot of jQuery work, replacing all the AJAX.NET crap in my project at work to speed the interface up. I&#8217;ve started using the awesome jQuery Context Menu [...]]]></description>
			<content:encoded><![CDATA[<p>Updated on May 28, 2009, due to partial fix. The fix should now be a complete fix.<br />
&#8211;<br />
Apologies for the somewhat confusing title.<br />
I&#8217;ve been doing a lot of jQuery work, replacing all the AJAX.NET crap in my project at work to speed the interface up. I&#8217;ve started using the awesome <a href="http://abeautifulsite.net/notebook/80">jQuery Context Menu</a> plugin. However, I found it was also messing around with <a href="http://www.jstree.com">jsTree</a> which I am using on the same page.</p>
<p>The problem is that the jQuery Context menu overzealously unbinds all click events from the document. This means that it&#8217;s going to break all your other Javascript that relies on clicking. Checking the <a href="http://docs.jquery.com/Events/unbind">documentation for jQuery&#8217;s <em>unbind</em> function</a>, you can see that it accepts a function as a second parameter. This is the function that will be unbound if you pass that in as a parameter.<br />
So, I fixed the jQuery Context Menu by changing the following:</p>
<ol>
<li>In the main <em>contextMenu</em> function, near the end, just above the <em>return</em> statement, I added the following:
<pre class="brush: javascript">
// External click event for document
function onDocumentClick(e) {
      var menu = $(&#039;#&#039; + o.menu);
      $(document).unbind(&#039;click&#039;, onDocumentClick).unbind(&#039;keypress&#039;);
      $(menu).fadeOut(o.outSpeed);
      return false;
}
</pre>
</li>
<li>Next, I change the function that assigns the <em>click</em> listener to the document to assign the defined function, instead of an anonymous function. So, change:
<pre class="brush: javascript">
// Hide bindings
setTimeout( function() { // Delay for Mozilla
      $(document).click( function() {
            $(document).unbind(&#039;click&#039;).unbind(&#039;keypress&#039;);
            $(menu).fadeOut(o.outSpeed);
            return false;
      });
}, 0);
</pre>
<p>to</p>
<pre class="brush: javascript">
// Hide bindings
setTimeout(function() { // Delay for Mozilla
      $(document).click(onDocumentClick);
}, 0);
</pre>
</li>
<li>Lastly, I remove all instances of:
<pre class="brush: javascript">
$(document).unbind(&#039;click&#039;);
</pre>
</li>
</ol>
<p>That&#8217;s it. That fixed the problem for me. You&#8217;ll notice I don&#8217;t bother with the <em>keypress</em> bindings. That&#8217;s because I&#8217;m not using them, so I&#8217;m not bothered. I&#8217;m assuming the fix for that will be a similar strategy, for those who are bothered.</p>
<p>I&#8217;ve uploaded my version for those who can&#8217;t get it working using the tips in this post, but remember the copyright remains with Cory S.N. LaViska over at <a href="http://abeautifulsite.net/notebook/80">A Beautiful Site</a>.<br />
<a href="http://www.timgittos.com/wordpress/wp-content/uploads/2009/04/jquerycontextmenu.js">jquery.contextMenu.js</a></p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/TimGittos?a=rsEJ1NERJ9E:CYHABNMO2eU:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/TimGittos?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TimGittos?a=rsEJ1NERJ9E:CYHABNMO2eU:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/TimGittos?i=rsEJ1NERJ9E:CYHABNMO2eU:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TimGittos?a=rsEJ1NERJ9E:CYHABNMO2eU:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/TimGittos?i=rsEJ1NERJ9E:CYHABNMO2eU:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TimGittos?a=rsEJ1NERJ9E:CYHABNMO2eU:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/TimGittos?i=rsEJ1NERJ9E:CYHABNMO2eU:V_sGLiPBpWU" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/TimGittos/~4/rsEJ1NERJ9E" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.timgittos.com/jquery-context-menu-unbind-click-fix/feed</wfw:commentRss>
		<slash:comments>19</slash:comments>
		<feedburner:origLink>http://www.timgittos.com/jquery-context-menu-unbind-click-fix?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=jquery-context-menu-unbind-click-fix</feedburner:origLink></item>
	</channel>
</rss>
