<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Gustavo&#039;s Blog</title>
	<atom:link href="http://www.grlira.com/?feed=rss2" rel="self" type="application/rss+xml" />
	<link>http://www.grlira.com</link>
	<description>May contain nerdiness</description>
	<lastBuildDate>Tue, 09 Apr 2013 07:59:31 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<item>
		<title>Game of Thrones: Season 3 episode 2</title>
		<link>http://www.grlira.com/?p=139&#038;utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=game-of-thrones-season-3-episode-2</link>
		<comments>http://www.grlira.com/?p=139#comments</comments>
		<pubDate>Tue, 09 Apr 2013 07:59:31 +0000</pubDate>
		<dc:creator>grlira</dc:creator>
				<category><![CDATA[Television]]></category>
		<category><![CDATA[a song of ice and fire]]></category>
		<category><![CDATA[Arya]]></category>
		<category><![CDATA[Clegane]]></category>
		<category><![CDATA[episode 2]]></category>
		<category><![CDATA[Game of Thrones]]></category>
		<category><![CDATA[HBO]]></category>
		<category><![CDATA[king's landing]]></category>
		<category><![CDATA[Lannister]]></category>
		<category><![CDATA[Margaery]]></category>
		<category><![CDATA[north]]></category>
		<category><![CDATA[review]]></category>
		<category><![CDATA[riverlands]]></category>
		<category><![CDATA[season 3]]></category>
		<category><![CDATA[Stark]]></category>
		<category><![CDATA[Tyrell]]></category>

		<guid isPermaLink="false">http://www.grlira.com/?p=139</guid>
		<description><![CDATA[SPOILER ALERT: Don&#8217;t read if you&#8217;re not caught up with the TV series AND the books. So I watched the new GoT episode last night, and boy was it awesome. While the first episode of the season was more of a recap, and used to get everything back into gear, this one really got into [...]]]></description>
				<content:encoded><![CDATA[<p><strong>SPOILER ALERT:</strong> Don&#8217;t read if you&#8217;re not caught up with the TV series AND the books.</p>
<p>So I watched the new GoT episode last night, and boy was it awesome. While the first episode of the season was more of a recap, and used to get everything back into gear, this one really got into the pace of things. We didn&#8217;t get to see much of what&#8217;s going on north of the wall, but what we did see established why the wildlings are all united under Mance Rayder, and really gave a sense of how scared they are of the White Walkers. In the North, we finally got to meet Ramsay Snow (god I hate that bastard). Looks like Theon is in for a fun season. I really like it that they decided to move the story of all the things that happen to him to season 3, instead of having him remember later. Hopefully we&#8217;ll get to see him transforming slowly (and painfully). I&#8217;m also really glad that they <strong>finally</strong> introduced Jojen and Meera Reed, although they did come a bit out of the blue. Had they been here last season this would have made a bit more sense, but oh well&#8230; To be honest, the Bran story line has always been the one that interests me the least (to the point of skipping some of his chapters and going back to read them later), but Jojen and Meera are the ones that have kept it somewhat interesting, so it&#8217;s really good they&#8217;re here now.</p>
<p>In the riverlands, we continue with the bastardization of Robb&#8217;s story line. The main gist of it is the same: he&#8217;s a good person and a piss poor decision maker, but the beauty of the books is in the details, and those have been somewhat lost. At least they finally found a way to leave Bolton at Harrenhal. I&#8217;m a bit disappointed that we don&#8217;t get to see Catelyn by her father&#8217;s side as he dies. That would have made for some really good character development. In lieu of that, they did that piece about Jon Snow getting pox which, in all honesty, sent shivers down my spine. All things considered, a very good scene, but unfortunately deviating from the books a little bit (at least as far as I remember). At the same time, we finally meet Thoros of Myr. I really like they way he looks on TV. Looking forward for his interaction with Clegane. And speaking of the Hound, really looking forward to see where his storyline with Arya goes.</p>
<p>But the real meat of the episode, at least for me, came from the scenes at King&#8217;s Landing. At last house Tyrell shows its colours (at least to the viewers). We already knew that Margaery wants to be <strong>the</strong> queen, but now we finally meet the Queen of Thorns and find out Margaery has the full strength of house Tyrell behind her. That scene where both of the Tyrell ladies press Sansa into spilling the beans was incredibly powerful. Particularly the rolling of the eyes Margaery does as she learns Joff is &#8220;a monster&#8221;. Instead of being scared, she assumes a &#8220;I&#8217;ll have to deal with that&#8221; attitude, and then puts that into action the next time we see her. Not only does she manage to diffuse Joffrey&#8217;s mood, but also plays the slightly clueless dame who doesn&#8217;t know much about politics (lies! damned lies!), and then approaches His Grace both physically and psychologically. By the end, Joff is convinced she&#8217;d like to shoot that crossbow into someone as much as he would. That final image in the mirror is almost frightening. At that point, Margaery is in control, Joff is totally lost in is (blood) lust, and they both look like evil itself. It remains to be seen if Margaery really is playing a part or if that was her shedding a bit of the shell she&#8217;s always wearing (ironic on account that she doesn&#8217;t wear much else, like Cersei so accurately pointed out).</p>
<p>The only thing I missed was a bit of Daenerys. I really want to see her story move forward. Looks like next week we&#8217;ll finally see her getting her Unsullied, which should be the turning point for things in Essos. Still, overall a really good episode with lots of new characters and very interesting story development. This show keeps on doing something really impressive: makes me want to see the next episode right after the one I just saw, despite the fact that I already know how the story.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.grlira.com/?feed=rss2&#038;p=139</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>I found something I wrote an year ago&#8230;</title>
		<link>http://www.grlira.com/?p=136&#038;utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=i-found-something-i-wrote-an-year-ago</link>
		<comments>http://www.grlira.com/?p=136#comments</comments>
		<pubDate>Fri, 29 Mar 2013 22:14:21 +0000</pubDate>
		<dc:creator>grlira</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.grlira.com/?p=136</guid>
		<description><![CDATA[&#8230;and I was extremely annoyed at myself. It was maybe one of the most pretentious things I&#8217;ve ever written. Like a friend said, I was being a smart-ass. The disturbing thing is that this is not the first time that&#8217;s happened to me. It&#8217;s not uncommon for me to find something I&#8217;ve written, done or [...]]]></description>
				<content:encoded><![CDATA[<p>&#8230;and I was extremely annoyed at myself. It was maybe one of the most pretentious things I&#8217;ve ever written. Like a friend said, I was being a smart-ass. The disturbing thing is that this is not the first time that&#8217;s happened to me. It&#8217;s not uncommon for me to find something I&#8217;ve written, done or made and find it stupid (or, in the case of code, terrible and of irritatingly low quality).<br />
And the funny thing is that I will probably read this months or years from now and think the exact same thing. In a way, I guess that&#8217;s good. It does reflect a certain will for self-improvement.</p>
<p>In any case, I&#8217;m glad I read what I found. Thinking I was being an idiot at the time and not finding that sort of idiocy in myself now is a reason to celebrate. Besides, I can always do with some criticism, even my own.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.grlira.com/?feed=rss2&#038;p=136</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Stop! Blocking network time!</title>
		<link>http://www.grlira.com/?p=132&#038;utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=stop-blocking-network-time</link>
		<comments>http://www.grlira.com/?p=132#comments</comments>
		<pubDate>Thu, 28 Mar 2013 03:49:55 +0000</pubDate>
		<dc:creator>grlira</dc:creator>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[block]]></category>
		<category><![CDATA[DatagramPacket]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[getData]]></category>
		<category><![CDATA[hang]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[object oriented]]></category>
		<category><![CDATA[scala]]></category>
		<category><![CDATA[unresponsive]]></category>

		<guid isPermaLink="false">http://www.grlira.com/?p=132</guid>
		<description><![CDATA[While working for that distributed systems course I mentioned a couple of posts ago, I came across a problem which stumped me for a long while. I&#8217;ll admit to my dumbness here in the interest of other people who, hopefully, will find this post before they want to head desk in frustration as I wanted [...]]]></description>
				<content:encoded><![CDATA[<p>While working for that distributed systems course I mentioned a couple of posts ago, I came across a problem which stumped me for a long while. I&#8217;ll admit to my dumbness here in the interest of other people who, hopefully, will find this post before they want to head desk in frustration as I wanted to.</p>
<p>Like I said, I&#8217;m using Scala for this course. This was the offending code:</p>
<pre class="brush: scala; title: ; notranslate">
class ControlListener extends Runnable {
    def run {
        val socket = DBS.sockets(&quot;control&quot;)_1 //acquire socket from central singleton
        var packet = new DatagramPacket(new Array[Byte](1024), 1024)
        while (true) {
            socket receive packet
            spawn {
                process(packet)
            }
        }
    }
    
    def process(packet: DatagramPacket) { 
        val message = packet getData
        //more stuff
    }
}
</pre>
<p>What I&#8217;m trying to do here is pretty simple. I have a class which repeatedly tries to read from an UDP socket, and pass the packet which has been read into an handling function (<code>process</code>). I want to do the handling asynchronously, so I call the <code>process</code> function within a <code>spawn</code> block, which is more or less the equivalent of doing this in Java:</p>
<pre class="brush: java; title: ; notranslate">
new Thread() {
    public void run() {
        //call process
    }
}.start()
</pre>
<p>In Java you actually have to call process differently, and <code>spawn</code> does more than this, but the idea is what I&#8217;ve shown.</p>
<p>Now, this seems like it should work, but the code was inexplicably blocking on the <code>val message = packet getData</code> line. Further more, it would continue execution when a new packet came in. Cue a lot of head scratching.</p>
<p>Here&#8217;s the problem: when <code>spawn</code> is invoked, it starts a new thread which will indeed run <code>process</code>, however, it also goes back to the top of the loop. What happens there? <code>receive</code> gets called again, and it locks access to the packet. Although this makes sense (you don&#8217;t want to read from a packet while it&#8217;s being written to, and vice versa), <strong>I could not find any documentation about this</strong>. Now, because this is Scala/Java, things are passed by reference. Thus, the packet within <code>process</code> is the same packet into which the socket is reading. Because access to the packet is locked, <code>process</code> blocks until <code>receive</code> returns, which happens when the next packet comes in.</p>
<p>The fix is obviously very simple: get the data you need from the packet before you spawn the new thread and go back to the top of the loop. Despite this, it took me a whole day to debug this. Here&#8217;s the corrected code:</p>
<pre class="brush: scala; title: ; notranslate">
class ControlListener extends Runnable {
    def run {
        val socket = DBS.sockets(&quot;control&quot;)_1 //acquire socket from central singleton
        var packet = new DatagramPacket(new Array[Byte](1024), 1024)
        while (true) {
            socket receive packet
            val message = new String(packet getData, 0, packet getLength)
            val address = packet.getAddress.getHostAddress
            spawn {
                process(message, address)
            }
        }
    }

    def process(message: String, address: String) {
        val fields = message.trim.split(&quot; &quot;)
        //more stuff here
    }

}
</pre>
<p>It actually hurts to look at how simple this is now.</p>
<p>If you want to try this on your own, here&#8217;s a handy Java class demonstrating the effect:</p>
<pre class="brush: java; title: ; notranslate">
import java.net.DatagramSocket;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.io.IOException;
import java.lang.Thread;

class SocketTest {
	public void test() {
		
	}
    public static void main(String[] args) throws IOException {
        DatagramSocket ds = new DatagramSocket(50000, InetAddress.getByName(&quot;localhost&quot;));
        final DatagramPacket dp = new DatagramPacket(new byte[1024], 1024); //packet used to read

        //thread used to try to access the packet's data
        new Thread() {
            public void run() {
            	//give the rest of the code enough time to do stuff
                try { sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }
                
                System.out.println(&quot;Will try to call getData on dp&quot;);
                dp.getData(); //should block
                System.out.println(&quot;getData ran&quot;);
            }
        }.start();

        //thread used to send a packet to the reading socket so that it returns
        new Thread() {
            public void run() {
            	//give everything else time to run and then leave them wating
                try { sleep(5000); } catch (InterruptedException e1) { e1.printStackTrace(); }

                //used to send something to ourselves
                DatagramSocket dsout = null;
				try { dsout = new DatagramSocket(50000); } catch (SocketException e) { e.printStackTrace(); }
                
				//used to carry some data for us
				DatagramPacket dpout = null;
				try {
					dpout = new DatagramPacket(new byte[1024], 1024, InetAddress.getByName(&quot;localhost&quot;), 50000);
				} catch (UnknownHostException e) { e.printStackTrace(); } 
                try { dsout.send(dpout); } catch (IOException e) { e.printStackTrace(); }
            }
        }.start();

        ds.receive(dp); //will block until the second thread runs
    }
}
</pre>
<p>If you run it, you should see &#8220;Will try to call getData on dp&#8221; come up after about a second, and then &#8220;getData ran&#8221; after another four seconds (the time left in the second thread, which forces receive to return).<br />
If you do not get these results, please let me know!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.grlira.com/?feed=rss2&#038;p=132</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>I get silent when I get busy</title>
		<link>http://www.grlira.com/?p=127&#038;utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=i-get-silent-when-i-get-busy</link>
		<comments>http://www.grlira.com/?p=127#comments</comments>
		<pubDate>Mon, 25 Mar 2013 02:06:46 +0000</pubDate>
		<dc:creator>grlira</dc:creator>
				<category><![CDATA[internet]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[dovecot]]></category>
		<category><![CDATA[email]]></category>
		<category><![CDATA[LAMP]]></category>
		<category><![CDATA[linode]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[nginx]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[phpmyadmin]]></category>
		<category><![CDATA[postfix]]></category>
		<category><![CDATA[postfixadmin]]></category>
		<category><![CDATA[roundcube]]></category>
		<category><![CDATA[server]]></category>
		<category><![CDATA[VPS]]></category>
		<category><![CDATA[webmail]]></category>

		<guid isPermaLink="false">http://www.grlira.com/?p=127</guid>
		<description><![CDATA[You may have noticed that I disappeared after that rant concerning web hosts. Well, that&#8217;s been, in part, because I decided to get a VPS with linode, and spent the better part of the weekend configuring it (the rest of the time was spent partying and actually working for uni, rather than blogging). The first [...]]]></description>
				<content:encoded><![CDATA[<p>You may have noticed that I disappeared after that rant concerning web hosts. Well, that&#8217;s been, in part, because I decided to get a VPS with linode, and spent the better part of the weekend configuring it (the rest of the time was spent partying and actually working for uni, rather than blogging). The first few steps were pretty easy: get in, get my public keys in, create an everyday user and lock down ssh. Then came installing logwatch and then apache, php, mysql and all of that. Up to this point, everything went really smooth, mostly because I&#8217;ve done these steps a couple of times now on different machines.</p>
<p>After that, things got a bit less familiar. I finally had to learn how to properly configure apache. By that I do not mean that it&#8217;s configured as it should right now, as I&#8217;ve still got some work to do on it, but I finally learned how to do virtual hosts and all of that. Fun stuff. Then I decided to install something I haven&#8217;t had before: phpmyadmin. I really like to use mysql on the command line (and actually did for the rest of the install process), but I figured that it can&#8217;t hurt, and it&#8217;s pretty handy at times.</p>
<p>And then, I had the brilliant idea of setting up my own mail server, which took me till about 15 minutes ago to get done. Let&#8217;s put this way: I am not the smartest guy on the planet, but I&#8217;ve installed a good amount of software and configured a couple of different servers, and this was stupidly hard to get done. My final setup is postfix+postfixadmin+dovecot+roundcube, all of them storing information in a couple of mysql databases. I&#8217;m not going to get into the nitty gritty, but overall let&#8217;s say postfixadmin was very easy, and roundcube wasn&#8217;t hard. The real problem was with postfix and dovecot. They&#8217;re both VERY sensitive to the configurations, and while getting one to work wasn&#8217;t a total nightmare, getting them talking was painful. Alas, I did get all of it working, and just sent an email from the VPS to my gamil account and it worked!</p>
<p>The next step is to get the memory usage down. Right now I&#8217;m all out of the 512Mb ram I get, and I still need to get gitosis up and running. This means I might have to change from nginx to apache. That&#8217;ll be another fun little adventure, I bet&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.grlira.com/?feed=rss2&#038;p=127</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Web hosting troubles, or why this blog won&#8217;t be on Surpass Hosting anymore.</title>
		<link>http://www.grlira.com/?p=121&#038;utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=web-hosting-troubles-or-why-this-blog-wont-be-on-surpass-hosting-anymore</link>
		<comments>http://www.grlira.com/?p=121#comments</comments>
		<pubDate>Thu, 21 Mar 2013 17:05:53 +0000</pubDate>
		<dc:creator>grlira</dc:creator>
				<category><![CDATA[internet]]></category>
		<category><![CDATA[rant]]></category>
		<category><![CDATA[bad]]></category>
		<category><![CDATA[customer]]></category>
		<category><![CDATA[hosting]]></category>
		<category><![CDATA[server]]></category>
		<category><![CDATA[shared]]></category>
		<category><![CDATA[support]]></category>
		<category><![CDATA[surpass]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://www.grlira.com/?p=121</guid>
		<description><![CDATA[One of the web hosts I use is surpass hosting. We (my father and I) originally got with these guys because they offered an year for free (never a good sign, I know. But it was free hosting!). After that year was up, both mine and my father&#8217;s website and personal e-mail were running on [...]]]></description>
				<content:encoded><![CDATA[<p>One of the web hosts I use is surpass hosting. We (my father and I) originally got with these guys because they offered an year for free (never a good sign, I know. But it was free hosting!). After that year was up, both mine and my father&#8217;s website and personal e-mail were running on the surpass server, so we just decided to keep it.</p>
<p>Now, surpass hasn&#8217;t been particularly amazing over the last couple of years. Their cPanel installation has a couple of bugs, their ssh access is kind of weird, the support is lack luster at best, and often down right useless. We&#8217;ve lived with it though, on account that it&#8217;s pretty cheap, and most times the thing actually runs and serves web pages.</p>
<p>These last few days have changed everything. The story begins with an e-mail from a couple of weeks ago warning about a server migration starting on the night of the 19th to the 20th of March. At the time, they told us we should expect about 12-14 hours of downtime (that alone for a server migration is &#8220;wtf&#8221; worthy, but ok). We just ground our teeth, sighed, and accepted that for about half a day there&#8217;d be no server. As predicted, my blog disappeared on the 20th at midnight (GMT, 8pm EDT). At the time I didn&#8217;t even associate that to the migration (I&#8217;d forgotten, in all honesty), but chalked it up to some DNS hickup or something, and on account that I was going to bed, I just let it be.</p>
<p>The next morning I had classes, so I was off the internet for a while. In the afternoon, though, my father told me there were some errors going on. I tried to access the server and everything was either down, or miss configured and throwing errors everywhere. Now getting an HTTP 500 error when trying to access your website&#8217;s homepage will scare you, specially if you haven&#8217;t been messing with .htaccess and know for a fact that there was no error in configuration last night. Trying to FTP in to see what&#8217;s going on and getting your connection denied will sound the rest of the alarms.</p>
<p>Long story short, we contacted support and the answer we got back was along the lines of &#8220;Try flushing your DNS cache, that might be the problem&#8221;. Now, I know that <em>I</em> thought it could be a DNS hickup the previous night, but at the time I didn&#8217;t remember that the server was being migrated. The support staff, on the other hand, had to be aware of that. And yet they replied with the standard &#8220;flush your DNS&#8221; response. No comments.</p>
<p>Skipping forward about a dozen messages back and forth with support, it&#8217;s now the 21st of March. It&#8217;s been 30 hours since the thing died. It&#8217;s mostly back up, but we&#8217;re still getting errors sometimes. Trying to access my web mail threw a HTTP 500 in my face, and I had to use an alternate access. Even after I got in, Round cube is throwing up a message about not being configured, so I&#8217;m forced to use horde. Uploading things trough FTP is also still raising some issues every now and then.</p>
<p>To add insult to injury, I decided to look around for reviews of surpass, just to see if anyone else has felt like I do right now. This lovely thing came up: <a href="http://hostjury.com/blog/view/55/surpass-hosting-employees-post-fake-reviews" target="_blank">http://hostjury.com/blog/view/55/surpass-hosting-employees-post-fake-reviews</a>. Just&#8230;wow!</p>
<p>Because of all of this I&#8217;m now looking for new solutions to host my website(s). One of the options I&#8217;m considering is Linode. Has anyone used it? Is it any good?</p>
<p>&lt;/rant&gt;</p>
<p>PS: I realize it&#8217;s ironic that the fact you can read this is proof that the server is up right now, as this blog is still hosted on surpass for now.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.grlira.com/?feed=rss2&#038;p=121</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Live chat with PHP and jQuery</title>
		<link>http://www.grlira.com/?p=111&#038;utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=live-chat-with-php-and-jquery</link>
		<comments>http://www.grlira.com/?p=111#comments</comments>
		<pubDate>Tue, 19 Mar 2013 22:09:54 +0000</pubDate>
		<dc:creator>grlira</dc:creator>
				<category><![CDATA[internet]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[chat]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[experiment]]></category>
		<category><![CDATA[facebook chat]]></category>
		<category><![CDATA[fast]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[live chat]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[prototype]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[web app]]></category>

		<guid isPermaLink="false">http://www.grlira.com/?p=111</guid>
		<description><![CDATA[This afternoon a friend of mine asked me about live chats in a browser-based environment (à la facebook), and if it would be hard to implement. Well, obviously something like facebook&#8217;s system is terribly complex and probably has a ton of lines of code behind the scenes to ensure it runs smoothly, but I figured [...]]]></description>
				<content:encoded><![CDATA[<p>This afternoon a friend of mine asked me about live chats in a browser-based environment (<em>à la facebook</em>), and if it would be hard to implement. Well, obviously something like facebook&#8217;s system is terribly complex and probably has a ton of lines of code behind the scenes to ensure it runs smoothly, but I figured a simple system couldn&#8217;t be too hard. So I gave my self a challenge: see what I could do in 2 hours of work, no more. I started at ten past six, and ended at ten past eight. The result was, all modesty aside, pretty cool for that short of a period.</p>
<p>Here&#8217;s what I came up with: the browser runs, with the help of jQuery, 3 ajax requests: one to connect, one to write messages and one to get messages. This last one is launched, waits for the server, and then is re-launched as soon as the server replies with something (this is known as long polling). On the other side, the server offers 3 matching services: connect, writeMessage and getMessage, via 3 PHP scripts.</p>
<p>Everything is tied together by a simple (literally a form to write stuff and a div where messages show up) html+css interface on the user&#8217;s side, and by a file to store the latest message on the server side.</p>
<p>So, without further ado, let&#8217;s get into some code. First up, the server side.</p>
<p>connect.php</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php
$chatId = 1; //for now
echo json_encode(array(&quot;chatId&quot; =&gt; $chatId));
?&gt;
</pre>
<p>Yes, that is ridiculous. This is only here because the idea is that we want a series of parallel chats, and the clients get to know which one they&#8217;ll end up in upon connecting. Obviously not implemented at this stage.</p>
<p>Moving along, the getMessage.php code:</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php

if(empty($_GET['chatId'])) {
	exit();
}

$filename = dirname(__FILE__).&quot;/../chats/&quot;.$_GET['chatId'].&quot;.txt&quot;;
$lastmodif = empty($_GET['timestamp']) ? 0 : $_GET['timestamp'];
$currentmodif = filemtime($filename);

while($currentmodif &lt;= $lastmodif) {
	usleep(10000);
	clearstatcache();
	$currentmodif = filemtime($filename);
}

$response = array();
$response['message'] = file_get_contents($filename);
$response['timestamp'] = $currentmodif;
echo json_encode($response);

?&gt;
</pre>
<p>Now it gets interesting. What the server is doing is taking a request with the time the client last read a message, then sitting in a loop waiting for the file containing the messages to be updated. Once it is, it sends the contents back to the client. This is obviously not very efficient on the server side, but that was not the point of this prototype.</p>
<p>Finally, here&#8217;s writeMessage.php</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php

if(empty($_POST['message']) || empty($_POST['chatId'])) {
	echo json_encode(array(&quot;status&quot; =&gt; &quot;ERROR: no data&quot;, &quot;data&quot; =&gt; print_r($_POST)));
	exit();
}

$filename = dirname(__FILE__).&quot;/../chats/&quot;.$_POST['chatId'].&quot;.txt&quot;;
file_put_contents($filename, $_POST['message']);

echo json_encode(array(&quot;status&quot; =&gt; &quot;OK&quot;));

?&gt;
</pre>
<p>All the writeMessage service does it receive some data and replace the contents of the chat file with that data. Yes, this does mean you can spam the server and effectively prevent anyone else from getting their messages saved long enough for people to read them. Again, not the point.</p>
<p>And that&#8217;s it for the server (aside from some configurations, such as <strong>turning magic quotes off</strong>)</p>
<p>On the client side, all we have is a chat.js Javascript file. I&#8217;ll break it up into functions to make it easier. Fair warning: this makes extensive use of jQuery. If you have any doubt about what one of the functions does, check out <a href="http://api.jquery.com/">http://api.jquery.com/</a>.</p>
<p>chat.js:connect</p>
<pre class="brush: jscript; title: ; notranslate">
function connect() {
    $.ajax({
        type : &quot;GET&quot;,
        url : &quot;services/connect.php&quot;,
        async : true,
        cache : false,

        success : function(data) {
            var contents = $.parseJSON(data);
            chatId = contents['chatId'];
            //setTimeout('waitForMsg()', 500); &lt;-- bad way of doing this
            setTimeout(waitForMsg, 500); //do this instead
        },

        error : function(XMLHttpRequest, textStatus, errorThrown) {
            console.log(&quot;Unable to connect: &quot; + textStatus + &quot;(&quot; + errorThrown + &quot;)&quot;);
        }
    });
}
</pre>
<p>So this is the pair to connect.php and all it does is get the chatId from the server and stick it into the correct variable. This is obviously meant to be expanded.</p>
<p>chat.js:waitForMsg</p>
<pre class="brush: jscript; title: ; notranslate">
function waitForMsg() {
    $.ajax({
        type : &quot;GET&quot;,
        url : &quot;services/getMessage.php?timestamp=&quot; + timestamp + &quot;&amp;chatId=&quot; + chatId,
        async : true,
        cache : false,

        success : function(data) {
            var contents = $.parseJSON(data);
            $(&quot;#messageBox&quot;).append(contents['message'] + &quot;&lt;br /&gt;&quot;);
            timestamp = contents['timestamp'];
            setTimeout(waitForMsg, 500);
        },

        error : function(XMLHttpRequest, textStatus, errorThrown) {
            console.log(&quot;Error reading: &quot; + textStatus + &quot;(&quot; + errorThrown + &quot;)&quot;);
            setTimeout(waitForMsg, 10000);
        }
    });
}

</pre>
<p>This is the function that handles asking the server for new messages. It does an ajax request which is then left hanging until the server replies, at which time the success function runs, and adds the message that&#8217;s been received to the DOM. The request includes the time stamp (which is then updated when the server replies), as well as the id of the current chat. At the end, the function is scheduled to run half a second later, so the polling process keeps on going.</p>
<p>chat.js:loadSendHandler</p>
<pre class="brush: jscript; title: ; notranslate">
function loadSendHandler() {
    $(&quot;#messageForm&quot;).submit(function() {

        $.ajax({
            type : &quot;POST&quot;,
            url : &quot;services/writeMessage.php&quot;,
            data : {
                &quot;chatId&quot; : chatId,
                &quot;message&quot; : &quot;&lt;b&gt;&quot; + $(&quot;#messageName&quot;).val() + &quot;:&lt;/b&gt; &quot; + $(&quot;#messageInput&quot;).val()
            },
            async : true,
            cache : false,

            success : function(data) {
                var contents = $.parseJSON(data);
                if (contents['status'] === &quot;OK&quot;) {
                    console.log(&quot;server said OK&quot;);
                } else {
                    console.log(&quot;server error'd: &quot; + contents);
                }
                $(&quot;#messageInput&quot;).val(&quot;&quot;);
            },
            error : function(XMLHttpRequest, textStatus, errorThrown) {
                console.log(&quot;Error writing: &quot; + textStatus + &quot;(&quot; + errorThrown + &quot;)&quot;);
            }
        });
        return false;
    });
}
</pre>
<p>This function loads an handler for the submit event on the form used to type in messages. All it does is send the data typed in, along with the name chosen by the user, to the writeMessage service on the server side.</p>
<p>And finally, here&#8217;s what runs when the DOM is done loading (and a couple of global variables declarations for good measure).</p>
<p>chat.js</p>
<pre class="brush: jscript; title: ; notranslate">
var timestamp = null;
var chatId = null;

$(document).ready(function() {
    connect();
    loadSendHandler();
});
</pre>
<p>Like said in the beggining, this is all tied together by a little html and a little css.<br />
index.html</p>
<pre class="brush: xml; title: ; notranslate">
&lt;!DOCTYPE html&gt;
&lt;html&gt;
    &lt;head&gt;
        &lt;title&gt;Livechat&lt;/title&gt;
        &lt;meta charset=&quot;UTF-8&quot;&gt;
        &lt;link rel=&quot;stylesheet&quot; href=&quot;style.css&quot;&gt;
        &lt;script src=&quot;//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js&quot;&gt;&lt;/script&gt;
        &lt;script src=&quot;scripts/chat.js&quot;&gt;&lt;/script&gt;
    &lt;/head&gt;
    &lt;body&gt;
        &lt;div id=&quot;wrapper&quot;&gt;
            &lt;div id=&quot;messageBox&quot;&gt;
                Messages will show up here
                &lt;br /&gt;
            &lt;/div&gt;
            &lt;div id=&quot;formBox&quot;&gt;
                &lt;form id=&quot;messageForm&quot;&gt;
                    &lt;input type=&quot;text&quot; name=&quot;name&quot; placeholder=&quot;Type your name here&quot; id=&quot;messageName&quot; /&gt;
                    &lt;br /&gt;
                    &lt;input type=&quot;text&quot; name=&quot;message&quot; placeholder=&quot;Type your message here&quot; id=&quot;messageInput&quot; /&gt;
                    &lt;br /&gt;
                    &lt;input type=&quot;submit&quot; name=&quot;Send&quot; value=&quot;Send&quot; /&gt;
                &lt;/form&gt;
            &lt;/div&gt;
        &lt;/div&gt;
    &lt;/body&gt;
&lt;/html&gt;
</pre>
<p>style.css</p>
<pre class="brush: css; title: ; notranslate">
#wrapper {
    width: 800px;
    margin: auto;
}

#messageBox {
    margin: 5px;
    min-width: 500px;
	border: 1px solid black;
	float: left;
}

#formBox {
    margin: 5px;
    width: auto;
	border: 1px solid black;
	float: right;
}
</pre>
<p>Just a little css so we get a fluid centered page. To be honest I hardly put any effort into this, on account that I was very near my two hour limit.</p>
<p>This little experiment was educational in two ways. Number one, I learned some new client <-> server with jQuery <-> PHP tricks. Number two, and most important, I learned this kind of thing is really easy to prototype fast. I might grab some more quick little projects like this in the future.</p>
<p>Finally, let me face the elephant in the room. The code above is obviously riddled with security holes. To be honest, I think it&#8217;s more like the whole thing is one giant security nightmare. But keep in mind that this was a prototype. An experiment. One of the things I want to do now is fix all of the problems I can find, and see how long it takes and how much bigger the code gets. Please, <strong>do not</strong>, I repeat <strong>DO NOT</strong> use this code. It kind of made me nervous to have it up just to test it, so yeah&#8230; </p>
]]></content:encoded>
			<wfw:commentRss>http://www.grlira.com/?feed=rss2&#038;p=111</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Private sector, public inefficiency</title>
		<link>http://www.grlira.com/?p=104&#038;utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=private-sector-public-inefficiency</link>
		<comments>http://www.grlira.com/?p=104#comments</comments>
		<pubDate>Mon, 18 Mar 2013 16:22:44 +0000</pubDate>
		<dc:creator>grlira</dc:creator>
				<category><![CDATA[rant]]></category>
		<category><![CDATA[acp]]></category>
		<category><![CDATA[driver's license]]></category>
		<category><![CDATA[personal]]></category>
		<category><![CDATA[portugal]]></category>

		<guid isPermaLink="false">http://www.grlira.com/?p=104</guid>
		<description><![CDATA[I recently moved, and as a consequence have had to change my address in a whole bunch of documents, one of them being my driver&#8217;s license. On account that my parents also had to take care of this, we all went to the office of the Automobile Club of Portugal (ignore the crappy translation), of [...]]]></description>
				<content:encoded><![CDATA[<p>I recently moved, and as a consequence have had to change my address in a whole bunch of documents, one of them being my driver&#8217;s license. On account that my parents also had to take care of this, we all went to the office of the Automobile Club of Portugal (ignore the crappy translation), of which my father is a (paying) member.</p>
<p>We were counting on the Club&#8217;s long-standing policy of offering their services to the direct family of a member, as if they were members themselves. Well, as it turns out that&#8217;s no longer the case, and they wanted to charge me and my mother one year&#8217;s membership to take care of the matter, on top of their service fee and the service fee the state charges. On the other hand, if we use the public service, all we have to pay is said state fee. On top of that, the process is simpler with the public service than it would be with the Club, with less documents going back and forward and whatnot.</p>
<p>So it seems that a private entity is both charging more and being more of a PITA than the state. This in a country where public services are famously bad. What the heck?!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.grlira.com/?feed=rss2&#038;p=104</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>On posting personal stuff</title>
		<link>http://www.grlira.com/?p=98&#038;utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=on-posting-personal-stuff</link>
		<comments>http://www.grlira.com/?p=98#comments</comments>
		<pubDate>Sun, 17 Mar 2013 02:17:20 +0000</pubDate>
		<dc:creator>grlira</dc:creator>
				<category><![CDATA[meta]]></category>
		<category><![CDATA[blog]]></category>
		<category><![CDATA[blogs]]></category>
		<category><![CDATA[personal]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://www.grlira.com/?p=98</guid>
		<description><![CDATA[So I went to bed (I promise this has nothing to do with the post title), and I was lying there thinking about posting something which is personal. Specifically, I was thinking about how many people would get what I would be talking about (the answer is a couple of close friends) and if it [...]]]></description>
				<content:encoded><![CDATA[<p>So I went to bed (I promise this has nothing to do with the post title), and I was lying there thinking about posting something which is personal. Specifically, I was thinking about how many people would get what I would be talking about (the answer is a couple of close friends) and if it would affect anyone. And then it hit me: the fact that I even had to consider that meant that I should not post it at all.</p>
<p>People tend to say blogs are like an on-line diary. They are, as long as you publish said diary in the newspaper (which, by the way, goes against the definition of diary). The truth is, blogs are a different type of writing medium. I don&#8217;t pretend to know much (anything, really) about blogging. I&#8217;ve only dabbled in it occasionally and for short periods. And yet, I think I can conclude this: if there&#8217;s even one person you&#8217;d rather not read it, don&#8217;t publish it.</p>
<p>Back to bed.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.grlira.com/?feed=rss2&#038;p=98</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>RMI on Scala</title>
		<link>http://www.grlira.com/?p=72&#038;utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=rmi-on-scala</link>
		<comments>http://www.grlira.com/?p=72#comments</comments>
		<pubDate>Fri, 15 Mar 2013 19:59:58 +0000</pubDate>
		<dc:creator>grlira</dc:creator>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[ClassNotFoundException]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[Remote]]></category>
		<category><![CDATA[RemoteException]]></category>
		<category><![CDATA[rmi]]></category>
		<category><![CDATA[scala]]></category>

		<guid isPermaLink="false">http://www.grlira.com/?p=72</guid>
		<description><![CDATA[So I&#8217;ve been getting into Scala lately, by using it for my Distributed Systems course (we&#8217;re allowed to use whichever language we want, which is very cool). The exercise in class today was to implement this basic Client/Server system we&#8217;d implemented with UDP and TCP sockets before, but using Java&#8217;s RMI. Scala being Scala has [...]]]></description>
				<content:encoded><![CDATA[<p>So I&#8217;ve been getting into <a href="http://www.scala-lang.org/">Scala</a> lately, by using it for my Distributed Systems course (we&#8217;re allowed to use whichever language we want, which is very cool). The exercise in class today was to implement this basic Client/Server system we&#8217;d implemented with UDP and TCP sockets before, but using Java&#8217;s RMI.</p>
<p>Scala being Scala has access to all of Java&#8217;s standard API. However, getting RMI to work is actually not straight forward, so here goes a  short guide, on account that I couldn&#8217;t find a condensed source of information anywhere. We&#8217;ll implement a simple echo service in 4 steps</p>
<p>1) RMI requires you to create an interface extending the <a href="http://docs.oracle.com/javase/7/docs/api/java/rmi/Remote.html">java.rmi.Remote</a> interface. This will be the general contract of your system, which both the client and the server must be aware of. In Scala, you can do something similar to interfaces using traits (traits are actually more powerful, but for the purposes of this post let&#8217;s assume they&#8217;re the same). Here&#8217;s what a trait might look like</p>
<pre class="brush: scala; title: ; notranslate">
import java.rmi.Remote
import java.rmi.RemoteException

trait Echoer extends Remote {
    @throws(classOf[RemoteException])
    def echo(input: String): String
}
</pre>
<p>The <code>@throws(classOf[RemoteException])</code> annotation is necessary because all of the methods of an interface used for RMI must be capable of throwing a <a href="http://docs.oracle.com/javase/7/docs/api/java/rmi/RemoteException.html">java.rmi.RemoteException</a>. In java you would state this by adding <code>throws RemoteException</code> after the method declaration. The annotation is Scala&#8217;s way of doing the same.</p>
<p>2) With the trait created, you now need to create a class which implements it. It has to extend the trait, implementing the method(s) we&#8217;ve declared there. It also has to start the service and bind it to the rmi registry. Enough talk, here&#8217;s some code:</p>
<pre class="brush: scala; title: ; notranslate">
import java.rmi.server.UnicastRemoteObject
import java.rmi.registry.Registry
import java.rmi.registry.LocateRegistry

class Server extends Echoer {
    def echo(input: String): String = {
        return input //just return what we got
    }
}

object Server {
    def main(args: Array[String]): Unit = {

        try {
            val server : Echoer = new Server
            val stub =UnicastRemoteObject.exportObject(server,0).asInstanceOf[Echoer]
            val registry = LocateRegistry.getRegistry()
            //the bit between quotes can be anything
            registry.rebind(&quot;echoservice&quot;, stub)

            println(&quot;Server ready&quot;)
        }
        catch {
            case e: Exception =&gt; e printStackTrace
        }

    }
}
</pre>
<p>We&#8217;re taking advantage of Scala&#8217;s class <-> companion object duality here. Note that these have to be defined in the same file. In case you&#8217;re not familiar with Scala&#8217;s companion objects, there&#8217;s a good explanation of what they are <a href="http://daily-scala.blogspot.pt/2009/09/companion-object.html">here</a>.</p>
<p>The class itself simply implements the method. If this were a real application it&#8217;d be much larger, of course. The object, on the other hand, is doing a lot of stuff. The server&#8217;s main method is embedded here. This is where we get the rmi registry, create an instance of our service, and then bind it to a service name. Once this is done, the application will run until we stop it.</p>
<p>3) The last bit of code needed is the client. We&#8217;ll implement a very simple client which sends a message to the server and prints out what it gets back. Before it can do that, however, it has to fetch the stub for the server from the rmi registry.</p>
<pre class="brush: scala; title: ; notranslate">
import java.rmi.registry.Registry
import java.rmi.registry.LocateRegistry

object Client {

    def main(args: Array[String]): Unit = {

        try {
            //replace localhost with the server's hostname or IP address
            val registry = LocateRegistry getRegistry(&quot;localhost&quot;) 
            
            //the name looked up has to match the
            //name the service is bound to in the server
            val stub = registry.lookup(&quot;echoservice&quot;).asInstanceOf[Echoer]
            
            println(&quot;Sending \&quot;Hello world!\&quot;&quot;)
            var response = stub echo(&quot;Hello world!&quot;)
            println(&quot;Got \&quot;&quot;+response+&quot;\&quot;&quot;)
        } catch {
            case e: Exception =&gt; e printStackTrace
        }
    }
}
</pre>
<p>As you can see, the client also has to know about the Echoer trait.</p>
<p>4) With everything coded up, you need to start the rmi registry. This is done by running <code>start rmiregistry</code> on windows (if it asks about allowing it trough the firewall, just say yes to everything) or <code>rmiregistry &#038;</code> on linux. If you&#8217;re told that rmiregistry doesn&#8217;t exist, make sure you have the path to the bin/ folder of your JRE/JDK installation added to your PATH.</p>
<p>5) Finally you can launch your application. If you&#8217;re using eclipse like I am, you&#8217;ll need to create a run configuration for the client and another one for the server. If you&#8217;re launching trough the command line, just run the proper scala command. Either way, you need to add this to your VM options, both for server and client:</p>
<p><code>-Djava.rmi.server.codebase=file:path/to/class/files/</code></p>
<p>The trailing slash is important! In eclipse&#8217;s particular case, the same argument would be something like:</p>
<p><code>-Djava.rmi.server.codebase=file:${workspace_loc}/ProjectNameHere/bin/</code></p>
<p>And voilà! RMI on Scala without writing a line of Java.</p>
<p>PS: My thanks to Pedro Cunha and Tiago Vila Verde for helping me getting this thing working.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.grlira.com/?feed=rss2&#038;p=72</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Bringing this back, and the indelibility of things on the internet</title>
		<link>http://www.grlira.com/?p=65&#038;utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=bringing-this-back-and-the-indelibility-of-things-on-the-internet</link>
		<comments>http://www.grlira.com/?p=65#comments</comments>
		<pubDate>Thu, 14 Mar 2013 08:23:27 +0000</pubDate>
		<dc:creator>grlira</dc:creator>
				<category><![CDATA[internet]]></category>
		<category><![CDATA[meta]]></category>

		<guid isPermaLink="false">http://www.grlira.com/?p=65</guid>
		<description><![CDATA[So it&#8217;s been a while. Again. This is a pretty common pattern with me, actually. I start a blog, I write on it for a bit, then I abandon it and end up coming back to it ages later. Anyway, I get to the university this morning, get an espresso, and sit outside with my [...]]]></description>
				<content:encoded><![CDATA[<p>So it&#8217;s been a while. Again. This is a pretty common pattern with me, actually. I start a blog, I write on it for a bit, then I abandon it and end up coming back to it ages later.</p>
<p>Anyway, I get to the university this morning, get an espresso, and sit outside with my laptop drinking it and reading e-mail and other assorted stuff (by assorted stuff I mean I opened Reddit and looked at titles that sparked my interest). As I&#8217;m doing this,  I find out that Google reader is closing. This doesn&#8217;t affect me in any way, except that people are going to be asking for an alternative RSS reader for a couple of weeks. I never really understood RSS, or the need to have your favourite websites&#8217; content delivered to you in a condensed, lossy way when you can just go to the website. But all that aside, that got me thinking about the repercussions of a product so many people use just closing down. To be honest, my first thought was &#8220;maybe people will stop using RSS now&#8221;. Which got me thinking about blogs, which led me to mine and wanting to reboot it.</p>
<p>Well, I got that done, but then&#8230;I thought about the concept of reboot, and how there are some posts here of which I am not particularly proud (mysql ids, I&#8217;m looking at you). I honestly considered just deleting everything and starting over. But here&#8217;s the thing: I simply can&#8217;t. Most of you know this, and I&#8217;m pretty much preaching to the choir, but some people need to learn a basic fact of life (hi, records&#8217; industry <em>et al</em>). You can&#8217;t remove anything from the internet. Period. If you &#8220;delete&#8221; your facebook, it&#8217;s still there. If you take some photos down, someone saved them and will eventually post them again. Etc, etc, etc. Once it&#8217;s on the internet, it&#8217;s there forever. Yes I can remove the data from my website, but there&#8217;s always, if nothing else, Google&#8217;s cache to keep it for you. Which brings us back to them. Google&#8217;s everywhere these days. Can you imagine if they were to just shut down? I think we might actually loose some data then&#8230;</p>
<p><strong>PS:</strong> on the topic of unique mysql ids, I have to address that one of these days. But for now, suffice it to say I was being an idiot. One word: transactions.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.grlira.com/?feed=rss2&#038;p=65</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
