<?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>W-Shadow.com &#187; Applications</title>
	<atom:link href="http://w-shadow.com/blog/category/applications/feed/" rel="self" type="application/rss+xml" />
	<link>http://w-shadow.com</link>
	<description>Slightly Advanced Computer Stuff (and some magic)</description>
	<lastBuildDate>Thu, 02 Sep 2010 11:04:00 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>micro-tweet &#8211; The Twitter Client That Fits In a Tweet</title>
		<link>http://w-shadow.com/blog/2010/08/10/micro-tweet/</link>
		<comments>http://w-shadow.com/blog/2010/08/10/micro-tweet/#comments</comments>
		<pubDate>Tue, 10 Aug 2010 10:55:23 +0000</pubDate>
		<dc:creator>White Shadow</dc:creator>
				<category><![CDATA[Applications]]></category>
		<category><![CDATA[command line]]></category>
		<category><![CDATA[fun]]></category>
		<category><![CDATA[minimalist]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[tweet]]></category>
		<category><![CDATA[twitter client]]></category>

		<guid isPermaLink="false">http://w-shadow.com/?p=1973</guid>
		<description><![CDATA[micro-tweet is an ultra-minimalist Twitter client that fits in a tweet. It can only do two things &#8211; display your friends tweets (one at a time) and post new tweets. It&#8217;s written in Python and works entirely from the command line. Source Code The source code of micro-tweet is exactly 137 characters, which is short [...]]]></description>
			<content:encoded><![CDATA[<p><em>micro-tweet</em> is an ultra-minimalist Twitter client that fits in a tweet. It can only do two things &#8211; display your friends tweets (one at a time) and post new tweets. It&#8217;s written in Python and works entirely from the command line.</p>
<h3>Source Code</h3>
<p>The source code of <em>micro-tweet</em> is exactly 137 characters, which is short enough to fit in a single tweet :</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">sys</span>,twitter <span style="color: #ff7700;font-weight:bold;">as</span> t<span style="color: #66cc66;">;</span>p=<span style="color: #dc143c;">sys</span>.<span style="color: black;">argv</span><span style="color: #66cc66;">;</span>a=t.<span style="color: black;">Api</span><span style="color: black;">&#40;</span><span style="color: #66cc66;">*</span>p<span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span>:<span style="color: #ff4500;">3</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">;</span>m=a.<span style="color: black;">GetFriendsTimeline</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">;</span>print m.<span style="color: #dc143c;">user</span>.<span style="color: black;">name</span>+<span style="color: #483d8b;">':'</span>,m.<span style="color: black;">text</span><span style="color: #66cc66;">;</span>p<span style="color: black;">&#91;</span><span style="color: #ff4500;">3</span>:<span style="color: black;">&#93;</span> <span style="color: #ff7700;font-weight:bold;">and</span> a.<span style="color: black;">PostUpdate</span><span style="color: black;">&#40;</span>p<span style="color: black;">&#91;</span><span style="color: #ff4500;">3</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span></pre></div></div>

<h3>Installation</h3>
<ol>
<li><a href="http://www.python.org/">Install Python</a>.</li>
<li>Install the <a href="http://cheeseshop.python.org/pypi/simplejson">simplejson</a> library.</li>
<li>Install the <a href="http://code.google.com/p/python-twitter/">python-twitter</a> library.</li>
<li>Copy the client source code (above) and paste it into a new file. Save it as &#8220;micro-tweet.py&#8221;.</li>
</ol>
<h3>Usage</h3>
<p>To run the client, execute micro-tweet.py using the Python interpreter and pass your Twitter username and password as the script arguments. This will output the latest tweet from your friends time line:</p>

<div class="wp_syntax"><div class="code"><pre class="shell" style="font-family:monospace;">python micro-tweet.py username password</pre></div></div>

<p>To post a status update, pass the tweet text as the third script argument. The following example will again output the latest tweet from your friends time line <em>and</em> post &#8220;Your tweet here!&#8221; (sans quotes) to Twitter:</p>

<div class="wp_syntax"><div class="code"><pre class="shell" style="font-family:monospace;">python micro-tweet.py username password &quot;Your tweet here!&quot;</pre></div></div>

<p>Note that the tweet text needs to be enclosed in quotes for it to be posted properly. Use "double quotes" on Windows and 'single quotes' on *nix-like systems. You will not receive any confirmation as to whether your tweet was posted successfully or not. To check, visit twitter.com or fire up a different Twitter client.</p>
<h3>Why micro-tweet?</h3>
<p>Just for fun <img src='http://w-shadow.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>micro-tweet was a little project I did over the weekend. The goal was to see if I could squeeze the essential features of a &#8220;real&#8221; Twitter client &#8211; reading and posting tweets &#8211; into less than 140 characters. It also served as a nice work-out for my rusty Python skills. </p>
<p>And yes, I&#8217;m aware that using a pre-existing library to interface with the Twitter API might be considered &#8220;cheating&#8221;, but it would be downright impossible to fit the script into the size constraints without it. The API endpoint URLs alone would probably be long enough to push the script over the limit.</p>
<hr/>Copyright &copy; 2010 <strong><a href="http://w-shadow.com">W-Shadow.com</a></strong>. This Feed is for personal non-commercial use only. If you are not reading this material in your news aggregator, the site you are looking at is guilty of copyright infringement.]]></content:encoded>
			<wfw:commentRss>http://w-shadow.com/blog/2010/08/10/micro-tweet/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Bookmarklet Combiner</title>
		<link>http://w-shadow.com/blog/2010/06/02/bookmarklet-combiner/</link>
		<comments>http://w-shadow.com/blog/2010/06/02/bookmarklet-combiner/#comments</comments>
		<pubDate>Wed, 02 Jun 2010 11:31:10 +0000</pubDate>
		<dc:creator>White Shadow</dc:creator>
				<category><![CDATA[Applications]]></category>
		<category><![CDATA[bookmark]]></category>
		<category><![CDATA[bookmark bar]]></category>
		<category><![CDATA[bookmarklets]]></category>
		<category><![CDATA[favelet]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[web browser]]></category>
		<category><![CDATA[web development]]></category>
		<category><![CDATA[webapps]]></category>

		<guid isPermaLink="false">http://w-shadow.com/?p=1858</guid>
		<description><![CDATA[I love bookmarklets. Over time, I have accumulated a sizable collection of bookmarklets ranging from development tools (yay for ReCSS!) to great little utilities like Readability. Chances are that some of you have, too. I also like to keep my browser window trim and slim, and a crowded bookmark bar is definitely not conducive to [...]]]></description>
			<content:encoded><![CDATA[<p>I love bookmarklets. Over time, I have accumulated a sizable collection of bookmarklets ranging from <a href="http://www.webresourcesdepot.com/15-must-have-bookmarklets-for-web-designers-and-developers/">development tools</a> (yay for <a href="http://dmachi.dojotoolkit.org/recss.html">ReCSS</a>!) to great little utilities like <a href="http://lab.arc90.com/experiments/readability/">Readability</a>. Chances are that some of you have, too.</p>
<p>I also like to keep my browser window trim and slim, and a crowded bookmark bar is definitely not conducive to that. Therefore, I have created a web app that lets you combine multiple bookmarklets into one. The combined bookmarklet can be configured either to display a pop-up menu of the input bookmarklets, or to automatically run them all.</p>
<p>Behold, the <a href="http://w-shadow.com/bookmarklet-combiner/">Bookmarklet Combiner</a>:</p>
<p><a href="http://w-shadow.com/bookmarklet-combiner/"></a><a href="http://w-shadow.com/bookmarklet-combiner/"><img style=' display: block; margin-right: auto; margin-left: auto;'  class="aligncenter size-full wp-image-1867" title="Bookmarklet Combiner screenshot" src="http://w-shadow.com/wp-content/uploads/2010/06/Bookmarklet-Combiner-screenshot-smaller.png" alt="Bookmarklet Combiner screenshot" width="410" height="460" /></a></p>
<p>And below is the combined bookmarklet that I was working on when I took this screenshot. Note that it may not work properly in IE.</p>
<p style="text-align: center;"><a title="Dev Tools" href="javascript:(function(n,g,q,c,f)%7Bvar%20s=document,l=s.onclick,h=%22ws_cmbm-%22+f,b=s.getElementById(h),d=%22ws_cmbms-%22+f,p=s.getElementById(d),e=null,o,a=%7Btl:%7Bleft:%2210px%22,top:%2210px%22%7D,tr:%7Bright:%2210px%22,top:%2210px%22%7D,bl:%7Bleft:%2210px%22,bottom:%2210px%22%7D,br:%7Bright:%2210px%22,bottom:%2210px%22%7D%7D,k,m=%22.ws_cmbmc%7Bposition:fixed;z-index:1001;width:200px;display:block;visibility:hidden;border:1px%20solid%20#b0b0b0;background:#fff;padding:3px%200%203px%203px;text-align:left;border-radius:3px;-moz-border-radius:3px;-webkit-border-radius:3px;box-shadow:2px%202px%203px%20#777;-moz-box-shadow:2px%202px%203px%20#777;-webkit-box-shadow:2px%202px%203px%20#777;%7D.ws_cmbmc%20a%7Bdisplay:block;float:left;margin:0;width:191px;border:none;padding:8px%200%208px%206px;background:#fff;color:black;text-decoration:none;font:normal%20normal%20normal%2012px/100%25%20Verdana,sans-serif;letter-spacing:normal;word-spacing:normal;%7D.ws_cmbmc%20a:hover%7Bbackground:#a0a0a0;color:white;border:none;text-decoration:none;font:normal%20normal%20normal%2012px/100%25%20Verdana,sans-serif;letter-spacing:normal;word-spacing:normal;%7D%22;function%20r()%7Bb.style.visibility=%22hidden%22%7Dfunction%20j()%7Bb.style.visibility=%22visible%22%7Dif(b)%7Bif(b.style.visibility==%22visible%22)%7Br()%7Delse%7Bj()%7Dreturn%7Dif(!p)%7Bm=m.replace(/.ws_cmbmc/g,%22#%22+h);p=s.createElement(%22style%22);p.type=%22text/css%22;p.id=d;p.appendChild(s.createTextNode(m));s.getElementsByTagName(%22head%22)%5B0%5D.appendChild(p)%7Db=s.createElement(%22div%22);b.setAttribute(%22id%22,h);b.className=%22ws_cmbmc%22;for(o=0;o%3Cn.length;o++)%7Be=s.createElement(%22a%22);e.appendChild(s.createTextNode(n%5Bo%5D.title));e.setAttribute(%22href%22,n%5Bo%5D.url);e.onclick=(function(i)%7Bif(q)%7Br()%7D%7D);b.appendChild(e)%7Ds.getElementsByTagName(%22body%22)%5B0%5D.appendChild(b);if(a.hasOwnProperty(g))%7Bfor(k%20in%20a%5Bg%5D)%7Bb.style%5Bk%5D=a%5Bg%5D%5Bk%5D%7D%7Delse%7Bif(g==%22c%22)%7Bb.style.left=Math.round((window.innerWidth-b.offsetWidth)/2)+%22px%22;b.style.top=Math.round((window.innerHeight-b.offsetHeight)/2)+%22px%22%7D%7Dif(c)%7Bs.onclick=(function()%7Br();if(typeof%20l==%22function%22)%7Bl()%7D%7D);b.onclick=(function(i)%7Bi.stopPropagation()%7D)%7Dj()%7D)(%5B%7Btitle:%22Aardvark%22,url:%22javascript:document.getElementsByTagName(%5Cx27head%5Cx27)%5B0%5D.appendChild(document.createElement(%5Cx27script%5Cx27)).setAttribute(%5Cx27src%5Cx27,%5Cx27http://www.karmatics.com/aardvark/bookmarklet.js%5Cx27)%22%7D,%7Btitle:%22Edit%20Any%20Website%22,url:%22javascript:document.body.contentEditable=%5Cx27true%5Cx27;%2520document.designMode=%5Cx27on%5Cx27;%2520void%25200%22%7D,%7Btitle:%22Favelet%20Suite%22,url:%22javascript:s=document.body.appendChild(document.createElement(%5Cx27script%5Cx27));s.id=%5Cx27fs%5Cx27;s.language=%5Cx27javascript%5Cx27;void(s.src=%5Cx27http://slayeroffice.com/tools/suite/suite.js%5Cx27);%22%7D,%7Btitle:%22Grid-Rule-Unit-Crosshair%22,url:%22javascript:function%2520fnStartDesign(sUrl)%2520%7Bvar%2520nScript%2520=%2520document.createElement(%5Cx27script%5Cx27);nScript.setAttribute(%5Cx27language%5Cx27,%5Cx27JavaScript%5Cx27);nScript.setAttribute(%5Cx27src%5Cx27,sUrl);document.body.appendChild(nScript);%7DfnStartDesign(%5Cx27http://www.sprymedia.co.uk/design/design/media/js/design-loader.js%5Cx27);%22%7D,%7Btitle:%22ReCSS%22,url:%22javascript:void(function()%7Bvar%20i,a,s;a=document.getElementsByTagName(%5Cx27link%5Cx27);for(i=0;i%3Ca.length;i++)%7Bs=a%5Bi%5D;if(s.rel.toLowerCase().indexOf(%5Cx27stylesheet%5Cx27)%3E=0&amp;&amp;s.href)%20%7Bvar%20h=s.href.replace(/(&amp;%7C%255C?)forceReload=%5C%5Cd+/,%5Cx27%5Cx27);s.href=h+(h.indexOf(%5Cx27?%5Cx27)%3E=0?%5Cx27&amp;%5Cx27:%5Cx27?%5Cx27)+%5Cx27forceReload=%5Cx27+(new%20Date().valueOf())%7D%7D%7D)();%22%7D,%7Btitle:%22W3C%20CSS%20Validator%22,url:%22javascript:void(location=%5Cx27http://jigsaw.w3.org/css-validator/validator?profile=css21&amp;warning=0&amp;uri=%5Cx27+escape(location))%22%7D,%7Btitle:%22W3C%20Markup%20Validator%22,url:%22javascript:void(location=%5Cx27http://validator.w3.org/check?verbose=1&amp;uri=%5Cx27+escape(location))%22%7D,%7Btitle:%22WTFramework%22,url:%22javascript:(function()%7Bvar%20m,n=%5B%5D,j,c,t=document.getElementById(%5Cx22_wtframework%5Cx22),q=0;c=function()%7Bdocument.body.removeChild(m);%7D;if(t)%7Bdocument.body.removeChild(t);return;%7Dvar%20b=%5B%5Cx22MooTools.version%5Cx22,%5Cx22MooTools.More.version%5Cx22,%5Cx22base2.version%5Cx22,%5Cx22dojo.version%5Cx22,%5Cx22Ext.version%5Cx22,%5Cx22jQuery.fn.jquery%5Cx22,%5Cx22$.ui.version%5Cx22,%5Cx22MochiKit.MochiKit.VERSION%5Cx22,%5Cx22Prototype.Version%5Cx22,%5Cx22Scriptaculous.Version%5Cx22,%5Cx22YAHOO.VERSION%5Cx22,%5Cx22S2.Version%5Cx22%5D;var%20r=%5B%5Cx22MooTools%20Core%5Cx22,%5Cx22MooTools%20More%5Cx22,%5Cx22Base2%5Cx22,%5Cx22Dojo%5Cx22,%5Cx22Ext%20JS%5Cx22,%5Cx22jQuery%5Cx22,%5Cx22jQuery%20UI%5Cx22,%5Cx22MochiKit%5Cx22,%5Cx22Prototype%5Cx22,%5Cx22Script.aculo.us%5Cx22,%5Cx22Yahoo%20UI%5Cx22,%5Cx22Scripty2%5Cx22%5D;var%20k=%7Bcursor:%5Cx22pointer%5Cx22,textAlign:%5Cx22left%5Cx22,padding:%5Cx228px%2010px%5Cx22,margin:%5Cx220%200%205px%5Cx22,listStyle:%5Cx22none%5Cx22,font:%5Cx22bold%2011px%20Lucida%20Grande%5Cx22,backgroundColor:%5Cx22rgba(0,%200,%200,%200.7)%5Cx22,color:%5Cx22#fff%5Cx22,BorderRadius:%5Cx225px%5Cx22,MozBorderRadius:%5Cx225px%5Cx22,WebkitBorderRadius:%5Cx225px%5Cx22,borderTop:%5Cx22solid%201px%20rgba(255,%20255,%20255,%200.4)%5Cx22,borderLeft:%5Cx22solid%201px%20rgba(0,%200,%200,%200.8)%5Cx22,borderRight:%5Cx22solid%201px%20rgba(0,%200,%200,%200.8)%5Cx22,borderBottom:%5Cx22solid%201px%20#000%5Cx22,textShadow:%5Cx220%201px%200%20#000%5Cx22,BoxShadow:%5Cx220%20-1px%200%20#000%5Cx22,MozBoxShadow:%5Cx220%20-1px%200%20#000%5Cx22,WebkitBoxShadow:%5Cx220%20-1px%200%20#000%5Cx22,cssFloat:%5Cx22right%5Cx22,clear:%5Cx22both%5Cx22%7D;var%20l=%7Bwidth:%5Cx22190px%5Cx22,position:%5Cx22fixed%5Cx22,padding:%5Cx220%5Cx22,margin:%5Cx220%5Cx22,right:%5Cx2210px%5Cx22,top:%5Cx2210px%5Cx22,zIndex:30000%7D;var%20e=%7Bonclick:c,id:%5Cx22_wtframework%5Cx22%7D;m=document.createElement(%5Cx22ul%5Cx22);for(var%20d%20in%20e)%7Bm%5Bd%5D=e%5Bd%5D;%7Dfor(var%20h%20in%20l)%7Bm.style%5Bh%5D=l%5Bh%5D;%7Ddocument.body.appendChild(m);var%20f=function(v,i)%7Bn=document.createElement(%5Cx22li%5Cx22);n.innerHTML=v+(i?%5Cx22%20(%5Cx22+i+%5Cx22)%5Cx22:%5Cx22%5Cx22);for(var%20u%20in%20k)%7Bn.style%5Bu%5D=k%5Bu%5D;%7Dm.appendChild(n);%7D;for(var%20a%20in%20b)%7Bif(b.hasOwnProperty(a))%7Bvar%20g=b%5Ba%5D.split(%5Cx22.%5Cx22),o=window;for(var%20p%20in%20g)%7Bif(g.hasOwnProperty(p))%7Bo=o&amp;&amp;o%5Bg%5Bp%5D%5D;%7D%7Dif(o)%7Bf(r%5Ba%5D,o);q++;%7D%7D%7Dif(q%3C1)%7Bf(%5Cx22No%20framework%20detected%5Cx22);%7D%7D)();%22%7D%5D,%22tl%22,true,true,1275469002616)"><strong>Dev Tools</strong></a></p>
<h3>Usage Instructions</h3>
<p>Here&#8217;s how to create your own combined bookmarklet :</p>
<ol>
<li>Enter the bookmarklets that you want to combine.
<ol>
<li>Open the homepage of the bookmarklet that you want to add to the combination.</li>
<li>Right-click on the bookmarklet and select &#8220;Copy link address&#8221; (or the equivalent) from the pop-up menu.</li>
<li>Paste the copied URL in the combiner&#8217;s &#8220;URL&#8221; box.</li>
<li>Enter the bookmarklet name in the corresponding &#8220;Title&#8221; box.</li>
<li>Repeat steps 1. &#8211; 4. for all other bookmarklets.</li>
</ol>
</li>
<li>Select the combination type.</li>
<li>Enter the name to use for the combined bookmarklet.</li>
<li>Drag the combined bookmarklet from the &#8220;Result&#8221;  box to your bookmark bar.</li>
</ol>
<p>The bookmarklet in the &#8220;Result&#8221; box is updated automatically whenever you modify the inputs. You don&#8217;t need to click or press anything to start the combination process.</p>
<p><strong>Tip :</strong> You can also enter a standard HTTP URL in the &#8220;URL&#8221; box. If the combined bookmarklet is set to display a menu, the corresponding menu entry will be a simple link. If it&#8217;s set to &#8220;Run all&#8221;, the combined bookmarklet will attempt to open each URL in a new window/tab. However, this only works in browsers that don&#8217;t block pop-ups created by bookmarklets.</p>
<p><strong>Disclaimer :</strong> The Bookmarklet Combiner does not work properly in Internet Explorer. Also, permanently saving bookmarklets on the server is not yet possible.</p>
<hr/>Copyright &copy; 2010 <strong><a href="http://w-shadow.com">W-Shadow.com</a></strong>. This Feed is for personal non-commercial use only. If you are not reading this material in your news aggregator, the site you are looking at is guilty of copyright infringement.]]></content:encoded>
			<wfw:commentRss>http://w-shadow.com/blog/2010/06/02/bookmarklet-combiner/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>Add Fuzzy Timestamps To Your Blog</title>
		<link>http://w-shadow.com/blog/2010/03/02/fuzzy-timestamp-plugin/</link>
		<comments>http://w-shadow.com/blog/2010/03/02/fuzzy-timestamp-plugin/#comments</comments>
		<pubDate>Tue, 02 Mar 2010 18:54:02 +0000</pubDate>
		<dc:creator>White Shadow</dc:creator>
				<category><![CDATA[Applications]]></category>
		<category><![CDATA[Blogging]]></category>
		<category><![CDATA[datetime]]></category>
		<category><![CDATA[fuzzy date]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[jQuery plugins]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[time ago]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[WordPress plugins]]></category>

		<guid isPermaLink="false">http://w-shadow.com/?p=1717</guid>
		<description><![CDATA[I recently stumbled upon a great jQuery plugin called &#8220;timeago&#8221; that lets you easily create fuzzy timestamps (e.g. &#8220;5 minutes ago&#8221;, &#8220;about 2 months ago&#8221;, etc). So I wrote a quickie WP plugin that you can use to add this neat feature to your blog. About Basically, with this plugin you can insert a little [...]]]></description>
			<content:encoded><![CDATA[<p>I recently stumbled upon a great jQuery plugin called &#8220;<a href="http://timeago.yarp.com/">timeago</a>&#8221; that lets you easily create fuzzy timestamps (e.g. &#8220;5 minutes ago&#8221;, &#8220;about 2 months ago&#8221;, etc). So I wrote a quickie WP plugin that you can use to add this neat feature to your blog.</p>
<h3>About</h3>
<p>Basically, with this plugin you can insert a little piece of code into your theme and get nice fuzzy timestamps for your posts/pages (see the <em>Usage</em> section below for details). The timestamps will even update automatically &#8211; that is, if you open a page that has a timestamp saying &#8220;Posted 1 minute ago&#8221; and wait 10 minutes without reloading the page, the timestamp will then say &#8220;Posted 11 minutes ago&#8221;. People who have JavaScript disabled will see normal, non-fuzzy timestamps instead.</p>
<p>Here&#8217;s a screenshot showing several example timestamps :</p>
<p><img style=' display: block; margin-right: auto; margin-left: auto;'  class="aligncenter size-full wp-image-1719" title="Fuzzy timestamps" src="http://w-shadow.com/wp-content/uploads/2010/03/fuzzy-timestamp-screenshots.png" alt="Fuzzy Timestamp plugin screenshots" width="385" height="449" /></p>
<p>Note : The calendar icon is not included with the plugin. The site in the screenshot is using the <a href="http://wordpress.org/extend/themes/inove">iNove</a> theme which adds these cute icons to post timestamps.</p>
<h3>Download</h3>
<p><a href="http://w-shadow.com/files/fuzzy-timestamp.zip"><strong>fuzzy-timestamp.zip</strong></a> (4 KB)</p>
<p>Requirements :</p>
<ul>
<li>WordPress 2.9+</li>
<li>PHP 5</li>
</ul>
<h3>Usage</h3>
<p>Once you&#8217;ve installed and activated the plugin, go to the theme editor and insert <code>&lt;?php do_action('fuzzy_timestamp'); ?&gt;</code> whereever you want to use a fuzzy timestamp. For example, to use fuzzy timestamps on single post pages, open the single.php template file and replace any the WordPress loop; i.e. you can&#8217;t use to change the comment timestamps (yet).</p>
<p>You can also pass a second parameter to the do_action() function to specify the datetime format for the tool-tip that shows up when you mouse over a fuzzy timestamp (people who have JavaScript disabled will also see the timestamp in this format). The parameter syntax is equivalent to that used by the the_time() template function.</p>
<p>For example, if your theme displays the timestamps using code like this :</p>
<p><code>&lt;?php the_time('F jS, Y'); ?&gt;</code></p>
<p>You can add the &#8221;F jS, Y&#8217; bit to the plugin&#8217;s code to use the same datetime format for the tool-tips and the no-JS fallback :</p>
<p><code>&lt;?php do_action('fuzzy_timestamp', 'F jS, Y'); ?&gt;</code></p>
<p>The timeago script also supports i18n/different languages, but I left that feature out to avoid over-complicating the plugin. Let me know if you&#8217;d like to see it added.</p>
<hr/>Copyright &copy; 2010 <strong><a href="http://w-shadow.com">W-Shadow.com</a></strong>. This Feed is for personal non-commercial use only. If you are not reading this material in your news aggregator, the site you are looking at is guilty of copyright infringement.]]></content:encoded>
			<wfw:commentRss>http://w-shadow.com/blog/2010/03/02/fuzzy-timestamp-plugin/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Track Your AdSense Earnings On Your Desktop</title>
		<link>http://w-shadow.com/blog/2010/02/16/adsensor-patch/</link>
		<comments>http://w-shadow.com/blog/2010/02/16/adsensor-patch/#comments</comments>
		<pubDate>Tue, 16 Feb 2010 18:44:04 +0000</pubDate>
		<dc:creator>White Shadow</dc:creator>
				<category><![CDATA[Applications]]></category>
		<category><![CDATA[adsense]]></category>
		<category><![CDATA[Google AdSense]]></category>
		<category><![CDATA[Konfabulator]]></category>
		<category><![CDATA[open source]]></category>
		<category><![CDATA[patch]]></category>
		<category><![CDATA[widget]]></category>
		<category><![CDATA[Yahoo Widgets]]></category>

		<guid isPermaLink="false">http://w-shadow.com/?p=1682</guid>
		<description><![CDATA[There are two things that I do every morning, right after turning on the computer. First, I read the latest strip of Schlock Mercenary. Then I check my Google AdSense earnings for the previous day. It&#8217;s the perfect mix of business and pleasure, and a great way to start a new day. But enough about [...]]]></description>
			<content:encoded><![CDATA[<p>There are two things that I do every morning, right after turning on the computer. First, I read the latest strip of <a href="http://www.schlockmercenary.com/">Schlock Mercenary</a>. Then I check my Google AdSense earnings for the previous day. It&#8217;s the perfect mix of business and pleasure, and a great way to start a new day.</p>
<p>But enough about my habits &#8211; lets talk convenience. Manually checking your AdSense earnings is not very convenient &#8211; you need to navigate to their site, log in, pick the time period you want to examine from the drop-down&#8230; The process is simple, but if you religiously check your stats several times per day (like I do) it can get tedious. Wouldn&#8217;t it be nice if there was some kind of a widget that would let you see all of your vital AdSense stats at a glance?</p>
<p>Turns out there are several, but most of them don&#8217;t work (any more) and are not supported by their authors. So I took the widget that looked the most promising &#8211; <a href="http://www.mvnet.fi/index.php?osio=Tietokoneet&amp;sivu=Widgetit_-_AdSensor">AdSensor</a> &#8211; and fixed it. You can download the widget below.</p>
<h3>What Is AdSensor?</h3>
<p><img style=' float: right; padding: 4px; margin: 0 0 2px 7px;'  class="size-full wp-image-1685 alignright" title="AdSensor screenshot" src="http://w-shadow.com/wp-content/uploads/2010/02/AdSensor-screenshot.png" alt="AdSensor 2.9 screenshot" width="212" height="216" />AdSensor is a widget that regularly queries your Google AdSense account and displays up-to-date information about earnings and clicks in the form of a compact table. Update frequency is configurable. The widget also comes with four beautiful skins, works both on Windows and Mac, and is available two different languages : English and Finnish. The widget requires the <a href="http://widgets.yahoo.com/">Yahoo! Widgets</a> framework.</p>
<p>You can find more information about this widget <a href="http://www.mvnet.fi/index.php?osio=Tietokoneet&amp;sivu=Widgetit_-_AdSensor">on the author&#8217;s site</a>.</p>
<h3>Download</h3>
<p><strong><a href="http://w-shadow.com/files/AdSensor.widget">Download AdSensor 2.9 &#8211; the patched version<br />
</a></strong>File size : 196 KB. Requires the <a href="http://widgets.yahoo.com/">Yahoo! Widgets</a> framework.</p>
<p>If you&#8217;re having problems with the above link, <a href="http://w-shadow.com/files/AdSensor.zip">try the zipped version</a>.</p>
<h3>Patch Notes</h3>
<p>My version is functionally almost completely identical to the original AdSensor widget. Most of the changes were internal :</p>
<ul>
<li>The original login routine relied on cookie-parsing magic and a hard-coded list of form field values. I added a simple regex-based parser that dynamically extracts the actual fields from the login form. This way, there&#8217;s a good chance the widget will continue working if Google decides to add a new hidden field to the form.</li>
<li>I also rewrote the regex that extracts the data on earnings and clicks from Google AdSense reports. For reasons unknown, the original regex would cause the widget to hang permanently on my system.</li>
<li>Finally, I made the earnings column display the right currency symbol (it can be either dollars or euros, depending on your country of residence and account settings).</li>
</ul>
<hr/>Copyright &copy; 2010 <strong><a href="http://w-shadow.com">W-Shadow.com</a></strong>. This Feed is for personal non-commercial use only. If you are not reading this material in your news aggregator, the site you are looking at is guilty of copyright infringement.]]></content:encoded>
			<wfw:commentRss>http://w-shadow.com/blog/2010/02/16/adsensor-patch/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>How To Disable Google Realtime Search</title>
		<link>http://w-shadow.com/blog/2009/12/14/disable-google-realtime-search/</link>
		<comments>http://w-shadow.com/blog/2009/12/14/disable-google-realtime-search/#comments</comments>
		<pubDate>Mon, 14 Dec 2009 15:55:26 +0000</pubDate>
		<dc:creator>White Shadow</dc:creator>
				<category><![CDATA[Applications]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[Google Realtime Search]]></category>
		<category><![CDATA[google results]]></category>
		<category><![CDATA[greasemonkey script]]></category>
		<category><![CDATA[opera]]></category>
		<category><![CDATA[twitter]]></category>
		<category><![CDATA[userscript]]></category>

		<guid isPermaLink="false">http://w-shadow.com/?p=1549</guid>
		<description><![CDATA[A week ago, Google introduced real-time search &#8211; a new feature that displays live updates from sites like Twitter and FriendFeed as part of the normal search results. Reactions were generally positive, but, as multiple users noted, there was one thing missing &#8211; an &#8220;off&#8221; button. You could pause the live updates, but not get [...]]]></description>
			<content:encoded><![CDATA[<p>A week ago, <a href="http://googleblog.blogspot.com/2009/12/relevance-meets-real-time-web.html">Google introduced real-time search</a> &#8211; a new feature that displays live updates from sites like Twitter and FriendFeed as part of the normal search results. Reactions were generally positive, but, as multiple users noted, there was one thing missing &#8211; an &#8220;off&#8221; button. You could pause the live updates, but not get rid of them entirely &#8211; until today. Today, I present you a way to remove the realtime search widget from your Google results.</p>
<p><a href="http://w-shadow.com/wp-content/uploads/2009/12/Disable-Google-Realtime-Search.png"><img style=' display: block; margin-right: auto; margin-left: auto;'  class="aligncenter size-medium wp-image-1551" title="Disable Google Realtime Search" src="http://w-shadow.com/wp-content/uploads/2009/12/Disable-Google-Realtime-Search-300x188.png" alt="Disable Google Realtime Search" width="300" height="188" /></a></p>
<p>I&#8217;ve written a Greasemonkey script that hides the &#8220;Latest results for &#8220;keyword&#8221;" box. It also suspends the live updates, preventing Google from wasting your bandwidth needlessly. Just install this userscript, and you won&#8217;t see the real-time results again.</p>
<p><a href="http://w-shadow.com/files/disable_realtime_search.user.js"><strong>Install &#8220;Disable Google Realtime Search&#8221;</strong></a> (2 KB)</p>
<p>Compatible browsers :</p>
<ul>
<li>Firefox + the <a href="https://addons.mozilla.org/en-US/firefox/addon/748">Greasemonkey extension</a>.</li>
<li>Opera (<a href="http://www.opera.com/browser/tutorials/userjs/using/"></a>see <a href="http://www.opera.com/browser/tutorials/userjs/using/">userscripts in Opera</a>).</li>
<li>Google Chrome 4.0</li>
</ul>
<p><em>Sidenote </em>: Even with this script installed, you can still access the realtime results directly by clicking on the &#8220;Latest updates&#8221; link in search options.</p>
<hr/>Copyright &copy; 2010 <strong><a href="http://w-shadow.com">W-Shadow.com</a></strong>. This Feed is for personal non-commercial use only. If you are not reading this material in your news aggregator, the site you are looking at is guilty of copyright infringement.]]></content:encoded>
			<wfw:commentRss>http://w-shadow.com/blog/2009/12/14/disable-google-realtime-search/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Deframe &#8211; Greasemonkey Script That Removes Frames &amp; Toolbars</title>
		<link>http://w-shadow.com/blog/2009/12/10/deframe-remove-frames-and-toolbars/</link>
		<comments>http://w-shadow.com/blog/2009/12/10/deframe-remove-frames-and-toolbars/#comments</comments>
		<pubDate>Thu, 10 Dec 2009 19:00:04 +0000</pubDate>
		<dc:creator>White Shadow</dc:creator>
				<category><![CDATA[Applications]]></category>
		<category><![CDATA[firefox]]></category>
		<category><![CDATA[frame breaker]]></category>
		<category><![CDATA[greasemonkey script]]></category>
		<category><![CDATA[opera]]></category>
		<category><![CDATA[remove frame]]></category>
		<category><![CDATA[remove toolbar]]></category>
		<category><![CDATA[stumbleupon toolbar]]></category>
		<category><![CDATA[userscript]]></category>

		<guid isPermaLink="false">http://w-shadow.com/?p=1536</guid>
		<description><![CDATA[Deframe is a Greasemonkey script that can remove frames and toolbars from (almost) any website. For example, it can remove the StumbleUpon toolbar that&#8217;s displayed on all su.pr links, get rid of the Ow.ly bar, bust the frames that some link sharing sites use on outgoing links, and so on. Deframe supports most frame-based websites [...]]]></description>
			<content:encoded><![CDATA[<p><em>Deframe</em> is a Greasemonkey script that can remove frames and toolbars from (almost) any website. For example, it can remove the StumbleUpon toolbar that&#8217;s displayed on all su.pr links, get rid of the Ow.ly bar, bust the frames that some link sharing sites use on outgoing links, and so on. <em>Deframe</em> supports most frame-based websites and toolbars out of the box.</p>
<h3>Installation</h3>
<p>This userscript is compatible both with Greasemonkey/Firefox and Opera.</p>
<p><strong>For Firefox :</strong></p>
<ol>
<li><a href="https://addons.mozilla.org/en-US/firefox/addon/748">Get Greasemonkey</a>.</li>
<li><a href="http://w-shadow.com/files/deframe.user.js"><strong>Install Deframe</strong></a>.</li>
<li>Add the sites you want to use it with to the &#8220;Included Pages&#8221; list in Greasemonkey. To access this list, right-click the GM icon, click <em>Manage User Scripts&#8230;</em> and select <em>Deframe</em> from the script listing.</li>
</ol>
<p><strong>For Opera :</strong></p>
<ol>
<li>Go to <em>Tools &gt; Preferences &gt; Advanced &gt; Content &gt; JavaScript options</em>, and select the directory where you will put your User JavaScript files. I recommend creating a new directory for this purpose.</li>
<li><a href="http://w-shadow.com/files/deframe.user.js">Download deframe.user.js</a> and place it in that directory.</li>
<li>Open deframe.user.js in a text editor, e.g. Notepad.</li>
<li>Add a new <a href="http://wiki.greasespot.net/Include_and_exclude_rules">include rule</a> for each site that you want to use the script with. Here are a few examples :
<pre>// @include        http://www.stumbleupon.com/su/*
// @include        http://ow.ly/*
// @include        http://www.linkive.com/home/browser/*</pre>
</li>
<li>Save and close the file. Opera will automatically load and execute it the next time you navigate to a new page.</li>
</ol>
<h3>How It Works</h3>
<p>Most other frame-busting and toolbar-killing scripts rely on site-specific algorithms. They&#8217;re easy to write, but inflexible and easily broken by small changes in the site&#8217;s design or layout. The only way to adapt them to other sites/toolbars is to manually edit the source code.<em></em></p>
<p><em>Deframe</em> is different &#8211; instead of a hard-coded list or per-site algorithms, it uses a very simple yet effective heuristic to identify the frame that&#8217;s most likely to contain the actual content of the page.  Here&#8217;s the algorithm in a nutshell : find the biggest visible frame that contains a page from a different domain. Then redirect the browser to the frame&#8217;s source URL.</p>
<p>Despite the apparent simplicity, this heuristic actually works very well. It correctly detected the content frame on all the social bookmarking links and assorted other sites that I threw at it. If you do find a site that it doesn&#8217;t work with, feel free to let me know by leaving a comment below.</p>
<hr/>Copyright &copy; 2010 <strong><a href="http://w-shadow.com">W-Shadow.com</a></strong>. This Feed is for personal non-commercial use only. If you are not reading this material in your news aggregator, the site you are looking at is guilty of copyright infringement.]]></content:encoded>
			<wfw:commentRss>http://w-shadow.com/blog/2009/12/10/deframe-remove-frames-and-toolbars/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Auto-Highlight New Items With The Newslight UserScript</title>
		<link>http://w-shadow.com/blog/2009/10/12/newslight-greasemonkey-script/</link>
		<comments>http://w-shadow.com/blog/2009/10/12/newslight-greasemonkey-script/#comments</comments>
		<pubDate>Mon, 12 Oct 2009 14:46:20 +0000</pubDate>
		<dc:creator>White Shadow</dc:creator>
				<category><![CDATA[Applications]]></category>
		<category><![CDATA[bookmarklet]]></category>
		<category><![CDATA[DOM]]></category>
		<category><![CDATA[firefox]]></category>
		<category><![CDATA[greasemonkey script]]></category>
		<category><![CDATA[highlight changes]]></category>
		<category><![CDATA[highlight new items]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[localStorage]]></category>
		<category><![CDATA[userscript]]></category>

		<guid isPermaLink="false">http://w-shadow.com/?p=1333</guid>
		<description><![CDATA[Newslight is a Greasemonkey script that you can use to automatically highlight new posts, new blog comments, recent product listings or any other kind of new content that has been added to your favourite website(s) since you last visited. The way it works is simple : when you see a web page you&#8217;d like to [...]]]></description>
			<content:encoded><![CDATA[<p><em>Newslight</em> is a Greasemonkey script that you can use to automatically highlight new posts, new blog comments, recent product listings or any other kind of new content that has been added to your favourite website(s) since you last visited.</p>
<p>The way it works is simple : when you see a web page you&#8217;d like to keep track of (e.g. an interesting forum discussion), click a button to save the current version of that page. Then, when you revisit that page at a later time, simply click another button to instantly highlight all the new text and images that have been added since your previous visit. You can also configure the script to do one or both of those steps automatically for all pages of a specific site.</p>
<h3>Screenshots</h3>
<div id="attachment_1347" class="wp-caption alignleft" style="width: 310px;  border: 1px solid #dddddd; background-color: #f3f3f3; padding-top: 4px; margin: 10px; text-align:center; float: left;"><a href="http://w-shadow.com/wp-content/uploads/2009/10/Newslight-screenshot1.png"><img class="size-medium wp-image-1347" title="Newslight screenshot : Automatically highlighting a new comment" src="http://w-shadow.com/wp-content/uploads/2009/10/Newslight-screenshot1-300x237.png" alt="Automatically highlighting a new comment" width="300" height="237" /></a><p style=' padding: 0 4px 5px; margin: 0;'  class="wp-caption-text">Highlighting a new comment</p></div>
<div id="attachment_1357" class="wp-caption alignleft" style="width: 310px;  border: 1px solid #dddddd; background-color: #f3f3f3; padding-top: 4px; margin: 10px; text-align:center; float: left;"><a href="http://w-shadow.com/wp-content/uploads/2009/10/Newslight-screenshot-Deviantart.jpg"><img class="size-medium wp-image-1357" title="Newslight screenshot : new images on DeviantArt" src="http://w-shadow.com/wp-content/uploads/2009/10/Newslight-screenshot-Deviantart-300x199.jpg" alt="Highlighting new images" width="300" height="199" /></a><p style=' padding: 0 4px 5px; margin: 0;'  class="wp-caption-text">Highlighting new images</p></div>
<div id="attachment_1350" class="wp-caption alignleft" style="width: 310px;  border: 1px solid #dddddd; background-color: #f3f3f3; padding-top: 4px; margin: 10px; text-align:center; float: left;"><a href="http://w-shadow.com/wp-content/uploads/2009/10/Newslight-screenshot-Reddit.png"><img class="size-medium wp-image-1350  " title="Newslight in action on the Reddit front-page" src="http://w-shadow.com/wp-content/uploads/2009/10/Newslight-screenshot-Reddit-300x198.png" alt="The script doesn't work so great on complex, frequently updated sites. Yet." width="300" height="198" /></a><p style=' padding: 0 4px 5px; margin: 0;'  class="wp-caption-text">The highlighting algorithm doesn&#39;t work that great on complex or frequently updated sites, yet.</p></div>
<div id="attachment_1351" class="wp-caption alignleft" style="width: 310px;  border: 1px solid #dddddd; background-color: #f3f3f3; padding-top: 4px; margin: 10px; text-align:center; float: left;"><a href="http://w-shadow.com/wp-content/uploads/2009/10/Newslight-GM-menu.png"><img class="size-medium wp-image-1351" title="Newslight Greasemonkey menu" src="http://w-shadow.com/wp-content/uploads/2009/10/Newslight-GM-menu-300x94.png" alt="Newslight's Greasemonkey menu" width="300" height="94" /></a><p style=' padding: 0 4px 5px; margin: 0;'  class="wp-caption-text">Newslight&#39;s Greasemonkey menu</p></div>
<h3 style="clear: both;">Download</h3>
<p><a href="http://w-shadow.com/files/newslight/newslight.user.js"><strong>Install Newslight.user.js</strong></a> (15 KB, requires FF 3.5+)</p>
<p>Once installed, you can access the script&#8217; s features by right-clicking the Greasemonkey icon on your status bar and selecting &#8220;User Script Commands&#8230;&#8221; from the pop-up menu :</p>
<ul>
<li><strong>Remember this version of the page</strong> &#8211; stores the current version of the page for later reference.</li>
<li><strong>Highlight changes</strong> &#8211; compares the contents of the current page to the latest saved version and highlights any new text/images. Clicking this again will toggle the highlighting on/off.</li>
<li><strong>Automatically remember pages on example.com</strong> (on/off) &#8211; automatically remember the contents of every page that you visit on this site.</li>
<li><strong>Automatically highlight changes on example.com</strong> (on/off) &#8211; automatically highlight new items on all pages of this site.</li>
</ul>
<p>You can also use these two bookmarklets to quickly access the script&#8217;s main functions without going through the Greasemonkey menu. Just drag them to your bookmark bar :</p>
<ul>
<li><a title="Save the current page state so that it can be used later to highlight changes" href="javascript:if(typeof window.NewslightSavePageState == 'function') { NewslightSavePageState(true); } else { alert('The Newslight userscript is not installed or is disabled!'); }">Remember this page</a></li>
<li><a title="Highlight new items detected on the current page" href="javascript:if(typeof window.NewslightToggleHighlights == 'function') { NewslightToggleHighlights(true); } else { alert('The Newslight userscript is not installed or is disabled!'); }">Highlight changes</a></li>
</ul>
<h3>How It Works</h3>
<p>I&#8217;ll be the first to admit that the highlighting algorithm is very primitive. For example, changing a single word in a paragraph will make the script highlight the entire paragraph, whereas swapping two paragraphs of an article will go completely undetected and un-highlighted. The reason it happens is the way the userscript works : instead of using complex tree manipulation or advanced stuff like revision tracking, it grabs all the text and image nodes from the web page and dumps them into a big lookup table (removing duplicates in the process). Then, when you ask it to highlight changes, it just loads up the aforementioned table and checks the current version of the page against it. Anything that&#8217;s not in the table gets highlighted. The actual algorithm for finding new items takes only a couple dozen lines.</p>
<p>For those interested in the technical details, here&#8217;s a quick run-down :</p>
<ul>
<li>The lookup table is just a simple wrapper around a plain JS object <a href="http://www.quirksmode.org/js/associative.html">being used as an associative array</a>.</li>
<li>The table is encoded in JSON and stored in a <a href="https://developer.mozilla.org/en/DOM/Storage#localStorage">localStorage</a> database (available in FF 3.5 and up). I&#8217;m using the <a href="http://pablotron.org/?cid=1557">PersistJS</a> library to handle the particulars, which should make it easier to port the userscript to other browsers eventually.</li>
<li>I tried various ways of fetching all text nodes from a DOM tree, but using the &#8220;//text()&#8221; XPath expression turned out to be the fastest and most straightforward approach, at least in this case.</li>
<li>Miscellaneous stuff, like adding/removing the CSS classes and showing pop-up notifications, is done either via direct DOM manipulation or jQuery.</li>
</ul>
<p>There&#8217;s certainly a lot of room for improvement &#8211; e.g. configurable highlight colours, converting the script to a proper FF addon,  better UI etc. &#8211; but the inherent simplicity of the algorithm is quite intentional. It&#8217;s not meant to precisely pinpoint new items on a site, but rather to serve as a useful hint as to where you might find them;  an imperfect but handy filter.</p>
<p>Why do it this way? Because determining what counts as new is ultimately an AI-hard problem &#8211; you&#8217;d need software with near-human intelligence to solve it. Sure, you could probably get a decent approximation by devoting a few weeks to research, but I&#8217;d rather have something up and running <em>now</em>, so I can collect some feedback and see if it&#8217;s worth doing that research <img src='http://w-shadow.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<hr/>Copyright &copy; 2010 <strong><a href="http://w-shadow.com">W-Shadow.com</a></strong>. This Feed is for personal non-commercial use only. If you are not reading this material in your news aggregator, the site you are looking at is guilty of copyright infringement.]]></content:encoded>
			<wfw:commentRss>http://w-shadow.com/blog/2009/10/12/newslight-greasemonkey-script/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Simple Fluid Simulation With Cellular Automata</title>
		<link>http://w-shadow.com/blog/2009/09/01/simple-fluid-simulation/</link>
		<comments>http://w-shadow.com/blog/2009/09/01/simple-fluid-simulation/#comments</comments>
		<pubDate>Tue, 01 Sep 2009 19:48:33 +0000</pubDate>
		<dc:creator>White Shadow</dc:creator>
				<category><![CDATA[Applications]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[cellular automata]]></category>
		<category><![CDATA[fluid dynamics]]></category>
		<category><![CDATA[fluid simulation]]></category>
		<category><![CDATA[how to]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Processing]]></category>
		<category><![CDATA[water dynamics]]></category>
		<category><![CDATA[water simulation]]></category>

		<guid isPermaLink="false">http://w-shadow.com/?p=1285</guid>
		<description><![CDATA[Last week I couldn&#8217;t use my regular dev. machine (broken graphics card), so all my WordPress-related plans were on hold. To pass the time, I built a simple water simulation in Processing. Today I&#8217;m going to show you this little application and explain how it works. Online demo and source code are included. Big Words, [...]]]></description>
			<content:encoded><![CDATA[<p>Last week I couldn&#8217;t use my regular dev. machine (broken graphics card), so all my WordPress-related plans were on hold. To pass the time, I built a simple water simulation in <a href="http://processing.org/">Processing</a>. Today I&#8217;m going to show you this little application and explain how it works. Online demo and source code are included.</p>
<h3>Big Words, or The Theoretical Part</h3>
<p>Fluid dynamics is a complex topic. If you so much as <a rel="nofollow" href="http://en.wikipedia.org/wiki/Computational_fluid_dynamics">look it up in Wikipedia</a>, you will be immediately assaulted by integrals, differentials  and other agents of mathematical insanity. To accurately model a fluid you would need a quite an in-depth understanding of physics and calculus. And while that&#8217;s certainly not something one couldn&#8217;t figure out given enough time, &#8220;proper&#8221; fluid simulation is still extremely rare in non-academic applications and games because it&#8217;s <strong>slow</strong>.</p>
<p>One way to create a faster (though less accurate) simulation is by using <a rel="nofollow" href="http://en.wikipedia.org/wiki/Cellular_automata">cellular automata</a> to represent the water. A cellular automaton is basically a grid where each cell can be in one of a finite number of states, plus a set of rules that determine how a cell can change from one state to another. The rules are typically local &#8211; that is, they consider only the current cell and it&#8217;s direct neighbours when determining the new state. During each step of the simulation, you simply loop through the entire grid and apply the rules to each cell.</p>
<p>When simulating water or other fluids it can more appropriate to store a continuous value (e.g. water mass) in each cell, instead of using discrete states.</p>
<h3>CA-Based Water Simulation</h3>
<p>Before we go into details, lets take a look at the promised online demo. It will give you a good idea about what you can achieve with this approach :</p>
<p><a href="http://w-shadow.com/files/water_sim/"><img style=' display: block; margin-right: auto; margin-left: auto;'  class="aligncenter size-large wp-image-1291" title="Click to run the simulation" src="http://w-shadow.com/wp-content/uploads/2009/09/Water-Simulation1-490x513.png" alt="Click to run the simulation" width="490" height="513" /></a> <em>(klicken Sie auf das Bild; Java required)</em></p>
<p>Alright, on to the code stuff. Lets try simulating the most common fluid &#8211; water.</p>
<p><strong>The basic data structure</strong></p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">//Map dimensions</span>
<span style="color: #000000; font-weight: bold;">final</span> <span style="color: #000066; font-weight: bold;">int</span> map_width <span style="color: #339933;">=</span> <span style="color: #cc66cc;">16</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">final</span> <span style="color: #000066; font-weight: bold;">int</span> map_height <span style="color: #339933;">=</span> <span style="color: #cc66cc;">16</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">//Block types</span>
<span style="color: #000000; font-weight: bold;">final</span> <span style="color: #000066; font-weight: bold;">int</span> AIR <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">final</span> <span style="color: #000066; font-weight: bold;">int</span> GROUND <span style="color: #339933;">=</span> <span style="color: #cc66cc;">1</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">final</span> <span style="color: #000066; font-weight: bold;">int</span> WATER <span style="color: #339933;">=</span> <span style="color: #cc66cc;">2</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">//Data structures</span>
<span style="color: #000066; font-weight: bold;">int</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> blocks <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #000066; font-weight: bold;">int</span><span style="color: #009900;">&#91;</span>map_width<span style="color: #339933;">+</span><span style="color: #cc66cc;">2</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>map_height<span style="color: #339933;">+</span><span style="color: #cc66cc;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000066; font-weight: bold;">float</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> mass <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #000066; font-weight: bold;">float</span><span style="color: #009900;">&#91;</span>map_width<span style="color: #339933;">+</span><span style="color: #cc66cc;">2</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>map_height<span style="color: #339933;">+</span><span style="color: #cc66cc;">2</span><span style="color: #009900;">&#93;</span>,
          new_mass <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #000066; font-weight: bold;">float</span><span style="color: #009900;">&#91;</span>map_width<span style="color: #339933;">+</span><span style="color: #cc66cc;">2</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>map_height<span style="color: #339933;">+</span><span style="color: #cc66cc;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span></pre></div></div>

<p>I use two two-dimensional arrays to represent the simulation world. The <code>blocks</code> array defines a basic &#8220;map&#8221; where each cell can contain ground (solid, stops water flow), air (an empty cell, water can flow in) or water. Each water cell also has a corresponding entry in the <code>mass</code> array that defines how much water it contains. All water cells/blocks start out with one unit of water.</p>
<p>There&#8217;s also a third array &#8211; <code>new_mass</code> that is used to store intermediate mass values when running the simulation. Operating directly on the <code>mass</code> array is unadvisable because you would get various sideffects like water spreading at different speeds depending on the order in which you update the cells.</p>
<p><strong>Overall algorithm</strong></p>
<p>The main idea is to treat water as a slightly compressible liquid, as described in <a href="http://home.comcast.net/~tom_forsyth/papers/cellular_automata_for_physical_modelling.html">this article</a>. In terms of implementation, this means that if there are two or more water cells stacked vertically, the bottom cells will be able to hold slightly more water than normal. This way we don&#8217;t need to explicitly track pressure to make the water level equalize in communicating vessels &#8211; we can just look at how much excess water a cell has, and move it upwards if required.</p>
<p>Lets set up the exact fluid properties as constants :</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">//Water properties</span>
<span style="color: #000000; font-weight: bold;">final</span> <span style="color: #000066; font-weight: bold;">float</span> MaxMass <span style="color: #339933;">=</span> <span style="color: #cc66cc;">1.0</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//The normal, un-pressurized mass of a full water cell</span>
<span style="color: #000000; font-weight: bold;">final</span> <span style="color: #000066; font-weight: bold;">float</span> MaxCompress <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0.02</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//How much excess water a cell can store, compared to the cell above it</span>
<span style="color: #000000; font-weight: bold;">final</span> <span style="color: #000066; font-weight: bold;">float</span> MinMass <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0.0001</span><span style="color: #339933;">;</span>  <span style="color: #666666; font-style: italic;">//Ignore cells that are almost dry</span></pre></div></div>

<p>For example, if one cell contains 1.0 units of water, the cell below it should contain up to 1.02 units, the cell below that one should contain 1.04, the next one 1.06, and so on. There is one however special case that we need to consider to get a plausible simulation &#8211; what if the if the top cell contains less than <code>MaxMass</code> units of water? In my implementation the bottom cell will contain a proportionally smaller excess amount, not the usual <code>mass_of_the_cell_above + MaxCompression</code> units.</p>
<p>Based on the above, we can simulate water movement by looping over the <code>mass</code> array and applying these cellular automaton rules to each cell :</p>
<ol>
<li>Take the mass of the current cell and the cell <strong>below</strong> it and figure out how much water the bottom cell should contain. If it has less than that, remove the corresponding amount from the current cell and add it to the bottom cell.</li>
<li>Check the cell to the <strong>left</strong> of this one. If it has less water, move over enough water to make both cells contain the same amount.</li>
<li>Do the same thing for the <strong>right</strong> neighbour.</li>
<li>Do the same thing as in step 1., but for the cell <strong>above</strong> the current one.</li>
</ol>
<p>While doing this you also need to keep track of how much water the current cell still has remaining, or you could end up with negative-mass water blocks.</p>
<p>After the new mass of each cell has been calculated, you can safely copy over the new values to the <code>mass</code> array. You also need to update the <code>blocks</code> array so that cells that are now dry get marked as empty and vice versa.</p>
<p>Here&#8217;s the simulation code :</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000066; font-weight: bold;">void</span> simulate_compression<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
  <span style="color: #000066; font-weight: bold;">float</span> Flow <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span>
  <span style="color: #000066; font-weight: bold;">float</span> remaining_mass<span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #666666; font-style: italic;">//Calculate and apply flow for each block</span>
  <span style="color: #000000; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">int</span> x <span style="color: #339933;">=</span> <span style="color: #cc66cc;">1</span><span style="color: #339933;">;</span> x <span style="color: #339933;">&lt;=</span> map_width<span style="color: #339933;">;</span> x<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
     <span style="color: #000000; font-weight: bold;">for</span><span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">int</span> y <span style="color: #339933;">=</span> <span style="color: #cc66cc;">1</span><span style="color: #339933;">;</span> y <span style="color: #339933;">&lt;=</span> map_height<span style="color: #339933;">;</span> y<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
       <span style="color: #666666; font-style: italic;">//Skip inert ground blocks</span>
       <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span> blocks<span style="color: #009900;">&#91;</span>x<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>y<span style="color: #009900;">&#93;</span> <span style="color: #339933;">==</span> GROUND<span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">continue</span><span style="color: #339933;">;</span>
&nbsp;
       <span style="color: #666666; font-style: italic;">//Custom push-only flow</span>
       Flow <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span>
       remaining_mass <span style="color: #339933;">=</span> mass<span style="color: #009900;">&#91;</span>x<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>y<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
       <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span> remaining_mass <span style="color: #339933;">&lt;=</span> <span style="color: #cc66cc;">0</span> <span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">continue</span><span style="color: #339933;">;</span>
&nbsp;
       <span style="color: #666666; font-style: italic;">//The block below this one</span>
       <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span> <span style="color: #009900;">&#40;</span>blocks<span style="color: #009900;">&#91;</span>x<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>y<span style="color: #339933;">-</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">!=</span> GROUND<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
         Flow <span style="color: #339933;">=</span> get_stable_state_b<span style="color: #009900;">&#40;</span> remaining_mass <span style="color: #339933;">+</span> mass<span style="color: #009900;">&#91;</span>x<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>y<span style="color: #339933;">-</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span> <span style="color: #009900;">&#41;</span> <span style="color: #339933;">-</span> mass<span style="color: #009900;">&#91;</span>x<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>y<span style="color: #339933;">-</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
         <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span> Flow <span style="color: #339933;">&gt;</span> MinFlow <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
           Flow <span style="color: #339933;">*=</span> <span style="color: #cc66cc;">0.5</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">//leads to smoother flow</span>
         <span style="color: #009900;">&#125;</span>
         Flow <span style="color: #339933;">=</span> constrain<span style="color: #009900;">&#40;</span> Flow, <span style="color: #cc66cc;">0</span>, min<span style="color: #009900;">&#40;</span>MaxSpeed, remaining_mass<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
         new_mass<span style="color: #009900;">&#91;</span>x<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>y<span style="color: #009900;">&#93;</span> <span style="color: #339933;">-=</span> Flow<span style="color: #339933;">;</span>
         new_mass<span style="color: #009900;">&#91;</span>x<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>y<span style="color: #339933;">-</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">+=</span> Flow<span style="color: #339933;">;</span>   
         remaining_mass <span style="color: #339933;">-=</span> Flow<span style="color: #339933;">;</span>
       <span style="color: #009900;">&#125;</span>
&nbsp;
       <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span> remaining_mass <span style="color: #339933;">&lt;=</span> <span style="color: #cc66cc;">0</span> <span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">continue</span><span style="color: #339933;">;</span>
&nbsp;
       <span style="color: #666666; font-style: italic;">//Left</span>
       <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span> blocks<span style="color: #009900;">&#91;</span>x<span style="color: #339933;">-</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>y<span style="color: #009900;">&#93;</span> <span style="color: #339933;">!=</span> GROUND <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
         <span style="color: #666666; font-style: italic;">//Equalize the amount of water in this block and it's neighbour</span>
         Flow <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>mass<span style="color: #009900;">&#91;</span>x<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>y<span style="color: #009900;">&#93;</span> <span style="color: #339933;">-</span> mass<span style="color: #009900;">&#91;</span>x<span style="color: #339933;">-</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>y<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">/</span><span style="color: #cc66cc;">4</span><span style="color: #339933;">;</span>
         <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span> Flow <span style="color: #339933;">&gt;</span> MinFlow <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span> Flow <span style="color: #339933;">*=</span> <span style="color: #cc66cc;">0.5</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span>
         Flow <span style="color: #339933;">=</span> constrain<span style="color: #009900;">&#40;</span>Flow, <span style="color: #cc66cc;">0</span>, remaining_mass<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
         new_mass<span style="color: #009900;">&#91;</span>x<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>y<span style="color: #009900;">&#93;</span> <span style="color: #339933;">-=</span> Flow<span style="color: #339933;">;</span>
         new_mass<span style="color: #009900;">&#91;</span>x<span style="color: #339933;">-</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>y<span style="color: #009900;">&#93;</span> <span style="color: #339933;">+=</span> Flow<span style="color: #339933;">;</span>
         remaining_mass <span style="color: #339933;">-=</span> Flow<span style="color: #339933;">;</span>
       <span style="color: #009900;">&#125;</span>
&nbsp;
       <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span> remaining_mass <span style="color: #339933;">&lt;=</span> <span style="color: #cc66cc;">0</span> <span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">continue</span><span style="color: #339933;">;</span>
&nbsp;
       <span style="color: #666666; font-style: italic;">//Right</span>
       <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span> blocks<span style="color: #009900;">&#91;</span>x<span style="color: #339933;">+</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>y<span style="color: #009900;">&#93;</span> <span style="color: #339933;">!=</span> GROUND <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
         <span style="color: #666666; font-style: italic;">//Equalize the amount of water in this block and it's neighbour</span>
         Flow <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>mass<span style="color: #009900;">&#91;</span>x<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>y<span style="color: #009900;">&#93;</span> <span style="color: #339933;">-</span> mass<span style="color: #009900;">&#91;</span>x<span style="color: #339933;">+</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>y<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">/</span><span style="color: #cc66cc;">4</span><span style="color: #339933;">;</span>
         <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span> Flow <span style="color: #339933;">&gt;</span> MinFlow <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span> Flow <span style="color: #339933;">*=</span> <span style="color: #cc66cc;">0.5</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span>
         Flow <span style="color: #339933;">=</span> constrain<span style="color: #009900;">&#40;</span>Flow, <span style="color: #cc66cc;">0</span>, remaining_mass<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
         new_mass<span style="color: #009900;">&#91;</span>x<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>y<span style="color: #009900;">&#93;</span> <span style="color: #339933;">-=</span> Flow<span style="color: #339933;">;</span>
         new_mass<span style="color: #009900;">&#91;</span>x<span style="color: #339933;">+</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>y<span style="color: #009900;">&#93;</span> <span style="color: #339933;">+=</span> Flow<span style="color: #339933;">;</span>
         remaining_mass <span style="color: #339933;">-=</span> Flow<span style="color: #339933;">;</span>
       <span style="color: #009900;">&#125;</span>
&nbsp;
       <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span> remaining_mass <span style="color: #339933;">&lt;=</span> <span style="color: #cc66cc;">0</span> <span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">continue</span><span style="color: #339933;">;</span>
&nbsp;
       <span style="color: #666666; font-style: italic;">//Up. Only compressed water flows upwards.</span>
       <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span> blocks<span style="color: #009900;">&#91;</span>x<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>y<span style="color: #339933;">+</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">!=</span> GROUND <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
         Flow <span style="color: #339933;">=</span> remaining_mass <span style="color: #339933;">-</span> get_stable_state_b<span style="color: #009900;">&#40;</span> remaining_mass <span style="color: #339933;">+</span> mass<span style="color: #009900;">&#91;</span>x<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>y<span style="color: #339933;">+</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
         <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span> Flow <span style="color: #339933;">&gt;</span> MinFlow <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span> Flow <span style="color: #339933;">*=</span> <span style="color: #cc66cc;">0.5</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span>
         Flow <span style="color: #339933;">=</span> constrain<span style="color: #009900;">&#40;</span> Flow, <span style="color: #cc66cc;">0</span>, min<span style="color: #009900;">&#40;</span>MaxSpeed, remaining_mass<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
         new_mass<span style="color: #009900;">&#91;</span>x<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>y<span style="color: #009900;">&#93;</span> <span style="color: #339933;">-=</span> Flow<span style="color: #339933;">;</span>
         new_mass<span style="color: #009900;">&#91;</span>x<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>y<span style="color: #339933;">+</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">+=</span> Flow<span style="color: #339933;">;</span>   
         remaining_mass <span style="color: #339933;">-=</span> Flow<span style="color: #339933;">;</span>
       <span style="color: #009900;">&#125;</span>
&nbsp;
&nbsp;
     <span style="color: #009900;">&#125;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #666666; font-style: italic;">//Copy the new mass values to the mass array</span>
  <span style="color: #000000; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">int</span> x <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span> x <span style="color: #339933;">&lt;</span> map_width <span style="color: #339933;">+</span> <span style="color: #cc66cc;">2</span><span style="color: #339933;">;</span> x<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">int</span> y <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span> y <span style="color: #339933;">&lt;</span> map_height <span style="color: #339933;">+</span> <span style="color: #cc66cc;">2</span><span style="color: #339933;">;</span> y<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
      mass<span style="color: #009900;">&#91;</span>x<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>y<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> new_mass<span style="color: #009900;">&#91;</span>x<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>y<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">int</span> x <span style="color: #339933;">=</span> <span style="color: #cc66cc;">1</span><span style="color: #339933;">;</span> x <span style="color: #339933;">&lt;=</span> map_width<span style="color: #339933;">;</span> x<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
     <span style="color: #000000; font-weight: bold;">for</span><span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">int</span> y <span style="color: #339933;">=</span> <span style="color: #cc66cc;">1</span><span style="color: #339933;">;</span> y <span style="color: #339933;">&lt;=</span> map_height<span style="color: #339933;">;</span> y<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
       <span style="color: #666666; font-style: italic;">//Skip ground blocks</span>
       <span style="color: #000000; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span>blocks<span style="color: #009900;">&#91;</span>x<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>y<span style="color: #009900;">&#93;</span> <span style="color: #339933;">==</span> GROUND<span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">continue</span><span style="color: #339933;">;</span>
       <span style="color: #666666; font-style: italic;">//Flag/unflag water blocks</span>
       <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>mass<span style="color: #009900;">&#91;</span>x<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>y<span style="color: #009900;">&#93;</span> <span style="color: #339933;">&gt;</span> MinMass<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
         blocks<span style="color: #009900;">&#91;</span>x<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>y<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> WATER<span style="color: #339933;">;</span>
       <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span>
         blocks<span style="color: #009900;">&#91;</span>x<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>y<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> AIR<span style="color: #339933;">;</span>
       <span style="color: #009900;">&#125;</span>
     <span style="color: #009900;">&#125;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #666666; font-style: italic;">//Remove any water that has left the map</span>
  <span style="color: #000000; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">int</span> x <span style="color: #339933;">=</span><span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span> x <span style="color: #339933;">&lt;</span> map_width<span style="color: #339933;">+</span><span style="color: #cc66cc;">2</span><span style="color: #339933;">;</span> x<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
    mass<span style="color: #009900;">&#91;</span>x<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span>
    mass<span style="color: #009900;">&#91;</span>x<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>map_height<span style="color: #339933;">+</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
  <span style="color: #000000; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">int</span> y <span style="color: #339933;">=</span> <span style="color: #cc66cc;">1</span><span style="color: #339933;">;</span> y <span style="color: #339933;">&lt;</span> map_height<span style="color: #339933;">+</span><span style="color: #cc66cc;">1</span><span style="color: #339933;">;</span> y<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
    mass<span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>y<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span>
    mass<span style="color: #009900;">&#91;</span>map_width<span style="color: #339933;">+</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span>y<span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>And here&#8217;s the function that calculates how to distribute a given amount of water between two vertically adjacent cells :</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">//Returns the amount of water that should be in the bottom cell.</span>
<span style="color: #000066; font-weight: bold;">float</span> get_stable_state_b <span style="color: #009900;">&#40;</span> <span style="color: #000066; font-weight: bold;">float</span> total_mass <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span> total_mass <span style="color: #339933;">&lt;=</span> <span style="color: #cc66cc;">1</span> <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #cc66cc;">1</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">else</span> <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span> total_mass <span style="color: #339933;">&lt;</span> <span style="color: #cc66cc;">2</span><span style="color: #339933;">*</span>MaxMass <span style="color: #339933;">+</span> MaxCompress <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #009900;">&#40;</span>MaxMass<span style="color: #339933;">*</span>MaxMass <span style="color: #339933;">+</span> total_mass<span style="color: #339933;">*</span>MaxCompress<span style="color: #009900;">&#41;</span><span style="color: #339933;">/</span><span style="color: #009900;">&#40;</span>MaxMass <span style="color: #339933;">+</span> MaxCompress<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #009900;">&#40;</span>total_mass <span style="color: #339933;">+</span> MaxCompress<span style="color: #009900;">&#41;</span><span style="color: #339933;">/</span><span style="color: #cc66cc;">2</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p><strong>Full source code</strong></p>
<ul>
<li><a href="http://w-shadow.com/files/water_sim.zip"><strong>Download the source</strong></a> (23 KB)</li>
<li>You will need the Java-based <a href="http://processing.org/">Processing programming language</a> to run the code.</li>
</ul>
<p>I didn&#8217;t discuss how to render the water, or how to handle user interaction, but the source code also includes a simplistic implementation of those things.</p>
<h3>Conclusion</h3>
<p>CA-based algorithms have both advantages and disadvantages. On the one hand, they&#8217;re relatively fast and the simulation quality is often good enough for games and software toys. On the other, they can produce behaviour that is very unrealistic &#8211; for example, water falling into a basin will form a little &#8220;hill&#8221; and spread out slowly, instead of near-instantly as real water would. Whether this is an acceptable downside depends on your application.</p>
<p>For a different take on simulating fluid dynamics with cellular automata, check out this <a href="http://www.gamasutra.com/view/feature/3549/interview_the_making_of_dwarf_.php?page=9">interview with the author of Dwarf Fortress</a>.</p>
<hr/>Copyright &copy; 2010 <strong><a href="http://w-shadow.com">W-Shadow.com</a></strong>. This Feed is for personal non-commercial use only. If you are not reading this material in your news aggregator, the site you are looking at is guilty of copyright infringement.]]></content:encoded>
			<wfw:commentRss>http://w-shadow.com/blog/2009/09/01/simple-fluid-simulation/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Changelog Generator For WordPress Plugins</title>
		<link>http://w-shadow.com/blog/2009/08/20/changelog-generator-for-wordpress-plugins/</link>
		<comments>http://w-shadow.com/blog/2009/08/20/changelog-generator-for-wordpress-plugins/#comments</comments>
		<pubDate>Thu, 20 Aug 2009 19:25:55 +0000</pubDate>
		<dc:creator>White Shadow</dc:creator>
				<category><![CDATA[Applications]]></category>
		<category><![CDATA[Blogging]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[changelog]]></category>
		<category><![CDATA[PHP script]]></category>
		<category><![CDATA[plugin directory]]></category>
		<category><![CDATA[repository]]></category>
		<category><![CDATA[SVN]]></category>
		<category><![CDATA[Trac]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[WordPress plugins]]></category>

		<guid isPermaLink="false">http://w-shadow.com/?p=1276</guid>
		<description><![CDATA[A few months ago, WordPress.org introduced a new feature available to plugins hosted in the Plugin Directory &#8211; changelogs. Having an easily accessible changelog is certainly a usability plus, but I felt it created unnecessary work for plugin developers. Personally, I usually provide meaningful log messages (example) when uploading a new version of a plugin [...]]]></description>
			<content:encoded><![CDATA[<p>A few months ago, WordPress.org introduced a new feature available to plugins hosted in the Plugin Directory &#8211; <a href="http://westi.wordpress.com/2009/06/20/changelogs-changelogs-changelogs/">changelogs</a><span>. Having an easily accessible changelog is certainly a usability plus, but I felt it created unnecessary work for plugin developers. Personally, I usually provide meaningful log messages (</span><a href="http://plugins.trac.wordpress.org/log/broken-link-checker">example</a><span>) when uploading a new version of a plugin to the repository, so updating the changelog with pretty much the same information seems redundant.</span></p>
<p><span>This gave me the idea to write a PHP script that can generate a wordpress.org-compatible changelog from the revision log. It works for any plugin hosted in the official plugins directory and <span class="hiddenGrammarError">can be</span> a handy starting point for adding a changelog to plugins that don&#8217;t have it yet :</span></p>
<ul>
<li><strong><a href="http://w-shadow.com/wpchangelog/"><span>Run the changelog generator</span></a></strong></li>
<li><a href="http://w-shadow.com/files/wpchangelog.zip">Download the source code</a> (97 KB, requires PHP 5)</li>
</ul>
<p>For those too lazy to click one of the above links, here&#8217;s a screenshot :</p>
<p><a href="http://w-shadow.com/wpchangelog/"><img style=' display: block; margin-right: auto; margin-left: auto;'  class="aligncenter size-full wp-image-1278" title="Changelog generator for WordPress plugins" src="http://w-shadow.com/wp-content/uploads/2009/08/Changelog-Generator.png" alt="Changelog generator for WordPress plugins" width="490" height="205" /></a></p>
<p>And I really do need to stop making these small hacks <img src='http://w-shadow.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<hr/>Copyright &copy; 2010 <strong><a href="http://w-shadow.com">W-Shadow.com</a></strong>. This Feed is for personal non-commercial use only. If you are not reading this material in your news aggregator, the site you are looking at is guilty of copyright infringement.]]></content:encoded>
			<wfw:commentRss>http://w-shadow.com/blog/2009/08/20/changelog-generator-for-wordpress-plugins/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Minecraft Serverlist Sorter</title>
		<link>http://w-shadow.com/blog/2009/08/05/minecraft-serverlist-sorter/</link>
		<comments>http://w-shadow.com/blog/2009/08/05/minecraft-serverlist-sorter/#comments</comments>
		<pubDate>Wed, 05 Aug 2009 17:55:32 +0000</pubDate>
		<dc:creator>White Shadow</dc:creator>
				<category><![CDATA[Applications]]></category>
		<category><![CDATA[greasemonkey script]]></category>
		<category><![CDATA[Minecraft]]></category>

		<guid isPermaLink="false">http://w-shadow.com/?p=1228</guid>
		<description><![CDATA[Minecraft is a huge waste of time. By which I mean, of course, that it&#8217;s a hugely addictive browser-based multiplayer game (see my mini-review) that makes people stay up till 5 AM every daycycle just so they can finish the latest megaproject. But if we&#8217;re wasting time we should at least waste it efficiently, right? [...]]]></description>
			<content:encoded><![CDATA[<p><img style=' float: right; padding: 4px; margin: 0 0 2px 7px;'  src="http://w-shadow.com/wp-content/uploads/2009/08/Minecraft_Sand_Temple-300x209.jpg" alt="Till 5 AM, I tell you!" title="Till 5 AM, I tell you!" width="300" height="209" class="alignright size-medium wp-image-1232" />Minecraft is a huge waste of time. By which I mean, of course, that it&#8217;s a hugely addictive browser-based multiplayer game (see <a href="http://w-shadow.com/blog/2009/06/15/minecraft-review/">my mini-review</a>) that makes people stay up till 5 AM every daycycle just so they can finish the latest megaproject. </p>
<p>But if we&#8217;re wasting time we should at least waste it <em>efficiently</em>, right? One of the inefficiencies of this game is that <a href="http://minecraft.net/servers.jsp">the serverlist</a> is not sortable &#8211; if you want to find a populated server you have to look over the entire listing that typically contains 50-100 active server at any given moment.</p>
<p>That&#8217;s why I made a <a href="https://addons.mozilla.org/firefox/addon/748">GreaseMonkey</a> script that lets you sort the Minecraft serverlist as you like. It adds two new links to the serverlist &#8211; &#8220;Sort by players&#8221; and &#8220;Sort by name&#8221;. The default is to sort by the number of active players which will put the most populated servers at the top of the page (this can be easily changed by editing one line in the script). </p>
<p><strong><a href="http://w-shadow.com/files/minecraft_serverlist_sort.user.js">Download userscript!</a></strong></p>
<p><em>P.S.<br />
I&#8217;m aware that blog updates have been lacking lately. I hope to remedy with this unfortunate situation in the nearest future.</em></p>
<hr/>Copyright &copy; 2010 <strong><a href="http://w-shadow.com">W-Shadow.com</a></strong>. This Feed is for personal non-commercial use only. If you are not reading this material in your news aggregator, the site you are looking at is guilty of copyright infringement.]]></content:encoded>
			<wfw:commentRss>http://w-shadow.com/blog/2009/08/05/minecraft-serverlist-sorter/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
