<?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>@dtinth&#039;s Blog</title>
	<atom:link href="http://blog.dt.in.th/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.dt.in.th</link>
	<description>Personal Weblog of Thai Pangsakulyanont</description>
	<lastBuildDate>Wed, 30 Nov 2011 07:53:25 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1.3</generator>
		<item>
		<title>Random Post: Changing Theme</title>
		<link>http://blog.dt.in.th/2011/06/random-post-changing-theme/</link>
		<comments>http://blog.dt.in.th/2011/06/random-post-changing-theme/#comments</comments>
		<pubDate>Fri, 24 Jun 2011 17:35:42 +0000</pubDate>
		<dc:creator>the DtTvB</dc:creator>
				<category><![CDATA[Random Stuff]]></category>

		<guid isPermaLink="false">http://blog.dt.in.th/?p=575</guid>
		<description><![CDATA[So I installed another WordPress installation on another site and then suddenly I like their default theme, TwentyTen. It&#8217;s well made, has beautiful typography, and stuff, so I&#8217;m making a new theme based on it (see how easy!). It&#8217;s not &#8230; <a href="http://blog.dt.in.th/2011/06/random-post-changing-theme/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>So I installed another WordPress installation on another site and then suddenly I like their default theme, TwentyTen. It&#8217;s well made, has beautiful typography, and stuff, so I&#8217;m making a new theme based on it (<a href="http://blog.dt.in.th/wp-content/themes/dtinth/style.css">see how easy!</a>). It&#8217;s not quite finished yet (as of writing) so you may see some changes.</p>

<p>Actually I got nothing (better) to do today so I just post this random blog post. Actually, I blogged less in the past two months (well, I didn&#8217;t blog at all in the past two months!), because during that time, I felt more like coding than blogging (spent most of my time with <a href="https://github.com/dtinth/">stuff on GitHub</a> or <a href="https://code.google.com/p/sm-ssc/">StepMania 5</a>).</p>

<p>And also I feel like I should put up more random blog posts, like this one! ^^</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.dt.in.th/2011/06/random-post-changing-theme/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>A Simple GPS Tracker is Too Simple. My GPS Tracking Webapp.</title>
		<link>http://blog.dt.in.th/2011/04/gps/</link>
		<comments>http://blog.dt.in.th/2011/04/gps/#comments</comments>
		<pubDate>Fri, 08 Apr 2011 12:05:52 +0000</pubDate>
		<dc:creator>the DtTvB</dc:creator>
				<category><![CDATA[iPad]]></category>
		<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://blog.dt.in.th/?p=564</guid>
		<description><![CDATA[I was looking for a free GPS tracker to record trips from my school to my university on my iPad. One that does the simplest things that a GPS tracker can do: record the coordinates and let me get these &#8230; <a href="http://blog.dt.in.th/2011/04/gps/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I was looking for a free GPS tracker to record trips from my school to my university on my iPad.</p>

<p>One that does the simplest things that a GPS tracker can do: record the coordinates and let me get these data out to do stuff with it.</p>

<h2>I Haven&#8217;t Found Any Which Works for Me</h2>

<p>Many GPS trackers are not free (and has a lot of features I don&#8217;t really want), or relies heavily on their own server.</p>

<p>I prefer to have full control over my data. I would like to only send them when I want, and have full access to them.</p>

<h2>My Simplest GPS Tracking Webapp</h2>

<p>This is the simplest GPS tracking webapp that works for me.</p>

<p><strong>What it does:</strong> It logs your location and time in localStorage and submits them to any URL when you click &#8220;Submit&#8221;. That&#8217;s it.</p>

<p>Without much talking, let&#8217;s <a href="https://github.com/dtinth/gps/blob/gh-pages/index.html">see the code</a> (or <a href="http://dtinth.github.com/gps/">the live version</a>).</p>

<p>It has got no map display, speedometer, or whatever. It just logs your coordinates locally into the textarea and localStorage and submits to the URL specified at the top.</p>

<p>This app won&#8217;t communicate with the server (the URL specified at the top) unless you click the submit button.</p>

<h2>Usage (for GPS-equipped iDevices)</h2>

<ul>
<li>Turn off &#8220;Auto-Lock&#8221; in the Settings app (set it to Never). This app won&#8217;t track your location when your device is off or locked.</li>
<li>Open Safari and navigate to the web app&#8217;s URL.</li>
<li>Specify the server&#8217;s URL.</li>
<li>Tap the &#8220;Start Tracking&#8221; button.</li>
<li>When tracking, no connection to the Internet is needed.</li>
<li>Once finished, tap the &#8220;Submit&#8221; button to submit them to the server.</li>
</ul>

<h2>Receiving The Log</h2>

<p>My GPS tracker sends the log (contents of the textarea) to the URL specified at the top by using the <code>coords</code> POST variable.</p>

<p>Your script should be able to handle it easily. Here is the script that runs on my server:</p>

<pre><code>&lt;?php file_put_contents('/path/to/gps.log', $_POST['coords']);
</code></pre>

<h2>Parsing The Log Format</h2>

<p>There are 4 kinds of line. A comment line, a start line, a coordinate line, or the failing line.</p>

<p>A comment line starts with <code>--</code>. Your log parser should ignore these lines. For example:</p>

<pre><code>-- this is a comment
</code></pre>

<p>A start line indicates the time that the user pressed the &#8220;Start Tracking&#8221; button. The format is <code>[time] // start</code>. For example:</p>

<pre><code>1302263615830 // start
</code></pre>

<p>A coordinate line looks like <code>[time] // [lat] // [lng]</code>. A example of this line:</p>

<pre><code>1302263698765 // 13.797455945576084 // 100.61361547747381
</code></pre>

<p>Finally, a failure line indicates that the tracker wasn&#8217;t able to track the position at a specified time. For example,</p>

<pre><code>1302263678901 // fail
</code></pre>

<h2>Have Fun With Your Data</h2>

<p>Use it with Google Maps API or whatever. Have fun!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.dt.in.th/2011/04/gps/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>I Put Stuff On GitHub</title>
		<link>http://blog.dt.in.th/2011/03/github-stuff/</link>
		<comments>http://blog.dt.in.th/2011/03/github-stuff/#comments</comments>
		<pubDate>Wed, 16 Mar 2011 09:08:22 +0000</pubDate>
		<dc:creator>the DtTvB</dc:creator>
				<category><![CDATA[Random Stuff]]></category>

		<guid isPermaLink="false">http://blog.dt.in.th/?p=559</guid>
		<description><![CDATA[I put some stuff on my GitHub profile, but did not mention it on this blog. You can take a look: https://github.com/dtinth I also moved several old projects to GitHub: oauthdamnit DtBMS This month, I&#8217;m staying at a computer camp, &#8230; <a href="http://blog.dt.in.th/2011/03/github-stuff/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I put some stuff on my GitHub profile, but did not mention it on this blog.</p>

<p>You can take a look: <a href="https://github.com/dtinth">https://github.com/dtinth</a></p>

<p>I also moved several old projects to GitHub:</p>

<ul>
<li><a href="https://github.com/dtinth/oauthdamnit">oauthdamnit</a></li>
<li><a href="https://github.com/dtinth/DtBMS">DtBMS</a></li>
</ul>

<p>This month, I&#8217;m staying at a computer camp, so I might not blog much.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.dt.in.th/2011/03/github-stuff/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Shell Script: Testing Gzip</title>
		<link>http://blog.dt.in.th/2011/02/httpgztest/</link>
		<comments>http://blog.dt.in.th/2011/02/httpgztest/#comments</comments>
		<pubDate>Sat, 26 Feb 2011 18:01:38 +0000</pubDate>
		<dc:creator>the DtTvB</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Mac OS X]]></category>
		<category><![CDATA[Random Stuff]]></category>

		<guid isPermaLink="false">http://blog.dt.in.th/?p=552</guid>
		<description><![CDATA[I found this old shell script I have written long time ago. I called it httpgztest. #!/bin/bash NOGZ=`wget "$1" -q -O- &#124; wc -c` echo "Without gzip: $NOGZ" YESGZ=`wget --header="Accept-Encoding: gzip, deflate" "$1" -q -O- &#124; wc -c` echo "With &#8230; <a href="http://blog.dt.in.th/2011/02/httpgztest/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I found this old shell script I have written long time ago. I called it <code>httpgztest</code>.</p>

<pre><code>#!/bin/bash
NOGZ=`wget "$1" -q -O- | wc -c`
echo "Without gzip:       $NOGZ"
YESGZ=`wget --header="Accept-Encoding: gzip, deflate" "$1" -q -O- | wc -c`
echo "With gzip:          $YESGZ"
RATIO=`echo "scale=3;$YESGZ/$NOGZ" | bc`
echo "Compression ratio:  $RATIO"
if [ $YESGZ -ge $NOGZ ]; then
    echo "Gzip is not enabled for this URL. Go check."
fi
</code></pre>

<p>To use it, run it, passing URL as the argument</p>

<pre><code>httpgztest http://dev.tw.dt.in.th/thaiWitter/js.js
</code></pre>

<p>and it shows the compression ratio.</p>

<pre><code>Without gzip:       79851
With gzip:          20839
Compression ratio:  .260
</code></pre>

<p>And if the first and the second number are the same, i.e., the compression ratio is 1, then your gzip is not working.</p>

<pre><code>Without gzip:       1820
With gzip:          1820
Compression ratio:  1.000
</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.dt.in.th/2011/02/httpgztest/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Serving Mercurial Over SSH, with Passwords</title>
		<link>http://blog.dt.in.th/2011/02/serving-mercurial-over-ssh-with-passwords/</link>
		<comments>http://blog.dt.in.th/2011/02/serving-mercurial-over-ssh-with-passwords/#comments</comments>
		<pubDate>Fri, 25 Feb 2011 15:06:00 +0000</pubDate>
		<dc:creator>the DtTvB</dc:creator>
				<category><![CDATA[Linux]]></category>

		<guid isPermaLink="false">http://blog.dt.in.th/?p=537</guid>
		<description><![CDATA[I&#8217;m doing a website project and I want to put them in a central repository on my server. I prefer to use password authentication on the server. The trick is to tell SSH to always execute hg instead of the &#8230; <a href="http://blog.dt.in.th/2011/02/serving-mercurial-over-ssh-with-passwords/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m doing a website project and I want to put them in a central repository on my server. I prefer to use password authentication on the server. The trick is to tell SSH to always execute hg instead of the shell.</p>

<p><strong>Note:</strong> These command are to be executed as <strong>root</strong>.</p>

<h2>Preparing for the environment</h2>

<p>I created a <code>/hg</code> directory to hold the repositories.</p>

<pre><code>mkdir /hg
cd /hg
</code></pre>

<h2>Setting up a skeleton</h2>

<pre><code>mkdir skel
mkdir skel/.ssh
mkdir skel/repo
echo &gt; skel/.ssh/authorized_keys
chmod 600 skel/.ssh/authorized_keys
</code></pre>

<p>This creates a skeleton directory.</p>

<h2>Creating A New User</h2>

<p>I do this by copying the skeleton, well, actually, I like doing this manually:</p>

<pre><code>cp -Rp skel hg-rwb
chown -R hg-username:hg hg-username/
</code></pre>

<p>Add the new user to <code>/etc/passwd</code></p>

<pre><code>hg-username:x:3001:3000::/hg/hg-username:/bin/sh
</code></pre>

<p>Take note of the group ID <code>3000</code>, we&#8217;ll add it in <code>/etc/group</code></p>

<pre><code>hg:x:3000:hg-username
</code></pre>

<p>Add the password:</p>

<pre><code>passwd hg-username
</code></pre>

<h2>Tell the SSH server to allow only Mercurial</h2>

<p>Edit <code>/etc/ssh/sshd_config</code> and add these lines:</p>

<pre><code>Match Group hg
    ForceCommand hg -R ~/repo serve --stdio
    AllowAgentForwarding no
    AllowTcpForwarding no
    X11Forwarding no
</code></pre>

<h2>Initialize the repository</h2>

<pre><code>su hg-username
cd ~/repo
exec hg init
</code></pre>

<h2>Use it!</h2>

<pre><code>hg init
hg add
hg commit
echo '[paths]' &gt;&gt; .hg/hgrc
echo 'default-push=ssh://hg-username@my.secret.server/' &gt;&gt; .hg/hgrc
hg push
</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.dt.in.th/2011/02/serving-mercurial-over-ssh-with-passwords/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Hacking Firefox to Always Show about:sessionrestore</title>
		<link>http://blog.dt.in.th/2011/02/firefox-sessionrestore/</link>
		<comments>http://blog.dt.in.th/2011/02/firefox-sessionrestore/#comments</comments>
		<pubDate>Mon, 21 Feb 2011 17:03:54 +0000</pubDate>
		<dc:creator>the DtTvB</dc:creator>
				<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://blog.dt.in.th/?p=545</guid>
		<description><![CDATA[It&#8217;s annoying when Firefox restores tabs when I don&#8217;t want it to. I would like it to ask if I want to restore them or not at startup time, not at closing time, so I came up with this hack: &#8230; <a href="http://blog.dt.in.th/2011/02/firefox-sessionrestore/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s annoying when Firefox restores tabs when I don&#8217;t want it to.</p>

<p>I would like it to ask if I want to restore them or not at startup time, not at closing time, so I came up with this hack:</p>

<p><strong>Warning:</strong> This is a very ugly hack! Perhaps someone can make it into a Firefox extension? <img src='http://blog.dt.in.th/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' /> </p>

<p>Go to your Firefox installation folder, navigate to <code>components</code> directory, and open <code>nsSessionStore.js</code>. Search for this:</p>

<pre><code>  /**
   * write a state object to disk
   */
  _saveStateObject: function sss_saveStateObject(aStateObj) {
</code></pre>

<p>Add this code after it:</p>

<pre><code>    aStateObj = { windows: [{ tabs: [{ entries: [{
      url: "about:sessionrestore",
      formdata: { "#sessionData": this._toJSONString(aStateObj) }
    }] }] }] };
</code></pre>

<p>The above code will force Firefox to always save the session data <strong>wrapped</strong> inside the session store page. That will force Firefox to show the <strong>&#8220;Well, this is embarrassing&#8221;</strong> page when restoring.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.dt.in.th/2011/02/firefox-sessionrestore/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>jQuery: Checkboxes Toggling Plugin</title>
		<link>http://blog.dt.in.th/2011/02/jquery-togglecheckboxes/</link>
		<comments>http://blog.dt.in.th/2011/02/jquery-togglecheckboxes/#comments</comments>
		<pubDate>Mon, 21 Feb 2011 07:07:05 +0000</pubDate>
		<dc:creator>the DtTvB</dc:creator>
				<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://blog.dt.in.th/?p=542</guid>
		<description><![CDATA[In hurry, I made this simple plugin to jQuery: $.fn.toggleCheckboxes = function() { var state = false; $('input:checkbox', this).each(function() { if (!this.checked) { state = true; return false; } }).each(function() { this.checked = state; }) }; It toggles all the &#8230; <a href="http://blog.dt.in.th/2011/02/jquery-togglecheckboxes/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>In hurry, I made this simple plugin to jQuery:</p>

<pre><code>    $.fn.toggleCheckboxes = function() {
        var state = false;
        $('input:checkbox', this).each(function() {
            if (!this.checked) {
                state = true;
                return false;
            }
        }).each(function() {
            this.checked = state;
        })
    };
</code></pre>

<p>It toggles all the checkboxes <strong>inside</strong> the matched elements all at once.</p>

<p>This allows you to do something like</p>

<pre><code>$('.toggle').click(function() {
    $(this).closest('tr').toggleCheckboxes();
});
</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.dt.in.th/2011/02/jquery-togglecheckboxes/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Crew To Play: My iPad Web Application</title>
		<link>http://blog.dt.in.th/2011/02/crew-to-play/</link>
		<comments>http://blog.dt.in.th/2011/02/crew-to-play/#comments</comments>
		<pubDate>Sat, 12 Feb 2011 01:57:33 +0000</pubDate>
		<dc:creator>the DtTvB</dc:creator>
				<category><![CDATA[iPad]]></category>
		<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://blog.dt.in.th/?p=528</guid>
		<description><![CDATA[I challenged myself by trying to make an iPad web application that feels like a native application, but without using full featured libraries like Sencha Touch or SproutCore Touch. It must also work on Firefox (Sencha Touch doesn&#8217;t). I ended &#8230; <a href="http://blog.dt.in.th/2011/02/crew-to-play/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I challenged myself by trying to make an iPad web application that feels like a native application, but without using full featured libraries like <a href="http://www.sencha.com/products/touch/">Sencha Touch</a> or <a href="http://www.sproutcore.com/">SproutCore Touch</a>. It must also work on Firefox (Sencha Touch doesn&#8217;t).</p>

<p>I ended up using just <a href="http://jquery.com/">jQuery</a>, <a href="http://jashkenas.github.com/coffee-script/">CoffeeScript</a>, and <a href="https://code.google.com/r/orgyidttvb-iscroll-js/">my version of iScroll</a> on the client.</p>

<p>I&#8217;m not the only one who go this way, the iPad version of <a href="https://www.bravenewcode.com/store/plugins/wptouch-pro/">WPtouch Pro</a> also uses jQuery and iScroll to provide iPad experience.</p>

<h2><a href="http://dtinth.github.com/crew-to-play">crew-to-play</a></h2>

<p>And this application is the result. It uses <a href="http://developer.yahoo.com/yql/">YQL</a> to fetch the current weekly courses from <a href="http://djmaxcrew.com/default.html">DJMAX TECHNIKA 2: Crew Race</a> website, and let the user search for crews by music.</p>

<p>I also use <a href="http://compass-style.org/">Compass</a> for quickly styling the web application.</p>

<p>In this blog post I will be highlighting common issues on achieving this and will be posting some code snippets. They are in CoffeeScript.</p>

<h2>Scrolled Columns</h2>

<p>The scrolled columns are made possible using <a href="https://code.google.com/p/iscroll-js/">iScroll</a>.</p>

<p><a href="https://code.google.com/r/orgyidttvb-iscroll-js/">My iScroll clone</a> makes it feels more native on iDevices, and added support for more advanced event handling.</p>

<p>Check them out!</p>

<h2>Tapping Without a Delay</h2>

<p>On MobileSafari, tapping on a link or any clickable element will have 150ms delay to allow double tapping or other actions. This is unwanted on my application, so I wrote a simple function that replaces the default behavior.</p>

<p>It always fire a click event when <code>touchend</code>. I did not make it detect that the finger is still on the control or not. It will just fire. Some improvement could be made by checking if the finger haven&#8217;t moved too far before firing.</p>

<p>iScroll.js also does this for you automatically. To prevent the element from being clicked 2 times, my iScroll.js stops the event before letting it reach the document.</p>

<pre><code>    cancel = (e) -&gt;
        e.preventDefault()

    up = (e) -&gt;
        # taken from iScroll.js
        ev = document.createEvent('MouseEvents')
        for point in e.changedTouches
            ev.initMouseEvent('click', true, true, e.view, 1,
                point.screenX, point.screenY, point.clientX, point.clientY,
                e.ctrlKey, e.altKey, e.shiftKey, e.metaKey,
                0, null)
            ev._fake = true
            point.target.dispatchEvent(ev)
        e.preventDefault()

    document.addEventListener 'touchstart', cancel, false
    document.addEventListener 'touchmove', cancel, false
    document.addEventListener 'touchend', up, false
</code></pre>

<h2>Touch Feedbacks</h2>

<p>Because <code>:hover</code> is not good enough, I had to make my own touch handler that displays feedbacks. It looks for elements with an attribute called <code>data-tappable</code> and will add a class <code>tapping</code> when is being tapped. CSS is then used to style it.</p>

<pre><code>jQuery.fn.tappable = -&gt;
    $fe = (e) -&gt;
        for point in e.changedTouches
            el = point.target
            while el and el != document.body
                if el.hasAttribute and el.hasAttribute('data-tappable')
                    return $(el)
                el = el.parentNode
        return
    this.each -&gt;
        down = (e) -&gt;
            el = $fe(e)
            if el then el.addClass('tapping')
        up = (e) -&gt;
            el = $fe(e)
            if el then el.removeClass('tapping')
        this.addEventListener 'touchstart', down, false
        this.addEventListener 'touchcancel', up, false
        this.addEventListener 'touchend', up, false

    return this
</code></pre>

<p>Usage:</p>

<pre><code>$(document).tappable()
</code></pre>

<p>On the HTML side, the tappable elements needs an extra attribute to indicate that it can be tapped.</p>

<pre><code>&lt;div class="back" data-tappable="true"&gt;Back&lt;/div&gt;
</code></pre>

<p>There seems to be problem with my version of iScroll.js which stops propagation, you need another <code>.tappable()</code> in each iScroll instance.</p>

<pre><code>new iScroll($('#element').tappable()[0])
</code></pre>

<h2>Hardware Accelerated Stuff</h2>

<p>You need to use hardware acceleration when you want to do smooth transitions on devices. This is done by using <code>-webkit-transform: translate3d(x, y, 0);</code> instead of <code>left: x; top: y;</code>.</p>

<p>You can check if the browser supports this 3d transform by checking for <code>has3d</code>, which came from iScroll.js:</p>

<pre><code># has3d from iScroll.js
has3d = `('WebKitCSSMatrix' in window &amp;&amp; 'm11' in new WebKitCSSMatrix())`
</code></pre>

<h2>The 3 Column Layout</h2>

<p>In the web application, I wanted to have 3 evenly spaced columns. I have tried a lot of CSS stuff, but the most effective way to achieve this is to use the old <code>&lt;table&gt;</code> with <code>table-layout: fixed</code>, and then assign to each <code>&lt;td&gt;</code> a same width.</p>

<h2>In Closing</h2>

<p>And that&#8217;s pretty much all. I hope that these snippets can be useful when you make your own iPad web apps.</p>

<p>As the <a href="https://github.com/dtinth/crew-to-play/">code is hosted on GitHub</a>, feel free to look at the source codes!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.dt.in.th/2011/02/crew-to-play/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Converting StepMania Stepcharts to Tap Studio</title>
		<link>http://blog.dt.in.th/2011/02/sm2tap/</link>
		<comments>http://blog.dt.in.th/2011/02/sm2tap/#comments</comments>
		<pubDate>Fri, 04 Feb 2011 16:19:46 +0000</pubDate>
		<dc:creator>the DtTvB</dc:creator>
				<category><![CDATA[iPad]]></category>
		<category><![CDATA[Mac OS X]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Random Stuff]]></category>

		<guid isPermaLink="false">http://blog.dt.in.th/?p=498</guid>
		<description><![CDATA[Tap Studio 3 is a nice game, but is full of off-synced tapcharts. This is mainly because of the way the tapcharts are made: It plays the song, the user records the tapchart as the song plays. When the song &#8230; <a href="http://blog.dt.in.th/2011/02/sm2tap/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><a href="http://itunes.apple.com/us/app/tap-studio-3/id393451834?mt=8"><strong>Tap Studio 3</strong></a> is a nice game, but is full of off-synced tapcharts.</p>

<p>This is mainly because of the way the tapcharts are made: It plays the song, the user records the tapchart as the song plays. When the song finishes, you get a tapchart ready to play. In Tap Studio 3, it has a basic UI for editing taps, but you can&#8217;t be sure that it syncs well with the song, and it fells unresponsive too.</p>

<p>Few days ago, I tried making my own taps, but each song took me a lot of time, because when I record, there will be an error in some point in the song (missing taps, extra taps, offbeat taps).</p>

<h2>StepMania is Much Better At Making Notecharts!</h2>

<p>Making stepcharts in StepMania is much more fun. You can record notes into your stepchart, or you can choose to add notes one by one. It has a lot of tools that you can use to fine-tune and sync your stepchart.</p>

<p>Also, most of the already available simfiles on the Internet are pretty time-accurate.</p>

<p>So I made a small Python script to convert my <code>.sm</code> files to be playable on Tap Studio, so I can play them anywhere.</p>

<h2>Prerequisites</h2>

<p>To be able to convert <code>.sm</code> files for playing in Tap Studio, you need:</p>

<ul>
<li>A Mac.</li>
<li>A jailbroken iDevice, with an SSH server installed.</li>
<li>Tap Studio (either version 2 or version 3 will do).</li>
<li><a href="https://github.com/dtinth/sm2tap">sm2tap</a>.</li>
</ul>

<h2>Converting Stepcharts</h2>

<h3>Song Initialization</h3>

<p>First, you need to have the song you want to convert in your device.</p>

<p>Then, you need to initialize a song. Open Tap Studio, then go to your song library and pick a song you want. After that, press <strong>Record</strong>. After the song starts, record <strong>only one note</strong> and <strong>save it</strong>.</p>

<h3>Copying the Song to Your Mac</h3>

<p>Then, SSH to your device, or run a terminal on your device <strong>as <code>mobile</code> user</strong>, and then issue this command:</p>

<pre><code>find Applications -name '*.tapd'
</code></pre>

<p>This should list all the tapfiles you have and the locations where they reside in. Copy the tap file you just created (the one with the song name) to your Mac.</p>

<h3>Converting StepMania Notes to Tap Studio Notes</h3>

<p>On your Mac, you need to convert the <code>.tapd</code> file into an XML file.</p>

<p>Open a Terminal, and then type in</p>

<pre><code>plutil -convert xml1
</code></pre>

<p>then press space, then drag the <code>.tapd</code> file into the terminal window, and then press Enter. You will see that the <code>.tapd</code> file will be slightly bigger.</p>

<p>After that, type in:</p>

<pre><code>python
</code></pre>

<p>Press space, and drag these files into the terminal window <strong>in order</strong>:</p>

<ol>
<li>My <code>convert.py</code> file.</li>
<li>The <code>.sm</code> file.</li>
<li>The <code>.tapd</code> file.</li>
</ol>

<p>Then go back to terminal and press enter. You should see a list of available step types that can be converted. Type in the name of the step type and press enter. Your <code>.tapd</code> file should be a lot bigger by now.</p>

<p>Finally, to convert it back into binary format,</p>

<pre><code>plutil -convert binary1
</code></pre>

<p>then press space, then drag the <code>.tapd</code> file into the terminal window, and then press Enter. The size of the <code>.tapd</code> file will be reduced.</p>

<h3>Copying the Modified Notes Back to Device</h3>

<p>Copy this file back into your device. You can now play your simfile on your device!</p>

<p>Enjoy!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.dt.in.th/2011/02/sm2tap/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CoffeeScripting @ Code Jom</title>
		<link>http://blog.dt.in.th/2011/02/coffeescripting-at-cofejom/</link>
		<comments>http://blog.dt.in.th/2011/02/coffeescripting-at-cofejom/#comments</comments>
		<pubDate>Wed, 02 Feb 2011 13:20:51 +0000</pubDate>
		<dc:creator>the DtTvB</dc:creator>
				<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://blog.dt.in.th/?p=510</guid>
		<description><![CDATA[Last year, I used JavaScript at Code Jom competition. It was great, and I thought that I will use JavaScript in this year, but not using the old PHP+SpiderMonkey shell. I wanted to try something different, and I was really &#8230; <a href="http://blog.dt.in.th/2011/02/coffeescripting-at-cofejom/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Last year, <a href="http://blog.dt.in.th/2010/02/javascripting-at-codejom/">I used JavaScript at Code Jom competition</a>. It was great, and I thought that I will use JavaScript in this year, but not using the old PHP+SpiderMonkey shell. I wanted to try something different, and I was really interested in <a href="http://nodejs.org/">Node.js</a> and <a href="http://narwhaljs.org/">Narwhal</a>.</p>

<p>However, I stumbled upon <a href="http://stackoverflow.com/questions/4679782/can-i-use-coffeescript-instead-of-js-for-node-js">a question on StackOverflow</a> asking about <strong>CoffeeScript</strong>, then I looked at <a href="http://jashkenas.github.com/coffee-script/">CoffeeScript&#8217;s home page</a>.</p>

<p>When I saw the example CoffeeScript in that page, compared to the compiled JavaScript, I had a feeling that I want to try to use it. The code indeed looked a lot less messy! And because CoffeeScript works with Node.js (it is available as a Node.js package), I went on with Node.js.</p>

<h2>First Round</h2>

<p>The first round started after I first knew CoffeeScript for less than 1 day. A day before that, I ported my old library for use in Code Jom written in JavaScript into CoffeeScript and used it.</p>

<p>Surprisingly, I felt very comfortable. I felt like I still have all the power of JavaScript, but in a new, cleaner syntax. I finished the first round with a score of 9 (out of 14, ranked third).</p>

<h2>Final Round</h2>

<p>I prepared for the final round by familiarizing myself with CoffeeScript. I made a simple mashup webapp called <a href="http://dtinth.github.com/crew-standings/">Crew Standings</a> in CoffeeScript and using jQuery and YQL.</p>

<p>Because I planned it a bit wrong and went on working on the main scope, things got messed up when I create functions as sometimes it use the variables outside the function&#8217;s scope (because I used a variable name outside that scope.</p>

<p>But JavaScript (and CoffeeScript) is specialized in string handling, for example, when I need to get the first digit of a number, I can just convert the number to a string and use it. When I want to match a pattern from a string, I simply check the string if it matches a regular expression.</p>

<p>I couldn&#8217;t do some questions that is based on some algorithm, where some others would be able to do it easily. For example, I was a bit too excited to be able to do the knapsack question.</p>

<p>Also, a lack of fixed multidimensional arrays in JavaScript made things a bit harder, my solution is to put it in an object:</p>

<pre><code>price[p + '-' + m] = ......
</code></pre>

<p>But that looked ugly and less straightforward than built-in fixed multidimensional arrays like in C where you can <code>int price[1000][1000];</code></p>

<p>However, I did it. My team got the first place for the student level.</p>

<h2>The Library</h2>

<p>I ported the last year&#8217;s library to CoffeeScript, so that I don&#8217;t have to learn all the new set of functions.</p>

<p>I used a simple hack for forcing functions into the global scope</p>

<pre><code>(-&gt; # force global scope

    @print = (x...) -&gt;
        sys.print y + '\n' for y in x

).call null
</code></pre>

<p>Anything that got added to <code>this</code> will be added to the global scope, thanks to CoffeeScript, <code>this.name</code> can be called <code>@name</code>, so the above code added <code>print</code> function to the global scope.</p>

<p>Here is the full library script:</p>

<script src="http://gist.github.com/807654.js"></script>

<p>And a small example:</p>

<pre><code>require './LIBRARY'

for testcase in [1..scanNumber()]
    n = scanNumber()
    print (n * (n + 1)) / 2
</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.dt.in.th/2011/02/coffeescripting-at-cofejom/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

