<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;CU8DRXo_cCp7ImA9WhRaGE4.&quot;"><id>tag:blogger.com,1999:blog-486398466531826618</id><updated>2012-02-21T16:17:54.448+02:00</updated><category term="business" /><category term="GWT" /><category term="personal" /><category term="Subversion" /><category term="movies" /><category term="web" /><category term="programming" /><category term="economy" /><category term="CVS" /><category term="Greece" /><category term="WebDAV" /><category term="FreeBSD" /><category term="Java" /><category term="FireStatus" /><category term="databases" /><category term="C++" /><category term="gss" /><category term="copyright" /><category term="jobs" /><category term="software" /><category term="Linux" /><category term="Mac" /><category term="mozilla" /><category term="JavaScript" /><category term="VC" /><category term="open-source" /><category term="startups" /><title>Past Midnight</title><subtitle type="html">...thoughts on people and software</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://blog.astithas.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://blog.astithas.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>Panagiotis Astithas</name><uri>https://profiles.google.com/116466326438420686438</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-ieNj_PE2fxE/AAAAAAAAAAI/AAAAAAAAAAA/l78jhJX3laA/s512-c/photo.jpg" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>42</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/PastMidnight" /><feedburner:info uri="pastmidnight" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;D0MBQHc4fip7ImA9WhRaFko.&quot;"><id>tag:blogger.com,1999:blog-486398466531826618.post-7390405967266302309</id><published>2012-02-19T19:30:00.003+02:00</published><updated>2012-02-19T20:17:31.936+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-19T20:17:31.936+02:00</app:edited><title>Debugging mobile phones</title><content type="html">&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;
&lt;a href="http://blog.astithas.com/2012/02/debugging-javascript.html"&gt;Last week&lt;/a&gt; I posted an update on the progress we are making towards a functional JavaScript debugger in Firefox. We still have a ways to go before we get there, but the foundation this is based on, namely the &lt;a href="https://wiki.mozilla.org/Remote_Debugging_Protocol"&gt;Remote Debugging Protocol&lt;/a&gt;, provides a solid basis for debugging mobile browsers, and as it turns out, even mobile operating systems. Supporting these use cases is still farther down our list, but I decided to spend a few hours the other day trying to estimate how far we are from this goal. It turns out we are not that far, and I have a screencast to prove it.&lt;br /&gt;
&lt;br /&gt;
I had done some prototyping work for Firefox for Android a while back, which was rather straightforward, so I was curious to know what would it take to tackle a more ambitious project: debugging &lt;a href="https://wiki.mozilla.org/B2G"&gt;Boot to Gecko&lt;/a&gt;. After a few hours of hacking and orienting myself around the B2G and Gaia code base, I got this far:&lt;br /&gt;
&lt;br /&gt;
&lt;iframe allowfullscreen="" frameborder="0" height="438" mozallowfullscreen="" src="http://player.vimeo.com/video/36966384?title=0&amp;amp;byline=0&amp;amp;portrait=0" webkitallowfullscreen="" width="700"&gt;&lt;/iframe&gt;
&lt;br /&gt;
&lt;br /&gt;
Not too bad I think for a few hours work. Don't expect this to be ready of course, before we have a working debugger in desktop Firefox. If, however, you'd like to follow along and maybe even lend a hand, you are always &lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=728244"&gt;welcome&lt;/a&gt;!&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/486398466531826618-7390405967266302309?l=blog.astithas.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/PastMidnight/~4/1078adeCg2U" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.astithas.com/feeds/7390405967266302309/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=486398466531826618&amp;postID=7390405967266302309" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/7390405967266302309?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/7390405967266302309?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/PastMidnight/~3/1078adeCg2U/last-week-i-shared-progress.html" title="Debugging mobile phones" /><author><name>Panagiotis Astithas</name><uri>https://profiles.google.com/116466326438420686438</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-ieNj_PE2fxE/AAAAAAAAAAI/AAAAAAAAAAA/l78jhJX3laA/s512-c/photo.jpg" /></author><thr:total>1</thr:total><feedburner:origLink>http://blog.astithas.com/2012/02/last-week-i-shared-progress.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C04DQnYyfSp7ImA9WhRaFko.&quot;"><id>tag:blogger.com,1999:blog-486398466531826618.post-4655048001149917491</id><published>2012-02-13T10:08:00.000+02:00</published><updated>2012-02-19T19:19:33.895+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-19T19:19:33.895+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript" /><category scheme="http://www.blogger.com/atom/ns#" term="software" /><category scheme="http://www.blogger.com/atom/ns#" term="mozilla" /><title>Debugging JavaScript</title><content type="html">&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;
&lt;i&gt;tl;dr: Firefox nightlies now ship with an experimental JavaScript debugger. It's not ready for end-users yet, but we are feverishly working on filling in the missing bits.&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
Debugging is always hard, especially when debugging other people's code. Adding a bunch of console.log() statements, becomes tedious after a while and that's assuming that you are familiar enough with the code in question to know where to place them. Tools like &lt;a href="http://getfirebug.com/"&gt;Firebug&lt;/a&gt; are a tremendous help in this case. Having the ability to pause the execution at any point or inspect variables and stack frames, provides valuable insights into the runtime behavior of a program.&lt;br /&gt;
&lt;br /&gt;
Firebug depends on the traditional &lt;a href="https://developer.mozilla.org/en/Code_snippets/JavaScript_Debugger_Service"&gt;JSD&lt;/a&gt; API in &lt;a href="https://developer.mozilla.org/en/SpiderMonkey"&gt;SpiderMonkey&lt;/a&gt; to perform its magic, but nowadays JSD is limiting in a number of ways. In order to overcome these limitations, the new &lt;a href="https://wiki.mozilla.org/Debugger"&gt;JSDBG2&lt;/a&gt; API was designed and implemented by &lt;a href="http://www.red-bean.com/jimb/"&gt;Jim Blandy&lt;/a&gt; and &lt;a href="http://blog.mozilla.com/jorendorff/"&gt;Jason&lt;/a&gt; &lt;a href="http://jorendorff.blogspot.com/"&gt;Orendorff&lt;/a&gt;, and the first version of this work landed in &lt;a href="http://www.mozilla.org/firefox/"&gt;Firefox&lt;/a&gt; 8. Jim, being the kind of guy that has forgotten more about debuggers than I will ever know, designed a &lt;a href="https://wiki.mozilla.org/Remote_Debugging_Protocol"&gt;remote debugging protocol&lt;/a&gt; to separate the debugger from the browser, allowing for debugging desktop browsers, mobile browsers, mail readers and even more exotic software in the future. &lt;a href="https://twitter.com/campd"&gt;Dave Camp&lt;/a&gt; got a great protocol implementation up and running, but was assigned managerial duties (poor sap!) before having a chance to finish the job, so &lt;a href="http://students.info.uaic.ro/%7Evictor.porof/"&gt;Victor Porof&lt;/a&gt;, &lt;a href="http://www.robodesign.ro/mihai/blog"&gt;Mihai Șucan&lt;/a&gt;  and yours truly lined up to carry the torch. The culmination of this work landed in mozilla-central last week, including the remote protocol implementation and a prototype UI (disabled by default). It is now available in &lt;a href="http://nightly.mozilla.org/"&gt;nightlies&lt;/a&gt; for adventurous souls to play with.&lt;br /&gt;
&lt;br /&gt;
Let me be clear about that last point: what's in there right now is not useful for day-to-day work, even for experienced developers. There is no UI to add breakpoints besides the experimental Graphical Command Line Interface (whose awesomeness deserves a separate post), no stepping, no variable inspection besides call parameters and 'this', and numerous other limitations. In short: it's not ready, yet. In the course of the next weeks we will be furiously working to add the missing bits and improve the UI, so that it becomes a worthy addition to our &lt;a href="http://thenextweb.com/apps/2012/01/31/firefox-adds-new-developer-tools-that-rival-chromes-offerings/"&gt;existing suite&lt;/a&gt; of developer tools.&lt;br /&gt;
&lt;br /&gt;
If, however, you are the kind of person who doesn't take no for an answer, here is what you need to do to play with it: type &lt;a href="about:config"&gt;about:config&lt;/a&gt; in the awesomebar and set the preference &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;devtools.debugger.enabled&lt;/span&gt; to &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;true&lt;/span&gt;. Also, set &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;devtools.gcli.enable&lt;/span&gt; to &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;true&lt;/span&gt; in order to be able to set breakpoints. Restart your browser and select Tools -&amp;gt; Web Developer -&amp;gt; Script Debugger to open it. You will need to reload the page for the debugger to become aware of the scripts in the page (see? It's not ready!). Browse through the source scripts to find a place where you would like to add a breakpoint, then open the web console and type &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;break add line &amp;lt;url&amp;gt; &amp;lt;line&amp;gt;&lt;/span&gt;. Don't worry about memorizing it, GCLI will guide you along the way, suggesting among the available options at each step. When the code hits the breakpoint, the debugger will display the stack frames and the variables in scope (not all of them, it's not ready, remember?) for inspection. &lt;br /&gt;
&lt;br /&gt;
If you have better things to do with your time than play with experimental, uninished debuggers, but would still like to take a peek into what's in store already, here is a short screencast that should give you a broad idea. Note that the stepping functionality in the demo is not in the nightlies yet, because, you guessed it, it's not quite ready.&lt;br /&gt;
&lt;br /&gt;
&lt;iframe allowfullscreen="" frameborder="0" height="517" mozallowfullscreen="" src="http://player.vimeo.com/video/35951775?title=0&amp;amp;byline=0&amp;amp;portrait=0" webkitallowfullscreen="" width="700"&gt;&lt;/iframe&gt;
&lt;br /&gt;
&lt;br /&gt;
Ready or not, we would love to have any feedback you might have. Drop by &lt;a href="irc://irc.mozilla.org/devtools"&gt;#devtools&lt;/a&gt; for a chat, or &lt;a href="https://bugzilla.mozilla.org/enter_bug.cgi?blocked=676586&amp;amp;product=Firefox&amp;amp;component=Developer%20Tools:%20Debugger"&gt;file bugs&lt;/a&gt; to &lt;strike&gt;torture&lt;/strike&gt;help us get things fixed. Rest assured, when it's done, debugging web apps will never be the same again.  &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/486398466531826618-4655048001149917491?l=blog.astithas.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/PastMidnight/~4/UZNEnw-IPIc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.astithas.com/feeds/4655048001149917491/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=486398466531826618&amp;postID=4655048001149917491" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/4655048001149917491?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/4655048001149917491?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/PastMidnight/~3/UZNEnw-IPIc/debugging-javascript.html" title="Debugging JavaScript" /><author><name>Panagiotis Astithas</name><uri>https://profiles.google.com/116466326438420686438</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-ieNj_PE2fxE/AAAAAAAAAAI/AAAAAAAAAAA/l78jhJX3laA/s512-c/photo.jpg" /></author><thr:total>2</thr:total><feedburner:origLink>http://blog.astithas.com/2012/02/debugging-javascript.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ck4BQn06eCp7ImA9WhZRGUU.&quot;"><id>tag:blogger.com,1999:blog-486398466531826618.post-1874895859765171283</id><published>2011-04-16T21:00:00.002+02:00</published><updated>2011-04-16T21:09:13.310+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-04-16T21:09:13.310+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="personal" /><category scheme="http://www.blogger.com/atom/ns#" term="jobs" /><title>Next stop: Mozilla</title><content type="html">&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-SpQbj6ssSVI/TanSdcbdG-I/AAAAAAAAAfQ/1Q4vQttg4_Q/s1600/Future-signpost.jpg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 268px;" src="http://2.bp.blogspot.com/-SpQbj6ssSVI/TanSdcbdG-I/AAAAAAAAAfQ/1Q4vQttg4_Q/s400/Future-signpost.jpg" alt="" id="BLOGGER_PHOTO_ID_5596235415273937890" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-93tJ5bYBONs/TanSoHKJ2bI/AAAAAAAAAfY/FPM9zj0Nfzg/s1600/mozilla-firefox.jpg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 369px; height: 356px;" src="http://1.bp.blogspot.com/-93tJ5bYBONs/TanSoHKJ2bI/AAAAAAAAAfY/FPM9zj0Nfzg/s400/mozilla-firefox.jpg" alt="" id="BLOGGER_PHOTO_ID_5596235598542789042" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0); font-style: normal; text-decoration: none; vertical-align: baseline; font-family: arial;font-family:Arial;font-size:100%;" id="internal-source-marker_0.2833058166034962"  &gt;Six  months ago I left my previous job, in order to join a &lt;a href="http://www.xe.gr/"&gt;product company&lt;/a&gt; and experience  new things. The move was rewarding in many ways, but most importantly, because of the people I've met. &lt;/span&gt;&lt;span style="font-style: normal; text-decoration: none; vertical-align: baseline; font-family: arial;font-family:Arial;font-size:100%;color:#000000;" id="internal-source-marker_0.2833058166034962"   &gt;We've accomplished a lot together and laid out the foundations for much more. As I've &lt;a href="http://blog.astithas.com/2010/10/moving-on.html"&gt;established&lt;/a&gt; before, this is not the right time to be moving on, but while in theory, theory and practice are the same, in practice, they are not. When good fortune knocks on your door,  it's a fool who does not answer.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-style: normal; text-decoration: none; vertical-align: baseline; font-family: arial;font-family:Arial;font-size:100%;color:#000000;" id="internal-source-marker_0.2833058166034962"   &gt;So I am seizing the opportunity to work with some of the  best hackers in the world, on a product that I adore, with technologies that until now I had to stay up late at night to use. In a few days I’ll be joining  Mozilla to work on Firefox Developer Tools, a passion of mine for quite &lt;a href="https://github.com/past/despin"&gt;some&lt;/a&gt; &lt;a href="https://github.com/past/nodify"&gt; time&lt;/a&gt;.&lt;/span&gt;&lt;span style="font-family:arial;font-size:100%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-style: normal; text-decoration: none; vertical-align: baseline; font-family: arial;font-family:Arial;font-size:100%;color:#000000;" id="internal-source-marker_0.2833058166034962"   &gt; I am thrilled with this opportunity to learn from the best, and have an impact on the lives of millions. And to do this with a non-profit organization, whose mission is to promote openness, innovation and opportunity on the web, for the public good.&lt;br /&gt;&lt;br /&gt;I'm almost wishing I gave-up this long-needed vacation.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/486398466531826618-1874895859765171283?l=blog.astithas.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/PastMidnight/~4/fjyi8NCquCU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.astithas.com/feeds/1874895859765171283/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=486398466531826618&amp;postID=1874895859765171283" title="10 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/1874895859765171283?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/1874895859765171283?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/PastMidnight/~3/fjyi8NCquCU/next-stop-mozilla.html" title="Next stop: Mozilla" /><author><name>Panagiotis Astithas</name><uri>https://profiles.google.com/116466326438420686438</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-ieNj_PE2fxE/AAAAAAAAAAI/AAAAAAAAAAA/l78jhJX3laA/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-SpQbj6ssSVI/TanSdcbdG-I/AAAAAAAAAfQ/1Q4vQttg4_Q/s72-c/Future-signpost.jpg" height="72" width="72" /><thr:total>10</thr:total><feedburner:origLink>http://blog.astithas.com/2011/04/next-stop-mozilla.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CE8ERnY5fCp7ImA9Wx5bFEU.&quot;"><id>tag:blogger.com,1999:blog-486398466531826618.post-3771969665423073712</id><published>2010-10-31T01:46:00.002+02:00</published><updated>2010-10-31T01:53:27.824+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-10-31T01:53:27.824+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="personal" /><category scheme="http://www.blogger.com/atom/ns#" term="startups" /><category scheme="http://www.blogger.com/atom/ns#" term="jobs" /><title>Moving On</title><content type="html">&lt;div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; background-color: transparent; font-family: Times; font-size: medium; "&gt;&lt;span id="internal-source-marker_0.857190610608086" style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;About 10 years ago, I was invited to become employee No1 of &lt;/span&gt;&lt;a href="http://www.ebs.gr/"&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 153); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap; "&gt;a new software startup&lt;/span&gt;&lt;/a&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;. I didn’t know much about &lt;/span&gt;&lt;a href="http://www.paulgraham.com/start.html"&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 153); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap; "&gt;startups&lt;/span&gt;&lt;/a&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt; back then, besides that they were supposedly cool, and employees weren’t treated like small cogs in a giant machine. Indeed, it felt really fun to build our first product in my 5 year-old laptop, running FreeBSD, of all things. That, and getting praised by our users, too.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;Things got even better as time went by: interesting projects to build, exciting technologies to explore, new colleagues to work with, new challenges to face. I felt my work was making a real impact, getting the team to follow new and exciting technological paths, often far away from the mainstream. I became partner, pushed for launching our first large consumer product, coded, mentored, planned and dreamed about where to go next. I had a 27-inch Mac, a big desk and a great view from my office window.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;And then I left.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;When is it a good time to leave? When everything is over, it’s obviously too late. When things are just starting to take shape, it’s definitely too soon. I used to say, &lt;/span&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: italic; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;‘when you are done’&lt;/span&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;. But it turns out that, in real life, you are never done. There are always more things to do, unfinished businesses to attend to, and existing plans to follow through. Perhaps a better answer is: &lt;/span&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: italic; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;‘when you are too comfortable, almost on the brink of getting bored’&lt;/span&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;A friend asked me why would I leave this company in what appears, by all accounts, to be the pinnacle of our accomplishments, &lt;/span&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: italic; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;‘now that your work is being recognised and respected’&lt;/span&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;, as he put it. Another said that we’re all going through some pretty hard times, and it wouldn’t be wise to take risks. A rather unsettled family member asked: ‘&lt;/span&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: italic; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;aren’t you afraid?’&lt;/span&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;Of course I was.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;&lt;/span&gt;&lt;br /&gt;&lt;p style="margin-right: 15pt; margin-top: 0pt; margin-bottom: 0pt; "&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;Afraid of leaving behind the tried-and-true for something new and unknown; afraid that the new gig might not live up to the initial impressions; afraid that my work-life balance might deteriorate. However, I’ve learned long ago that fear isn’t something to be afraid of. As Eleanor Roosevelt &lt;/span&gt;&lt;a href="http://womenshistory.about.com/cs/quotes/a/qu_e_roosevelt.htm"&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 153); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap; "&gt;said&lt;/span&gt;&lt;/a&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt; once: ‘&lt;/span&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;You gain strength, courage, and confidence by every experience in which you really stop to look fear in the face. You must do the thing which you think you cannot do.’ What I wanted to do, is to become even better at my craft. To have an impact on even more people’s lives through my work. To inspire and be inspired. To be afraid and excited again.&lt;/span&gt;&lt;/p&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;So, as of a few days ago I’ve taken up an offer to work for &lt;/span&gt;&lt;a href="http://www.xe.gr/"&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 153); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap; "&gt;Golden&lt;/span&gt;&lt;/a&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt; &lt;/span&gt;&lt;a href="http://goldendeals.gr/"&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 153); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap; "&gt;Deal&lt;/span&gt;&lt;/a&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;. It’s a product company, something I’ve always been keen on, with a great track record and an awesome crew that is rapidly expanding (are you a senior dev or admin? we’re hiring!). I’m still getting to know the place around here, but it feels good, and I think we have a shot at becoming one of the greatest Internet companies in Greece. &lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;I know that my former teammates will continue to rock on, and I’ll be cheering from the sidelines for their future accomplishments. As for me, I just might find more time to blog again. &lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;P.S.: For folks contemplating a career move, here are some tips for choosing your next gig. This is not how I approached my own case, since I wasn’t really on the market for a job. I was more like seduced, from some pretty persuasive folks. However, had I been looking for a new employer, this is what I would have looked out for:&lt;/span&gt;&lt;ul&gt;&lt;li style="list-style-type: disc; font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; "&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;Product company: this is where you have a better chance at learning the ropes of modern technologies, without doing pure academic exercises that have little to no importance for the business.&lt;/span&gt;&lt;/li&gt;&lt;li style="list-style-type: disc; font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; "&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;Startup mentality: you want to be a part of a group that fights as a whole for the success of the company, not a bunch of bureaucrats isolated in their silos.&lt;/span&gt;&lt;/li&gt;&lt;li style="list-style-type: disc; font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; "&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;Experienced team with a good track record: so you can learn from people better, smarter or wiser than you, and improve your skills.&lt;/span&gt;&lt;/li&gt;&lt;li style="list-style-type: disc; font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; "&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;Teams not afraid to experiment with new and unproven technologies: because innovation is the name of the game, at least for startups and product companies.&lt;/span&gt;&lt;/li&gt;&lt;li style="list-style-type: disc; font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; "&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;A ‘&lt;/span&gt;&lt;a href="http://www.joelonsoftware.com/articles/GuerrillaInterviewing3.html"&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 153); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap; "&gt;getting things done&lt;/span&gt;&lt;/a&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;’ attitude: because success apparently only comes for the right kind of people.&lt;/span&gt;&lt;/li&gt;&lt;li style="list-style-type: disc; font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; "&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;Honest presentation: this is rather obvious.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;Bear in mind that people have a tendency to present a rosy picture of their situation, because, if nothing else, it makes them feel better about themselves. Be a little pessimist and assume things are a tad worse, and you’ll be closer to the truth most of the time. Also, do some research on what you’re being told, don’t trust their sales pitch blindly.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;I know I did.&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/486398466531826618-3771969665423073712?l=blog.astithas.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/PastMidnight/~4/EWl-ddm20Vg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.astithas.com/feeds/3771969665423073712/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=486398466531826618&amp;postID=3771969665423073712" title="13 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/3771969665423073712?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/3771969665423073712?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/PastMidnight/~3/EWl-ddm20Vg/moving-on.html" title="Moving On" /><author><name>Panagiotis Astithas</name><uri>https://profiles.google.com/116466326438420686438</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-ieNj_PE2fxE/AAAAAAAAAAI/AAAAAAAAAAA/l78jhJX3laA/s512-c/photo.jpg" /></author><thr:total>13</thr:total><feedburner:origLink>http://blog.astithas.com/2010/10/moving-on.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0MCRXk_fyp7ImA9Wx5VGUw.&quot;"><id>tag:blogger.com,1999:blog-486398466531826618.post-6975307554232582841</id><published>2010-10-12T22:55:00.000+02:00</published><updated>2010-10-12T23:37:44.747+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-10-12T23:37:44.747+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="databases" /><category scheme="http://www.blogger.com/atom/ns#" term="open-source" /><category scheme="http://www.blogger.com/atom/ns#" term="Java" /><category scheme="http://www.blogger.com/atom/ns#" term="gss" /><category scheme="http://www.blogger.com/atom/ns#" term="software" /><category scheme="http://www.blogger.com/atom/ns#" term="programming" /><title>GSS/Pithos update: iPhone, Android, Mongo &amp; getting to 2.0</title><content type="html">&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_zFF22LLF49M/TLTUUcxuYPI/AAAAAAAAAd4/Sn5KhT8NmHI/s1600/icon.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 57px; height: 57px;" src="http://2.bp.blogspot.com/_zFF22LLF49M/TLTUUcxuYPI/AAAAAAAAAd4/Sn5KhT8NmHI/s400/icon.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5527276090477666546" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; background-color: transparent; font-family: Times; font-size: medium; "&gt;&lt;span id="internal-source-marker_0.27477506059221923" style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;It has been a while since my last post on &lt;a href="http://code.google.com/p/gss"&gt;GSS&lt;/a&gt;/&lt;a href="http://pithos.grnet.gr/"&gt;Pithos&lt;/a&gt;, and there have been quite a few important announcements that I have not blogged about, only tweeted:&lt;/span&gt;&lt;ul&gt;&lt;li style="list-style-type: disc; font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; "&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;a shiny &lt;a href="http://code.google.com/p/igss/"&gt;native&lt;/a&gt; &lt;a href="http://itunes.apple.com/app/pithos/id367821572?mt=8"&gt;iPhone client&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;&lt;li style="list-style-type: disc; font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; "&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;a brand new &lt;a href="http://code.google.com/p/gssdroid/"&gt;Android client&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;&lt;li style="list-style-type: disc; font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; "&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;a back-office application for statistics and admin tasks&lt;/span&gt;&lt;/li&gt;&lt;li style="list-style-type: disc; font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; "&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;public folders for hosting static web sites&lt;/span&gt;&lt;/li&gt;&lt;li style="list-style-type: disc; font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; "&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;a slew of performance, usability and bug fixes for the web &amp;amp; desktop clients&lt;/span&gt;&lt;/li&gt;&lt;li style="list-style-type: disc; font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; "&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;new user registration and quota upgrade workflows&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;And since the code base has been adopted by other European NRNs, we have also improved our release engineering process and &lt;a href="http://code.google.com/p/gss/w/list"&gt;documentation&lt;/a&gt;. This however was just the tip of the iceberg. What we are now close to completing, is nothing short of an almost complete rewrite of the core GSS server, aiming at even greater performance and scalability. We are about to release GSS 2.0.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;The initial plan was far more modest. We had identified the &lt;a href="http://www.postgresql.org/"&gt;PostgreSQL&lt;/a&gt; installation that stores all of the the system’s data besides the actual files, as a future bottleneck when user adoption would start to accelerate. In such an event there were a few low-to-medium-cost solutions that we could pursue, like replication and manual sharding, but since the problem seemed best suited for a &lt;a href="http://en.wikipedia.org/wiki/NoSQL"&gt;NoSQL&lt;/a&gt; solution, we decided to bite the bullet and attempt a transition. &lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;Our field search included lots of products, like &lt;a href="http://en.wikipedia.org/wiki/MongoDB"&gt;Mongo&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/CouchDB"&gt;Couch&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Cassandra_(database)"&gt;Cassandra&lt;/a&gt;, &lt;a href="https://wiki.basho.com/display/RIAK/Riak"&gt;Riak&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Redis_(data_store)"&gt;Redis&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Hbase"&gt;HBase&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Memcachedb"&gt;MemcacheDB&lt;/a&gt; and others. The basic requirements were high write throughput, sharding, replication and easy migration. Most of the products boasted high performance for writes and lots supported replication. In the end we discarded the ones that didn’t support sharding, which limited the options a lot, and we investigated the various APIs, trying to figure out what it would mean to rewrite GSS for one of these. In the end we chose Mongo for its rich query support, since it was the best fit for our problem at hand, making the transition of the existing code base easier. Although we’d love to have had the opportunity to try different ports for each of those datastores, it is most likely that we would have had to rewrite the entire server from scratch, which was not an option.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;The initial plan was to try to isolate the changes to the data access layer, essentially building a new adapter for the middle tier that would appear almost identical to the existing code. This effort was fruitless however, since we could not find satisfactory solutions for various issues, like transactions, data mapping, entity lifecycle, etc. We came to the conclusion that even if we managed to build a not-too-leaky abstraction for Mongo, it would have probably killed the performance, making the switch from PostgreSQL pointless.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;So we ditched JPA and container-managed transactions and decided to make a simpler POJO mapping to Mongo using &lt;a href="http://code.google.com/p/morphia/"&gt;Morphia&lt;/a&gt;, a Java data mapper for Mongo that takes care of the nitty-gritty details and repetitive coding, for only a minor performance hit. Since Mongo only supports atomicity for a single query, we reverted to manual transaction handling and decided to ditch the EJBs that formed the backbone of GSS altogether, since they didn’t buy us anything at that point. The new GSS server would be a set of servlets, service and domain objects, wired together via &lt;a href="http://code.google.com/p/google-guice/"&gt;Google Guice&lt;/a&gt;. Since we could host the new server in a plain servlet container, we went from JBoss to Jetty, which vastly reduced the server startup time from 60 seconds down to 2. As a consequence, development round-trip times went down, and coding was fast again. Lots of object copying and conversions from entities to DTOs and back again were now unnecessary, since there was no more a transaction boundary at the session bean layer. This kept memory usage low, increased cache locality and boosted performance. There are lots of interesting details about our approach, but they would be better discussed in separate blog posts. If you are interested, you can already check out the code in the gss2 branch of the GSS &lt;a href="http://code.google.com/p/gss/source/checkout"&gt;repository&lt;/a&gt;.&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; background-color: transparent; font-family: Times; font-size: medium; "&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; background-color: transparent; font-family: Times; font-size: medium; "&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;The next generation GSS server is not production ready yet, but we'll be getting there soon, and so far it has been a great ride!&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/486398466531826618-6975307554232582841?l=blog.astithas.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/PastMidnight/~4/4O1WW-E9nk8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.astithas.com/feeds/6975307554232582841/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=486398466531826618&amp;postID=6975307554232582841" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/6975307554232582841?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/6975307554232582841?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/PastMidnight/~3/4O1WW-E9nk8/gsspithos-update-iphone-android-mongo.html" title="GSS/Pithos update: iPhone, Android, Mongo &amp; getting to 2.0" /><author><name>Panagiotis Astithas</name><uri>https://profiles.google.com/116466326438420686438</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-ieNj_PE2fxE/AAAAAAAAAAI/AAAAAAAAAAA/l78jhJX3laA/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_zFF22LLF49M/TLTUUcxuYPI/AAAAAAAAAd4/Sn5KhT8NmHI/s72-c/icon.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://blog.astithas.com/2010/10/gsspithos-update-iphone-android-mongo.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0cDQXo7fSp7ImA9WxBVFkw.&quot;"><id>tag:blogger.com,1999:blog-486398466531826618.post-5629015476837849520</id><published>2010-02-19T22:23:00.006+02:00</published><updated>2010-02-20T00:37:50.405+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-02-20T00:37:50.405+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="open-source" /><category scheme="http://www.blogger.com/atom/ns#" term="software" /><category scheme="http://www.blogger.com/atom/ns#" term="startups" /><category scheme="http://www.blogger.com/atom/ns#" term="web" /><title>The Cloud Desktop</title><content type="html">&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_zFF22LLF49M/S38Q_jQChrI/AAAAAAAAAbE/NZOHJyZeuCo/s1600-h/3-mnf-logo-big%5B1%5D.png"&gt;&lt;img style="display:block; margin:0 10px 10px 0; text-align:center;cursor:pointer; cursor:hand; width: 400px; height: 63px;" src="http://2.bp.blogspot.com/_zFF22LLF49M/S38Q_jQChrI/AAAAAAAAAbE/NZOHJyZeuCo/s400/3-mnf-logo-big%5B1%5D.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5440085558867166898" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;&lt;i&gt;This was originally &lt;/i&gt;&lt;a href="http://home.mynetworkfolders.com/general/browser-days/"&gt;&lt;i&gt;posted&lt;/i&gt;&lt;/a&gt;&lt;i&gt; in the mynetworkfolders.com &lt;/i&gt;&lt;a href="http://home.mynetworkfolders.com/blog/"&gt;&lt;i&gt;blog&lt;/i&gt;&lt;/a&gt;&lt;i&gt;.&lt;/i&gt;&lt;/div&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;We live in a browser these days. &lt;a href="http://mail.google.com/"&gt;E-mail&lt;/a&gt;, &lt;a href="http://docs.google.com/"&gt;word-processing&lt;/a&gt;, &lt;a href="http://docs.google.com/"&gt;spreadsheets&lt;/a&gt;, &lt;a href="http://www.facebook.com/"&gt;chat&lt;/a&gt;, are all occupying a browser window in front of me. Maybe not for everyone yet, but the trend is clear, and has been clear for quite some time now. This is a good thing. The Web of today bears little similarity to the Web of the millennium. It's fast, it's powerful and it's ubiquitous. A consequence of that evolution is the simplicity with which I can continue my work when leaving my Linux workstation at work and sit in front of my Mac at home. Since my applications are web-based, they are OS- and browser-agnostic. More importantly, my data are always there when I need them. Readily accessible from my desktop, laptop or mobile phone. I may keep local backups for archival purposes, but my master copies are always online.&lt;/div&gt;&lt;br /&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;Assuming this trend is indeed inescapable, one can't help but wonder: what are the applications that have not migrated to the cloud, yet? What kind of things would I like to do online, seamlessly, from every device I own? What are the barriers that make our current online experience less powerful than the desktop one?&lt;/div&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;One thing that we noticed was missing from the online desktop, was the... desktop! Yes, my spreadsheets are online. Sure, my pictures are online. Yes, I can upload arbitrary files in various storage services. But, I couldn't find a way to use a familiar file manager interface to work with my data in the cloud, as I do on my computer. This was the need we decided to fulfill with &lt;a href="http://home.mynetworkfolders.com/"&gt;MyNetworkFolders&lt;/a&gt;.&lt;/div&gt;&lt;br /&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;MyNetworkFolders attempts to provide an answer to the question: how would my desktop look in the cloud? And even though we are nowhere near done yet, the results so far are exciting and very promising.&lt;/div&gt;&lt;br /&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 249px;" src="http://1.bp.blogspot.com/_zFF22LLF49M/S378OvaKdlI/AAAAAAAAAa8/lXj0k2kGyeE/s400/mnf-desktop.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5440062730084709970" /&gt;MyNetworkFolders offers a familiar file manager &lt;a href="http://home.mynetworkfolders.com/tour/"&gt;interface&lt;/a&gt; for my cloud storage needs, with &lt;a href="http://home.mynetworkfolders.com/features/"&gt;advanced functionality&lt;/a&gt; and ease of use. Documents can be viewed, modified, searched or sent to the trash. They can be shared with other users or among the members of a group using flexible ACLs, or even be publicly accessible from the whole internet. They can be versioned for tracking changes more effectively. The service can be accessed from a variety of ways, including a web browser, a desktop client, a WebDAV network share or (really soon) a mobile phone. But most importantly, there is no vendor lock-in. There is a REST-like API available, battle-tested from all the above client implementations, giving everyone the opportunity to access his data in his own particular way. Or even get them out of our service altogether.&lt;br /&gt;&lt;br /&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;Oh, and one other thing. It's all based on open-source software. The &lt;a href="http://code.google.com/p/gss/"&gt;core&lt;/a&gt; infrastructure, the &lt;a href="http://code.google.com/p/gss/"&gt;various&lt;/a&gt; &lt;a href="http://code.google.com/p/mnf-desktop/"&gt;clients&lt;/a&gt; we have built, even API &lt;a href="http://code.google.com/p/gss/wiki/APIClients"&gt;helpers&lt;/a&gt; in various programming languages, are all available for anyone and everyone to see, use and modify. Or maybe used to setup and run YourNetworkFolders, if you feel really ambitious.&lt;/div&gt;&lt;br /&gt;&lt;div style="margin-top: 0px; margin-bottom: 0px; "&gt;If however you just want a true desktop environment, with unparalleled flexibility, and maybe also see how far the cloud desktop rabbit-hole goes, then come along. It's going to be an exciting ride.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/486398466531826618-5629015476837849520?l=blog.astithas.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/PastMidnight/~4/-gy3V89hjdA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.astithas.com/feeds/5629015476837849520/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=486398466531826618&amp;postID=5629015476837849520" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/5629015476837849520?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/5629015476837849520?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/PastMidnight/~3/-gy3V89hjdA/cloud-desktop.html" title="The Cloud Desktop" /><author><name>Panagiotis Astithas</name><uri>https://profiles.google.com/116466326438420686438</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-ieNj_PE2fxE/AAAAAAAAAAI/AAAAAAAAAAA/l78jhJX3laA/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_zFF22LLF49M/S38Q_jQChrI/AAAAAAAAAbE/NZOHJyZeuCo/s72-c/3-mnf-logo-big%5B1%5D.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://blog.astithas.com/2010/02/cloud-desktop.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkcBRXw8fyp7ImA9WxBTEks.&quot;"><id>tag:blogger.com,1999:blog-486398466531826618.post-3460608531914453116</id><published>2009-12-07T23:50:00.002+02:00</published><updated>2009-12-08T12:27:34.277+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-12-08T12:27:34.277+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript" /><category scheme="http://www.blogger.com/atom/ns#" term="Java" /><category scheme="http://www.blogger.com/atom/ns#" term="startups" /><category scheme="http://www.blogger.com/atom/ns#" term="programming" /><category scheme="http://www.blogger.com/atom/ns#" term="web" /><category scheme="http://www.blogger.com/atom/ns#" term="business" /><title>Lessons from Startup Weekend</title><content type="html">&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_zFF22LLF49M/Sx11UJYl82I/AAAAAAAAAZI/XgWYmJrAy98/s1600-h/newspeek3.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 64px; height: 64px;" src="http://1.bp.blogspot.com/_zFF22LLF49M/Sx11UJYl82I/AAAAAAAAAZI/XgWYmJrAy98/s400/newspeek3.png" alt="" id="BLOGGER_PHOTO_ID_5412611316146107234" border="0" /&gt;&lt;/a&gt;I had an exhausting but fun weekend at the &lt;a href="http://athens.startupweekend.org/"&gt;Athens Startup Weekend&lt;/a&gt; a few days ago. Along with &lt;a href="http://chstath.blogspot.com/"&gt;Christos&lt;/a&gt; I joined Yannis Kekatos, Panagiotis Christakos and Babis Makrinikolas on the Newspeek project. When Yannis pitched the idea on Friday night, the main concept was to create a mobile phone application that would provide a better way to view news on the go. I don't believe it was very clear in his mind then, what would constitute a "better" experience, but after some chatting about it we all defined a few key aspects, which we refined later with lots of useful feedback and help from &lt;a href="http://gtziralis.com/"&gt;George&lt;/a&gt;. Surprisingly, for me at least, in only two days we managed to design, build and present a working prototype in front of the judges and the other teams. And even though the demo wasn't exactly on par with our accomplishments, I'm still amazed at what can be created in such a short time frame. &lt;div&gt;&lt;img style="margin: 0pt auto 10px; display: block; text-align: center; cursor: pointer; width: 213px; height: 400px;" src="http://2.bp.blogspot.com/_zFF22LLF49M/Sx11pJyGaZI/AAAAAAAAAZY/Xm3utRl6ymo/s400/newspeek2.png" alt="" id="BLOGGER_PHOTO_ID_5412611677030345106" border="0" /&gt;&lt;/div&gt;&lt;div&gt;Newspeek, our product, had a server-side component that periodically collected news items from various news feeds, stored them and provided them to clients through a simple REST API. It also had an iPhone client that fetched the news items and presented them to the user in a way that respected the UI requirements and established UX norms for that device.&lt;/div&gt;&lt;div&gt;&lt;div style="text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;img style="margin: 0pt auto 10px; display: block; text-align: center; cursor: pointer; width: 215px; height: 400px;" src="http://3.bp.blogspot.com/_zFF22LLF49M/Sx11eGpzIuI/AAAAAAAAAZQ/JpBrHMOp-rM/s400/newspeek1.png" alt="" id="BLOGGER_PHOTO_ID_5412611487211660002" border="0" /&gt;&lt;/div&gt;&lt;div&gt;So, in the interest of informing future participants about what works and what doesn't work in Startup Weekend, here are the lessons I learned:&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;&lt;b&gt;If you plan to win, work on the business aspect, not on the technology&lt;/b&gt;. Personally, I didn't go to ASW with plans to create a startup, so I didn't care that much about winning. I mostly considered the event as a hackathon, and tried my best to end up with a working prototype. Other teams focused more on the business side of things, which is understandable, given the prize. Investors fund teams that have a good chance to return a profit, not the ones with cool technology and (mostly) working demos. Still, the small number of actual working prototypes was a disappointment for me. Even though the developers were the majority in the event, you obviously can't have too many of them in a Startup Weekend.&lt;/li&gt;&lt;li&gt;&lt;b&gt;For quick server-side prototyping and hosting, &lt;/b&gt;&lt;a href="http://code.google.com/appengine/"&gt;&lt;b&gt;Google App Engine&lt;/b&gt;&lt;/a&gt;&lt;b&gt; is your friend&lt;/b&gt;. Since everyone in the team had Java experience, we could have gone with a JavaEE solution and set up a dedicated server to host the site. But, since I've always wanted to try App Engine for Java and the service architecture mapped nicely to it, we tried a short experiment to see if it could fly. We built a stub service in just a few minutes, so we decided it was well worth it. Building our RESTful service was really fast, scalability was never a concern and the deployment solution was a godsend, since the hosting service provided for free by the event sponsors was evidently overloaded. We're definitely going to use it again for other projects.&lt;/li&gt;&lt;li&gt;&lt;b&gt;jQTouch rocks&lt;/b&gt;! Since our main deliverable would be an iPhone application, and there were only two of us who had ever built an iPhone application (of the Hello World variety), we knew we had a problem. Fortunately, I had followed the jQTouch development from a reasonable distance and had &lt;a href="http://ajaxian.com/archives/jqtouch-releases-new-version-of-mobile-goodness"&gt;witnessed&lt;/a&gt; &lt;a href="http://ajaxian.com/archives/jqtouch-a-mobile-webkit-javascript-framework"&gt;the&lt;/a&gt; &lt;a href="http://twitter.com/joehewitt/status/5906794560"&gt;good&lt;/a&gt; &lt;a href="http://twitter.com/joehewitt/status/5907177503"&gt;things&lt;/a&gt; people had to say, so I pitched the idea of a web application to the team and it was well received. iPhone applications built with web technologies and &lt;a href="http://www.jqtouch.com/"&gt;jQTouch&lt;/a&gt; can be almost indistinguishable from native ones. We all had some experience in building web applications, so the prospect of having a working prototype in only two days seemed within the realm of possibility again. The future option of packaging the application with &lt;a href="http://phonegap.com/"&gt;PhoneGap&lt;/a&gt; and selling it in the App Store was also a bonus point for our modest business plan. &lt;/li&gt;&lt;li&gt;&lt;b&gt;For ad-hoc collaboration, Mercurial wins&lt;/b&gt;. Without time to set up central repositories, a DVCS was the obvious choice, and Mercurial has both &lt;a href="http://mercurial.selenic.com/wiki/Bundle"&gt;bundles&lt;/a&gt; and a standalone &lt;a href="http://mercurial.selenic.com/wiki/Serve"&gt;server&lt;/a&gt; that make collaborative coding a breeze. If we had zeroconf/bonjour set up in all of our laptops, we would have used the &lt;a href="http://mercurial.selenic.com/wiki/ZeroconfExtension"&gt;zeroconf&lt;/a&gt; extension for dead easy machine lookup, but even without it things worked flawlessly.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;You can write code with a netbook&lt;/span&gt;. Since I haven't owned a laptop for the last three years, my only portable computer is an Asus EEE PC 901 &lt;a href="http://astithas.blogspot.com/2009/06/ubuntu-on-eee-pc.html"&gt;running Linux&lt;/a&gt;. Its original purpose was to allow me to browse the web from the comfort of my couch. Lately however, I'm finding myself using it to write software more than anything else. During the Startup Weekend it had constantly open Eclipse (for server-side code), Firefox (for JavaScript debugging), Chrome (for webkit rendering), gedit (for client-side code) and a terminal, without breaking a sweat.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;When demoing an iPhone application, whatever you do, don't sweat&lt;/b&gt;. Half-way through our presentation, tapping the buttons didn't work reliably all the time, so anxiety ensued. Since we couldn't make a proper presentation due to a missing cable, we opted for a live demo, wherein Yannis held the mic and made the presentation, and I posed as the bimbo that holds the product and clicks around. After a while we ended up both touching the screen, trying to make the bloody buttons click, which ensured the opposite effect. In retrospect, using a cloth occasionally would have made for a smoother demo, plus we could have slipped a joke in there, to keep the spirit up.&lt;/li&gt;&lt;/ol&gt;All in all it was an awesome experience, where we learned how far we can stretch ourselves, made new friends and caught up with old ones. Next year, I'll make sure I have a napkin, too.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/486398466531826618-3460608531914453116?l=blog.astithas.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/PastMidnight/~4/oPE_mDZ520U" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.astithas.com/feeds/3460608531914453116/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=486398466531826618&amp;postID=3460608531914453116" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/3460608531914453116?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/3460608531914453116?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/PastMidnight/~3/oPE_mDZ520U/lessons-from-startup-weekend.html" title="Lessons from Startup Weekend" /><author><name>Panagiotis Astithas</name><uri>https://profiles.google.com/116466326438420686438</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-ieNj_PE2fxE/AAAAAAAAAAI/AAAAAAAAAAA/l78jhJX3laA/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_zFF22LLF49M/Sx11UJYl82I/AAAAAAAAAZI/XgWYmJrAy98/s72-c/newspeek3.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://blog.astithas.com/2009/12/lessons-from-startup-weekend.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUAFRH45eyp7ImA9WxNSEUg.&quot;"><id>tag:blogger.com,1999:blog-486398466531826618.post-7763781294935709117</id><published>2009-08-20T14:06:00.002+03:00</published><updated>2009-08-25T00:41:55.023+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-08-25T00:41:55.023+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript" /><category scheme="http://www.blogger.com/atom/ns#" term="open-source" /><category scheme="http://www.blogger.com/atom/ns#" term="software" /><category scheme="http://www.blogger.com/atom/ns#" term="programming" /><title>Spell-checking in JavaScript</title><content type="html">I just heard of &lt;a href="http://www.codinghorror.com/blog/archives/000913.html"&gt;Atwood's Law&lt;/a&gt; a few days ago. Apparently &lt;a href="http://www.codinghorror.com/"&gt;Jeff Atwood&lt;/a&gt; first published his discovery a couple of years ago, which is like a century in Internet time, but I can't keep up with everything. The Law states that "any application that &lt;i&gt;can&lt;/i&gt; be written in JavaScript, &lt;i&gt;will&lt;/i&gt; eventually be written in JavaScript". As Atwood explains, it is based on Tim Berners-Lee's &lt;a href="http://www.w3.org/DesignIssues/Principles.html"&gt;Principle Of Least Power&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;Computer Science spent the last forty years making languages which were as powerful as possible. Nowadays we have to appreciate the reasons for &lt;b&gt;picking not the most powerful solution but the &lt;i&gt;least&lt;/i&gt; powerful&lt;/b&gt;. The less powerful the language, the more you can do with the data stored in that language.&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;I think there is a common theme between Atwood's Law, &lt;a href="http://en.wikipedia.org/wiki/Zawinski%27s_law_of_software_envelopment#Quotes"&gt;Zawinski's Law&lt;/a&gt; ("Every program attempts to expand until it can read &lt;a href="http://en.wikipedia.org/wiki/E-mail" title="E-mail"&gt;mail&lt;/a&gt;. Those programs which cannot so expand are replaced by ones which can") and &lt;a href="http://en.wikipedia.org/wiki/Greenspun%27s_Tenth_Rule"&gt;Greenspun's Tenth Rule&lt;/a&gt; ("Any sufficiently complicated &lt;a href="http://en.wikipedia.org/wiki/C_%28programming_language%29" title="C (programming language)"&gt;C&lt;/a&gt; or &lt;a href="http://en.wikipedia.org/wiki/Fortran" title="Fortran"&gt;Fortran&lt;/a&gt; program contains an ad hoc, informally-specified, &lt;a href="http://en.wikipedia.org/wiki/Computer_bug" title="Computer bug" class="mw-redirect"&gt;bug-ridden&lt;/a&gt;, slow implementation of half of &lt;a href="http://en.wikipedia.org/wiki/Common_Lisp" title="Common Lisp"&gt;Common Lisp&lt;/a&gt;"). The inevitability of the specified outcome makes the world seem like a much simpler place. There is no need to argue. Believe and ye shall be redeemed.&lt;br /&gt;&lt;br /&gt;I might have been in this state of mind, when I came across Peter Norvig's "&lt;a href="http://norvig.com/spell-correct.html"&gt;How to Write a Spelling Corrector&lt;/a&gt;", because I knew instantly I had to port the algorithm to JavaScript. The algorithm is quite simple and has already been ported to many different languages, so I seized the opportunity to study the differences in expressiveness, performance and style, between these languages and my latest affection, JavaScript.&lt;br /&gt;&lt;br /&gt;After a few night's work I have it working and free (as in beer &lt;span style="font-style: italic;"&gt;and&lt;/span&gt; speech) for anyone to use. Check out the &lt;a href="http://github.com/past/speller/tree/master"&gt;speller&lt;/a&gt; project on GitHub. If you want to understand how the algorithm works, you should go and read Norvig's &lt;a href="http://norvig.com/spell-correct.html"&gt;article&lt;/a&gt;,  although you might get some hints from the &lt;a href="http://github.com/past/speller/raw/master/lib/speller.js"&gt;comments&lt;/a&gt; in my code. The modestly condensed version of the code is 53 lines:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: js"&gt;&lt;br /&gt;var speller = {};&lt;br /&gt;speller.train = function (text) {&lt;br /&gt;  var m;&lt;br /&gt;  while ((m = /[a-z]+/g.exec(text.toLowerCase()))) {&lt;br /&gt;    speller.nWords[m[0]] = speller.nWords.hasOwnProperty(m[0]) ? speller.nWords[m[0]] + 1 : 1;&lt;br /&gt;  }&lt;br /&gt;};&lt;br /&gt;speller.correct = function (word) {&lt;br /&gt;  if (speller.nWords.hasOwnProperty(word)) return word;&lt;br /&gt;  var candidates = {}, list = speller.edits(word);&lt;br /&gt;  list.forEach(function (edit) {&lt;br /&gt;    if (speller.nWords.hasOwnProperty(edit)) candidates[speller.nWords[edit]] = edit;&lt;br /&gt;  });&lt;br /&gt;  if (speller.countKeys(candidates) &amp;gt; 0) return candidates[speller.max(candidates)];&lt;br /&gt;  list.forEach(function (edit) {&lt;br /&gt;    speller.edits(edit).forEach(function (w) {&lt;br /&gt;      if (speller.nWords.hasOwnProperty(w)) candidates[speller.nWords[w]] = w;&lt;br /&gt;    });&lt;br /&gt;  });&lt;br /&gt;  return speller.countKeys(candidates) &amp;gt; 0 ? candidates[speller.max(candidates)] : word;&lt;br /&gt;};&lt;br /&gt;speller.nWords = {};&lt;br /&gt;speller.countKeys = function (object) {&lt;br /&gt;  var attr, count = 0;&lt;br /&gt;  for (attr in object)&lt;br /&gt;    if (object.hasOwnProperty(attr))&lt;br /&gt;      count++;&lt;br /&gt;  return count;&lt;br /&gt;};&lt;br /&gt;speller.max = function (candidates) {&lt;br /&gt;  var candidate, arr = [];&lt;br /&gt;  for (candidate in candidates)&lt;br /&gt;    if (candidates.hasOwnProperty(candidate))&lt;br /&gt;      arr.push(candidate);&lt;br /&gt;  return Math.max.apply(null, arr);&lt;br /&gt;};&lt;br /&gt;speller.letters = "abcdefghijklmnopqrstuvwxyz".split("");&lt;br /&gt;speller.edits = function (word) {&lt;br /&gt;  var i, results = [];&lt;br /&gt;  for (i=0; i &amp;lt; word.length; i++)&lt;br /&gt;    results.push(word.slice(0, i) + word.slice(i+1));&lt;br /&gt;  for (i=0; i &amp;lt; word.length-1; i++)&lt;br /&gt;    results.push(word.slice(0, i) + word.slice(i+1, i+2) + word.slice(i, i+1) + word.slice(i+2));&lt;br /&gt;  for (i=0; i &amp;lt; word.length; i++)&lt;br /&gt;    speller.letters.forEach(function (l) {&lt;br /&gt;      results.push(word.slice(0, i) + l + word.slice(i+1));&lt;br /&gt;    });&lt;br /&gt;  for (i=0; i &amp;lt;= word.length; i++)&lt;br /&gt;    speller.letters.forEach(function (l) {&lt;br /&gt;      results.push(word.slice(0, i) + l + word.slice(i));&lt;br /&gt;    });&lt;br /&gt;  return results;&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;It may not be as succinct as Norvig's Python version (21 lines), or the record-holding Awk and F# versions (15 lines), but is much better than C (184 lines), C++, Perl, PHP, Rebol and Erlang. There is even a Java version with 372 lines. It must contain some sort of spell-checking framework in there, or something. The condensed version above, although correct, has terrible performance in most JavaScript engines, however. For real-world use you should pick the &lt;a href="http://github.com/past/speller/raw/master/lib/speller.js"&gt;regular&lt;/a&gt; version which may be slightly longer, but performs &lt;span style="font-style: italic;"&gt;much&lt;/span&gt; better.&lt;br /&gt;&lt;br /&gt;Since this was a toy project of mine, I wanted to play with &lt;a href="https://wiki.mozilla.org/ServerJS"&gt;ServerJS&lt;/a&gt; modules as well, in order to run it as a shell script. I turned the code into a securable module, so you can run it from the command line, using &lt;a href="http://www.narwhaljs.org/"&gt;narwhal&lt;/a&gt;. I have a &lt;a href="http://github.com/past/speller/raw/master/bin/spellcheck"&gt;couple&lt;/a&gt; &lt;a href="http://github.com/past/speller/raw/master/tests/test"&gt;of scripts&lt;/a&gt; to that end. Of course since this is JavaScript, you can try it from your browser, by visiting the &lt;a href="http://past.github.com/speller/"&gt;demo&lt;/a&gt; page, courtesy of GitHub Pages. Be sure to use a modern browser, like Firefox 3.5, Safari 4 or Chrome 3 (beta), otherwise you won't be able to run the test suite, since I used the brand-new &lt;a href="http://www.whatwg.org/specs/web-workers/current-work/"&gt;Web Workers&lt;/a&gt; to make the long-running tasks run in the background.&lt;br /&gt;&lt;br /&gt;Norvig's Python implementation took 16 seconds for test 1 and the best I got was 25 seconds with Safari 4 on my Mac. Narwhal is using &lt;a href="http://www.mozilla.org/rhino/"&gt;Rhino&lt;/a&gt; by default, so it is definitely not competitive in such tests (139 seconds), but I'm planning to fix support for &lt;a href="http://code.google.com/p/v8cgi/"&gt;v8cgi&lt;/a&gt; and give that a try.&lt;br /&gt;&lt;br /&gt;And it goes without saying that I'd love to hear about ways to improve the performance or the conciseness of the code. If you have any ideas, don't be shy, leave a comment or even better fork the code and send me a pull request on GitHub.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/486398466531826618-7763781294935709117?l=blog.astithas.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/PastMidnight/~4/v0uH-MqrelI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.astithas.com/feeds/7763781294935709117/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=486398466531826618&amp;postID=7763781294935709117" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/7763781294935709117?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/7763781294935709117?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/PastMidnight/~3/v0uH-MqrelI/spell-checking-in-javascript.html" title="Spell-checking in JavaScript" /><author><name>Panagiotis Astithas</name><uri>https://profiles.google.com/116466326438420686438</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-ieNj_PE2fxE/AAAAAAAAAAI/AAAAAAAAAAA/l78jhJX3laA/s512-c/photo.jpg" /></author><thr:total>3</thr:total><feedburner:origLink>http://blog.astithas.com/2009/08/spell-checking-in-javascript.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEEHRHo9fCp7ImA9WxJUEE0.&quot;"><id>tag:blogger.com,1999:blog-486398466531826618.post-7272064534739273552</id><published>2009-07-07T16:23:00.001+03:00</published><updated>2009-07-08T01:43:55.464+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-07-08T01:43:55.464+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript" /><category scheme="http://www.blogger.com/atom/ns#" term="open-source" /><category scheme="http://www.blogger.com/atom/ns#" term="Java" /><category scheme="http://www.blogger.com/atom/ns#" term="gss" /><category scheme="http://www.blogger.com/atom/ns#" term="software" /><category scheme="http://www.blogger.com/atom/ns#" term="programming" /><category scheme="http://www.blogger.com/atom/ns#" term="web" /><title>GSS authentication</title><content type="html">As I've described &lt;a href="http://astithas.blogspot.com/2009/04/introduction-to-gss-api.html"&gt;before&lt;/a&gt;, the &lt;a href="http://code.google.com/p/gss/wiki/API"&gt;GSS API&lt;/a&gt; is a REST-like interface for interacting with a GSS-based service, like &lt;a href="http://pithos.grnet.gr/"&gt;Pithos&lt;/a&gt;. Using regular HTTP commands a client can upload, download, browse and modify files and folders stored in the GSS server. These interactions have two important properties: they store no client state to the server and they are not encrypted. I have &lt;a href="http://astithas.blogspot.com/2009/04/introduction-to-gss-api.html"&gt;already&lt;/a&gt; mentioned the most important benefits from the stateless architecture of the GSS protocol, namely scalability and loose coupling along the client-server boundary. In the same line of thought, SSL/TLS encryption of the transport was avoided for &lt;a href="http://astithas.blogspot.com/2009/04/gss-architecture.html"&gt;scalability reasons&lt;/a&gt;. Consequently, these two properties of the communication protocol, lead to another requirement: message authentication for each API call.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Since no session state is stored in the server, the client must authenticate each request as if it were the first one. Traditional web applications use an initial authentication interaction between client and server, that creates a unique session ID, which is transmitted with each subsequent request in that same session. While using this ID, the client does not need to authenticate again to the server. Stateless protocols, like &lt;a href="http://webdav.org/"&gt;WebDAV&lt;/a&gt; for instance, cannot rely on such an ID and have to transmit authentication data in each call. Ultimately the tradeoff is a minor increase in the message payload, in return for a big boost in scalability. The HTTP specification &lt;a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.8"&gt;defines&lt;/a&gt; an Authorization header for use in such cases and WebDAV uses the &lt;a href="http://www.ietf.org/rfc/rfc2617.txt"&gt;HTTP Digest Access Authentication&lt;/a&gt; scheme. The GSS API uses a slight variation in that theme, blended with some ideas from &lt;a href="http://oauth.net/core/1.0a#signing_process"&gt;OAuth request signing&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Essentially the standard HTTP Authorization header is populated with a concatenation of the username (for identifying the user making the request) and a &lt;a href="http://en.wikipedia.org/wiki/HMAC"&gt;HMAC-SHA1&lt;/a&gt; signature of the request. The request signature is obtained by applying a secret authentication token to a concatenated string of the HTTP method name, the date and time of the request and the actual requested path. The GSS API &lt;a href="http://code.google.com/p/gss/wiki/API"&gt;page&lt;/a&gt; has all the details. The inclusion of the date and time helps thwart replay attacks using a previously sniffed signature. Furthermore, a separate header with timestamp information, X-GSS-Date, is used to thwart replay attacks with a full copy of the payload. The authentication token is issued securely by the server to the client and is the time-limited secret that is shared between the client and server. Since it is not the user password that is used as a shared secret, were the authentication token to be compromised, any ill effects would have been limited to the time period the token was valid. There are two ways for client applications to obtain the user's authentication token, and they are both described in detail in the API documentation.&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;br /&gt;&lt;div&gt;In my experience, protocol descriptions are one thing and working code is a totally different one. In that spirit, I'm closing this post with a few tested implementations of the GSS API signature calculation, for client applications in different languages. Here is the method for signing a GSS API request in Java (full code &lt;a href="http://code.google.com/p/gss/source/browse/test/gr/ebs/gss/client/TestClient.java"&gt;here&lt;/a&gt;):&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;public static String sign(String httpMethod, String timestamp,&lt;br /&gt;        String path, String token) {&lt;br /&gt;  String input = httpMethod + timestamp + path;&lt;br /&gt;  String signed = null;&lt;br /&gt;&lt;br /&gt;  try {&lt;br /&gt;    System.err.println("Token:" + token);&lt;br /&gt;    // Get an HMAC-SHA1 key from the authentication token.&lt;br /&gt;    System.err.println("Input: " + input);&lt;br /&gt;    SecretKeySpec signingKey = new SecretKeySpec(&lt;br /&gt;        Base64.decodeBase64(token.getBytes()), "HmacSHA1");&lt;br /&gt;&lt;br /&gt;    // Get an HMAC-SHA1 Mac instance and initialize with the signing key.&lt;br /&gt;    Mac hmac = Mac.getInstance("HmacSHA1");&lt;br /&gt;    hmac.init(signingKey);&lt;br /&gt;&lt;br /&gt;    // Compute the HMAC on the input data bytes.&lt;br /&gt;    byte[] rawMac = hmac.doFinal(input.getBytes());&lt;br /&gt;&lt;br /&gt;    // Do base 64 encoding.&lt;br /&gt;    signed = new String(Base64.encodeBase64(rawMac), "US-ASCII");&lt;br /&gt;&lt;br /&gt;  } catch (InvalidKeyException ikex) {&lt;br /&gt;    System.err.println("Fatal key exception: " + ikex.getMessage());&lt;br /&gt;    ikex.printStackTrace();&lt;br /&gt;  } catch (UnsupportedEncodingException ueex) {&lt;br /&gt;    System.err.println("Fatal encoding exception: "&lt;br /&gt;                + ueex.getMessage());&lt;br /&gt;  } catch (NoSuchAlgorithmException nsaex) {&lt;br /&gt;    System.err.println("Fatal algorithm exception: "&lt;br /&gt;                + nsaex.getMessage());&lt;br /&gt;    nsaex.printStackTrace();&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  if (signed == null)&lt;br /&gt;    System.exit(-1);&lt;br /&gt;  System.err.println("Signed: " + signed);&lt;br /&gt;  return signed;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Here is a method for signing GSS API requests in JavaScript, that uses the SHA-1 JavaScript &lt;a href="http://pajhome.org.uk/crypt/md5/sha1.html"&gt;implementation&lt;/a&gt; by Paul Johnston (full code &lt;a href="http://github.com/past/igss/raw/master/iGSS.dcproj/project/gss.js"&gt;here&lt;/a&gt;):&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;pre class="brush: js"&gt;&lt;br /&gt;function sign(method, time, resource, token) {&lt;br /&gt;  var q = resource.indexOf('?');&lt;br /&gt;  var res = q == -1? resource: resource.substring(0, q);&lt;br /&gt;  var data = method + time + res;&lt;br /&gt;  // Use strict RFC compliance&lt;br /&gt;  b64pad = "=";&lt;br /&gt;  return b64_hmac_sha1(atob(token), data);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Here is a Tcl implementation by Alexios Zavras (full code &lt;a href="http://gssc.svn.sourceforge.net/viewvc/gssc/gssc.vfs/lib/rest/sign.tcl?view=markup"&gt;here&lt;/a&gt;):&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;pre class="brush: shell"&gt;&lt;br /&gt;proc ::rest::_sign {id} {&lt;br /&gt;  variable $id&lt;br /&gt;  upvar 0 $id data&lt;br /&gt;  set str2sign ""&lt;br /&gt;  append str2sign $data(method)&lt;br /&gt;  append str2sign $data(date)&lt;br /&gt;  set idx [string first ? $data(path)]&lt;br /&gt;  if {$idx &amp;lt; 0} {&lt;br /&gt;    set str $data(path)&lt;br /&gt;  } else {&lt;br /&gt;    incr idx -1&lt;br /&gt;    set str [string range $data(path) 0 $idx]&lt;br /&gt;  }&lt;br /&gt;  # append str2sign [::util::url::encode $str]&lt;br /&gt;  append str2sign $str&lt;br /&gt;  puts "SIGN $str2sign"&lt;br /&gt;  set sig [::base64::encode [::sha1::hmac -bin -key $::GG(gsstoken) $str2sign]]&lt;br /&gt;  set data(signature) $sig&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'd love to show implementations of the signature calculation for other languages as well, but since my time is scarce these days, I could use some help here. If you've written one yourself and you'd like to share, leave a comment and I'll update this post, with proper attribution of course.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/486398466531826618-7272064534739273552?l=blog.astithas.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/PastMidnight/~4/YqGVcnac_Eg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.astithas.com/feeds/7272064534739273552/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=486398466531826618&amp;postID=7272064534739273552" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/7272064534739273552?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/7272064534739273552?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/PastMidnight/~3/YqGVcnac_Eg/gss-authentication.html" title="GSS authentication" /><author><name>Panagiotis Astithas</name><uri>https://profiles.google.com/116466326438420686438</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-ieNj_PE2fxE/AAAAAAAAAAI/AAAAAAAAAAA/l78jhJX3laA/s512-c/photo.jpg" /></author><thr:total>2</thr:total><feedburner:origLink>http://blog.astithas.com/2009/07/gss-authentication.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ak4MQH09cSp7ImA9WxJWEko.&quot;"><id>tag:blogger.com,1999:blog-486398466531826618.post-1372264105244185506</id><published>2009-06-17T19:25:00.004+03:00</published><updated>2009-06-18T01:49:41.369+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-06-18T01:49:41.369+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="databases" /><category scheme="http://www.blogger.com/atom/ns#" term="Java" /><category scheme="http://www.blogger.com/atom/ns#" term="gss" /><category scheme="http://www.blogger.com/atom/ns#" term="software" /><category scheme="http://www.blogger.com/atom/ns#" term="programming" /><title>Retrying transactions with exponential backoff</title><content type="html">The method I described in my previous post about &lt;a href="http://astithas.blogspot.com/2009/06/retrying-transactions-in-java.html"&gt;retrying transactions&lt;/a&gt; could use some improvement. A deficiency that will only become relevant in highly congested servers is the constant retry interval. When two or more transactions try to commit at the same time and fail, with the code from the last post they will retry probably simultaneously again. Random runtime events (like process/thread scheduler decisions, JIT compiler invocations, etc.) might help avoid collisions, but in general the collided transactions may well collide again. And again. And then again, until the specified maximum number of retries is reached.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The general method to alleviate such problems is to randomize the retry intervals. The most well-known algorithm in this category is called &lt;a href="http://en.wikipedia.org/wiki/Exponential_backoff"&gt;exponential backoff&lt;/a&gt;. This is one way to implement it for the utility method in my previous post (full code in &lt;a href="http://code.google.com/p/gss/source/browse/src/gr/ebs/gss/server/rest/TransactionHelper.java"&gt;gss&lt;/a&gt;):&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;public T tryExecute(final Callable&amp;lt;T&amp;gt; command) throws Exception {&lt;br /&gt;  T returnValue = null;&lt;br /&gt;  // Schedule a Future task to call the command after delay milliseconds.&lt;br /&gt;  int delay = 0;&lt;br /&gt;  ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);&lt;br /&gt;  for (int i = 0; i &amp;lt; TRANSACTION_RETRIES; i++) {&lt;br /&gt;    final int retry = i;&lt;br /&gt;    ScheduledFuture&amp;lt;T&amp;gt; future = executor.schedule(new Callable&amp;lt;T&amp;gt;() {&lt;br /&gt;&lt;br /&gt;      @Override&lt;br /&gt;      public T call() throws Exception {&lt;br /&gt;        return command.call();&lt;br /&gt;      }&lt;br /&gt;    }, delay, TimeUnit.MILLISECONDS);&lt;br /&gt;&lt;br /&gt;    try {&lt;br /&gt;      returnValue = future.get();&lt;br /&gt;      break;&lt;br /&gt;    } catch (ExecutionException e) {&lt;br /&gt;      Throwable cause = e.getCause();&lt;br /&gt;      if (!(cause instanceof EJBTransactionRolledbackException) ||&lt;br /&gt;          retry == TRANSACTION_RETRIES - 1) {&lt;br /&gt;        executor.shutdownNow();&lt;br /&gt;        throw new Exception(cause);&lt;br /&gt;      }&lt;br /&gt;      delay = MIN_TIMEOUT + (int) (MIN_TIMEOUT * Math.random() * (i + 1));&lt;br /&gt;      String origCause = cause.getCause() == null ?&lt;br /&gt;          cause.getClass().getName() :&lt;br /&gt;          cause.getCause().getClass().getName();&lt;br /&gt;      logger.info("Transaction retry #" + (i+1) + " scheduled in " + delay +&lt;br /&gt;          " msec due to " + origCause);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;  }&lt;br /&gt;  executor.shutdownNow();&lt;br /&gt;  return returnValue;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;The notable changes in this version are the delayed invocations of the Callable and the retry interval calculation. The former is accomplished using a &lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/ScheduledFuture.html"&gt;ScheduledFuture&lt;/a&gt; from the excellent utilities in java.util.concurrent, which gets executed after a random time period. The interval calculation is something that can be implemented in a number of ways, either with monotonically increasing intervals or not. I opted for the formula above since it provided the fastest collision elimination in my tests, much faster than the monotonically increasing interval formulas I tried. The MIN_TIMEOUT constant is more of a black art. It should be tuned to the particular hardware and network setup in order to attain maximum efficiency: the minimum number of retries with the minimum interval between retries.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Another issue raised in a &lt;a href="http://astithas.blogspot.com/2009/06/retrying-transactions-in-java.html?showComment=1245148011391#c1967231916381453980"&gt;comment&lt;/a&gt; in my previous post was that the exception I am using as guard, &lt;a href="http://java.sun.com/javaee/5/docs/api/javax/ejb/EJBTransactionRolledbackException.html"&gt;EJBTransactionRolledbackException&lt;/a&gt;, may be too generic for this purpose. This is definitely true, EJBTransactionRolledbackException just wraps an &lt;a href="http://java.sun.com/javaee/5/docs/api/javax/persistence/OptimisticLockException.html"&gt;OptimisticLockException&lt;/a&gt; as one would expect for this case, which in turn wraps the Hibernate-specific &lt;a href="https://www.hibernate.org/hib_docs/v3/api/org/hibernate/StaleObjectStateException.html"&gt;StaleObjectStateException&lt;/a&gt; that is thrown initially. However, contention in a database table, index or row might not necessarily result in optimistic locking violations, but in deadlocks as well, when one transaction holds exclusive locks on resources that are needed by the other and vice versa. Deadlock detection is performed by the DBMS, which forces a rollback of both transactions. This time however the initial exception (at least in my testing, might be DBMS or JDBC driver-specific) is &lt;a href="https://www.hibernate.org/hib_docs/v3/api/org/hibernate/exception/GenericJDBCException.html"&gt;GenericJDBCException&lt;/a&gt; which gets wrapped in a &lt;a href="http://java.sun.com/javaee/5/docs/api/javax/persistence/PersistenceException.html"&gt;PersistenceException&lt;/a&gt;, which in turn is put inside a EJBTransactionRolledbackException before being received by our call site. Therefore, the generic nature of the guard is not a problem in this case. On the contrary it covers more relevant cases and one might argue even that there is no better service that can be offered to the caller, than retrying in all such occasions.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/486398466531826618-1372264105244185506?l=blog.astithas.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/PastMidnight/~4/08hVwCCPvgg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.astithas.com/feeds/1372264105244185506/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=486398466531826618&amp;postID=1372264105244185506" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/1372264105244185506?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/1372264105244185506?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/PastMidnight/~3/08hVwCCPvgg/retrying-transactions-with-exponential.html" title="Retrying transactions with exponential backoff" /><author><name>Panagiotis Astithas</name><uri>https://profiles.google.com/116466326438420686438</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-ieNj_PE2fxE/AAAAAAAAAAI/AAAAAAAAAAA/l78jhJX3laA/s512-c/photo.jpg" /></author><thr:total>1</thr:total><feedburner:origLink>http://blog.astithas.com/2009/06/retrying-transactions-with-exponential.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkcNRXg4cCp7ImA9WxJWEko.&quot;"><id>tag:blogger.com,1999:blog-486398466531826618.post-550396475024477534</id><published>2009-06-15T16:18:00.011+03:00</published><updated>2009-06-18T01:34:54.638+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-06-18T01:34:54.638+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="databases" /><category scheme="http://www.blogger.com/atom/ns#" term="Java" /><category scheme="http://www.blogger.com/atom/ns#" term="gss" /><category scheme="http://www.blogger.com/atom/ns#" term="software" /><category scheme="http://www.blogger.com/atom/ns#" term="programming" /><title>Retrying transactions in Java</title><content type="html">When building a web-based system, the most often encountered persistence solution is the use of a relational DBMS. This provides many benefits, but probably the most important one is that its behavior and usage are widely understood after so many decades of use. The simplicity of the ACID transactional model, coupled with the nice fit of the HTTP request/response protocol, make for a killer combination.&lt;br /&gt;&lt;br /&gt;The simplicity starts to break down however, when the load on the DBMS server increases, causing transactions to start failing. The DBMS can guarantee that no data corruption will occur, but handling such cases is not that simple. The scalable &lt;a href="http://en.wikipedia.org/wiki/Optimistic_locking"&gt;Optimistic Locking&lt;/a&gt; model requires transactions to be resubmitted when failure occurs. Since this is supposed to be rather rare (otherwise optimistic locking should probably not be used), developers often cheat by not dealing with such errors, letting them bubble up to the user, who is then responsible for resubmitting the transaction. This leads to simple, elegant codebases and unhappy users.&lt;br /&gt;&lt;br /&gt;Adding &lt;a href="http://en.wikipedia.org/wiki/Object-relational_mapping"&gt;ORM&lt;/a&gt; to the mix only makes things worse. In JavaEE, the &lt;a href="http://en.wikipedia.org/wiki/Java_Persistence_API"&gt;JPA&lt;/a&gt; API hides much of the complexity of dealing with relational databases, but corner cases become &lt;a href="http://weblogs.java.net/blog/davidvc/archive/2007/04/jpa_and_rollbac.html"&gt;harder&lt;/a&gt;. Add the container-managed transaction boundaries provided by session EJBs and one might be tempted to raise his hands up in despair.&lt;br /&gt;&lt;br /&gt;However a solution is not as hard as it sounds. Provided that session EJB methods are sufficiently free from side effects, one can replay a transaction for a number of times from the call site (external to the session bean) with a small amount of code and a small added complexity to the call sites. Since I seem to come up against this requirement quite often, I thought I should describe one way to do it. The following tryExecute() helper method, retries any action supplied in a standard &lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/Callable.html"&gt;Callable&lt;/a&gt; interface for a number of times, in the face of optimistic locking violations:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;public T tryExecute(Callable&amp;lt;T&amp;gt; command) throws Exception {&lt;br /&gt;  T returnValue = null;&lt;br /&gt;  for (int i = 0; i &amp;lt; TRANSACTION_RETRIES; i++) {&lt;br /&gt;    try {&lt;br /&gt;      returnValue = command.call();&lt;br /&gt;      break;&lt;br /&gt;    } catch(EJBTransactionRolledbackException trbe) {&lt;br /&gt;      if (i == TRANSACTION_RETRIES - 1)&lt;br /&gt;        throw trbe;&lt;br /&gt;      } catch (Exception e) {&lt;br /&gt;        throw e;&lt;br /&gt;      }&lt;br /&gt;      logger.debug("Transaction retry: " + (i+1));&lt;br /&gt;    }&lt;br /&gt;  return returnValue;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;By abstracting away the session bean method code in a parameterized class we can reuse this method in every place that needs to retry transactions. Using a Callable as a parameter lets us return any values received from the session bean. For supplying bean methods that do not return values, we could create &lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Runnable.html"&gt;Runnable&lt;/a&gt; instances and wrap them to Callable using &lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/Executors.html"&gt;Executors&lt;/a&gt;.callable(). You can see the original code &lt;a href="http://code.google.com/p/gss/source/browse/src/gr/ebs/gss/server/rest/TransactionHelper.java"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;If you use the above code in a JavaSE environment without EJB, you should probably need to catch &lt;a href="http://java.sun.com/javaee/5/docs/api/javax/persistence/OptimisticLockException.html"&gt;OptimisticLockException&lt;/a&gt; for JPA, or even &lt;a href="https://www.hibernate.org/hib_docs/v3/api/org/hibernate/StaleObjectStateException.html"&gt;StaleObjectStateException&lt;/a&gt;, if you don't mind depending on a Hibernate API. I use the above helper method like this in my code:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;file = new TransactionHelper&amp;lt;FileHeaderDTO&amp;gt;().tryExecute(new Callable&amp;lt;FileHeaderDTO&amp;gt;() {&lt;br /&gt;  @Override&lt;br /&gt;  public FileHeaderDTO call() throws Exception {&lt;br /&gt;    return sessionBean.createFile(user.getId(), folder.getId(), name, mimeType, uploadedFile);&lt;br /&gt;  }&lt;br /&gt;});&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Java's verbosity makes this not that easy to understand at first sight, but what happens is very simple indeed: I wrap a one-liner call to the session bean method createFile(), in a Callable and supply it to tryExecute(). The result from the bean method is received in a local variable as usual. One thing to keep in mind though is that since Java doesn't have closures, the above anonymous function can only receive final variables as parameters. In my example user, folder, name, mimeType and uploadedFile are all final. You might have to resort to using temporary local variables for storing final values on some occasions.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/486398466531826618-550396475024477534?l=blog.astithas.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/PastMidnight/~4/TlePKpf2UT0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.astithas.com/feeds/550396475024477534/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=486398466531826618&amp;postID=550396475024477534" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/550396475024477534?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/550396475024477534?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/PastMidnight/~3/TlePKpf2UT0/retrying-transactions-in-java.html" title="Retrying transactions in Java" /><author><name>Panagiotis Astithas</name><uri>https://profiles.google.com/116466326438420686438</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-ieNj_PE2fxE/AAAAAAAAAAI/AAAAAAAAAAA/l78jhJX3laA/s512-c/photo.jpg" /></author><thr:total>2</thr:total><feedburner:origLink>http://blog.astithas.com/2009/06/retrying-transactions-in-java.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUENQnw7eSp7ImA9WxJXEUg.&quot;"><id>tag:blogger.com,1999:blog-486398466531826618.post-3494681038446811325</id><published>2009-06-04T12:19:00.000+03:00</published><updated>2009-06-05T01:14:53.201+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-06-05T01:14:53.201+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="open-source" /><category scheme="http://www.blogger.com/atom/ns#" term="Linux" /><title>Ubuntu on EEE PC</title><content type="html">&lt;div&gt;A few weeks ago I set out to upgrade Ubuntu on my EEE PC 901 from Intrepid to Jaunty. It was an, um, interesting experience, so I'm jotting down these notes for next time. Upgrading from Update Manager was not an option, because my root partition was not big enough to host the upgrade. The 901 has a 4GB SSD that I'm using as root and an 8GB (or 12GB) SSD that I've put /home on. It turns out that 4GB is OK for running a modern operating system, but a little short for updating it. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The usual procedure for upgrading is to use the official ISO images to boot from. As always you need a USB stick, or an external optical drive. I settled for the former, as you can see below.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_zFF22LLF49M/ShJqMGfkTiI/AAAAAAAAAWw/bo6YbTCjyt4/s1600-h/%CE%95%CE%B9%CE%BA%CF%8C%CE%BD%CE%B1205.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 320px;" src="http://1.bp.blogspot.com/_zFF22LLF49M/ShJqMGfkTiI/AAAAAAAAAWw/bo6YbTCjyt4/s400/%CE%95%CE%B9%CE%BA%CF%8C%CE%BD%CE%B1205.jpg" alt="" id="BLOGGER_PHOTO_ID_5337445264521448994" border="0" /&gt;&lt;/a&gt;The good news with Jaunty is that a special netbook edition is available for &lt;a href="http://www.ubuntu.com/getubuntu/download-netbook"&gt;download&lt;/a&gt;. With previous editions you had to start with the desktop edition and do lots of tweaking, to arrive at a satisfactory result. With the netbook edition however things were unbelievably smooth. Everything worked out of the box with my EEE PC. Well, almost everything, but I will get to that in a while.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The first step after downloading the ISO (for the security paranoid at least) is verifying the download:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;$ md5sum ubuntu-9.04-netbook-remix-i386.img&lt;br /&gt;8f921e001aebc3e98e8e8e7d29ee1dd4  ubuntu-9.04-netbook-remix-i386.img&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Then, we can write the image to the disk. I used Ubuntu ImageWriter (package usb-imagewriter) from another Ubuntu PC:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_zFF22LLF49M/ShEoeHv-u7I/AAAAAAAAAWo/2yUnKWeg3a0/s1600-h/Screenshot-ImageWriter.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 183px;" src="http://2.bp.blogspot.com/_zFF22LLF49M/ShEoeHv-u7I/AAAAAAAAAWo/2yUnKWeg3a0/s400/Screenshot-ImageWriter.png" alt="" id="BLOGGER_PHOTO_ID_5337091531352226738" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;That went very smooth. Next step was booting the EEE PC with the newly formatted USB disk. Hitting ESC on boot, allows one to change the boot drive sequence. If this is the first time you are replacing the original OS, you probably need to disable Boot Booster from the BIOS first. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The installation process is quite simple. The only important thing was partitioning in my case, since I wanted to preserve my /home partition intact. Last time I installed Ubuntu I went with ext2 filesystems, trying to squeeze as much life from my solid state disks as I could. After doing some more research on the subject, I decided that I'll probably throw away my EEE long before the disks begin to wear out. Either that, or I'll throw an SD card in the expansion slot. Life is full of choices, particularly on the $300 range.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So I selected manual partitioning and chose ext3 for my first SSD. This is a screenshot from my first attempt. No, actually it was my second attempt. I screwed up the first one. Turns out I screwed up this one, too. See if you can spot why.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_zFF22LLF49M/ShJqUOeHLjI/AAAAAAAAAW4/Y2DahRbEWM4/s1600-h/%CE%95%CE%B9%CE%BA%CF%8C%CE%BD%CE%B1207.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 320px;" src="http://4.bp.blogspot.com/_zFF22LLF49M/ShJqUOeHLjI/AAAAAAAAAW4/Y2DahRbEWM4/s400/%CE%95%CE%B9%CE%BA%CF%8C%CE%BD%CE%B1207.jpg" alt="" id="BLOGGER_PHOTO_ID_5337445404101783090" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It may not be that obvious, but swap should not be on the first disk. If you are using swap at all (and I know many suggest that you don't), it would be a better choice to put it on the second disk. With 1GB of RAM, swap should be at least 1GB, which leaves only 3GB for Linux. The default installation needs something north of 2GB, so that leaves less than a gig to install software you use. Unless of course you are planning to play symlink tricks, in which case I should probably offer my condolences. Anyway, I ended up chopping 1GB with gparted from the second disk and redoing the installation again, but fortunately you won't have to.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;What you should definitely do however, is put aside 16MB of space in the first disk for enabling Boot Booster in the BIOS again. This is an ASUS feature that persists the BIOS configuration on the disk, shaving a couple of seconds on each boot. It may not seem much, but think about how many times you are going to boot this thing. If you add them up, it starts to matter. Boot Booster needs only 8MB of disk to function, but I found that the installer's partition editor would only allocate one cylinder for 8MB, while we need two. Using 16MB did the right thing.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The regular customization I always do is to put /tmp and /var/tmp on tmpfs, so that many common operations don't touch the disks at all. Put the following lines in fstab to do that:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;tmpfs        /tmp        tmpfs    defaults,noexec,nosuid        0       0&lt;br /&gt;tmpfs        /var/tmp    tmpfs    defaults,noexec,nosuid        0       0&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;After editing &lt;code&gt;/etc/fstab&lt;/code&gt; the proper way to remount these file systems is by following these steps:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Log out of the Ubuntu desktop in order to minimize the number of open temp files.&lt;/li&gt;&lt;li&gt;Press CTRL-ALT-F1 on your keyboard. You should see a login prompt. Login with your usual user/pass.&lt;/li&gt;&lt;li&gt;Clear out the files in the existing /tmp and /var/tmp directories.&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;sudo rm -rf /tmp/* /var/tmp/*&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;Mount the filesystems using tmpfs.&lt;br /&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;sudo mount /tmp&lt;br /&gt;sudo mount /var/tmp&lt;/span&gt;&lt;/li&gt;&lt;li&gt;Reboot the EEE PC.&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;sudo shutdown -r now&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;Next, from the boot-as-fast-as-you-can department comes another tweak. In &lt;code&gt;/boot/grub/menu.lst&lt;/code&gt; set &lt;code&gt;"timeout 0"&lt;/code&gt; in order to skip the kernel selection delay. If I ever need to boot a different kernel, I'll change it back to something larger, thankyouverymuch.&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Log out of the Ubuntu desktop. (Yes.. I said log out. This will go a long way to ensuring the fewest number of temp files are currently open.)&lt;/li&gt;&lt;li&gt;Press CTRL-ALT-F1 on your keyboard.  You should see a login prompt.  Login with your usual user/pass.&lt;/li&gt;&lt;li&gt;Clear out the files in the existing /tmp and /var/tmp directories.&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;sudo rm -rf /tmp/* /var/tmp/*&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;Mount the filesystems using tmpfs.&lt;br /&gt;&lt;span style=";font-family:courier new;font-size:85%;"&gt;sudo mount /tmp&lt;br /&gt;sudo mount /var/tmp&lt;/span&gt;&lt;/li&gt;&lt;li&gt;Reboot the EEE PC.&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;sudo shutdown -r now&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;Now in order to enable back Boot Booster follow &lt;a href="https://help.ubuntu.com/community/EeePC/Using"&gt;these instructions&lt;/a&gt; for configuring the small partition we created earlier. When you reboot make sure to enable the option in the BIOS (it will be hidden when the proper partition isn't found).&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Now you are all set. At least if you have no use for WPA-secured WiFi. Because if you do, you'll hit a bug with the included rt2860 driver. The details aren't that interesting, but the available options are two: either use the &lt;a href="http://array.org/ubuntu/"&gt;array.org kernel&lt;/a&gt; or &lt;a href="https://bugs.launchpad.net/ubuntu/+source/linux/+bug/339891"&gt;patch the driver&lt;/a&gt;. The former solution used to be necessary with Intrepid, since lots of things were not working with the default kernel. However after trying out both, I don't see much need for Adam's kernel in Jaunty, unless you are terrified when encountering &lt;code&gt;patch&lt;/code&gt;, &lt;code&gt;make&lt;/code&gt; and their ilk. Since I'm on first name basis with them, I went with the second option, hoping that a future kernel update will bring along the fixes.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;All in all, the process this time around was very easy. Almost &lt;a href="http://www.geteasypeasy.com/"&gt;easy peasy&lt;/a&gt;. My EEE PC with Ubuntu Netbook Remix makes me almost forget that I'm not on my beloved Mac.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Almost.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/486398466531826618-3494681038446811325?l=blog.astithas.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/PastMidnight/~4/hJGSTsVrwmk" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.astithas.com/feeds/3494681038446811325/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=486398466531826618&amp;postID=3494681038446811325" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/3494681038446811325?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/3494681038446811325?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/PastMidnight/~3/hJGSTsVrwmk/ubuntu-on-eee-pc.html" title="Ubuntu on EEE PC" /><author><name>Panagiotis Astithas</name><uri>https://profiles.google.com/116466326438420686438</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-ieNj_PE2fxE/AAAAAAAAAAI/AAAAAAAAAAA/l78jhJX3laA/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_zFF22LLF49M/ShJqMGfkTiI/AAAAAAAAAWw/bo6YbTCjyt4/s72-c/%CE%95%CE%B9%CE%BA%CF%8C%CE%BD%CE%B1205.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://blog.astithas.com/2009/06/ubuntu-on-eee-pc.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0MHQHo-fSp7ImA9WxJTFkw.&quot;"><id>tag:blogger.com,1999:blog-486398466531826618.post-7289725450704667371</id><published>2009-04-23T12:10:00.008+02:00</published><updated>2009-04-25T02:23:51.455+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-25T02:23:51.455+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="open-source" /><category scheme="http://www.blogger.com/atom/ns#" term="gss" /><category scheme="http://www.blogger.com/atom/ns#" term="software" /><category scheme="http://www.blogger.com/atom/ns#" term="programming" /><category scheme="http://www.blogger.com/atom/ns#" term="web" /><title>An introduction to the GSS API</title><content type="html">Application Programming Interface or &lt;a href="http://en.wikipedia.org/wiki/API"&gt;API&lt;/a&gt; design is one of my favorite topics in programming, probably because it is both a science and an art. It is a science because there are widely accepted principles about how to design an API, but at the same time applying these principles within the constraints of a given programming language, requires the finesse of an experienced practicioner. Therefore it is with great pleasure that I'll try to explain the ins and outs of the &lt;a href="http://code.google.com/p/gss/"&gt;GSS&lt;/a&gt;  REST-like &lt;a href="http://code.google.com/p/gss/wiki/API"&gt;API&lt;/a&gt;, as promised &lt;a href="http://astithas.blogspot.com/2009/04/gss-architecture.html"&gt;before&lt;/a&gt;. As I've already &lt;a href="http://astithas.blogspot.com/2009/04/introducing-gss.html"&gt;mentioned&lt;/a&gt;, GSS is both the name of the source code project in Google Code, as well as the GRNET-sponsored service for the Greek research and academic network (although, it's official name after leaving the beta stage will be Pithos). Since anyone can use the open-source code to setup a GSS service, in this post I'll use generic examples, so anyone writing a client for the GRNET service should modify them accordingly.&lt;br /&gt;&lt;br /&gt;When developing an application in a particular programming language, we are used to thinking about the APIs presented to us by the various libraries, which are invariably specified in that same language. For instance, for communicating with an HTTP server from a Java program we might use the &lt;a href="http://hc.apache.org/httpcomponents-client/index.html"&gt;HttpClient&lt;/a&gt; library &lt;a href="http://hc.apache.org/httpcomponents-client/httpclient/apidocs/index.html"&gt;API&lt;/a&gt;. This library presents a set of Java classes, interfaces and methods for interacting with web servers. These classes hide the underlying complexity of making the low-level HTTP protocol operations, allowing our mental process to remain constantly in a Java world. We could however interact with a web server without such a library, opting to implement the HTTP protocol interactions ourselves instead. Unfortunately, there is no such higher-level library for GSS yet, wrapping the low-level HTTP communications. Therefore this post will present a low-level API, in the sense that one has to make direct HTTP calls in his chosen programming language. The good news is that the following discussion is useful for programmers with any background, since there is support for the ubiquitus HTTP protocol in every modern programming language.&lt;br /&gt;&lt;br /&gt;A RESTful API models its entities as resources. Resources are identified by Uniform Resource Identifiers, or &lt;a href="http://en.wikipedia.org/wiki/URI"&gt;URIs&lt;/a&gt;. There are four kinds of resources in GSS: files, folders, users &amp;amp; groups. These resources have a number of properties that contain various attributes. The API models these entities and their properties in the &lt;a href="http://json.org/"&gt;JSON&lt;/a&gt; format. There is also a fifth entity that is not modeled as a resource, but is important enough to warrant special mention: permissions.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:180%;"&gt;&lt;span style="font-weight: bold;"&gt;Users&lt;/span&gt;&lt;span style="font-weight: bold;"&gt; ·&lt;/span&gt;&lt;/span&gt; Users are the entities that represent the actual users of the system. They are used to login to the service and separate namespaces of files and folders. User entities have attributes like full name, e-mail, username, authentication token, creation/modification times, groups, etc. The URI of a user with username &lt;code&gt;paul&lt;/code&gt; would be:&lt;br /&gt;&lt;blockquote&gt;&lt;code&gt;http://host.domain/gss/rest/paul/&lt;/code&gt;&lt;br /&gt;&lt;/blockquote&gt;The JSON representation of this user would be something like this:&lt;br /&gt;&lt;pre&gt;{&lt;br /&gt;    "name": "Paul Smith",&lt;br /&gt;    "username": "paul",&lt;br /&gt;    "email": "paul@gmail.com",&lt;br /&gt;    "files": "http://hostname.domain/gss/rest/paul/files",&lt;br /&gt;    "trash": "http://hostname.domain/gss/rest/paul/trash",&lt;br /&gt;    "shared": "http://hostname.domain/gss/rest/paul/shared",&lt;br /&gt;    "others": "http://hostname.domain/gss/rest/paul/others",&lt;br /&gt;    "tags": "http://hostname.domain/gss/rest/paul/tags",&lt;br /&gt;    "groups": "http://hostname.domain/gss/rest/paul/groups",&lt;br /&gt;    "creationDate": 1223372769275,&lt;br /&gt;    "modificationDate": 1223372769275,&lt;br /&gt;    "quota": {&lt;br /&gt;        "totalFiles": 7,&lt;br /&gt;        "totalBytes": 429330,&lt;br /&gt;        "bytesRemaining": 10736988910&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:180%;" &gt;Groups&lt;/span&gt; &lt;span style="font-weight: bold;"&gt;·&lt;/span&gt; Groups are entities used to organize users for easier sharing of files and folders among peers. They can be used to facilitate sharing files to multiple users at once. Groups belong to the user who created them and cannot be shared. The URI of a group named &lt;code&gt;work&lt;/code&gt; created by the user with username &lt;code&gt;paul&lt;/code&gt; would be:&lt;br /&gt;&lt;blockquote&gt;&lt;code&gt;http://host.domain/gss/rest/paul/groups/work&lt;/code&gt;&lt;br /&gt;&lt;/blockquote&gt;The JSON representation of this group would be something like this:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;[&lt;br /&gt;    "http://hostname.domain/gss/rest/paul/groups/work/tom",&lt;br /&gt;    "http://hostname.domain/gss/rest/paul/groups/work/jim",&lt;br /&gt;    "http://hostname.domain/gss/rest/paul/groups/work/mary"&lt;br /&gt;]&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-size:180%;"&gt;Files&lt;/span&gt; ·&lt;/span&gt; Files are the most basic resources in GSS. They represent actual operating system files from the client's computer that have been augmented with extra metadata for storage, retrieval and sharing purposes. Familiar metadata from modern file systems are also maintained in GSS, like file name, creation/modification times, creator, modifier, tags, permissions, etc. Furthermore, files can be versioned in GSS. Updating versioned files retains the previous versions, while updating an unversioned file replaces irrevocably the old file contents. The URI of a file named &lt;code&gt;doc.txt&lt;/code&gt; located in the root folder of the user with username &lt;code&gt;paul&lt;/code&gt; would be:&lt;br /&gt;&lt;blockquote&gt;&lt;code&gt;http://host.domain/gss/rest/paul/files/doc.txt&lt;/code&gt;&lt;/blockquote&gt;The JSON representation of the metadata in this file would be something like this:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;{&lt;br /&gt;   "name": "doc.txt",&lt;br /&gt;   "creationDate": 1232449958563,&lt;br /&gt;   "createdBy": "paul",&lt;br /&gt;   "readForAll": true,&lt;br /&gt;   "modifiedBy": "paul",&lt;br /&gt;   "owner": "paul",&lt;br /&gt;   "modificationDate": 1232449944444,&lt;br /&gt;   "deleted": false,&lt;br /&gt;   "versioned": true,&lt;br /&gt;   "version": 1,&lt;br /&gt;   "size": 802,&lt;br /&gt;   "content": "text/plain",&lt;br /&gt;   "uri": "http://hostname.domain/gss/rest/paul/files/doc.txt",&lt;br /&gt;   "folder": {&lt;br /&gt;       "uri": "http://hostname/gss/rest/aaitest@uth.gr/files/",&lt;br /&gt;       "name": "Paul Smith"&lt;br /&gt;   },&lt;br /&gt;   "path": "/",&lt;br /&gt;   "tags": [&lt;br /&gt;       "work",&lt;br /&gt;       "personal"&lt;br /&gt;   ],&lt;br /&gt;   "permissions": [&lt;br /&gt;       {&lt;br /&gt;           "modifyACL": true,&lt;br /&gt;           "write": true,&lt;br /&gt;           "read": true,&lt;br /&gt;           "user": "paul"&lt;br /&gt;       },&lt;br /&gt;       {&lt;br /&gt;           "modifyACL": false,&lt;br /&gt;           "write": true,&lt;br /&gt;           "read": true,&lt;br /&gt;           "group": "work"&lt;br /&gt;       }&lt;br /&gt;   ]&lt;br /&gt;} &lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:180%;"&gt;&lt;span style="font-weight: bold;"&gt;Folders&lt;/span&gt;&lt;/span&gt;&lt;span style="font-weight: bold;"&gt; ·&lt;/span&gt; Folders are resources that are used for grouping files. They represent the file system concept of folders or directories and can be used to mirror a client's computer file system on GSS. Familiar metadata from modern file systems are also maintained in GSS, like folder name, creation/modification times, creator, modifier, permissions, etc. The URI of a folder named &lt;code&gt;documents&lt;/code&gt; located in the root folder of the user with username &lt;code&gt;paul&lt;/code&gt; would be:&lt;br /&gt;&lt;blockquote&gt;&lt;code&gt;http://host.domain/gss/rest/paul/files/documents&lt;/code&gt;&lt;/blockquote&gt;The JSON representation of this folder would be something like this:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;{&lt;br /&gt;   "name": "documents",&lt;br /&gt;   "owner": "paul",&lt;br /&gt;   "deleted": false,&lt;br /&gt;   "createdBy": "paul",&lt;br /&gt;   "creationDate": 1223372795825,&lt;br /&gt;   "modifiedBy": "paul",&lt;br /&gt;   "modificationDate": 1223372795825,&lt;br /&gt;   "parent": {&lt;br /&gt;       "uri": "http://hostname.domain/gss/rest/paul/files/",&lt;br /&gt;       "name": "Paul Smith"&lt;br /&gt;   },&lt;br /&gt;   "files": [&lt;br /&gt;       {&lt;br /&gt;           "name": "notes.txt",&lt;br /&gt;           "owner": "paul",&lt;br /&gt;           "creationDate": 1233758218866,&lt;br /&gt;           "deleted":false,&lt;br /&gt;           "size":4567,&lt;br /&gt;           "content": "text/plain",&lt;br /&gt;           "version": 1,&lt;br /&gt;           "uri": "http://hostname.domain/gss/rest/paul/files/documents/notes.txt",&lt;br /&gt;           "folder": {&lt;br /&gt;               "uri": "http://hostname.domain/gss/rest/paul/files/documents/",&lt;br /&gt;               "name": "documents"&lt;br /&gt;           },&lt;br /&gt;           "path": "/documents/"&lt;br /&gt;       }&lt;br /&gt;   ],&lt;br /&gt;   "folders": [],&lt;br /&gt;   "permissions": [&lt;br /&gt;       {&lt;br /&gt;           "modifyACL": true,&lt;br /&gt;           "write": true,&lt;br /&gt;           "read": true,&lt;br /&gt;           "user": "paul"&lt;br /&gt;       },&lt;br /&gt;       {&lt;br /&gt;           "modifyACL": false,&lt;br /&gt;           "write": true,&lt;br /&gt;           "read": true,&lt;br /&gt;           "group": "work"&lt;br /&gt;       }&lt;br /&gt;   ]&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Working with these resources is accomplished by sending HTTP protocol requests to the resource URI with GET, HEAD, DELETE, POST, PUT methods. GET requests retrieve the resource representation, either the file contents, or the JSON representations for the resources specified above. HEAD requests for files return just the metadata of the file and DELETE requests remove the resource from the system. PUT requests upload files to the system from the client, while POST requests perform various modifications to the resources, like renaming, moving, copying, moving files to the trash, restoring them from the trash, creating folders and more. The operations are numerous and I hope to cover them in more detail in a future post.&lt;br /&gt;&lt;br /&gt;One important aspect of every RESTful API is the use of URIs to allow the client to maintain a stateful conversation. For example, fetching the user URI would provide the &lt;code&gt;files&lt;/code&gt; URI for fetching the available files and folders. Fetching the &lt;code&gt;files&lt;/code&gt; URI would in turn return the URIs for the particular files and folders contained in the root folder (along with other folder properties). Returning to the parent of the current folder would entail following the URI contained in the parent property. This mechanism removes the state handling from the server and puts the burden on the client, providing excellent scalability for the service. Furthermore, since the URIs are treated opaquely by the client, the API allows client reuse across server deployments. A client can target multiple GSS services, as long as they speak the same RESTful API. Moreover, links from service A can refer to resources in service B without a problem (in the same authentication domain, e.g. the same Shibboleth federation). This is the same as using a single web browser to communicate with multiple web servers, by following links among them.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/486398466531826618-7289725450704667371?l=blog.astithas.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/PastMidnight/~4/I38ekP4DYFM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.astithas.com/feeds/7289725450704667371/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=486398466531826618&amp;postID=7289725450704667371" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/7289725450704667371?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/7289725450704667371?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/PastMidnight/~3/I38ekP4DYFM/introduction-to-gss-api.html" title="An introduction to the GSS API" /><author><name>Panagiotis Astithas</name><uri>https://profiles.google.com/116466326438420686438</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-ieNj_PE2fxE/AAAAAAAAAAI/AAAAAAAAAAA/l78jhJX3laA/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.astithas.com/2009/04/introduction-to-gss-api.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0QCQnw_fip7ImA9WxJTEkg.&quot;"><id>tag:blogger.com,1999:blog-486398466531826618.post-1257190549439172023</id><published>2009-04-20T21:01:00.008+02:00</published><updated>2009-04-20T22:29:23.246+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-20T22:29:23.246+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="open-source" /><category scheme="http://www.blogger.com/atom/ns#" term="Java" /><category scheme="http://www.blogger.com/atom/ns#" term="software" /><category scheme="http://www.blogger.com/atom/ns#" term="programming" /><title>Reconciling Apache Commons Configuration with JBoss 5</title><content type="html">There are many ways to configure a JavaEE application. Among the available solutions are DBMS tables, JNDI, &lt;a href="http://java.sun.com/j2se/1.5.0/docs/guide/jmx/overview/architecture.html"&gt;JMX MBeans&lt;/a&gt; and even plain old files in a variety of formats. While we have used most of the above in various occasions, I find that plain files resonate with all types of sysadmins, when no other administrative interface is available. For such scenarios, &lt;a href="http://commons.apache.org/configuration/"&gt;Apache Commons Configuration&lt;/a&gt; is undoubtedly the best tool for the job. Recently, I came across an undocumented incompatibility when using Commons Configuration with &lt;a href="http://www.jboss.org/"&gt;JBoss&lt;/a&gt; 5 and I thought I should describe our solution for the benefit of others.&lt;br /&gt;&lt;br /&gt;Usually we are storing our configuration files in the standard place for JBoss, which is &lt;code&gt;JBOSS_HOME/server/default/conf&lt;/code&gt;, for the default server configuration. This has the disadvantage that is not as easy to remember as &lt;code&gt;/etc&lt;/code&gt; in UNIX/Linux or &lt;code&gt;\Program Files&lt;/code&gt; and &lt;code&gt;\Windows&lt;/code&gt; in Windows systems, but it has the important advantage of being specified as a relative path in our code, making it more cross-platform without cluttering it with platform-specific if/else path resolution checks.&lt;br /&gt;&lt;br /&gt;Commons Configuration can reload the configuration files automatically when changed in the file system, which helps prolong the server uptime. However JBoss 5 has introduced the concept of a virtual file system that caches all file system accesses performed through the context class loaders using relative paths. Unfortunately this generates resource URLs in the form vfsfile:foo.properties that Commons Configuration does not know how to deal with. Fixing this requires extending FileChangedReloadingStrategy, like we do in &lt;a href="http://code.google.com/p/gss/source/detail?r=266"&gt;gss&lt;/a&gt;. Alternatively, one could patch Commons Configuration with the following &lt;a href="https://issues.apache.org/jira/browse/CONFIGURATION-381"&gt;change&lt;/a&gt; and use the standard FileChangedReloadingStrategy unchanged:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Index: FileChangedReloadingStrategy.java&lt;br /&gt;===================================================================&lt;br /&gt;--- FileChangedReloadingStrategy.java    (revision 764760)&lt;br /&gt;+++ FileChangedReloadingStrategy.java    (working copy)&lt;br /&gt;@@ -46,6 +46,9 @@&lt;br /&gt;  /** Constant for the jar URL protocol.*/&lt;br /&gt;  private static final String JAR_PROTOCOL = "jar";&lt;br /&gt;&lt;br /&gt;+    /** Constant for the JBoss MC VFSFile URL protocol.*/&lt;br /&gt;+    private static final String VFSFILE_PROTOCOL = "vfsfile";&lt;br /&gt;+&lt;br /&gt;  /** Constant for the default refresh delay.*/&lt;br /&gt;  private static final int DEFAULT_REFRESH_DELAY = 5000;&lt;br /&gt;&lt;br /&gt;@@ -161,7 +164,8 @@&lt;br /&gt;&lt;br /&gt;  /**&lt;br /&gt;   * Helper method for transforming a URL into a file object. This method&lt;br /&gt;-     * handles file: and jar: URLs.&lt;br /&gt;+     * handles file: and jar: URLs, as well as JBoss VFS-specific vfsfile:&lt;br /&gt;+     * URLs.&lt;br /&gt;   *&lt;br /&gt;   * @param url the URL to be converted&lt;br /&gt;   * @return the resulting file or &lt;b&gt;null &lt;/b&gt;&lt;br /&gt;@@ -181,6 +185,18 @@&lt;br /&gt;              return null;&lt;br /&gt;          }&lt;br /&gt;      }&lt;br /&gt;+        else if (VFSFILE_PROTOCOL.equals(url.getProtocol()))&lt;br /&gt;+        {&lt;br /&gt;+            String path = url.getPath();&lt;br /&gt;+            try&lt;br /&gt;+            {&lt;br /&gt;+                return ConfigurationUtils.fileFromURL(new URL("file:" + path));&lt;br /&gt;+            }&lt;br /&gt;+            catch (MalformedURLException mex)&lt;br /&gt;+            {&lt;br /&gt;+                return null;&lt;br /&gt;+            }&lt;br /&gt;+        }&lt;br /&gt;      else&lt;br /&gt;      {&lt;br /&gt;          return ConfigurationUtils.fileFromURL(url);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Neither of these solutions covers the case of storing configuration files in zip or jar containers, but since it is something I haven't found a use for yet, I can't test a fix for it. If anyone is interested in such a use case, I'd advise extending FileChangedReloadingStrategy, combining the logic in jar: and vfsfile: URL handling.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/486398466531826618-1257190549439172023?l=blog.astithas.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/PastMidnight/~4/StqJFzvPRv4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.astithas.com/feeds/1257190549439172023/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=486398466531826618&amp;postID=1257190549439172023" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/1257190549439172023?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/1257190549439172023?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/PastMidnight/~3/StqJFzvPRv4/reconciling-apache-commons.html" title="Reconciling Apache Commons Configuration with JBoss 5" /><author><name>Panagiotis Astithas</name><uri>https://profiles.google.com/116466326438420686438</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-ieNj_PE2fxE/AAAAAAAAAAI/AAAAAAAAAAA/l78jhJX3laA/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.astithas.com/2009/04/reconciling-apache-commons.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ck8AQ3wzeyp7ImA9WxVaFks.&quot;"><id>tag:blogger.com,1999:blog-486398466531826618.post-5462759268406883151</id><published>2009-04-13T22:38:00.006+02:00</published><updated>2009-04-14T00:14:02.283+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-14T00:14:02.283+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="open-source" /><category scheme="http://www.blogger.com/atom/ns#" term="Java" /><category scheme="http://www.blogger.com/atom/ns#" term="gss" /><category scheme="http://www.blogger.com/atom/ns#" term="software" /><category scheme="http://www.blogger.com/atom/ns#" term="programming" /><category scheme="http://www.blogger.com/atom/ns#" term="web" /><title>GSS architecture</title><content type="html">Handling a large number of concurrent connections requires many servers. Not only because scaling vertically (throwing bigger hardware at the problem) is very costly, but also because even if an application can be designed to scale vertically, the underlying stack probably can not. Java applications for instance, like &lt;a href="http://astithas.blogspot.com/2009/04/introducing-gss.html"&gt;GSS&lt;/a&gt;, run on the JVM and although the latter is an excellent piece of engineering, using huge amounts of heap is not something it's tuned for. Big Iron servers with many cores and 20+ GB of RAM are usually running more than one JVM, since garbage collection is not all that efficient with huge heaps. And since running application instances with a 4-8 GB heap size can be done with cheap off-the-shelf hardware, why spend big bucks on Big Iron?&lt;br /&gt;&lt;br /&gt;So having a large number of servers is a sane choice, but brings it's own set of problems. Unless one partitions users to servers (having all requests a particular user makes be delivered to the same server), all servers must have a consistent view of the system data, in order to deliver meaningful results. Assigning user requests to particular servers, usually requires expensive application layer load-balancers or customized application code on each server, so it would rarely be your first option. Having all servers work on the same data is a more tractable problem, since it can be solved by having the application state being replicated among server nodes. Usually, only a small part of the application state needs to be replicated, for each user, that is the part which concerns his current session. But even though session clustering solutions have been a well studied field and implementations abound, having no session to replicate is an even better option.&lt;br /&gt;&lt;br /&gt;For &lt;a href="http://code.google.com/p/gss/"&gt;GSS&lt;/a&gt; we have implemented a stateless architecture for the core server, that should provide us with good scalability in a very cost-effective manner. The most important part in this architecture is the REST-like &lt;a href="http://code.google.com/p/gss/wiki/API"&gt;API&lt;/a&gt; that moves part of the responsibility for session state maintenance to the client applications, effectively distributing the system load to more systems than the available server pool. Furthermore, client requests can be authenticated without requiring an SSL/TLS transport layer (even though it can be used if extra privacy is required), which would entail higher load on the application servers or require expensive load balancers. In the server side, API requests are being handled by servlets that enlist the services of stateless session beans, for easier transaction management. Our persistence story so far is JPA with a DBMS backing, plus high-speed SAN storage for the file contents. If or when this becomes a bottleneck, we have various contingency plans, depending on the actual characteristics of the load that will be observed.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_zFF22LLF49M/SeOmXlASduI/AAAAAAAAAV0/q2tTluFkTI0/s1600-h/gss-request.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 202px;" src="http://2.bp.blogspot.com/_zFF22LLF49M/SeOmXlASduI/AAAAAAAAAV0/q2tTluFkTI0/s400/gss-request.png" alt="" id="BLOGGER_PHOTO_ID_5324282108482582242" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;The above image depicts the path user requests will travel along, while various nodes interact in order to serve them. A key element in this diagram is the number of different servers that can be found, effectively specializing in their own particular domain. Although the system can be deployed on a single physical server (and regularly is, for development and testing), consisting of a number of standalone sub-services instead of a big monolithic service is a boon to scalability.&lt;br /&gt;&lt;br /&gt;This high-level overview of the GSS architecture should help those interested to find their way around the open-source &lt;a href="http://code.google.com/p/gss/"&gt;codebase&lt;/a&gt; and explain some of the design decisions. But the most interesting part from a user's point of view would be the REST-like API, that allows one to take advantage of the service for scratching his own itch.&lt;br /&gt;&lt;br /&gt;So that will be the subject of my next post.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/486398466531826618-5462759268406883151?l=blog.astithas.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/PastMidnight/~4/mDNsKDrOmSY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.astithas.com/feeds/5462759268406883151/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=486398466531826618&amp;postID=5462759268406883151" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/5462759268406883151?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/5462759268406883151?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/PastMidnight/~3/mDNsKDrOmSY/gss-architecture.html" title="GSS architecture" /><author><name>Panagiotis Astithas</name><uri>https://profiles.google.com/116466326438420686438</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-ieNj_PE2fxE/AAAAAAAAAAI/AAAAAAAAAAA/l78jhJX3laA/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_zFF22LLF49M/SeOmXlASduI/AAAAAAAAAV0/q2tTluFkTI0/s72-c/gss-request.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://blog.astithas.com/2009/04/gss-architecture.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUUEQH06fyp7ImA9WxVaEk8.&quot;"><id>tag:blogger.com,1999:blog-486398466531826618.post-2075472722580003312</id><published>2009-04-08T16:40:00.000+02:00</published><updated>2009-04-08T23:46:41.317+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-08T23:46:41.317+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript" /><category scheme="http://www.blogger.com/atom/ns#" term="GWT" /><category scheme="http://www.blogger.com/atom/ns#" term="open-source" /><category scheme="http://www.blogger.com/atom/ns#" term="Java" /><category scheme="http://www.blogger.com/atom/ns#" term="gss" /><category scheme="http://www.blogger.com/atom/ns#" term="software" /><category scheme="http://www.blogger.com/atom/ns#" term="WebDAV" /><category scheme="http://www.blogger.com/atom/ns#" term="programming" /><category scheme="http://www.blogger.com/atom/ns#" term="web" /><title>Introducing GSS</title><content type="html">&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_zFF22LLF49M/SdpbaLyvutI/AAAAAAAAAVo/0J1GFLL5bBQ/s1600-h/gss-logo.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 69px; height: 44px;" src="http://4.bp.blogspot.com/_zFF22LLF49M/SdpbaLyvutI/AAAAAAAAAVo/0J1GFLL5bBQ/s400/gss-logo.png" alt="" id="BLOGGER_PHOTO_ID_5321666415092021970" border="0" /&gt;&lt;/a&gt;During my recent work-induced blog hiatus, I've been working on a new software system, called GSS. I've been more than enjoying the ride so far and since we have released the code as open-source, I thought discussing some of the experience I've gained might be interesting to others as well.&lt;br /&gt;&lt;br /&gt;GSS is a network, er grid, er I mean cloud service, for providing access to a file system on a remote storage space. It is the name of both a &lt;a href="http://gss.grnet.gr/"&gt;service&lt;/a&gt; (currently in beta) for the Greek research and academic community and the open source &lt;a href="http://code.google.com/p/gss/"&gt;software&lt;/a&gt; used for it, that can also be used by others for deploying such services. It is similar in some ways to services like &lt;a href="http://www.idrive.com/"&gt;iDrive&lt;/a&gt;, &lt;a href="https://www.getdropbox.com/"&gt;DropBox&lt;/a&gt; and &lt;a href="http://drop.io/"&gt;drop.io&lt;/a&gt;, but it can also be regarded as a more high-level &lt;a href="http://aws.amazon.com/s3/"&gt;Amazon S3&lt;/a&gt;. Its purpose is to let the desktop computer's file system meet the cloud. The familiar file system metaphors of files and folders are used to store information in a remote storage space, that can be accessed from a variety of user and system interfaces, from any place in the world that has an Internet connection. All usual file manager operations are supported and users can share their files with selected other users or groups, or even make them public. Currently there are four user interfaces available, a web-based application, a desktop client, a WebDAV interface and an iPhone web application, in various stages of development. Underlying these user interfaces is a common REST-like API that can be used to extend the service in new, unanticipated ways.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_zFF22LLF49M/SdOvi1vj3iI/AAAAAAAAAVI/Z8KAUyD_aks/s1600-h/webclient.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 256px;" src="http://4.bp.blogspot.com/_zFF22LLF49M/SdOvi1vj3iI/AAAAAAAAAVI/Z8KAUyD_aks/s400/webclient.png" alt="" id="BLOGGER_PHOTO_ID_5319788597931662882" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;The main focus of this service was to provide the users of the Greek research and academic community with a free, large storage space that can be used to store, access, backup and share their work, from as many computer systems as they want. Since the available user base is close to half a million (although the expected users of the service are projected to the low ten thousands), we needed a scalable system, that would be able to accommodate high network traffic and a high storage capacity at the same time. A Java Enterprise Edition server coupled with a GWT-based web client and a stateless architecture were our solution. In future posts I will describe the system architecture with all the gory details. The exposed virtual file system features file versioning, trash bin support, access control lists, tagging, full text search and more.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_zFF22LLF49M/SdJ25ldTHVI/AAAAAAAAAVA/FAlJCd0smGI/s1600-h/webdav.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 400px; height: 221px;" src="http://2.bp.blogspot.com/_zFF22LLF49M/SdJ25ldTHVI/AAAAAAAAAVA/FAlJCd0smGI/s400/webdav.png" alt="" id="BLOGGER_PHOTO_ID_5319444841557597522" border="0" /&gt;&lt;/a&gt;All of these features are presented through an &lt;a href="http://code.google.com/p/gss/wiki/API"&gt;API&lt;/a&gt; for third party developers to create scripts, applications or even full blown services that will fulfill their own particular needs or serve other niches. This API has a REST-like design and though it will probably fail a formal RESTful definition, it sports many of the advantages of such architectures:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;system resources such as users, groups, files and folders are represented by URIs&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;GET, HEAD, POST, PUT and DELETE methods on resources have the expected semantics&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;HTTP caching is explicitly supported via Last-Modified, ETag &amp;amp; If-* headers&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;resource formats for everything besides files are simple JSON representations&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;only authenticated requests are allowed, except for public resources&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Users are authenticated through the GRNET Shibboleth infrastructure. User passwords are never transmitted to the GSS service. Instead GSS-issued authentication tokens are used by both client and server to sign the API requests after the initial user login. SSL transport can provide even stronger privacy guarantees, but it is not required, nor enabled by default.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_zFF22LLF49M/SdJ0a8iCBHI/AAAAAAAAAU4/bMTHCK5UxkQ/s1600-h/igss.png"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 208px; height: 400px;" src="http://2.bp.blogspot.com/_zFF22LLF49M/SdJ0a8iCBHI/AAAAAAAAAU4/bMTHCK5UxkQ/s400/igss.png" alt="" id="BLOGGER_PHOTO_ID_5319442116152263794" border="0" /&gt;&lt;/a&gt;The GSS code base is GPL-licensed and therefore anyone can use it as a starting point to implement his own file storage service. We have yet to provide binary downloads, due to the various dependencies, but the build instructions should be enough to get someone started. We are always interested in source or documentation patches, of course (did I mention it's open source?). Most importantly, the REST API will ensure that clients developed for one such service can be reused for every other one.&lt;br /&gt;&lt;br /&gt;I will have much more to say about the API in a future post. In the meantime you can peruse the code and documentation, or even try it out yourself. I'd be very interested in any comments you might have.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/486398466531826618-2075472722580003312?l=blog.astithas.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/PastMidnight/~4/jKEfRpxuTD0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.astithas.com/feeds/2075472722580003312/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=486398466531826618&amp;postID=2075472722580003312" title="7 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/2075472722580003312?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/2075472722580003312?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/PastMidnight/~3/jKEfRpxuTD0/introducing-gss.html" title="Introducing GSS" /><author><name>Panagiotis Astithas</name><uri>https://profiles.google.com/116466326438420686438</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-ieNj_PE2fxE/AAAAAAAAAAI/AAAAAAAAAAA/l78jhJX3laA/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/_zFF22LLF49M/SdpbaLyvutI/AAAAAAAAAVo/0J1GFLL5bBQ/s72-c/gss-logo.png" height="72" width="72" /><thr:total>7</thr:total><feedburner:origLink>http://blog.astithas.com/2009/04/introducing-gss.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0EAQ3c4fSp7ImA9WxVUEE4.&quot;"><id>tag:blogger.com,1999:blog-486398466531826618.post-2412064422038285889</id><published>2009-03-14T15:00:00.001+02:00</published><updated>2009-03-14T15:00:42.935+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-14T15:00:42.935+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="personal" /><category scheme="http://www.blogger.com/atom/ns#" term="software" /><title>Applications meme</title><content type="html">It's been a while since my last post, but I've been wanting to write about the interesting stuff that I've been working on. Unfortunately it took longer than anticipated, but now we're almost done and I'll be posting soon with the gory details. However, since I got &lt;a href="http://blog.postmaster.gr/2009/03/14/re-applications-meme/"&gt;tagged&lt;/a&gt;, I suppose I can throw in a not-so-interesting post, about my Linux application preferences.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;Which desktop manager do you use more often ? &lt;p&gt;Gnome. It's the only one that reminds me of OS X somewhat (appearance- and functionality-wise). &lt;/p&gt;&lt;/li&gt;&lt;li&gt;Which desktop application you would not like to see implemented again on linux? And why? &lt;p&gt;A desktop manager. If you are going to provide yet another incarnation of a 30-year old idea, please don't bother. The concept is pretty well understood: icons/workspace/file manager/drag'n'drop/mouse/menus/launcher/whatever, it's been done before. Like a million times. If you want to be useful, try to fix some of the shortcomings of the existing ones (notification mechanisms, translucent effects, faster access patterns, application integration, etc.).&lt;br /&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;Which desktop application you definitely would like to see implemented on linux? Describe it briefly or point out to a similar application. &lt;p&gt;Adobe Premiere, or iMovie, or any other semi-decent video editing software. This was the main reason I bought a Mac.&lt;br /&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;Write the name of the last project (not the very best, the last!) that made you wish to thank their developers so you can thank them now! &lt;p&gt;&lt;a href="http://git-scm.com/"&gt;Git&lt;/a&gt;. You guys rock! (And if you improve on the UI, you will jazz!)&lt;br /&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;(Optional) Link the blogs of 1-3 people you’d like to take part to this meme. (no more than three). you can skip this question if you like. &lt;p&gt;Let's hear from &lt;a href="http://chstath.blogspot.com/"&gt;chstath&lt;/a&gt;, &lt;a href="http://kotsokalis.wordpress.com/"&gt;ckotso&lt;/a&gt; and &lt;a href="http://keramida.wordpress.com/"&gt;keramida&lt;/a&gt; (who may s/Linux/FreeBSD/ at his discretion).&lt;br /&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/486398466531826618-2412064422038285889?l=blog.astithas.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/PastMidnight/~4/2ySMzBUEuTg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.astithas.com/feeds/2412064422038285889/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=486398466531826618&amp;postID=2412064422038285889" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/2412064422038285889?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/2412064422038285889?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/PastMidnight/~3/2ySMzBUEuTg/applications-meme.html" title="Applications meme" /><author><name>Panagiotis Astithas</name><uri>https://profiles.google.com/116466326438420686438</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-ieNj_PE2fxE/AAAAAAAAAAI/AAAAAAAAAAA/l78jhJX3laA/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.astithas.com/2009/03/applications-meme.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0YBRnw8fCp7ImA9WxRQFEw.&quot;"><id>tag:blogger.com,1999:blog-486398466531826618.post-8099319830657571760</id><published>2008-10-07T23:30:00.000+02:00</published><updated>2008-10-07T23:32:37.274+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-10-07T23:32:37.274+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript" /><category scheme="http://www.blogger.com/atom/ns#" term="FireStatus" /><category scheme="http://www.blogger.com/atom/ns#" term="open-source" /><category scheme="http://www.blogger.com/atom/ns#" term="programming" /><category scheme="http://www.blogger.com/atom/ns#" term="web" /><title>Programming for fun</title><content type="html">&lt;div&gt;I've been in a hiatus from blogging lately, mainly because free time has been in short supply. It's not just the very busy days at work, nights have been even busier. Instead of churning out long blog posts, I've been banging on code instead, day and night. Unfortunately I only get paid for the code I write during the day, but surprisingly (or not) I enjoy the code I write at night the most. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I have written code for banks, multinational corporations, the kind of places where the phrase "professional dress code" is not used strictly in jokes. I've helped build software that was resilient, scalable, secure and intuitive, although granted, not all those at the same time. This was mainly Custom Enterprise Software, or to put it more plainly, Software That Runs On Computers At Work. So I thought I'd try a different angle in my spare time: write software that people use at work, or at home. Or at a coffee shop. Or at the airport. Or wherever they feel like using a computer, anyway. This is sometimes called  End-User Software, or to put it in layman's terms, Software People May Actually Like. After trying out some ideas that didn't seem worthwhile, I discovered that &lt;a href="http://chstath.blogspot.com/"&gt;some of&lt;/a&gt; &lt;a href="http://synodinos.net/"&gt;my buddies&lt;/a&gt; had similar thoughts. This is how &lt;a href="https://addons.mozilla.org/en-US/firefox/addon/8973"&gt;FireStatus&lt;/a&gt; was born.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;FireStatus is a Firefox extension that aims to be a swiss army knife for dealing with various social networks, right from your browser, without visiting any particular website. &lt;a href="http://facebook.com/"&gt;Facebook&lt;/a&gt;, &lt;a href="http://twitter.com/"&gt;Twitter&lt;/a&gt; and &lt;a href="http://friendfeed.com/"&gt;FriendFeed&lt;/a&gt; are currently supported, but more are in the pipeline. For starters, it allows you to simultaneously update your status to all or some of these services, so that all your friends see it, no matter what they are using. The notion of a status that is occasionally updated is familiar to Twitter and Facebook users, since the text field that asks 'What are you doing?' is prominent in their user pages. FriendFeed does not have the notion of a status, but its users can post short (or long) messages, just like Twitter's. FriendFeed also allows posting links to web pages, accompanied with a short description, something that many Twitter and Facebook users have been doing by constructing status updates that start with the description text and are followed by an appended link, usually shortened.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;FireStatus can ease the task of posting these messages or status updates, by being always available, instead of needing to have the service pages open and without a large memory footprint, like other similar applications, since it takes advantage of the fact that most people nowadays always have one browser open. I know I do. Come to think of it, I don't know anyone who uses computers that does not keep a browser running most of the time. At least untile the darned thing crashes, which fortunately is something I haven't experienced in Firefox for quite some time.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_zFF22LLF49M/SOaWFwY8dBI/AAAAAAAAAPc/dbhEyAMYQ2I/s1600-h/post-screenshot.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://4.bp.blogspot.com/_zFF22LLF49M/SOaWFwY8dBI/AAAAAAAAAPc/dbhEyAMYQ2I/s400/post-screenshot.png" alt="" id="BLOGGER_PHOTO_ID_5253051041007301650" border="0" /&gt;&lt;/a&gt;&lt;span class="Apple-style-span"  style="font-size:78%;"&gt;Posting a message or status update&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;Clicking on the FireStatus icon, pops up a small toolbar window just above the status bar and below the window document. It is similar to the Firefox findbar that pops up when one searches for text in a page, albeit slightly larger. That was a deliberate design decision that aimed to imitate the success in the usability of the findbar. Lots of little details like this one have been carefully thought out and occasionally debated at length among the team and our &lt;a href="http://broadbandprime.blogspot.com/"&gt;beta testers&lt;/a&gt;:&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Enabling the spell checker in the status message field, for catching those typos when hastily typing a message.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Having the URL inclusion unchecked by default, while the shortening checked, since most posts do not include URLs (and it might be embarrassing if done inadvertently), but those that do usually want them short.&lt;/li&gt;&lt;li&gt;Adding a character counter to help guard against the maximum message length imposed by some services (e.g. Twitter).&lt;/li&gt;&lt;li&gt;Tightly placing the available services in a way that allows for an unambiguous selection. &lt;/li&gt;&lt;li&gt;Using the Escape and Enter keys as shortcuts for canceling and sending the update respectively.&lt;/li&gt;&lt;/ul&gt;As one reviewer in addons.mozilla.org so eloquently put it, "the simplicity &amp;amp; minimal design are the key components here".&lt;br /&gt;&lt;br /&gt;Posting is not the whole story, though. These services provide continuous streams of updates from friends that we need to monitor. Sifting through the updates in every service, while very useful, becomes tedious after a while. It is like making a mental note to check your e-mail every once in a while for new messages. It's one way to do it for sure, but mail notifiers have been around for ages and provide more of a "live" experience. &lt;/div&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://2.bp.blogspot.com/_zFF22LLF49M/SOaWTIlJxdI/AAAAAAAAAPk/RRbEuTRG-ps/s400/twitter-screenshot.png" alt="" id="BLOGGER_PHOTO_ID_5253051270839256530" border="0" /&gt;&lt;div&gt;FireStatus imitates their success in making e-mail conversations "alive", for conversations in the social network space. Every time a new incoming update is received, a notification popup appears, so I can continue using whatever application I was using, but being instantly aware of the news. Twitter notifications contain the name and the picture of the message author as well as the message sent. Low-priority or uninteresting messages can be just glanced at and then automatically dismissed, while important ones can be clicked on, so that the message can be viewed in the browser. FriendFeed notifications can be of various flavors, since FriendFeed aggregates updates from a large variety of online services.&lt;/div&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://2.bp.blogspot.com/_zFF22LLF49M/SOaWfEhJ-EI/AAAAAAAAAPs/nVVSIdrIdA4/s400/ff-screenshot.png" alt="" id="BLOGGER_PHOTO_ID_5253051475907180610" border="0" /&gt;&lt;div&gt; Therefore FriendFeed updates display the service icon along with the author's name for quick identification of the type of update. Clicking on an interesting update opens a browser window to the link contained in the message. Facebook notifications currently contain new message counts, pokes and shares, but work for getting more data is underway.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Although the notifications appear instantaneous, as with e-mail notifications there is a polling process involved underneath. The polling frequency for each service can be separately tuned in the preferences window. The preference window can be opened by right-clicking on the FireStatus icon and selecting the appropriate option in the popup menu. Along with the time intervals between polling for updates, one can enable posting and/or receiving updates for the various services, as well as the authentication credentials where appropriate. For Facebook the user logs in in a Facebook-supplied browser window that pops up, similar to regular Facebook use. No credentials need to be stored separately by FireStatus. For FriendFeed the username and remote key have to be stored locally in the extension preferences. The remote key is not the same as the user password, but is provided by FriendFeed specifically for use by third-party applications, like ours. It can be found by clicking on the link displayed in the explanatory note. Twitter can work either way. If a username and password are entered in the preference window, they will be stored locally in the extension preferences and used for subsequent authentication. If, on the other hand, the fields are blank, FireStatus will consult the browser's Password Manager for any stored Twitter credentials. This will probably cause the master password dialog to pop up once, but the credentials will remain stored only in the Password Manager.&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://2.bp.blogspot.com/_zFF22LLF49M/SOaWodiMuPI/AAAAAAAAAP0/uibidlblDTM/s400/prefs-screenshot.png" alt="" id="BLOGGER_PHOTO_ID_5253051637241264370" border="0" /&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;span class="Apple-style-span"  style="font-size:78%;"&gt;FireStatus preferences&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Since we built this thing for our own personal use, pleasure and self-punishment, and as we don't plan to ever get rich out of it, we have released it from the beginning as open-source software through the permissive BSD license. You are most welcome to come by the &lt;a href="http://code.google.com/p/firestatus/"&gt;project's home&lt;/a&gt; at Google Code, study the code, fix a bug (or two), help with the (embarrassingly outdated) documentation, &lt;a href="https://addons.mozilla.org/en-US/firefox/reviews/add/8973"&gt;contribute a review&lt;/a&gt; (otherwise it will remain an experimental extension forever) or just chat with us at the mailing list. Heck, if you feel like it, you can grab the whole code and use it in your own lucrative business and you don't owe us a dime.&lt;br /&gt;&lt;br /&gt;With the shape the world economy currently is in, you probably couldn't afford it, anyway.&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/486398466531826618-8099319830657571760?l=blog.astithas.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/PastMidnight/~4/QgCOdwkiTPE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.astithas.com/feeds/8099319830657571760/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=486398466531826618&amp;postID=8099319830657571760" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/8099319830657571760?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/8099319830657571760?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/PastMidnight/~3/QgCOdwkiTPE/programming-for-fun.html" title="Programming for fun" /><author><name>Panagiotis Astithas</name><uri>https://profiles.google.com/116466326438420686438</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-ieNj_PE2fxE/AAAAAAAAAAI/AAAAAAAAAAA/l78jhJX3laA/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/_zFF22LLF49M/SOaWFwY8dBI/AAAAAAAAAPc/dbhEyAMYQ2I/s72-c/post-screenshot.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://blog.astithas.com/2008/10/programming-for-fun.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0MBSXo_cSp7ImA9WxdVF0s.&quot;"><id>tag:blogger.com,1999:blog-486398466531826618.post-864238574787381067</id><published>2008-07-23T01:24:00.000+03:00</published><updated>2008-07-23T01:24:18.449+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-07-23T01:24:18.449+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript" /><category scheme="http://www.blogger.com/atom/ns#" term="Java" /><category scheme="http://www.blogger.com/atom/ns#" term="programming" /><category scheme="http://www.blogger.com/atom/ns#" term="C++" /><title>Murdered by Numbers</title><content type="html">&lt;blockquote style="font-style: italic;"&gt;"JavaScript has a single number type. Internally, it is represented as 64-bit floating point, the same as Java's double. Unlike most other programming languages, there is no separate integer type, so 1 and 1.0 are the same value. This is significant convenience because problems of overflow in short integers are completely avoided, and all you need to know about a number is that it is a number. A large class of numeric type errors is avoided."&lt;br /&gt;&lt;br /&gt;Douglas Crockford, JavaScript: The Good Parts&lt;/blockquote&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_zFF22LLF49M/SIZX_2QL8xI/AAAAAAAAAMI/9FKMfcTOGtg/s1600-h/bits-small.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp2.blogger.com/_zFF22LLF49M/SIZX_2QL8xI/AAAAAAAAAMI/9FKMfcTOGtg/s400/bits-small.jpg" alt="" id="BLOGGER_PHOTO_ID_5225961172016821010" border="0" /&gt;&lt;/a&gt;&lt;span style="font-size:78%;"&gt;&lt;a href="http://flickr.com/photos/barnoid/2025811494/"&gt;Bitscuits&lt;/a&gt; © &lt;a href="http://flickr.com/people/barnoid/"&gt;Barney Livingston&lt;/a&gt; / &lt;a title="used under Creative Commons Attribution 2.0 License" href="http://creativecommons.org/licenses/by-sa/2.0/deed.en"&gt;CC&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;When I was twenty-something, I liked watching &lt;a href="http://www.imdb.com/title/tt0103586/"&gt;The Young Indiana Jones Chronicles&lt;/a&gt;. Besides the regular stuff that your average Indy fan loves, I was particularly fond of Indy's apparently insatiable appetite for traveling and learning different languages. So while I was contemplating what it would take for me to follow in his footsteps, I figured I'd better start with learning foreign languages. By that time I had already got my English certificate and I had a few years of learning French under my belt that had at least provided me with some means to court women (with little success, regrettably). So I started learning Italian, which everyone said was easy to pick up, especially if you had already mastered some other foreign language. That turned out to be true, and I managed to get a degree in Italian after two years of intensive studies. What made that period frustrating (and occasionally funny) however, were the times that I would inadvertently mix all three languages in the same sentence, creating my own version of &lt;a href="http://en.wikipedia.org/wiki/Esperanto"&gt;Esperanto&lt;/a&gt;. Due to the similarities among them, I might be trying to speak Italian, but use an English noun while constructing the past tense of a verb in French. Sometimes I would even be oblivious to my mistake until someone else pointed it out to me. It all seemed very natural as I was doing it.&lt;br /&gt;&lt;br /&gt;Lately I'm having a déjà vu, when I find myself coding in Java, JavaScript and C++, often in the same day. More than once I tried to initialize a Java object using a JavaScript object literal. Sadly, the compiler was not very accommodating. While writing a GWT-based front-end, I often transmitted POJOs without being aware that a long value was silently converted to a JavaScript Number, which essentially amounts to a Java double. Reading David Flanagan's "Rhino" book had already left me with the impression that JavaScript was rather flawed for not having separate types for integers, bytes, chars and all the other goodies that languages like C/C++ and Java spoil us with. But after getting a copy of Douglas Crockford recent, highly opinionated, "Good parts" book, his argument resonated with me: "A large class of numeric type errors is avoided." It's Richard Gabriel's &lt;a href="http://en.wikipedia.org/wiki/Worse_is_Better"&gt;"Worse Is Better"&lt;/a&gt; principle, or alternatively "Less Is More", in new clothes. Recent events made sure that the message was permanently bolted in my brain.&lt;br /&gt;&lt;br /&gt;I've been writing a desktop application in Java that communicates with various Bluetooth and USB devices. The communication protocol is some sort of terminal-like commands and responses that initiate at the Java application and travel through a thin JNI layer down to the C/C++ device driver, and then to the actual device. The protocol documentation describes in... er, &lt;span style="font-style: italic;"&gt;broad terms&lt;/span&gt;, the sequences of bytes that constitute the various requests and responses. Suffice it to say that my system administrator's experience in sniffing and deciphering network packets proved invaluable.&lt;br /&gt;&lt;br /&gt;Sending the command was easy (or so I thought): fill a &lt;code&gt;byte[]&lt;/code&gt; array with the right numbers and flush it through the JNI layer. There we get the &lt;code&gt;jbyteArray &lt;/code&gt;and put it inside an &lt;code&gt;unsigned char&lt;/code&gt; array, which is later send through the device driver to the actual device. When receiving responses the sequence was reversed. It all seemed to work fine for quite some time, until suddenly I discovered that one particular command caused the device to misbehave. I couldn't be sure if the device was faulty or my code was buggy, but since I had zero chances of proving the former, I focused on investigating the latter. A couple of days of debugging later I was still on square one, since as far as I could tell the command reached the device unscathed. Logic says that if a fine command reaches a fine device, then one would be entitled to a fine response. Since I wasn't getting it, I began questioning my assumptions.&lt;br /&gt;&lt;br /&gt;I resisted the urge to blame the device, since I couldn't prove it conclusively, and started blaming the command. There was definitely something fishy about it, and to be honest, I had a bad feeling all along. The other commands were simple sequences, like:&lt;br /&gt;&lt;br /&gt;0x14, 0x18, 0x1a, 0x3e&lt;br /&gt;&lt;br /&gt;or&lt;br /&gt;&lt;br /&gt;0x13, 0x17, 0x19, 0x26&lt;br /&gt;&lt;br /&gt;This particular one however, was icky:&lt;br /&gt;&lt;br /&gt;0x11, 0x15, 0x17, 0xf0&lt;br /&gt;&lt;br /&gt;If you can't see the ickiness (and I won't blame you), let me help you.&lt;br /&gt;&lt;br /&gt;Java's &lt;a href="http://java.sun.com/docs/books/tutorial/java/nutsandbolts/datatypes.html"&gt;byte type&lt;/a&gt; is a signed 8-bit integer. C++'s &lt;a href="http://www.cppreference.com/data_types.html"&gt;unsigned char type&lt;/a&gt; is an unsigned 8-bit integer (at least in 32-bit Windows). Therefore we can represent values from -128 to 127 in Java and values from 0 to 255 in C. So, if you have a value between 128 and 255, ickiness ensues. 0xf0 is, you guessed it, between 128 and 255. It is 240 to be precise, if Windows Calculator is to be trusted.&lt;br /&gt;&lt;br /&gt;Now, of course I am not &lt;span style="font-style: italic;"&gt;that&lt;/span&gt; dumb. I knew that you can't assign 0xf0 to a byte in Java, so I had already made the conversion. You see, what is actually transmitted is a sequence of 8 bits. If you get the sequence right, it will reach it's destination no matter what. When you convert 0xf0 to bits you get 11110000. The first bit is the sign bit, which is causing all the trouble. If it was zero instead, we would be dealing with 1110000, or 0x70, or 112 if you're into decimal numbers.&lt;br /&gt;&lt;br /&gt;So that's what I had done. I'd constructed the negative version of 112 and used that to fill my command buffer:&lt;br /&gt;&lt;br /&gt;0x11, 0x15, 0x17, -112&lt;br /&gt;&lt;br /&gt;Looking at it made me feel a bit uneasy, without being able to explain why. I used to think it was the mixed hex and decimal numbers. Yeah, I'm weird like that. However, the zillionth time I reread the Java's &lt;a href="http://java.sun.com/docs/books/tutorial/java/nutsandbolts/datatypes.html"&gt;byte type&lt;/a&gt; definition, a lightbulb lit up over my head. I actually paid attention to the words in front of me: "&lt;span style="font-style: italic;"&gt;&lt;/span&gt;The &lt;code&gt;byte&lt;/code&gt; data type is an 8-bit signed two's complement integer".&lt;br /&gt;&lt;br /&gt;Sure, it's 8 bits wide and yes it's signed, using the most common representation for negative binary numbers, two's complement. What's new here? I know how to negate in two's complem...&lt;br /&gt;&lt;br /&gt;Whoa! Wait a minute. What I just described above isn't how you negate a number in &lt;a href="http://en.wikipedia.org/wiki/Two%27s_complement"&gt;two's complement&lt;/a&gt;. It's actually how you do it in the &lt;a href="http://en.wikipedia.org/wiki/Signed_number_representations"&gt;sign-and-magnitude&lt;/a&gt; variant. In two's complement you invert the bits and add one to the result:&lt;br /&gt;&lt;br /&gt;11110000 -&gt; 00001111 -&gt; 00010000 or 16, or 0x10&lt;br /&gt;&lt;br /&gt;Yep, 16, not 112. So the proper command sequence becomes&lt;br /&gt;&lt;br /&gt;0x11, 0x15, 0x17, -16&lt;br /&gt;&lt;br /&gt;and, yes, the device seems quite happy with that. As happy as devices get, that is.&lt;br /&gt;&lt;br /&gt;So, basically, I wasted many many hours and suffered innumerable hair-pulling episodes for falling prey to a numeric type error. The kind Doug Crockford alludes to in his book. Now, don't get me wrong, I like mucking with bits as much as the next guy. But had I been living solely in JavaScript-land, with the single number type, I'd feel less tired and probably not hate my work as much. Though, granted, I might be needing a haircut right now.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/486398466531826618-864238574787381067?l=blog.astithas.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/PastMidnight/~4/m_gLbssAPfg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.astithas.com/feeds/864238574787381067/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=486398466531826618&amp;postID=864238574787381067" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/864238574787381067?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/864238574787381067?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/PastMidnight/~3/m_gLbssAPfg/murdered-by-numbers.html" title="Murdered by Numbers" /><author><name>Panagiotis Astithas</name><uri>https://profiles.google.com/116466326438420686438</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-ieNj_PE2fxE/AAAAAAAAAAI/AAAAAAAAAAA/l78jhJX3laA/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://bp2.blogger.com/_zFF22LLF49M/SIZX_2QL8xI/AAAAAAAAAMI/9FKMfcTOGtg/s72-c/bits-small.jpg" height="72" width="72" /><thr:total>1</thr:total><feedburner:origLink>http://blog.astithas.com/2008/07/murdered-by-numbers.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CU8GRnY9eip7ImA9WxdRE0g.&quot;"><id>tag:blogger.com,1999:blog-486398466531826618.post-2111676110324666093</id><published>2008-06-01T23:57:00.000+03:00</published><updated>2008-06-01T23:57:07.862+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-06-01T23:57:07.862+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript" /><category scheme="http://www.blogger.com/atom/ns#" term="open-source" /><category scheme="http://www.blogger.com/atom/ns#" term="Subversion" /><title>Why you should go to conferences</title><content type="html">One thing I like about working in a large corporation is that you get to meet all sorts of interesting people. You actually &lt;span style="font-style: italic;"&gt;have to&lt;/span&gt; meet them, since you can't get anything done without coordinating with a whole bunch of them. But since this tends to get nothing done most of the time, I chose to work in a small company instead. Here if you want to do anything, you probably have to do it yourself (there are some interesting repercussions of this that I will leave for a future post). Now, if you work in a small company &lt;span style="font-style: italic;"&gt;and&lt;/span&gt; want to meet lots of interesting people, you basically have &lt;s&gt;three&lt;/s&gt; two options:&lt;ol&gt;&lt;li&gt;Use the net - blogs, mailing lists, newsgroups, twitter, friendfeed, etc. (&lt;a href="http://twitter.com/pastith"&gt;done&lt;/a&gt; &lt;a href="http://friendfeed.com/past"&gt;that&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;Attend conferences.&lt;/li&gt;&lt;li&gt;&lt;s&gt;Go to parties.&lt;/s&gt;&lt;/li&gt;&lt;/ol&gt;Now as you can personally attest to, I've got  No.1 covered. So  the last couple of days I worked on number 2 instead. The nice guys at ellak.gr organized the &lt;a href="http://conf.ellak.gr/2008/"&gt;3rd FLOSS conference&lt;/a&gt; and since it took place very close to where I work, I took the opportunity to &lt;s&gt;avoid working&lt;/s&gt; meet some old friends and make some new ones.&lt;br /&gt;&lt;br /&gt;Number One of course, is &lt;a href="http://en.wikipedia.org/wiki/Wietse_Venema"&gt;Wietse Venema&lt;/a&gt;. Since his work was an inspiration for me to pursue a PhD in computer security, I just &lt;span style="font-style: italic;"&gt;had&lt;/span&gt; to see him in person once. He was more fun that I expected, to be honest. Security guys have a reputation of being a wee bit paranoid and itsy-bitsy abrupt on normal people, not to mention complete strangers. Wietse however was neither. This probably has to do with his academic background or maybe the fact that he is Dutch, who knows. He proved to be a warm, funny guy instead, who runs FreeBSD on his laptop (&lt;span style="font-style: italic;"&gt;that&lt;/span&gt; always shows character in my book).&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_zFF22LLF49M/SD5HD9O2CII/AAAAAAAAALg/naTC66oTuBM/s1600-h/VenemaFLOSS08.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp1.blogger.com/_zFF22LLF49M/SD5HD9O2CII/AAAAAAAAALg/naTC66oTuBM/s400/VenemaFLOSS08.jpg" alt="" id="BLOGGER_PHOTO_ID_5205676352588875906" border="0" /&gt;&lt;/a&gt;His talk was about &lt;a href="http://conf.ellak.gr/2008/index.php?option=com_eventlist&amp;amp;Itemid=119&amp;amp;func=details&amp;amp;did=2"&gt; Open Source and Security&lt;/a&gt;, both matters dear to my heart. The discussion of Postfix was a walk down memory lane for me. I can still remember the excitement around its initial release: "Hooray! No more sendmail exploits!". Wietse briefly discussed the architecture of postfix and how it relates to its security. He also showed some statistics comparing postfix to sendmail and qmail that I had seen in the past, but was curious to where everyone currently stands. Apparently postfix holds the second place in number of deployments (good), the first in number of lines of code (bad), but that is caused by having reached sendmail's feature list, without compromising the original architectural goals (good). For the problem of security at large, the most provocative suggestion was to make software development too hard for the laymen, so only experts could do it. Heh. As John Wayne so eloquently used to put it: "that'll be the day".&lt;br /&gt;&lt;br /&gt;Lots of comparisons were presented in the talk by Diomidis Spinellis, titled &lt;a href="http://conf.ellak.gr/2008/index.php?option=com_eventlist&amp;amp;Itemid=119&amp;amp;func=details&amp;amp;did=53"&gt;A Tale of Four Kernels&lt;/a&gt;. The talk covered a code quality comparison of four major commercial and open-source operating systems, Windows, Solaris, Linux and FreeBSD. Diomidis is a well known author and FreeBSD commiter, and that was evident in the quality of his work and presentation. The room was packed, and the Q&amp;amp;A session lasted almost as long as the presentation itself. I suppose the sensitivity of the subject had something to do with it. Diomidis went through heaps of information so fast you could barely comprehend each slide, unless you had the forethought to study his paper before the conference, like your truly did. Although he was very delicate in his conclusions, stating that all systems had comparable quality, there were some members of the audience that seemed to have already made up their minds and didn't care for diplomacy.&lt;br /&gt;&lt;br /&gt;Another great talk was by Jim Blandy. The talk was about &lt;a href="http://conf.ellak.gr/2008/index.php?option=com_eventlist&amp;amp;Itemid=119&amp;amp;func=details&amp;amp;did=9"&gt; Open Source Infrastructure for Software Development&lt;/a&gt;, which covered the evolution of version control systems (VCS), from SCCS, to the recent crop of distributed VCS. Being one of the people who gave us CVS and Subversion, his recollection of the history of this area was very exciting. Besides sharing some colorful historical tidbits, he also gave a meaningful comparison of the algorithms and data structures used by the various systems. He gave high marks to Subversion for being a fine choice in a centralized organization structure, but eloquently presented the fundamental paradigm shift that distributed VCS present. He said (as best as I can remember) that controlling access to the commit step (what all centralized VCS do) is the wrong (worst?) place to do it, since adding a change is not that big a deal. Instead the point of merging is what should be guarded, since that is when another changeset gets incorporated in our code. The fact that distributed VCS replicate whole repositories, not just working copies, makes allowing commits a natural thing, while making merge selection part of the release engineering process. I've read many pro-distributed-VCS arguments, but I found Jim's focus on the social aspect of the merge process a refreshing one. Luckily, most of my cohorts were present in this talk, so switching our team to Mercurial might not be just a dream after all.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_zFF22LLF49M/SD5HhNO2CJI/AAAAAAAAALo/6K399NebzIk/s1600-h/JimBlandy.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp2.blogger.com/_zFF22LLF49M/SD5HhNO2CJI/AAAAAAAAALo/6K399NebzIk/s400/JimBlandy.jpg" alt="" id="BLOGGER_PHOTO_ID_5205676855100049554" border="0" /&gt;&lt;/a&gt;Jim currently works on Mozilla, on the new &lt;a href="http://wiki.mozilla.org/JavaScript:ActionMonkey"&gt;ActionMonkey&lt;/a&gt; JavaScript engine. Since that work was outside the scope of this talk, I managed to corner Jim afterwards to find out more about its current status. The project attempts to integrate the current Mozilla JavaScript engine, SpiderMonkey, with the &lt;a href="http://www.mozilla.org/projects/tamarin/"&gt;Tamarin&lt;/a&gt; engine contributed by Adobe. The plan was to replace various parts of the old engine with the new ones, like the garbage collector, the JIT compiler, etc. However doing so leads to performance regressions in some areas and Jim said that one lesson they have learned is that if you ship with worse performance, no matter how rare the circumstances that expose it, you will pay for it at some point. String manipulation appears to be one of those areas, since the old engine had been carefully optimized during all this time and achieving the same performance with the new one, requires work. I have been wondering for some time now whether SpiderMonkey uses some variation of the &lt;a href="http://www.cs.ubc.ca/local/reading/proceedings/spe91-95/spe/vol25/issue12/spe986.pdf"&gt;Ropes&lt;/a&gt; data structure for String representation, but Jim explained to me that was not the case.&lt;br /&gt;&lt;br /&gt;He was also very excited about the experimental &lt;a href="http://wiki.mozilla.org/Tamarin:Tracing"&gt;tracing JIT&lt;/a&gt; that they are working on, that appears to be a perfect fit for dynamic languages and is expected to boost JavaScript performance on future versions of the browser. I told him that I had already heard of it from &lt;a href="http://steve-yegge.blogspot.com/2008/05/dynamic-languages-strike-back.html"&gt;Steve Yegge&lt;/a&gt;, and I've been meaning to read the literature Real Soon Now(TM), which I swear is the truth, the whole truth and nothing but the truth. After I finish this belated post of course. Jim said that Steve is a great story-teller, which means that Steve, if you ever find yourself in Athens and want a free dinner, just let me know. Explaining the benefits of tracing JIT led us to a detour into LISP-land and while Jim has written a &lt;a href="http://www.red-bean.com/trac/minor/"&gt;Scheme compiler&lt;/a&gt;, I've only done LISP programming for a class as a student. Which is another way of saying I didn't understand a word he said, alas. Anyway, the cool things they are working on will probably come to us in firefox 4, so I still have time to get up to speed.&lt;br /&gt;&lt;br /&gt;All in all, the conference was quite an enjoyable experience. Old friends, new friends, free food, stimulating discussions, what's more to ask?&lt;br /&gt;&lt;br /&gt;What? To be on TV? Hey, that's easy. You just have to hang outside the main conference room chatting with random people, until you notice a cameraman and a journalist taking interviews from conference organizers and speakers. Then you make sure to be in the camera frame and &lt;a href="http://www.skai.gr/master_avod.php?id=83051&amp;amp;lsc=1"&gt;voil&lt;span class="variant"&gt;à&lt;/span&gt;!&lt;/a&gt; You've got your 3 seconds of fame.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/486398466531826618-2111676110324666093?l=blog.astithas.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/PastMidnight/~4/dnfWwVwb-_0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.astithas.com/feeds/2111676110324666093/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=486398466531826618&amp;postID=2111676110324666093" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/2111676110324666093?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/2111676110324666093?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/PastMidnight/~3/dnfWwVwb-_0/why-you-should-go-to-conferences.html" title="Why you should go to conferences" /><author><name>Panagiotis Astithas</name><uri>https://profiles.google.com/116466326438420686438</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-ieNj_PE2fxE/AAAAAAAAAAI/AAAAAAAAAAA/l78jhJX3laA/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://bp1.blogger.com/_zFF22LLF49M/SD5HD9O2CII/AAAAAAAAALg/naTC66oTuBM/s72-c/VenemaFLOSS08.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://blog.astithas.com/2008/06/why-you-should-go-to-conferences.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C04BSHg7fip7ImA9WxZUEUo.&quot;"><id>tag:blogger.com,1999:blog-486398466531826618.post-7997658996911806749</id><published>2008-04-03T00:30:00.001+02:00</published><updated>2008-04-02T23:32:39.606+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-04-02T23:32:39.606+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript" /><category scheme="http://www.blogger.com/atom/ns#" term="programming" /><category scheme="http://www.blogger.com/atom/ns#" term="web" /><title>JavaScript on the server with Helma</title><content type="html">Rumor has it that the most widely deployed programming language is JavaScript, due to being embedded in every contemporary browser. This extraordinary feat has obscured the fact that the language itself is not only suitable for client programming, but for server-side development as well. Dynamic, loosely-typed languages offer shorter development cycles, agility in meeting changing customer requirements, particularly for enterprises without well-specified business processes, or rapidly expanding enterprises that constantly adapt their core business. JavaScript on the browser is a de-facto standard; using it on the server provides the benefit of reusing a single code base and data model, and debugging it once.&lt;br /&gt;&lt;br /&gt;It is also relatively unknown that there exist already more than one frameworks for programming on the server with JavaScript. The most mature among them is &lt;a href="http://helma.org/"&gt;Helma&lt;/a&gt;, an open-source framework that has been used in &lt;a href="http://helma.org/about/"&gt;production environments for years&lt;/a&gt;, like the Austrian Broadcasting Corporation. I've been playing with it for quite some time and I'd like to show how easy it is to get up and running, in order to make any adventurous souls less afraid to give it a try.&lt;br /&gt;&lt;br /&gt;Setting up Helma is fairly straightforward. First you have to download the latest version from &lt;a href="http://helma.org/download/"&gt;http://helma.org/download/&lt;/a&gt;. Follow the proper link for your platform and the zip or tar archive will be downloaded in your system. After extracting the archive it will create a folder with the latest version of Helma (1.6.1 as of this writing) in it. The only prerequisite is that you have Java installed on your system, since Helma uses the &lt;a href="http://www.mozilla.org/rhino/"&gt;Rhino&lt;/a&gt; JavaScript engine underneath. This arrangement allows the reuse of existing Java code through the Rhino APIs. If your system did not come with Java preinstalled, a visit to &lt;a href="http://java.com/"&gt;java.com&lt;/a&gt; should suffice. You should get the latest version available (Java 6 as of this writing), but anything after 1.4 should be good. If you are set, go to the Helma directory and execute &lt;code&gt;start.bat&lt;/code&gt; or &lt;code&gt;start.sh&lt;/code&gt; depending on your platform and you should see some brief startup messages:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;Mac:~/helma-1.6.1 panagiotisastithas$ ./start.sh&lt;br /&gt;Starting Helma in directory /Users/&lt;/code&gt;&lt;code&gt;panagiotisastithas&lt;/code&gt;&lt;code&gt;/helma-1.6.1&lt;br /&gt;Starting HTTP server on port 8080&lt;br /&gt;Starting Helma 1.6.1 (January 8 2008) on Java 1.5.0_13&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The server is now ready to accept requests. Helma embeds &lt;a href="http://www.mortbay.org/"&gt;Jetty&lt;/a&gt; for its HTTP engine, something that makes the startup process a snap and provides for some interesting architectural choices with its support for &lt;a href="http://dev.helma.org/wiki/Continuations/"&gt;continuations&lt;/a&gt;. Point your browser to &lt;a href="http://localhost:8080/"&gt;http://localhost:8080/&lt;/a&gt; and you should see the welcome page:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_zFF22LLF49M/R_Prh4HXzHI/AAAAAAAAAJE/ZoqzGag7KKM/s1600-h/helma1.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp3.blogger.com/_zFF22LLF49M/R_Prh4HXzHI/AAAAAAAAAJE/ZoqzGag7KKM/s400/helma1.png" alt="" id="BLOGGER_PHOTO_ID_5184746563265088626" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;This is an actual application, the “welcome” application, that you are interacting with. You might want to navigate around a bit to skim through the available on-line documentation. When you've had enough, you can stop the server by getting back to the console window and hitting Control-C:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;^CShutting down Helma - please stand by...&lt;br /&gt;Mac:~/helma-1.6.1 &lt;/code&gt;&lt;code&gt;panagiotisastithas&lt;/code&gt;&lt;code&gt;$&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;Just to recap:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Download Helma from http://helma.org/download/&lt;/li&gt;&lt;li&gt;Unzip&lt;/li&gt;&lt;li&gt;Go to the unzipped directory&lt;/li&gt;&lt;li&gt;Make sure you have Java 1.4+ installed&lt;/li&gt;&lt;li&gt;Execute start.bat/start.sh&lt;/li&gt;&lt;li&gt;Point the browser to http://localhost:8080/&lt;/li&gt;&lt;/ol&gt;&lt;/blockquote&gt;&lt;br /&gt;Creating a simple application with Helma involves only a few easy steps. First of all create a directory called '&lt;code&gt;hello&lt;/code&gt;' inside the subdirectory '&lt;code&gt;apps&lt;/code&gt;' of the main Helma installation directory. Inside '&lt;code&gt;hello&lt;/code&gt;' create a directory named '&lt;code&gt;Root&lt;/code&gt;'. Inside '&lt;code&gt;Root&lt;/code&gt;' create a file called &lt;code&gt;actions.js&lt;/code&gt; with the following content:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;function main_action() {&lt;br /&gt;   res.write("Hello, World!")&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The following screenshot illustrates our progress so far:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_zFF22LLF49M/R_PsAYHXzII/AAAAAAAAAJM/3dEIx3Xb82E/s1600-h/helma2.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp1.blogger.com/_zFF22LLF49M/R_PsAYHXzII/AAAAAAAAAJM/3dEIx3Xb82E/s400/helma2.png" alt="" id="BLOGGER_PHOTO_ID_5184747087251098754" border="0" /&gt;&lt;/a&gt;&lt;/pre&gt;&lt;br /&gt;Then open the file &lt;code&gt;apps.properties&lt;/code&gt; in the main Helma installation directory and add a single line at the end of the file with the following content:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;hello&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Now start (or restart if it is already running) the server and point your browser to &lt;a href="http://localhost:8080/hello"&gt;http://localhost:8080/hello&lt;/a&gt;. This is what you should see in your browser:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_zFF22LLF49M/R_PsUIHXzJI/AAAAAAAAAJU/3aj8Nj0h5Cg/s1600-h/helma3.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp0.blogger.com/_zFF22LLF49M/R_PsUIHXzJI/AAAAAAAAAJU/3aj8Nj0h5Cg/s400/helma3.png" alt="" id="BLOGGER_PHOTO_ID_5184747426553515154" border="0" /&gt;&lt;/a&gt;&lt;/pre&gt;&lt;br /&gt;That's it! Your first server-side JavaScript application is ready. In future posts I intend to discuss how Helma wires the various pieces together and explore some of its more interesting features. In the meantime, I suggest that you download it and experiment. You might be pleasantly surprised!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/486398466531826618-7997658996911806749?l=blog.astithas.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/PastMidnight/~4/NOeeKw0i_0o" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.astithas.com/feeds/7997658996911806749/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=486398466531826618&amp;postID=7997658996911806749" title="6 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/7997658996911806749?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/7997658996911806749?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/PastMidnight/~3/NOeeKw0i_0o/javascript-on-server-with-helma.html" title="JavaScript on the server with Helma" /><author><name>Panagiotis Astithas</name><uri>https://profiles.google.com/116466326438420686438</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-ieNj_PE2fxE/AAAAAAAAAAI/AAAAAAAAAAA/l78jhJX3laA/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://bp3.blogger.com/_zFF22LLF49M/R_Prh4HXzHI/AAAAAAAAAJE/ZoqzGag7KKM/s72-c/helma1.png" height="72" width="72" /><thr:total>6</thr:total><feedburner:origLink>http://blog.astithas.com/2008/04/javascript-on-server-with-helma.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CU8FRXwyfSp7ImA9WxZVEEg.&quot;"><id>tag:blogger.com,1999:blog-486398466531826618.post-8400716056180093496</id><published>2008-03-21T00:41:00.003+02:00</published><updated>2008-03-21T00:56:54.295+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-03-21T00:56:54.295+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript" /><category scheme="http://www.blogger.com/atom/ns#" term="programming" /><title>(Grease) Monkey Business</title><content type="html">&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_zFF22LLF49M/R-GM1le6hEI/AAAAAAAAAHc/91swR_urd_A/s1600-h/greasemonkey.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp3.blogger.com/_zFF22LLF49M/R-GM1le6hEI/AAAAAAAAAHc/91swR_urd_A/s320/greasemonkey.png" alt="" id="BLOGGER_PHOTO_ID_5179575898675512386" border="0" /&gt;&lt;/a&gt;I've been reading &lt;a href="http://journal.davidbyrne.com/"&gt;David Byrne's journal&lt;/a&gt; (of the Talking Heads fame) since before I heard about blogs and blogging. In an ocean of software blogs that flood my Google Reader, it's one of the few that remind me that I have other interests besides computers. From this journal I found out that he also hosts an &lt;a href="http://davidbyrne.com/radio/index.php"&gt;internet radio station&lt;/a&gt; that I've been often enjoying while at work or sometimes at home.&lt;br /&gt;&lt;br /&gt;For this task I've been using &lt;a href="http://www.apple.com/itunes/"&gt;iTunes&lt;/a&gt; on my Mac at home and &lt;a href="http://www.gnome.org/projects/rhythmbox/"&gt;Rhythmbox&lt;/a&gt; on Linux at work. Besides the easier subscription to the station, the one thing I miss from iTunes while at work is seeing the currently playing song on Rhythmbox. I don't know how iTunes does it, but it's always showing the correct song title and artist, while on Rhythmbox all I see is the station name.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_zFF22LLF49M/R-LjLVe6hKI/AAAAAAAAAIM/49BP9QpjDAo/s1600-h/radio.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp3.blogger.com/_zFF22LLF49M/R-LjLVe6hKI/AAAAAAAAAIM/49BP9QpjDAo/s400/radio.png" alt="" id="BLOGGER_PHOTO_ID_5179952305314366626" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Therefore I had resorted to having a tab open in Firefox all day that displayed the radio home page that shows the playlist and refreshes each time a new song begins. I still had to switch to the browser from whatever I was doing when a new song started, in order to glance on its title and performer. A few days ago I thought to myself: "wouldn't it be nice to have the Firefox title bar display that information and only take my eyes off what I'm currently doing and not my fingers too?".&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_zFF22LLF49M/R-KA5le6hFI/AAAAAAAAAHk/wgUWD8k2ElM/s1600-h/Screenshot-Radio+DavidByrne.com.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp0.blogger.com/_zFF22LLF49M/R-KA5le6hFI/AAAAAAAAAHk/wgUWD8k2ElM/s320/Screenshot-Radio+DavidByrne.com.png" alt="" id="BLOGGER_PHOTO_ID_5179844248232166482" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;It turns out that I'm very persuasive when I'm talking to myself, so I set off to make my wish come true. I've been also trying to find an excuse to learn more about &lt;a href="http://www.greasespot.net/"&gt;Greasemonkey&lt;/a&gt; for some time and it seemed like the right time to do it. So after I spent some time &lt;a href="http://www.oreillynet.com/pub/a/network/2005/09/01/what-is-greasemonkey.html"&gt;reading&lt;/a&gt; &lt;a href="http://www.oreillynet.com/pub/a/network/2005/11/01/avoid-common-greasemonkey-pitfalls.html"&gt;up&lt;/a&gt; &lt;a href="http://diveintogreasemonkey.org/"&gt;stuff&lt;/a&gt; from the web, I came up with something that made me happy:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(function() {&lt;br /&gt;  window.addEventListener("load", function(e) {&lt;br /&gt;&lt;br /&gt;   var PLAYLIST_URL = 'http://www.live365.com/pls/front?handler=playlist&amp;cmd=view&amp;viewType=xml&amp;handle=todomundo&amp;maxEntries=1';&lt;br /&gt;&lt;br /&gt;   (function fetchCurrentSong() {&lt;br /&gt;      GM_xmlhttpRequest({&lt;br /&gt;          method: "GET",&lt;br /&gt;          url: PLAYLIST_URL,&lt;br /&gt;          onload: function(details) {&lt;br /&gt;            var xmlString = details.responseText;&lt;br /&gt;            var parser = new DOMParser();&lt;br /&gt;            var xmlDoc = parser.parseFromString(xmlString, "application/xml");&lt;br /&gt;            var refresh = xmlDoc.getElementsByTagName('Refresh')[0].textContent;&lt;br /&gt;            var artist = xmlDoc.getElementsByTagName('Artist')[0].textContent;&lt;br /&gt;            var album = xmlDoc.getElementsByTagName('Album')[0].textContent;&lt;br /&gt;            var title = xmlDoc.getElementsByTagName('Title')[0].textContent;&lt;br /&gt;            var label = title+' by '+artist+' from '+album;&lt;br /&gt;            document.title = label;&lt;br /&gt;            setTimeout(fetchCurrentSong, refresh);&lt;br /&gt;          }&lt;br /&gt;      });&lt;br /&gt;   })();&lt;br /&gt;&lt;br /&gt;  }, false);&lt;br /&gt;})();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;It's amazing what 20 lines of JavaScript can do. You can install this user script by clicking &lt;a href="http://pastith.googlepages.com/radiodavidbyrnenowplaying.user.js"&gt;here&lt;/a&gt;,&lt;a href="http://www.ebs.gr/past/radiodavidbyrnenowplaying.user.js"&gt;&lt;/a&gt; assuming you have Greasemonkey installed and enabled. If you don't have Greasemonkey or prefer to install a firefox extension that does not require it, click &lt;a href="http://pastith.googlepages.com/radiodavidbyrnenowplaying.xpi"&gt;this&lt;/a&gt; link instead. It was automagically created with the very nifty &lt;a href="http://arantius.com/misc/greasemonkey/script-compiler"&gt;User Script Compiler&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;This is what I see now when I'm listening to David's playlist (although many times I just glance at the title in the minimized button on the bottom panel):&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_zFF22LLF49M/R-KJDle6hII/AAAAAAAAAH8/9K7-vVwOSeY/s1600-h/Screenshot-Take+Five+by+Dave+Brubeck+Quartet+from+Time+Out+-+Mozilla+Firefox.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp0.blogger.com/_zFF22LLF49M/R-KJDle6hII/AAAAAAAAAH8/9K7-vVwOSeY/s400/Screenshot-Take+Five+by+Dave+Brubeck+Quartet+from+Time+Out+-+Mozilla+Firefox.png" alt="" id="BLOGGER_PHOTO_ID_5179853216123880578" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.amazon.com/dp/0596101651?tag=diveintomark-20&amp;amp;camp=14573&amp;amp;creative=327641&amp;amp;linkCode=as1&amp;amp;creativeASIN=0596101651&amp;amp;adid=0FWXP9M5TQZJJDFQ3FYN&amp;amp;"&gt;Remixing the web&lt;/a&gt;, indeed.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/486398466531826618-8400716056180093496?l=blog.astithas.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/PastMidnight/~4/F6c6WS3_CLo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.astithas.com/feeds/8400716056180093496/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=486398466531826618&amp;postID=8400716056180093496" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/8400716056180093496?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/8400716056180093496?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/PastMidnight/~3/F6c6WS3_CLo/grease-monkey-business.html" title="(Grease) Monkey Business" /><author><name>Panagiotis Astithas</name><uri>https://profiles.google.com/116466326438420686438</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-ieNj_PE2fxE/AAAAAAAAAAI/AAAAAAAAAAA/l78jhJX3laA/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://bp3.blogger.com/_zFF22LLF49M/R-GM1le6hEI/AAAAAAAAAHc/91swR_urd_A/s72-c/greasemonkey.png" height="72" width="72" /><thr:total>1</thr:total><feedburner:origLink>http://blog.astithas.com/2008/03/grease-monkey-business.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0EAQnczeyp7ImA9WxZWGUs.&quot;"><id>tag:blogger.com,1999:blog-486398466531826618.post-4825663374437021742</id><published>2008-03-19T23:20:00.001+02:00</published><updated>2008-03-19T23:20:43.983+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-03-19T23:20:43.983+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="personal" /><title>Re: I wish I could...</title><content type="html">I can tell that spring is here, when my friend &lt;a href="http://blog.postmaster.gr/"&gt;George&lt;/a&gt; tags me with another blog meme. Apparently it's like a ritual to him, but it came a few weeks earlier this year, so I figured I could delay posting at least until last year's &lt;a href="http://astithas.blogspot.com/2007/03/movies.html"&gt;anniversary&lt;/a&gt;. With the frequency I blog, he doesn't have much to expect anyway.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://blog.postmaster.gr/2008/03/04/re-ax-%ce%ba%ce%b1%ce%b9-%ce%bd%ce%b1-%ce%bc%cf%80%ce%bf%cf%81%ce%bf%cf%8d%cf%83%ce%b1%e2%80%a6/"&gt;This year's theme&lt;/a&gt; is to write about crazy or stupid things you'd like to do, but can't, or stupid things that you do anyway. Since I'm running an old-fashioned, respectable blog here, I'll restrict my answer to appropriate stuff, namely computers and software. And with that I expect to have lost 50% of my audience, so I guess that leaves me and you George. So without further ado, here are 10 things (in no particular order) I wish I could do, but probably won't:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;...stop reading FreeBSD mailing lists.&lt;/li&gt;&lt;li&gt;...convince my colleagues at work to switch to Mercurial for version control.&lt;/li&gt;&lt;li&gt;...transfer a call at work (in a Linksys IP Phone) without loosing it.&lt;/li&gt;&lt;li&gt;...build the zero-administration appliance I was planning.&lt;/li&gt;&lt;li&gt;...use and contribute to &lt;a href="http://www.jnode.org/"&gt;JNode&lt;/a&gt;, an operating system written in Java.&lt;/li&gt;&lt;li&gt;...write a book about a computer-related subject.&lt;/li&gt;&lt;li&gt;...implement &lt;a href="http://java.sun.com/j2se/1.5.0/docs/guide/vm/class-data-sharing.html"&gt;class data sharing&lt;/a&gt; for 64 bit VMs.&lt;/li&gt;&lt;li&gt;...write Objective-C code using Xcode.&lt;/li&gt;&lt;li&gt;...stop subscribing to more blogs and even ditch a few altogether.&lt;/li&gt;&lt;li&gt;...blog more often.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;I guess I'm not that ambitious after all...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/486398466531826618-4825663374437021742?l=blog.astithas.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/PastMidnight/~4/hVG44fesZKI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.astithas.com/feeds/4825663374437021742/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=486398466531826618&amp;postID=4825663374437021742" title="7 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/4825663374437021742?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/4825663374437021742?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/PastMidnight/~3/hVG44fesZKI/re-i-wish-i-could.html" title="Re: I wish I could..." /><author><name>Panagiotis Astithas</name><uri>https://profiles.google.com/116466326438420686438</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-ieNj_PE2fxE/AAAAAAAAAAI/AAAAAAAAAAA/l78jhJX3laA/s512-c/photo.jpg" /></author><thr:total>7</thr:total><feedburner:origLink>http://blog.astithas.com/2008/03/re-i-wish-i-could.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0ECSXg6eip7ImA9WxZWFU4.&quot;"><id>tag:blogger.com,1999:blog-486398466531826618.post-3834807385628545203</id><published>2008-03-15T01:59:00.000+02:00</published><updated>2008-03-15T01:01:08.612+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-03-15T01:01:08.612+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Java" /><category scheme="http://www.blogger.com/atom/ns#" term="WebDAV" /><category scheme="http://www.blogger.com/atom/ns#" term="programming" /><title>How to create a WebDAV interface in 10 easy steps</title><content type="html">&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_zFF22LLF49M/R9sC-l84d7I/AAAAAAAAAG8/DPT-QktEHK4/s1600-h/webdav-logo.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp3.blogger.com/_zFF22LLF49M/R9sC-l84d7I/AAAAAAAAAG8/DPT-QktEHK4/s320/webdav-logo.jpg" alt="" id="BLOGGER_PHOTO_ID_5177735470955132850" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Test Driven Development (TDD) is all the rage these days. And rightly so, if you ask me. Compare developing software against constantly changing client requirements and developing against a specification in the form of tests that your code must pass. I've done my share of the former for the better part of the last 9 years and I've got the gray hair to prove it. However, I only got a chance to practice the latter very recently and I must say I'm hooked.&lt;br /&gt;&lt;br /&gt;My TDD endeavor concerns a small project to add a &lt;a href="http://en.wikipedia.org/wiki/WebDAV"&gt;WebDAV&lt;/a&gt; interface to an existing server-side code base. The system already featured other interfaces for manipulating the resources stored in it, but a cross-platform, standards-based, nicely integrated, native client was  deemed necessary.  Enter WebDAV, a.k.a. HTTP on steroids. Most desktop systems nowadays have a WebDAV client installed by default (Windows calls it Web Folders, others prefer not to rename it), so testing a WebDAV server is not that complicated: if you can mount, browse, store and retrieve files and folders using your desktop client, the server implementation is fine. Nevertheless, we can do better than that. Using &lt;a href="http://www.webdav.org/neon/litmus/"&gt;litmus&lt;/a&gt;, a "WebDAV server protocol compliance suite", we can make sure that our implementation respects the protocol, even in its more obscure corner cases and more importantly, perform the testing automatically, without painstaking clickety-click.&lt;br /&gt;&lt;br /&gt;Implementing a WebDAV interface from scratch by reading the &lt;a href="http://tools.ietf.org/html/rfc4918"&gt;protocol specification&lt;/a&gt; is not the easiest nor the smartest path. You &lt;span style="font-style: italic;"&gt;will&lt;/span&gt; have to read it in order to figure out what goes where, but you could also reuse some parts from an existing implementation. If you are extending an existing Java codebase, like me, your best bet is reusing the &lt;a href="http://tomcat.apache.org/"&gt;Tomcat&lt;/a&gt; &lt;a href="http://svn.apache.org/repos/asf/tomcat/tc6.0.x/trunk/java/org/apache/catalina/servlets/WebdavServlet.java"&gt;implementation&lt;/a&gt;. You can run the litmus suite against a vanilla Tomcat installation, just to verify its WebDAV functionality. Not all tests pass, since the implementation is incomplete, but don't worry, most clients don't implement the spec completely either. However take a note of the results, since this is your target outcome.&lt;br /&gt;&lt;br /&gt;For your own convenience, I have described the whole development process in 10 easy steps, ready to print, free of charge, batteries not included:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Download the litmus test suite.&lt;/li&gt;&lt;li&gt;Download the sources for Tomcat, particularly WebdavServlet.java and DefaultServlet.java.&lt;/li&gt;&lt;li&gt;Create your own version of WebdavServlet that will delegate the actual functionality to your own backend and fill it with empty stub methods that correspond to the ones in Tomcat.&lt;/li&gt;&lt;li&gt;Build &amp;amp; deploy your server.&lt;/li&gt;&lt;li&gt;Run the litmus test. All tests fail the first time, but when it eventually succeeds (i.e. matches the result of vanilla tomcat), go to step 9.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Fill one method at a time from Tomcat's sources, substituting the JNDI communications with your backend logic.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Add any other helper methods from other Tomcat classes as necessary.&lt;/li&gt;&lt;li&gt;Go to step 4.&lt;/li&gt;&lt;li&gt;Most tests succeeded, so you are done!&lt;/li&gt;&lt;li&gt;For extra credit: fix the code to pass some more tests and send your changes upstream.&lt;/li&gt;&lt;/ol&gt;You are bound to come across some hair-splitting problems when modifying the codebase to fit in you own backend, but it beats writing it all from scratch hands down, unless you are Greg Stein or Jim Whitehead. In my case, after two weeks and a submitted &lt;a href="https://issues.apache.org/bugzilla/show_bug.cgi?id=43706"&gt;patch&lt;/a&gt;, I was done and had the tests to prove it. Furthermore, when the need for a code refactoring arises, I can rest assured that my changes won't break the protocol functionality if the litmus tests still pass. Not to mention that I have now contributed to Tomcat.&lt;br /&gt;&lt;br /&gt;Man, I haven't felt that good in ages.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/486398466531826618-3834807385628545203?l=blog.astithas.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/PastMidnight/~4/UnTUGqXEKj0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.astithas.com/feeds/3834807385628545203/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=486398466531826618&amp;postID=3834807385628545203" title="8 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/3834807385628545203?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/3834807385628545203?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/PastMidnight/~3/UnTUGqXEKj0/how-to-create-webdav-interface-in-10.html" title="How to create a WebDAV interface in 10 easy steps" /><author><name>Panagiotis Astithas</name><uri>https://profiles.google.com/116466326438420686438</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-ieNj_PE2fxE/AAAAAAAAAAI/AAAAAAAAAAA/l78jhJX3laA/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://bp3.blogger.com/_zFF22LLF49M/R9sC-l84d7I/AAAAAAAAAG8/DPT-QktEHK4/s72-c/webdav-logo.jpg" height="72" width="72" /><thr:total>8</thr:total><feedburner:origLink>http://blog.astithas.com/2008/03/how-to-create-webdav-interface-in-10.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A08FQno6eip7ImA9WB9UGEk.&quot;"><id>tag:blogger.com,1999:blog-486398466531826618.post-3287588659022856234</id><published>2007-12-17T01:59:00.000+02:00</published><updated>2007-12-17T02:03:33.412+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2007-12-17T02:03:33.412+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="jobs" /><category scheme="http://www.blogger.com/atom/ns#" term="business" /><title>Job hunting is like dating</title><content type="html">&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_zFF22LLF49M/R2W19u7N9YI/AAAAAAAAAGE/SQ_XcF-eNYg/s1600-h/1234618279_c2cfafb29d_m.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp2.blogger.com/_zFF22LLF49M/R2W19u7N9YI/AAAAAAAAAGE/SQ_XcF-eNYg/s200/1234618279_c2cfafb29d_m.jpg" alt="" id="BLOGGER_PHOTO_ID_5144718221513717122" border="0" /&gt;&lt;/a&gt;&lt;a href="http://paulbuchheit.blogspot.com/"&gt;Paul Buchheit&lt;/a&gt; posted an &lt;a href="http://paulbuchheit.blogspot.com/2007/12/theres-no-such-thing-as-social-network.html"&gt;interesting analysis&lt;/a&gt; of social networking products, their similarities and differences. In there he has hidden a rare gem:&lt;br /&gt;&lt;blockquote style="font-style: italic;"&gt;10. Jobs. Job hunting and hiring are essentially the "professional" analog of dating and seem to work in somewhat similar ways.&lt;/blockquote&gt;&lt;span style=";font-family:trebuchet ms;font-size:78%;"  &gt;&lt;a href="http://www.flickr.com/photos/25945304@N00/1234618279/"&gt;Shaking Hands&lt;/a&gt;, by Aidan Jones&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If you  ponder it a bit, it sounds about right, doesn't it? People look for jobs they like and hiring managers look for candidates they like. When there is a match, there is a hire. The parallels are many:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Dumping/seduction: an employee will dump his current job for a better one, often due to seducing promises from their hiring manager. &lt;/li&gt;&lt;li&gt;Bachelorhood/marriage: some people change jobs like crazy (especially in the States), while others stick to one for life (quite common in Japan).&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Stagnation: employment relationships, like sexual ones, tend to stagnate after a long period of time, when people lose interest in it.&lt;/li&gt;&lt;li&gt;We might as well admit it, women and work are the two dominant discussion subjects with one's friends, after midnight.&lt;/li&gt;&lt;li&gt;When one gets caught cheating on his wife/company, they go to court.&lt;/li&gt;&lt;li&gt;Girls have breasts, jobs have salaries. The bigger, the better.&lt;/li&gt;&lt;li&gt;People get jealous of their friends who make more money than they do.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;Now, what does that mean for us? Are you happy with your current girlfr..., er, job? If not, could you perhaps find some new project / technology / tool / sexual position to stimulate your interest? Or is it perhaps time to be on the market again?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/486398466531826618-3287588659022856234?l=blog.astithas.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/PastMidnight/~4/2KgBI1IzfWU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.astithas.com/feeds/3287588659022856234/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=486398466531826618&amp;postID=3287588659022856234" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/3287588659022856234?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/486398466531826618/posts/default/3287588659022856234?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/PastMidnight/~3/2KgBI1IzfWU/job-hunting-is-like-dating.html" title="Job hunting is like dating" /><author><name>Panagiotis Astithas</name><uri>https://profiles.google.com/116466326438420686438</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-ieNj_PE2fxE/AAAAAAAAAAI/AAAAAAAAAAA/l78jhJX3laA/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://bp2.blogger.com/_zFF22LLF49M/R2W19u7N9YI/AAAAAAAAAGE/SQ_XcF-eNYg/s72-c/1234618279_c2cfafb29d_m.jpg" height="72" width="72" /><thr:total>2</thr:total><feedburner:origLink>http://blog.astithas.com/2007/12/job-hunting-is-like-dating.html</feedburner:origLink></entry></feed>

