<?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>Jeff Mesnil &#187; web</title>
	<atom:link href="http://jmesnil.net/weblog/category/web/feed/" rel="self" type="application/rss+xml" />
	<link>http://jmesnil.net/weblog</link>
	<description>Thoughts about Java, Web and Software Development</description>
	<lastBuildDate>Wed, 25 Jan 2012 10:23:13 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>How Browsers Work &#9755;</title>
		<link>http://www.html5rocks.com/en/tutorials/internals/howbrowserswork/</link>
		<comments>http://jmesnil.net/weblog/2011/08/19/how-browsers-work/#comments</comments>
		<pubDate>Fri, 19 Aug 2011 15:52:20 +0000</pubDate>
		<dc:creator>Jeff Mesnil</dc:creator>
				<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://jmesnil.net/weblog/?p=1755</guid>
		<description><![CDATA[As a web developer, learning the internals of browser operations helps you make better decisions and know the justifications behind development best practices. While this is a rather lengthy document, we recommend you spend some time digging in; we guarantee you&#8217;ll be glad you did. All you have ever wanted to know about the internals [...]<a href="http://jmesnil.net/weblog/2011/08/19/how-browsers-work/" rel="bookmark" title="Permanent link to 'How Browsers Work'" class="glyph">&#9873;</a>
]]></description>
			<content:encoded><![CDATA[<blockquote>
  <p>As a web developer, learning the internals of browser operations helps you make better decisions and know the justifications behind development best practices. While this is a rather lengthy document, we recommend you spend some time digging in; we guarantee you&#8217;ll be glad you did.</p>
</blockquote>

<p>All you have ever wanted to know about the internals of Web browsers and more&#8230;</p>

<p>I link to the document on <a href="http://www.html5rocks.com/en/tutorials/internals/howbrowserswork/">HTML5 rocks</a> which is nicely presented but the original is available on <a href="http://taligarsiel.com/Projects/howbrowserswork1.htm">Tali Garsiel web site</a>.</p>

<p>(via <a href="http://functionsource.com/post/how-browsers-work">FunctionSource</a>)</p>
<p><a href="http://jmesnil.net/weblog/2011/08/19/how-browsers-work/" rel="bookmark" title="Permanent link to 'How Browsers Work'" class="glyph">&#9873;</a></p>
]]></content:encoded>
			<wfw:commentRss>http://jmesnil.net/weblog/2011/08/19/how-browsers-work/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>&#9873; HornetQ Talks at Marseille &amp; Nice JUGs</title>
		<link>http://jmesnil.net/weblog/2011/03/04/hornetq-talks-at-marseille-nice-jugs/</link>
		<comments>http://jmesnil.net/weblog/2011/03/04/hornetq-talks-at-marseille-nice-jugs/#comments</comments>
		<pubDate>Fri, 04 Mar 2011 21:17:23 +0000</pubDate>
		<dc:creator>Jeff Mesnil</dc:creator>
				<category><![CDATA[java]]></category>
		<category><![CDATA[redhat]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://jmesnil.net/weblog/?p=1601</guid>
		<description><![CDATA[Next week, I will talk about HornetQ and Messaging at the French mediterranean JUGs. The first talk will be at Marseille on Thursday 2011/03/10 and the second at Nice on Friday 2011/03/11. On the same days, Arnaud Simon from Red Hat will also present AMQP and Qpid. My talks will be about HornetQ &#38; the [...]]]></description>
			<content:encoded><![CDATA[<p>Next week, I will talk about <a href="http://jboss.org/hornetq">HornetQ</a> and Messaging at the French mediterranean JUGs.</p>

<p>The first talk will be at <a href="http://www.marsjug.org/reunions#TOC-Soir-e-Messaging-le-jeudi-10-mars-2">Marseille</a> on Thursday 2011/03/10 and the second at <a href="http://www.rivierajug.org/xwiki/bin/view/Main/201103%2Dfiles%2Dmessages">Nice</a> on Friday 2011/03/11.
On the same days, Arnaud Simon from <a href="http://redhat.com">Red Hat</a> will also present AMQP and Qpid.</p>

<p>My talks will be about HornetQ &amp; the Web, how HornetQ embraces the Web and offers messaging features on top of Web technologies (REST, HTML5, etc.). It will also have a (brief) introduction to Messaging and JMS for developers who want to leverage messages for their application (Web-based or not).</p>

<p>See you there!</p>
]]></content:encoded>
			<wfw:commentRss>http://jmesnil.net/weblog/2011/03/04/hornetq-talks-at-marseille-nice-jugs/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>URL Design &#9755;</title>
		<link>http://warpspire.com/posts/url-design/</link>
		<comments>http://jmesnil.net/weblog/2010/12/30/url-design/#comments</comments>
		<pubDate>Thu, 30 Dec 2010 18:20:12 +0000</pubDate>
		<dc:creator>Jeff Mesnil</dc:creator>
				<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://jmesnil.net/weblog/?p=1557</guid>
		<description><![CDATA[Kyle Neath: URLs are universal. They work in Firefox, Chrome, Safari, Internet Explorer, cURL, wget, your iPhone, Android and even written down on sticky notes. They are the one universal syntax of the web. Don’t take that for granted. GitHub URLs are a good example to imitate. I often edit them directly to switch from [...]<a href="http://jmesnil.net/weblog/2010/12/30/url-design/" rel="bookmark" title="Permanent link to 'URL Design'" class="glyph">&#9873;</a>
]]></description>
			<content:encoded><![CDATA[<p>Kyle Neath:</p>

<blockquote>
  <p>URLs are <em>universal</em>. They work in Firefox, Chrome, Safari, Internet Explorer, cURL, wget, your iPhone, Android and even written down on sticky notes. They are the one universal syntax of the web. Don’t take that for granted.</p>
</blockquote>

<p><a href="https://github.com/">GitHub</a> URLs are a good example to imitate. I often edit them directly to switch from one project to another.</p>

<p>It is painful to see how some Web sites are not bothered by their ugly URLs.<br />
Don&#8217;t get me started on the URLs generated by some Web frameworks. I suspect they are ugly on purpose so that you can know which framework is used by a Web site just by looking at its URLs.</p>

<p><a href="http://www.cryptonomicon.com/beginning.html">In the beginning was the command line</a>, and then came the address bar&#8230;</p>
<p><a href="http://jmesnil.net/weblog/2010/12/30/url-design/" rel="bookmark" title="Permanent link to 'URL Design'" class="glyph">&#9873;</a></p>
]]></content:encoded>
			<wfw:commentRss>http://jmesnil.net/weblog/2010/12/30/url-design/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>WebSocket disabled in Firefox 4 &#9755;</title>
		<link>http://hacks.mozilla.org/2010/12/websockets-disabled-in-firefox-4/</link>
		<comments>http://jmesnil.net/weblog/2010/12/08/websocket-disabled-in-firefox-4/#comments</comments>
		<pubDate>Wed, 08 Dec 2010 20:54:54 +0000</pubDate>
		<dc:creator>Jeff Mesnil</dc:creator>
				<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://jmesnil.net/weblog/?p=1510</guid>
		<description><![CDATA[This is a serious threat to the Internet and Websocket and not a browser specific issue. The protocol vulnerabilities also affect Java and Flash solutions. In a web environment that could for example mean that a widely used JavaScript file – like Google analytics – could be replaced on a cache you go through with [...]<a href="http://jmesnil.net/weblog/2010/12/08/websocket-disabled-in-firefox-4/" rel="bookmark" title="Permanent link to 'WebSocket disabled in Firefox 4'" class="glyph">&#9873;</a>
]]></description>
			<content:encoded><![CDATA[<blockquote>
  <p>This is a serious threat to the Internet and Websocket and not a browser specific issue. The protocol vulnerabilities also affect Java and Flash solutions. In a web environment that could for example mean that a widely used JavaScript file – like Google analytics – could be replaced on a cache you go through with a malware file.</p>
</blockquote>

<p>I think Mozilla decision makes sense and they are right to be cautious.</p>

<p>I am interested by Web Sockets (I implemented a JavaScript library to use <a href="http://jmesnil.net/stomp-websocket/doc/">STOMP over Web Sockets</a> for messaging) but we need to be very careful about opening a new communication channel between Web clients and servers. Web Sockets must integrate with the whole Web infrastructure (including caches and proxies) and not open a whole can of security issues.</p>

<p>The HTML5 Web Socket API has a lot of potental, especially now that it is available on iOS-based devices (I wrote a <a href="https://github.com/jmesnil/board-node">node.js-based application</a> which uses it) but it is critical to get the protocol right before it is widespread.</p>

<p>Once Web Sockets are out in the wild, we will have to live with them for a long time, deal with their issues on our own and face ugly consequences for rushing it out.</p>
<p><a href="http://jmesnil.net/weblog/2010/12/08/websocket-disabled-in-firefox-4/" rel="bookmark" title="Permanent link to 'WebSocket disabled in Firefox 4'" class="glyph">&#9873;</a></p>
]]></content:encoded>
			<wfw:commentRss>http://jmesnil.net/weblog/2010/12/08/websocket-disabled-in-firefox-4/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>James Clark: XML vs the Web &#9755;</title>
		<link>http://blog.jclark.com/2010/11/xml-vs-web_24.html</link>
		<comments>http://jmesnil.net/weblog/2010/11/30/james-clark-xml-vs-the-web/#comments</comments>
		<pubDate>Tue, 30 Nov 2010 20:29:11 +0000</pubDate>
		<dc:creator>Jeff Mesnil</dc:creator>
				<category><![CDATA[web]]></category>
		<category><![CDATA[xml]]></category>

		<guid isPermaLink="false">http://jmesnil.net/weblog/?p=1429</guid>
		<description><![CDATA[James Clark: So what&#8217;s the way forward? I think the Web community has spoken, and it&#8217;s clear that what it wants is HTML5, JavaScript and JSON. XML isn&#8217;t going away but I see it being less and less a Web technology; it won&#8217;t be something that you send over the wire on the public Web, [...]<a href="http://jmesnil.net/weblog/2010/11/30/james-clark-xml-vs-the-web/" rel="bookmark" title="Permanent link to 'James Clark: XML vs the Web'" class="glyph">&#9873;</a>
]]></description>
			<content:encoded><![CDATA[<p>James Clark:</p>

<blockquote>
  <p>So what&#8217;s the way forward? I think the Web community has spoken, and it&#8217;s clear that what it wants is HTML5, JavaScript and JSON. XML isn&#8217;t going away but I see it being less and less a Web technology; it won&#8217;t be something that you send over the wire on the public Web, but just one of many technologies that are used on the server to manage and generate what you do send over the wire.</p>
</blockquote>

<p>My background is in &#8220;enterprisey&#8221; Java and I use XML in Maven, Ant, configuration files, etc.
All the Java projects I worked had lots of code to map between XML and Java data structures.
I tried to use XML schema and bindings but it replaces some noisy boilerplate code by <em>other</em> noisy boilerplate code. Using schema did help to enforce a structure but not all constraints can be expressed with it and I ended up having an additional programmatic validation phase in Java.</p>

<p>In comparison, working with JavaScript and JSON on the Web is much more simpler. I create JavaScript objects, send them over the wire with the string representation returned by <code>JSON.stringify()</code> and use again JavaScript objects on the server (with <code>JSON.parse()</code> in <code>node.js</code>  or using a JSON to Java library for Java servers).<br />
I don&#8217;t have schema and I don&#8217;t need it. A good documentation is enough in most cases (in the same way, I learn about a XML document by looking at its structure and documentation and rarely its schema).</p>

<p>I believe than XML (and its associated technologies) will end up as an  <em>enterprise</em> technology and a <em>opaque</em> content model (e.g. to save OpenOffice documents) and be less and less prevalent on the Web where HTML (with microformats) and JSON are better suited to represent data.</p>

<p>(via <a href="http://daringfireball.net/linked/2010/11/30/clark-xml">John Gruber</a>)</p>
<p><a href="http://jmesnil.net/weblog/2010/11/30/james-clark-xml-vs-the-web/" rel="bookmark" title="Permanent link to 'James Clark: XML vs the Web'" class="glyph">&#9873;</a></p>
]]></content:encoded>
			<wfw:commentRss>http://jmesnil.net/weblog/2010/11/30/james-clark-xml-vs-the-web/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>JSApp.US: a node.js Hosting Provider &#9755;</title>
		<link>http://jsapp.us/</link>
		<comments>http://jmesnil.net/weblog/2010/11/27/jsapp-us-a-node-js-hosting-provider/#comments</comments>
		<pubDate>Fri, 26 Nov 2010 23:56:29 +0000</pubDate>
		<dc:creator>Jeff Mesnil</dc:creator>
				<category><![CDATA[javascript]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://jmesnil.net/weblog/?p=1414</guid>
		<description><![CDATA[I was looking for a provider to host the HTML5 / node.js Web application that I am blogging about here and there and JSApp.US is the first one that I found. It is straightforward to use and I have deployed my Web application on it. You can try it by yourself on your iPhone or [...]<a href="http://jmesnil.net/weblog/2010/11/27/jsapp-us-a-node-js-hosting-provider/" rel="bookmark" title="Permanent link to 'JSApp.US: a node.js Hosting Provider'" class="glyph">&#9873;</a>
]]></description>
			<content:encoded><![CDATA[<p>I was looking for a provider to host the HTML5 / <a href="http://nodejs.org/">node.js</a> Web application that I am blogging about <a href="/weblog/2010/11/24/html5-web-application-for-iphone-and-ipad-with-node-js/">here</a> and <a href="/weblog/2010/11/26/offline-support-and-standalone-mode-for-html5-web-application/">there</a> and <a href="http://jsapp.us/">JSApp.US</a> is the first one that I found.</p>

<p>It is straightforward to use and I have deployed my Web application on it. You can try it by yourself on your iPhone or iPad by going to <a href="http://board.jsapp.us/">http://board.jsapp.us/</a>.</p>

<p>At first, it complained that <code>__dirname</code> was not defined when <code>server.js</code> is trying to read files based on the URL path.
I modified <code>server.js</code> to remove the leading <code>/</code> from the path and it works fine:</p>


<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #006600; font-style: italic;">// won't work on JSApp.us</span>
fs.<span style="color: #660066;">readFile</span><span style="color: #009900;">&#40;</span>__dirname <span style="color: #339933;">+</span> path<span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>err<span style="color: #339933;">,</span> data<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
   ...
<span style="color: #009900;">&#125;</span>
<span style="color: #006600; font-style: italic;">// but this works</span>
fs.<span style="color: #660066;">readFile</span><span style="color: #009900;">&#40;</span>path.<span style="color: #660066;">substring</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> path.<span style="color: #660066;">length</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>err<span style="color: #339933;">,</span> data<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
   ...
<span style="color: #009900;">&#125;</span></pre></div></div>


<p>The offline support does not work: somehow this provider does not return the <code>Content-Type</code> HTTP header set by <code>server.js</code>.
Since the cache manifest is not served with the expected <code>text/cache-manifest</code>, I suppose that Safari does not take it into account and bypass the offline configuration.</p>

<p><strong>update:</strong> I was wrong the <code>cache.manifest</code> file is returned with the correct <code>Content-Type</code>:</p>


<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ curl <span style="color: #660033;">-Gi</span> http:<span style="color: #000000; font-weight: bold;">//</span>board.jsapp.us<span style="color: #000000; font-weight: bold;">/</span>cache.manifest
HTTP<span style="color: #000000; font-weight: bold;">/</span><span style="color: #000000;">1.1</span> <span style="color: #000000;">200</span> OK
Server: nginx<span style="color: #000000; font-weight: bold;">/</span>0.8.53
Date: Sat, <span style="color: #000000;">27</span> Nov <span style="color: #000000;">2010</span> 00:06:<span style="color: #000000;">45</span> GMT
Content-Type: text<span style="color: #000000; font-weight: bold;">/</span>cache-manifest
Transfer-Encoding: chunked
Connection: keep-alive
&nbsp;
CACHE MANIFEST
<span style="color: #666666; font-style: italic;"># 2010-11-27</span>
&nbsp;
CACHE:
<span style="color: #000000; font-weight: bold;">/</span>screen.css
<span style="color: #000000; font-weight: bold;">/</span>client.js
<span style="color: #000000; font-weight: bold;">/</span>jquery.min.js</pre></div></div>


<p>I don&#8217;t know why offline support is not working&#8230;
The rest of the application seems to work fine though.</p>

<p>It will make the next version of the application more interesting. I want to add Web Sockets support to display the pieces of the other users on the Web application (in addition to its own piece).
With this hosting provider, I&#8217;ll be able to release a version that everyone will be able to try.</p>

<p>As an aside, it uses <a href="https://mozillalabs.com/skywriter/">SkyWriter</a> (n&eacute; Bespin) to edit the code and the integration is pretty slick.</p>
<p><a href="http://jmesnil.net/weblog/2010/11/27/jsapp-us-a-node-js-hosting-provider/" rel="bookmark" title="Permanent link to 'JSApp.US: a node.js Hosting Provider'" class="glyph">&#9873;</a></p>
]]></content:encoded>
			<wfw:commentRss>http://jmesnil.net/weblog/2010/11/27/jsapp-us-a-node-js-hosting-provider/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>&#9873; Offline Support and Standalone Mode for HTML5 Web Application</title>
		<link>http://jmesnil.net/weblog/2010/11/26/offline-support-and-standalone-mode-for-html5-web-application/</link>
		<comments>http://jmesnil.net/weblog/2010/11/26/offline-support-and-standalone-mode-for-html5-web-application/#comments</comments>
		<pubDate>Fri, 26 Nov 2010 20:54:28 +0000</pubDate>
		<dc:creator>Jeff Mesnil</dc:creator>
				<category><![CDATA[iphone]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://jmesnil.net/weblog/?p=1376</guid>
		<description><![CDATA[Let&#8217;s continue working on the HTML5 Web Application for the iPhone with node.js Last time, I created the first version of the Web application to move a piece when the user moves the iPhone and coded a simple Web server on top of node.js. The Web application works fine but it is not pretty and [...]]]></description>
			<content:encoded><![CDATA[<p>Let&#8217;s continue working on the HTML5 Web Application for the iPhone with node.js</p>

<p><a href="http://jmesnil.net/weblog/2010/11/24/html5-web-application-for-iphone-and-ipad-with-node-js/">Last time</a>, I created the first version of the Web application to move a piece when the user moves the iPhone and coded a simple Web server on top of node.js.</p>

<p>The Web application works fine but it is not pretty and there are a few things we can improve.
Before looking at Web Sockets and other fancy code, let&#8217;s make the Web application prettier.</p>

<h2>iPhone Standalone Web Application</h2>

<p>The major annoyance is that Safari chrome takes a lot of space and hides the bottom of the board:</p>

<p><img src="http://jmesnil.net/weblog/wp-content/uploads/2010/11/chrome.png" alt="" title="chrome" width="320" height="155" class="aligncenter size-full wp-image-1383" /></p>

<p>To display a Web application without Safari chrome, we can make it a <a href="http://developer.apple.com/library/safari/#documentation/AppleApplications/Reference/SafariWebContent/ConfiguringWebApplications/ConfiguringWebApplications.html%23//apple_ref/doc/uid/TP40002051-CH3-SW2">standalone Web application</a>.</p>

<p>In <code>index.html</code>, we add some <code>&lt;meta&gt;</code> information to the <code>&lt;head&gt;</code> part:</p>


<div class="wp_syntax"><div class="code"><pre class="html4strict" style="font-family:monospace;"><span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">head</span>&gt;</span>
  ...
  <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">meta</span> <span style="color: #000066;">name</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;viewport&quot;</span> <span style="color: #000066;">content</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;width=device-width, user-scalable=0&quot;</span> <span style="color: #66cc66;">/</span>&gt;</span>
  <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">meta</span> <span style="color: #000066;">name</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;apple-mobile-web-app-capable&quot;</span> <span style="color: #000066;">content</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;yes&quot;</span> <span style="color: #66cc66;">/</span>&gt;</span>
  <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">meta</span> <span style="color: #000066;">name</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;apple-mobile-web-app-status-bar-style&quot;</span> <span style="color: #000066;">content</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;black&quot;</span>&gt;</span>
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">head</span>&gt;</span></pre></div></div>


<p>The <a href="http://developer.apple.com/library/safari/documentation/AppleApplications/Reference/SafariWebContent/UsingtheViewport/UsingtheViewport.html#//apple_ref/doc/uid/TP40006509-SW1"><code>viewport</code></a> meta ensures that the Web page will be sized to the device width and prevents the user to change the page scale (by pinching it).</p>

<p>The <a href="http://developer.apple.com/library/safari/#documentation/AppleApplications/Reference/SafariWebContent/ConfiguringWebApplications/ConfiguringWebApplications.html%23//apple_ref/doc/uid/TP40002051-CH3-SW2"><code>apple-mobile-web-app-capable</code></a> will launch the Web application in full-screen mode (without Safari chrome) to look like a native application. The Web application must be added to the iPhone home screen and start from there to appear in full-screen mode.</p>

<p>Last thing is to render the iPhone status bar in black by setting the <a href="http://developer.apple.com/library/safari/#documentation/AppleApplications/Reference/SafariWebContent/ConfiguringWebApplications/ConfiguringWebApplications.html%23//apple_ref/doc/uid/TP40002051-CH3-SW1"><code>apple-mobile-web-app-status-bar-style</code></a> to black.</p>

<p>With these 3 meta information, the Web application looks better and display the whole board</p>

<p><img src="http://jmesnil.net/weblog/wp-content/uploads/2010/11/Board-2nd-version.jpg" alt="" title="Board - 2nd version" width="320" height="480" class="aligncenter size-full wp-image-1380" /></p>

<h2>Offline Support</h2>

<p>At the moment, node.js serves only static pages. When the iPhone has loaded the Web application, it no longer connects to the Web server.</p>

<p>Let&#8217;s add offline support so that we can run the Web application even when the server is down (or unreachable).</p>

<p>HTML5 supports <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/offline.html">offline</a> applications through the cache manifest. The best introduction on the subject is the <a href="http://diveintohtml5.org/offline.html">Offline chapter in Dive into HTML5</a>.</p>

<p>For this Web application this means that we must write a <code>cache.manifest</code> file:</p>


<div class="wp_syntax"><div class="code"><pre class="manifest" style="font-family:monospace;">CACHE MANIFEST
&nbsp;
CACHE:
/screen.css
/client.js
/jquery.min.js</pre></div></div>


<p>This cache manifest tells the Web browsers to call all these files to run the Web application offline.</p>

<p>This cache manifest must be declared in the entry point of the Web application (<code>index.html</code> in this case) with the <code>manifest</code> attribute of the <code>html</code> element:</p>


<div class="wp_syntax"><div class="code"><pre class="html4strict" style="font-family:monospace;"><span style="color: #009900;">&lt;!doctype html&gt;</span>
<span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">html</span> manifest<span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;/cache.manifest&quot;</span>&gt;</span>
...</pre></div></div>


<p>Finally, we need to update <code>server.js</code> to send the <code>cache.manifest</code> file with the correct HTTP <code>Content-Type</code>.
Only the <code>getContentType()</code>function needs to be modified:</p>


<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">function</span> contentType<span style="color: #009900;">&#40;</span>path<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
   <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>path.<span style="color: #660066;">match</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'.js$'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #3366CC;">&quot;text/javascript&quot;</span><span style="color: #339933;">;</span>
   <span style="color: #009900;">&#125;</span> <span style="color: #000066; font-weight: bold;">else</span> <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>path.<span style="color: #660066;">match</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'.css$'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #000066; font-weight: bold;">return</span>  <span style="color: #3366CC;">&quot;text/css&quot;</span><span style="color: #339933;">;</span>           
   <span style="color: #009900;">&#125;</span> <span style="color: #000066; font-weight: bold;">else</span> <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>path.<span style="color: #660066;">match</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'.manifest$'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #000066; font-weight: bold;">return</span>  <span style="color: #3366CC;">&quot;text/cache-manifest&quot;</span><span style="color: #339933;">;</span>
   <span style="color: #009900;">&#125;</span>  <span style="color: #000066; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #3366CC;">&quot;text/html&quot;</span><span style="color: #339933;">;</span>
   <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>


<p>With this modification, <code>cache.manifest</code> will be sent to the Web browser with the correct <code>text/cache-manifest</code> Content-Type.</p>

<p>We must restart the server to take into account the <code>server.js</code> modification:</p>


<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ node.js server.js
HTTP server running at htpp:<span style="color: #000000; font-weight: bold;">//</span>0.0.0.0:<span style="color: #000000;">8080</span></pre></div></div>


<p>I can then reload the Web application and add it to the iPhone home screen.
With offline support, I will be able to use the Web application even if the server is not running or unreachable.</p>

<p>Here is a small video of the result with the updated Web application:</p>

<p><object width="640" height="385"><param name="movie" value="http://www.youtube.com/v/yoJAC2Qc0uo?fs=1&amp;hl=fr_FR&amp;rel=0&amp;hd=1"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/yoJAC2Qc0uo?fs=1&amp;hl=fr_FR&amp;rel=0&amp;hd=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="385"></embed></object></p>

<p>Note the black status bar and the full screen mode after I started the Web application from the iPhone home screen. It is indistinguishable from a native application but runs on the Web (it’s not obvious from the video but the camera was recording from above: the iPhone was held horizontally)</p>

<h2>Source Code</h2>

<p>I have pushed the application on <a href="http://github.com/jmesnil/board-node">Github</a>. You can clone it with Git:</p>


<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">git</span> clone <span style="color: #c20cb9; font-weight: bold;">git</span>:<span style="color: #000000; font-weight: bold;">//</span>github.com<span style="color: #000000; font-weight: bold;">/</span>jmesnil<span style="color: #000000; font-weight: bold;">/</span>board-node.git</pre></div></div>


<h2>Conclusion</h2>

<p>By adding a few <code>meta</code> information to the Web application, it is possible to make it look better integrated to the iPhone.<br />
Offline support is trickier than this simple example make it look like but it gives the right idea to start dealing with it.</p>

<p>Next step is to add Web Sockets support to the node.js to display the moving pieces of <em>other users</em> on the Web application.</p>

<h2>Further Reading</h2>

<ul>
<li><a href="http://developer.apple.com/library/safari/#documentation/AppleApplications/Reference/SafariWebContent/Introduction/Introduction.html">Safari Web Content Guide</a></li>
<li><a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/offline.html">HTML5 Offline Web applications</a> (and its corresponding <a href="http://diveintohtml5.org/offline.html">&#8220;Dive into HTML5&#8243; chapter</a>)</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://jmesnil.net/weblog/2010/11/26/offline-support-and-standalone-mode-for-html5-web-application/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>&#9873; HTML5 Web Application for iPhone and iPad With node.js</title>
		<link>http://jmesnil.net/weblog/2010/11/24/html5-web-application-for-iphone-and-ipad-with-node-js/</link>
		<comments>http://jmesnil.net/weblog/2010/11/24/html5-web-application-for-iphone-and-ipad-with-node-js/#comments</comments>
		<pubDate>Wed, 24 Nov 2010 21:38:55 +0000</pubDate>
		<dc:creator>Jeff Mesnil</dc:creator>
				<category><![CDATA[iphone]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://jmesnil.net/weblog/?p=1333</guid>
		<description><![CDATA[Update: I have written another post about adding offline support to the Web application and making it look like a native iPhone application. On the server, I want to learn more about node.js which is an interesting way to develop server-side applications. On the client-side, I also wanted to check what can be done with [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Update:</strong> <em>I have written <a href="/weblog/2010/11/26/offline-support-and-standalone-mode-for-html5-web-application/">another post</a> about adding offline support to the Web application and making it look like a native iPhone application.</em></p>

<p>On the server, I want to learn more about <a href="http://nodejs.org/">node.js</a> which is an interesting way to develop server-side applications.
On the client-side, I also wanted to check what can be done with HTML5 on iPhone and iPad with the release of iOS 4.2.1.</p>

<p>I will write a simple web application to do both at the same time. The idea is simple enough but will allow me to dive into node.js and HTML5 quite extensively.</p>

<p>The idea is to write a web application that display a piece moving on a board when the user moves its device. 
Later on, I will expand it so that the user will also see the pieces of all others users connected to the server.</p>

<p>But the first iteration will be enough to familiarize with:</p>

<ul>
<li>node.js (to serve static content at first)</li>
<li><a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html">Canvas API</a> (to draw the board and the piece)</li>
<li><a href="http://dev.w3.org/geo/api/spec-source-orientation.html">DeviceOrientation Event API</a> (to detect the orientation of the mobile, it was added in iOS 4.2.1)</li>
</ul>

<h1>Web Server</h1>

<p>I will use node.js as my Web server (I installed it from Git by following the <a href="http://nodejs.org/#build">build instructions</a> on its web site).</p>

<p>The first version of the server needs to serve static files with the correct HTTP <code>Content-Type</code>.
At first, it will serve only HTML pages, CSS stylesheets and JavaScript files.</p>

<p>The whole <code>server.js</code> code is:</p>


<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">var</span> http <span style="color: #339933;">=</span> require<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'http'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #003366; font-weight: bold;">var</span> url <span style="color: #339933;">=</span> require<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'url'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #003366; font-weight: bold;">var</span> fs <span style="color: #339933;">=</span> require<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'fs'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #003366; font-weight: bold;">var</span> sys <span style="color: #339933;">=</span> require<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'sys'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #006600; font-style: italic;">// the HTTP server</span>
<span style="color: #003366; font-weight: bold;">var</span> server<span style="color: #339933;">;</span>
<span style="color: #006600; font-style: italic;">// the HTTP port</span>
<span style="color: #003366; font-weight: bold;">var</span> port <span style="color: #339933;">=</span> <span style="color: #CC0000;">8080</span><span style="color: #339933;">;</span>
&nbsp;
server <span style="color: #339933;">=</span> http.<span style="color: #660066;">createServer</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>req<span style="color: #339933;">,</span> res<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
  <span style="color: #003366; font-weight: bold;">var</span> path <span style="color: #339933;">=</span> url.<span style="color: #660066;">parse</span><span style="color: #009900;">&#40;</span>req.<span style="color: #660066;">url</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">pathname</span><span style="color: #339933;">;</span>
  <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>path <span style="color: #339933;">==</span> <span style="color: #3366CC;">'/'</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
     path <span style="color: #339933;">=</span> <span style="color: #3366CC;">'/index.html'</span>
  <span style="color: #009900;">&#125;</span>
  console.<span style="color: #660066;">log</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;serving &quot;</span> <span style="color: #339933;">+</span> path<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  fs.<span style="color: #660066;">readFile</span><span style="color: #009900;">&#40;</span>__dirname <span style="color: #339933;">+</span> path<span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>err<span style="color: #339933;">,</span> data<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
     <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>err<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        res.<span style="color: #660066;">writeHead</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">404</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        res.<span style="color: #660066;">end</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>        
     <span style="color: #009900;">&#125;</span> <span style="color: #000066; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span>
        res.<span style="color: #660066;">writeHead</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">200</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#123;</span><span style="color: #3366CC;">'Content-Type'</span><span style="color: #339933;">:</span> contentType<span style="color: #009900;">&#40;</span>path<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        res.<span style="color: #000066; font-weight: bold;">write</span><span style="color: #009900;">&#40;</span>data<span style="color: #339933;">,</span> <span style="color: #3366CC;">'utf8'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        res.<span style="color: #660066;">end</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
     <span style="color: #009900;">&#125;</span>
  <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #003366; font-weight: bold;">function</span> contentType<span style="color: #009900;">&#40;</span>path<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
   <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>path.<span style="color: #660066;">match</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'.js$'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #3366CC;">&quot;text/javascript&quot;</span><span style="color: #339933;">;</span>
   <span style="color: #009900;">&#125;</span> <span style="color: #000066; font-weight: bold;">else</span> <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>path.<span style="color: #660066;">match</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'.css$'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #000066; font-weight: bold;">return</span>  <span style="color: #3366CC;">&quot;text/css&quot;</span><span style="color: #339933;">;</span>           
   <span style="color: #009900;">&#125;</span>  <span style="color: #000066; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #3366CC;">&quot;text/html&quot;</span><span style="color: #339933;">;</span>
   <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
server.<span style="color: #660066;">listen</span><span style="color: #009900;">&#40;</span>port<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
console.<span style="color: #660066;">log</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;HTTP server running at htpp://0.0.0.0:&quot;</span> <span style="color: #339933;">+</span> port <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>


<p>The code is straightforward: when a request is handled by the server, it looks in the current directory (where <code>server.js</code> is) for a file with the given path and writes its content in the HTTP response body.<br />
The <code>contentType(path)</code> function checks the file suffix to use the correct HTTP <code>Content-Type</code> for the response.</p>

<p>It will serve files from <code>http://&lt;server-name&gt;:8080/</code>.<br />
For the rest of the example, I will use the name of my machine, <code>blackbook.local</code>: to access the Web application from my iPhone, I am using <a href="http://blackbook.local:8080">http://blackbook.local:8080</a>.</p>

<p>In future iterations, I will add more interesting code to node.js (to use WebSockets for example) but for the moment this simple server is enough.</p>

<h1>Web Application</h1>

<p>Let&#8217;s now focus on the client-side part of the Web application.</p>

<h2>index.html</h2>

<p>The Web application is loaded from a single HTML5 page, <code>index.html</code>:</p>


<div class="wp_syntax"><div class="code"><pre class="html4strict" style="font-family:monospace;"><span style="color: #009900;">&lt;!doctype html&gt;</span>
<span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">html</span>&gt;</span>
<span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">head</span>&gt;</span>
  <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">meta</span> <span style="color: #000066;">charset</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;UTF-8&quot;</span> <span style="color: #66cc66;">/</span>&gt;</span>
  <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">meta</span> <span style="color: #000066;">name</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;viewport&quot;</span> <span style="color: #000066;">content</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;width=device-width, user-scalable=0&quot;</span> <span style="color: #66cc66;">/</span>&gt;</span>
  <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">title</span>&gt;</span>Board<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">title</span>&gt;</span>
  <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">link</span> <span style="color: #000066;">rel</span><span style="color: #66cc66;">=</span>stylesheet <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span>screen.css&gt;</span>
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">head</span>&gt;</span>
<span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">body</span>&gt;</span>
  <span style="color: #009900;">&lt;canvas <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;board&quot;</span> <span style="color: #000066;">width</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;320&quot;</span> <span style="color: #000066;">height</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;460&quot;</span>&gt;&lt;<span style="color: #66cc66;">/</span>canvas&gt;</span>
&nbsp;
  <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">script</span> <span style="color: #000066;">src</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">'jquery.min.js'</span>&gt;&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">script</span>&gt;</span>  
  <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">script</span> <span style="color: #000066;">src</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;client.js&quot;</span>&gt;&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">script</span>&gt;</span>
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">body</span>&gt;</span>
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">html</span>&gt;</span></pre></div></div>


<p>The page contains a single &lt;canvas> element named <code>board</code>. All the code to draw on the canvas is in <code>client.js</code> JavaScript file.</p>

<h2>client.js</h2>

<p><code>client.js</code> contains code to:</p>

<ul>
<li>get orientation information from the device (using the DeviceOrientation Event API)</li>
<li>draw the board and the piece based on the orientation information (using the Canvas API)</li>
</ul>

<p>First, it defines a few constants used to draw the board and the piece:</p>


<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">var</span> kBoardWidth <span style="color: #339933;">=</span> <span style="color: #CC0000;">320</span><span style="color: #339933;">;</span>
<span style="color: #003366; font-weight: bold;">var</span> kBoardHeight <span style="color: #339933;">=</span> <span style="color: #CC0000;">460</span><span style="color: #339933;">;</span>
<span style="color: #003366; font-weight: bold;">var</span> kCircleRadius <span style="color: #339933;">=</span> <span style="color: #CC0000;">32</span><span style="color: #339933;">;</span></pre></div></div>


<p>The <code>piece</code> object is defined literally:</p>


<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">var</span> piece <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span>
   center <span style="color: #339933;">:</span> <span style="color: #009900;">&#123;</span>
      x<span style="color: #339933;">:</span> kBoardWidth <span style="color: #339933;">/</span> <span style="color: #CC0000;">2</span><span style="color: #339933;">,</span>
      y<span style="color: #339933;">:</span> kBoardHeight <span style="color: #339933;">/</span> <span style="color: #CC0000;">2</span><span style="color: #339933;">,</span>
      xShift <span style="color: #339933;">:</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">,</span>
      yShift <span style="color: #339933;">:</span> <span style="color: #CC0000;">0</span>
   <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
   color<span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;#000&quot;</span>
<span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span></pre></div></div>


<p>The piece has a center position with its coordinates (initially at the center of the board) and its acceleration on the x and y axes, and its color is black.</p>

<p>I use <a href="http://jquery.com/">jQuery</a> to bootstrap the application when the document is ready:</p>


<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">$<span style="color: #009900;">&#40;</span>document<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">ready</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
   <span style="color: #003366; font-weight: bold;">var</span> board <span style="color: #339933;">=</span> document.<span style="color: #660066;">getElementById</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;board&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   <span style="color: #003366; font-weight: bold;">var</span> context <span style="color: #339933;">=</span> board.<span style="color: #660066;">getContext</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;2d&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   window.<span style="color: #660066;">addEventListener</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;devicemotion&quot;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>event<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      <span style="color: #003366; font-weight: bold;">var</span> accel <span style="color: #339933;">=</span> event.<span style="color: #660066;">accelerationIncludingGravity</span><span style="color: #339933;">;</span>
      piece.<span style="color: #660066;">center</span> <span style="color: #339933;">=</span> computeCenter<span style="color: #009900;">&#40;</span>piece.<span style="color: #660066;">center</span><span style="color: #339933;">,</span> accel<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      drawGrid<span style="color: #009900;">&#40;</span>context<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      drawPiece<span style="color: #009900;">&#40;</span>context<span style="color: #339933;">,</span> piece<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>


<p>First we keep a reference on the <code>board</code> canvas that was declared in the HTML page and its associated 2D context.
The <code>context</code> will be used to draw the piece and the board on the canvas.</p>

<p>We use the DeviceOrientation API (supported by the iPhone and the iPad since iOS 4.2.1) to detect the acceleration of the device.
Periodically, the browser will call the handler associated to the <code>devicemotion</code> event.<br />
When that happens, the handler retrieves the <code>accelerationIncludingGravity</code> property, compute the new center position of the piece and draw the board and the piece on the canvas.</p>

<p>The method to draw the board is using the 2D context (the board is displayed as a grid):</p>


<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">function</span> drawBoard<span style="color: #009900;">&#40;</span>context<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
   context.<span style="color: #660066;">clearRect</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">0</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">,</span> kBoardWidth<span style="color: #339933;">,</span> kBoardHeight<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   <span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> x <span style="color: #339933;">=</span> <span style="color: #CC0000;">0.5</span><span style="color: #339933;">;</span> x <span style="color: #339933;">&lt;</span> kBoardWidth<span style="color: #339933;">;</span> x <span style="color: #339933;">+=</span> <span style="color: #CC0000;">10</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
       context.<span style="color: #660066;">moveTo</span><span style="color: #009900;">&#40;</span>x<span style="color: #339933;">,</span> <span style="color: #CC0000;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
       context.<span style="color: #660066;">lineTo</span><span style="color: #009900;">&#40;</span>x<span style="color: #339933;">,</span> kBoardHeight<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   <span style="color: #009900;">&#125;</span>
   <span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> y <span style="color: #339933;">=</span> <span style="color: #CC0000;">0.5</span><span style="color: #339933;">;</span> y <span style="color: #339933;">&lt;</span> kBoardHeight<span style="color: #339933;">;</span> y <span style="color: #339933;">+=</span> <span style="color: #CC0000;">10</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      context.<span style="color: #660066;">moveTo</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">0</span><span style="color: #339933;">,</span> y<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      context.<span style="color: #660066;">lineTo</span><span style="color: #009900;">&#40;</span>kBoardWidth<span style="color: #339933;">,</span> y<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   <span style="color: #009900;">&#125;</span>
   context.<span style="color: #660066;">strokeStyle</span> <span style="color: #339933;">=</span> <span style="color: #3366CC;">&quot;#eee&quot;</span><span style="color: #339933;">;</span>
   context.<span style="color: #660066;">stroke</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>


<p>The code to draw the piece is also using the 2D context to draw a circle from the piece&#8217;s center and its color:</p>


<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">function</span> drawPiece<span style="color: #009900;">&#40;</span>context<span style="color: #339933;">,</span> piece<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
   context.<span style="color: #660066;">fillStyle</span> <span style="color: #339933;">=</span> piece.<span style="color: #660066;">color</span><span style="color: #339933;">;</span>
   context.<span style="color: #660066;">beginPath</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   context.<span style="color: #660066;">arc</span><span style="color: #009900;">&#40;</span>piece.<span style="color: #660066;">center</span>.<span style="color: #660066;">x</span><span style="color: #339933;">,</span> piece.<span style="color: #660066;">center</span>.<span style="color: #660066;">y</span><span style="color: #339933;">,</span> kCircleRadius<span style="color: #339933;">,</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">,</span> Math.<span style="color: #660066;">PI</span> <span style="color: #339933;">*</span> <span style="color: #CC0000;">2</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   context.<span style="color: #660066;">closePath</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   context.<span style="color: #660066;">fill</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>


<p>Finally, we need to compute the updated position of the piece&#8217;s center based on its current position and the acceleration information from the browser:</p>


<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">function</span> computeCenter <span style="color: #009900;">&#40;</span>oldCenter<span style="color: #339933;">,</span> acceleration<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
   newCenter <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span>
   newCenter.<span style="color: #660066;">xShift</span> <span style="color: #339933;">=</span> oldCenter.<span style="color: #660066;">xShift</span> <span style="color: #339933;">*</span> <span style="color: #CC0000;">0.8</span> <span style="color: #339933;">+</span> acceleration.<span style="color: #660066;">x</span> <span style="color: #339933;">*</span> <span style="color: #CC0000;">2.0</span><span style="color: #339933;">;</span>
   newCenter.<span style="color: #660066;">yShift</span> <span style="color: #339933;">=</span> oldCenter.<span style="color: #660066;">yShift</span> <span style="color: #339933;">*</span> <span style="color: #CC0000;">0.8</span> <span style="color: #339933;">+</span> acceleration.<span style="color: #660066;">y</span> <span style="color: #339933;">*</span> <span style="color: #CC0000;">2.0</span><span style="color: #339933;">;</span>
   newCenter.<span style="color: #660066;">x</span> <span style="color: #339933;">=</span> oldCenter.<span style="color: #660066;">x</span> <span style="color: #339933;">+</span> oldCenter.<span style="color: #660066;">xShift</span><span style="color: #339933;">;</span>
   <span style="color: #006600; font-style: italic;">// use *minus* to compute the center's new y</span>
   newCenter.<span style="color: #660066;">y</span> <span style="color: #339933;">=</span> oldCenter.<span style="color: #660066;">y</span> <span style="color: #339933;">-</span> oldCenter.<span style="color: #660066;">yShift</span><span style="color: #339933;">;</span>
   <span style="color: #006600; font-style: italic;">// do not go outside the boundaries of the canvas</span>
   <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>newCenter.<span style="color: #660066;">x</span> <span style="color: #339933;">&lt;</span> kCircleRadius<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      newCenter.<span style="color: #660066;">x</span> <span style="color: #339933;">=</span> kCircleRadius<span style="color: #339933;">;</span>
   <span style="color: #009900;">&#125;</span>
   <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>newCenter.<span style="color: #660066;">x</span> <span style="color: #339933;">&gt;</span> kBoardWidth <span style="color: #339933;">-</span> kCircleRadius<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      newCenter.<span style="color: #660066;">x</span> <span style="color: #339933;">=</span> kBoardWidth <span style="color: #339933;">-</span> kCircleRadius<span style="color: #339933;">;</span>
   <span style="color: #009900;">&#125;</span>
   <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>newCenter.<span style="color: #660066;">y</span> <span style="color: #339933;">&lt;</span> kCircleRadius<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      newCenter.<span style="color: #660066;">y</span> <span style="color: #339933;">=</span> kCircleRadius<span style="color: #339933;">;</span>
   <span style="color: #009900;">&#125;</span>
   <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>newCenter.<span style="color: #660066;">y</span> <span style="color: #339933;">&gt;</span> kBoardHeight <span style="color: #339933;">-</span> kCircleRadius<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      newCenter.<span style="color: #660066;">y</span> <span style="color: #339933;">=</span> kBoardHeight <span style="color: #339933;">-</span> kCircleRadius<span style="color: #339933;">;</span>
   <span style="color: #009900;">&#125;</span>
   <span style="color: #000066; font-weight: bold;">return</span> newCenter<span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>


<p>To smooth the movement and increase the acceleration when the mobile is moved, I applied a low-pass filter:</p>


<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">newCenter.<span style="color: #660066;">xShift</span> <span style="color: #339933;">=</span> oldCenter.<span style="color: #660066;">xShift</span> <span style="color: #339933;">*</span> <span style="color: #CC0000;">0.8</span> <span style="color: #339933;">+</span> acceleration.<span style="color: #660066;">x</span> <span style="color: #339933;">*</span> <span style="color: #CC0000;">2.0</span><span style="color: #339933;">;</span>
newCenter.<span style="color: #660066;">yShift</span> <span style="color: #339933;">=</span> oldCenter.<span style="color: #660066;">yShift</span> <span style="color: #339933;">*</span> <span style="color: #CC0000;">0.8</span> <span style="color: #339933;">+</span> acceleration.<span style="color: #660066;">y</span> <span style="color: #339933;">*</span> <span style="color: #CC0000;">2.0</span><span style="color: #339933;">;</span></pre></div></div>


<p>The rest of the method ensures that the piece will remain in the boundaries of the board.</p>

<h1>screen.css</h1>

<p>Last thing is to make sure that the canvas fills the whole Web page by removing the margin and padding on the <code>body</code> element. This is done through CSS in the <code>screen.css</code> file:</p>


<div class="wp_syntax"><div class="code"><pre class="css" style="font-family:monospace;">body <span style="color: #00AA00;">&#123;</span>
   <span style="color: #000000; font-weight: bold;">margin</span><span style="color: #00AA00;">:</span> <span style="color: #933;">0px</span><span style="color: #00AA00;">;</span>
   <span style="color: #000000; font-weight: bold;">padding</span><span style="color: #00AA00;">:</span> <span style="color: #933;">0px</span><span style="color: #00AA00;">;</span>
<span style="color: #00AA00;">&#125;</span></pre></div></div>


<p>All these files are located in the same directory than <code>server.js</code>.</p>

<h1>Run the example</h1>

<p>Let&#8217;s start the node.js server:</p>


<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ node server.js
HTTP server running at htpp:<span style="color: #000000; font-weight: bold;">//</span>0.0.0.0:<span style="color: #000000;">8080</span></pre></div></div>


<p>Now, from my iPhone, I go to the Web page on <a href="http://blackbook.local:8080">http://blackbook.local:8080</a> (if you go on the Web application from your machine, nothing will happen since the <code>devicemotion</code> event is not available on desktop browsers).</p>

<p>As I have not found a way to prevent the iPhone to change the screen orientation when it is moved, I have locked the iPhone in portrait mode before running the Web application.</p>

<p>Here is a small video of the result:</p>

<p><object width="640" height="385"><param name="movie" value="http://www.youtube.com/v/hqVcLpsO728?fs=1&amp;hl=fr_FR&amp;rel=0&amp;hd=1"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/hqVcLpsO728?fs=1&amp;hl=fr_FR&amp;rel=0&amp;hd=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="385"></embed></object></p>

<p>It&#8217;s not obvious from the video but the camera was recording from above: the iPhone was held horizontally.</p>

<h2>Source Code</h2>

<p>I have pushed the application on <a href="https://github.com/jmesnil/board-node">Github</a>. You can clone it with Git:</p>


<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">git</span> clone <span style="color: #c20cb9; font-weight: bold;">git</span>:<span style="color: #000000; font-weight: bold;">//</span>github.com<span style="color: #000000; font-weight: bold;">/</span>jmesnil<span style="color: #000000; font-weight: bold;">/</span>board-node.git</pre></div></div>


<p>The code is slightly different as I have already started the next iteration but the main idea remains the same.</p>

<h2>Conclusion</h2>

<p>With a few lines of JavaScript on both the client and server sides, it is possible to:</p>

<ul>
<li>use node.js to write a Web server returning files</li>
<li>use the Canvas API to draw things on a Web page</li>
<li>use the DeviceOrientation Event API orientation to have interaction between the device and the Web page </li>
</ul>

<p>Next steps will be to improve the user experience:</p>

<ul>
<li>make the application appear as a standalone application on the iPhone home screen and remove Safari chrome</li>
<li>support offline mode to use the Web application even when the server is not running</li>
</ul>

<h1>Further Reading</h1>

<ul>
<li><a href="http://nodejs.org/">node.js</a></li>
<li><a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html">Canvas API</a> (and its corresponding <a href="http://diveintohtml5.org/canvas.html">&#8220;Dive into HTML5&#8243; chapter</a>)</li>
<li><a href="http://dev.w3.org/geo/api/spec-source-orientation.html">DeviceOrientation Event API</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://jmesnil.net/weblog/2010/11/24/html5-web-application-for-iphone-and-ipad-with-node-js/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>&#9873; &#8220;Read Lature&#8221;: A Web Application to Save Articles and Read Them Later</title>
		<link>http://jmesnil.net/weblog/2009/08/25/read-lature-a-web-application-to-save-articles-and-read-them-later/</link>
		<comments>http://jmesnil.net/weblog/2009/08/25/read-lature-a-web-application-to-save-articles-and-read-them-later/#comments</comments>
		<pubDate>Tue, 25 Aug 2009 16:31:52 +0000</pubDate>
		<dc:creator>Jeff Mesnil</dc:creator>
				<category><![CDATA[java]]></category>
		<category><![CDATA[misc]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://jmesnil.net/weblog/?p=766</guid>
		<description><![CDATA[As an exercice when I learn a new programming language or a new environment, I develop simple applications to get a feel on the language, the platform, its libraries, etc. When I lack ideas for these applications, I redevelop applications that I use. In order to learn Clojure and Google App Engine, I have developed [...]]]></description>
			<content:encoded><![CDATA[<p>As an exercice when I learn a new programming language or a new environment, I develop simple applications to get a feel on the language, the platform, its libraries, etc.  When I lack ideas for these applications, I redevelop applications that I use.</p>

<p>In order to learn <a href="http://clojure.org/">Clojure</a> and <a href="http://appengine.google.com">Google App Engine</a>, I have developed <a href="http://readlature.appspot.com">Read Lature</a>, a web application to save articles and read them later (very similar to <a href="http://www.instapaper.com/u">Instapaper</a>)<a id="fnr1-2009-08-25" href="#fn1-2009-08-25"<sup>1</sup></a>.</p>

<p>The idea is simple: I want to keep reference on articles or blog posts that can be interesting but I don&#8217;t want or don&#8217;t have time to read them immediately.
I do not use bookmarks for that (either using my browser bookmarks or <a href="http://delicious.com/">delicious</a>): my bookmarks are long-lived while I want to keep a reference to these articles only for a short period (and keeping them open in tabs does not scale).</p>

<p>To save articles, you just need to drag a bookmarklet to your bookmarks bar.
When you find a good article or blog post, you click on the bookmarklet to save it. It will be added to Read Lature so that you can read it when you have some time. Once it is read, it is automatically moved to the archive. Articles can also be <em>starred</em> for further readings.</p>

<p>The second way to save article to Read Lature is to use <a href="http://google.com/reader">Google Reader</a>. Setup a custom link and you can send articles to Read Lature directly from Google Reader (as explained in the <a href="http://readlature.appspot.com/public/google-reader.html">instructions</a>).</p>

<p>I mainly use Read Lature to save articles and read them later on my iPhone when I am away:</p>

<p><img src="http://jmesnil.net/weblog/wp-content/uploads/2009/08/photo-200x300.jpg" alt="Reading from the iPhone" title="Reading from the iPhone" width="200" height="300" class="aligncenter size-medium wp-image-765" /></p>

<p>The application is hosted on Google &#8220;Cloud&#8221; and leverages Google accounts for  user credentials.<br />
To try it, go to <a href="http://readlature.appspot.com">Read Lature</a>, login using your Google (or Gmail) account, and follow the instructions.</p>

<p>The application is written using Clojure, <a href="http://github.com/weavejester/compojure/">Compojure</a> and <a href="http://jquery.com/">jQuery</a> and is less than 500 SLOC (75% is Clojure code, the rest is JavaScript).<br />
Read Lature code is released the code under <a href="http://apache.org/licenses/LICENSE-2.0">Apache 2.0 License</a> on <a href="http://github.com/jmesnil/readlature/">GitHub</a>.</p>

<p>I will write later a review of  the book <a href="http://www.pragprog.com/titles/shcloj/programming-clojure">&#8220;Progamming Clojure&#8221;</a>, that I have just finished reading, and some thoughts about Clojure base on my experience with it so far.</p>

<hr />

<ol>
<li><a id="fn1-2009-08-25"></a> So similar in fact that I first named the project <em>Instapapure</em> for &#8220;Instapaper in Clojure&#8221; but I did not like it and renamed it <em>Read Lature</em> (for &#8220;Read Later with Clojure&#8221;). Naming projects is a dark art that I do not master&#8230;&nbsp;<a href="#fnr1-2009-08-25">&#8617;</a></li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://jmesnil.net/weblog/2009/08/25/read-lature-a-web-application-to-save-articles-and-read-them-later/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>&#9873; HTML Glyphs Cheatsheet</title>
		<link>http://jmesnil.net/weblog/2009/08/12/html-glyph-cheatsheet/</link>
		<comments>http://jmesnil.net/weblog/2009/08/12/html-glyph-cheatsheet/#comments</comments>
		<pubDate>Wed, 12 Aug 2009 19:32:38 +0000</pubDate>
		<dc:creator>Jeff Mesnil</dc:creator>
				<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://jmesnil.net/weblog/?p=606</guid>
		<description><![CDATA[I don&#8217;t often need HTML glyphs apart from the usual suspects (&#38;amp; for &#38;, &#38;lt; for &#60;, etc.) but when I need to find a specific one, I always waste time finding it again. I found a good reference which lists all the glyphs. However it is slow to load all the glyphs and the [...]]]></description>
			<content:encoded><![CDATA[<p>I don&#8217;t often need HTML glyphs apart from the usual suspects (&amp;amp; for &amp;, &amp;lt; for &lt;, etc.) but when I need to find a specific one, I always waste time finding it again.</p>

<p>I found a  <a href="http://www.public.asu.edu/~rjansen/glyph_encoding.html">good reference</a> which lists all the glyphs. However it is slow to load all the glyphs and the default font size is too slow to see the details of the glyphs. I need to increase the text size (and reload the whole page) several times to have a better look at the glyphs, making it really slow.</p>

<p>I finally decided to have my own <a href="http://jmesnil.net/weblog/html-glyphs-cheatsheet/">cheatsheet</a> to reference the glyphs I sometimes need (and some I may use one day&#8230;).<br />
I will never waste time again to find the Command key &#8984; (&amp;8984;).</p>
]]></content:encoded>
			<wfw:commentRss>http://jmesnil.net/weblog/2009/08/12/html-glyph-cheatsheet/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

