<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.mikewest.org/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" xml:lang="en">
    <title type="text">Mike West - Posts Only</title>
    <link rel="alternate" type="text/html" href="http://mikewest.org/" />
    
    <id>http://mikewest.org/</id>
    <author>
        <name>Mike West</name>
        <uri>http://mikewest.org/</uri>
        <email>mike@mikewest.org</email>
    </author>

    
    <updated>2011-10-30T00:00:00+02:00</updated>
    
    <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.mikewest.org/just_posts" /><feedburner:info uri="just_posts" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><subtitle type="html">Just the posts, please. None of that linky goodness for me, thanks.</subtitle><link rel="license" type="text/html" href="http://creativecommons.org/licenses/by-nc-nd/3.0/" /><entry>
        <title type="text">Secure Chrome extensions: Content Security Policy</title>
        <link rel="alternate" href="http://feeds.mikewest.org/~r/just_posts/~3/fS-z-MkXOHM/secure-chrome-extensions-content-security-policy" />
        <id>http://mikewest.org/2011/10/secure-chrome-extensions-content-security-policy</id>
        <updated>2011-10-30T00:00:00+02:00</updated>
        <published>2011-10-30T00:00:00+02:00</published>
        <content type="html">
&lt;p&gt;After reading the &lt;a href="http://mikewest.org/2011/10/content-security-policy-a-primer"&gt;Content Security Policy primer&lt;/a&gt; that I wrote earlier this month, you should have a good idea of the benefits that CSP can offer a website developer. Whitelisting known-good resource origins, refusing to execute potentially dangerous inline JavaScript, and banning the use of &lt;code&gt;eval&lt;/code&gt; are all effective mechanisms for mitigating cross-site scripting attacks. Implementing and enforcing such policies is simply a good idea.&lt;/p&gt;

&lt;p&gt;Recognizing these advantages, Chrome&amp;rsquo;s engineers have extended CSP&amp;rsquo;s reach beyond websites into other areas of the browser where policies can serve as a defense against attacks. Most notably, policies can be applied to &lt;a href="http://code.google.com/chrome/extensions/apps.html"&gt;packaged applications&lt;/a&gt; and &lt;a href="http://code.google.com/chrome/extensions/index.html"&gt;extensions&lt;/a&gt;. Both can make use of Chrome&amp;rsquo;s powerful and modular set of &lt;a href="http://code.google.com/chrome/extensions/api_index.html"&gt;extension APIs&lt;/a&gt;, which give developers capabilities above and beyond what it makes sense for the web platform to offer normal websites. To whatever extent possible, therefore, developers need to ensure that those additional capabilities aren&amp;rsquo;t leaked out to the broader web. Content Security Policies mitigate this risk by helping developers ensure that the only code that runs with elevated privileges is their own.&lt;/p&gt;

&lt;p&gt;Defining policies for an extension is quite straightforward, and we&amp;rsquo;re working to add them to all the sample extensions in the Chromium project. Walking through one of these samples together should give you a good idea of how it all works.&lt;/p&gt;

&lt;h2 id="implementation"&gt;Implementation&lt;/h2&gt;

&lt;p&gt;The &lt;a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/extensions/mappy/"&gt;Mappy&lt;/a&gt; sample extension injects a content script into every page a user visits, searches the page for addresses, and passes them back to the extension so that a map can be displayed in the extension&amp;rsquo;s popup. This is exactly the sort of dangerous scenario in which we need to worry about malicious websites exploiting the extension&amp;rsquo;s permissions, perhaps by cleverly embedding JavaScript into the address which might then be executed if we&amp;rsquo;re not careful when it&amp;rsquo;s passed back to the extension&amp;rsquo;s context. A content security policy is absolutely necessary.&lt;/p&gt;

&lt;p&gt;The first step towards securing the extension is to define exactly which resources it needs to load. Mappy&amp;rsquo;s needs are pretty simple: it loads CSS and JavaScript from the local extension package, connects to &lt;code&gt;https://maps.googleapis.com&lt;/code&gt; to geolocate an address, and finally displays a static map image from &lt;code&gt;https://maps.google.com&lt;/code&gt;.&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" rel="footnote"&gt;1&lt;/a&gt;&lt;/sup&gt; A sufficiently paranoid policy would use a &lt;code&gt;default-src&lt;/code&gt; policy directive to deny access to &lt;em&gt;everything&lt;/em&gt; by default, and then specifically whitelist only those resources via &lt;code&gt;style-src&lt;/code&gt;, &lt;code&gt;script-src&lt;/code&gt;, &lt;code&gt;connect-src&lt;/code&gt;, and &lt;code&gt;img-src&lt;/code&gt; directives. I&amp;rsquo;ve annotated Mappy&amp;rsquo;s definition (which does exactly that) below:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# Block everything, then whitelist from there.
default-src 'none';

# Accept CSS from the extension's package.
style-src 'self';

# Accept JavaScript from the extension's package.
script-src 'self';

# Allow XHR connections over HTTPS to Google Maps APIs.
connect-src https://maps.googleapis.com; 

# Allow images from Google Maps to load over HTTPS.
img-src https://maps.google.com;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For normal websites, content security policies are delivered via an HTTP header. Chrome extensions use the same policy syntax, but define policies in the package&amp;rsquo;s &lt;a href="http://code.google.com/chrome/extensions/manifest.html"&gt;manifest JSON&lt;/a&gt; as a simple key-value pair. Simply take the policy you&amp;rsquo;ve defined, and add it to &lt;code&gt;manifest.json&lt;/code&gt;: you can see how Mappy&amp;rsquo;s CSP is defined by visiting &lt;a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/extensions/mappy/manifest.json?view=markup"&gt;Chromium&amp;rsquo;s source repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With the &lt;a href="http://codereview.chromium.org/8311007/diff/9001/chrome/common/extensions/docs/examples/extensions/mappy/manifest.json"&gt;manifest changes&lt;/a&gt; in place, the next step is to take a close look at the extension&amp;rsquo;s code to make sure we comply with the new restrictions we&amp;rsquo;re defining. Generally speaking, this means ensuring that CSS and JavaScript is moved out from the extension&amp;rsquo;s background page and popup into separate files. Most of the time, this is a straight copy/paste job, simply moving code wholesale from an inline &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; block into a &lt;code&gt;background.js&lt;/code&gt; file. For Mappy, the &lt;code&gt;background.html&lt;/code&gt; change is &lt;a href="http://codereview.chromium.org/8311007/diff/9001/chrome/common/extensions/docs/examples/extensions/mappy/background.html"&gt;captured in this diff&lt;/a&gt;, and the &lt;code&gt;popup.html&lt;/code&gt; change is &lt;a href="http://codereview.chromium.org/8311007/diff/9001/chrome/common/extensions/docs/examples/extensions/mappy/popup.html"&gt;visible in this diff&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;That&amp;rsquo;s it! Once you&amp;rsquo;ve defined a policy, and adjusted your extension&amp;rsquo;s code to match it, just test the extension locally, bump the version number, and push the update to your users. They&amp;rsquo;ll be more secure, and the world will be a (slightly) better place.&lt;/p&gt;

&lt;h2 id="next-steps"&gt;Next Steps&lt;/h2&gt;

&lt;p&gt;Your task is clear: update the extensions you own! It&amp;rsquo;s very straightforward work, and a real win for security. Content Security Policy support was added to Mappy in &lt;a href="http://crrev.com/106043"&gt;revision 106043&lt;/a&gt;; take a look at &lt;a href="http://codereview.chromium.org/8311007"&gt;the code review&lt;/a&gt; to get some implementation ideas for your own extensions.&lt;/p&gt;

&lt;p&gt;At the same time you&amp;rsquo;re working on your extensions, the Chromium team is working to set a better example by updating the 70 or so sample extensions and applications that Chromium makes available to include the new &lt;code&gt;content_security_policy&lt;/code&gt; manifest entry. It&amp;rsquo;s easy work &amp;ndash; following the steps listed above takes less than half-hour on average &amp;ndash; but 70 is a big number, so we&amp;rsquo;re a bit behind. You can follow our progress on that effort at &lt;a href="http://crbug.com/92644"&gt;crbug.com/92644&lt;/a&gt;: star the bug if you&amp;rsquo;re interested in updates, and pitch in if you&amp;rsquo;re interested! &lt;a href="http://www.chromium.org/developers/contributing-code"&gt;Patches are welcome&lt;/a&gt;: just send any code reviews my way (&lt;code&gt;mkwst@chromium.org&lt;/code&gt;).&lt;/p&gt;

&lt;div class="footnotes"&gt;
  &lt;ol&gt;
    &lt;li id="fn:1"&gt;
      &lt;p&gt;Whenever possible, load resources over HTTPS rather than unencrypted HTTP. This has a number of benefits for privacy and security, most importantly (for our current context) a guarantee that the code you&amp;rsquo;re loading hasn&amp;rsquo;t been modified since it left the server. Active network attackers need to do a &lt;em&gt;lot&lt;/em&gt; more work to inject code into a HTTPS stream, wheres it&amp;rsquo;s a trivial task via HTTP.&lt;a href="#fnref:1" rev="footnote"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;

&lt;img src="http://feeds.feedburner.com/~r/just_posts/~4/fS-z-MkXOHM" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://mikewest.org/2011/10/secure-chrome-extensions-content-security-policy</feedburner:origLink></entry>

    
    <entry>
        <title type="text">Content Security Policy: A Primer</title>
        <link rel="alternate" href="http://feeds.mikewest.org/~r/just_posts/~3/c3cLBxLjJ4c/content-security-policy-a-primer" />
        <id>http://mikewest.org/2011/10/content-security-policy-a-primer</id>
        <updated>2011-10-11T00:00:00+02:00</updated>
        <published>2011-10-11T00:00:00+02:00</published>
        <content type="html">
&lt;blockquote&gt;
  &lt;p&gt;The browser is not a safe programming environment. It is
inherently insecure. &amp;ndash; Douglas Crockford, &lt;a href="http://www.slideshare.net/webdirections/douglas-crockford-ajax-security-presentation"&gt;&amp;ldquo;Ajax Security&amp;rdquo;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The web&amp;rsquo;s security model is fundamentally broken, and has been since the beginning. Browsers trust the code they receive from a website, so each chunk of JavaScript that executes on a page runs with access to the entire origin&amp;rsquo;s data. Cross-site scripting (XSS) attacks exploit this trust, injecting malicious code and other resources into a site in a wide variety of ways. At best, sites are defaced. At worst, user session data is compromised and leaked to untrusted third-parties.&lt;/p&gt;

&lt;p&gt;It is, of course, possible to completely eliminate this class of attacks by properly escaping every bit of data that makes it onto a site. A brief glance back at the web&amp;rsquo;s history shows that this defense is unlikely to be effective; it&amp;rsquo;s simply a tough problem, given the convoluted set of escaping rules in various HTML contexts, differences in cross-browser implementation, and browser bugs (like &lt;a href="http://en.wikipedia.org/wiki/UTF-7#security"&gt;UTF-7 support&lt;/a&gt;). Even with our solid, modern understanding of the issue, and a variety of secure frameworks, it remains trivial to accidentally create a hole, and one hole is all it takes.&lt;/p&gt;

&lt;p&gt;Content Security Policy (CSP) is a relatively new addition to the web platform that promises to mitigate the risk of XSS attacks by giving administrators fine-grained control over the data and code that ought to be allowed to run on their site. The feature boils down to a whitelisting mechanism for images, script, style, and a variety of other resource types. A site declares an acceptable list of origins for each data type it cares about via a straightforward HTTP header, and browsers that support the feature simply refuse to load resources that aren&amp;rsquo;t listed, thereby ensuring that user data can&amp;rsquo;t be leaked to third-parties. Browsers that don&amp;rsquo;t support the feature simply ignore the header, and proceed as per usual.&lt;/p&gt;

&lt;p&gt;Though the feature is still very much bleeding-edge, implementations of &lt;a href="https://dvcs.w3.org/hg/content-security-policy/raw-file/tip/csp-specification.dev.html"&gt;the draft specification&lt;/a&gt; exist in both Firefox 4+ and Chrome 16+, and the W3C has &lt;a href="http://www.w3.org/2011/07/security-activity.html"&gt;proposed&lt;/a&gt; a &lt;a href="http://www.w3.org/2011/08/appsecwg-charter.html"&gt;Web Application Security Working Group&lt;/a&gt; which includes CSP as a top-level deliverable. All that in mind, CSP is practically available right now, has no negative effects on browsers that don&amp;rsquo;t support it, and is already being used successfully by some pretty high-profile sites (like &lt;a href="http://engineering.twitter.com/2011/03/improving-browser-security-with-csp.html"&gt;Twitter&lt;/a&gt;&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" rel="footnote"&gt;1&lt;/a&gt;&lt;/sup&gt;). The implementations are being iterated upon, and things are still a bit fast and loose, but getting involved now is certainly something I&amp;rsquo;d recommend.&lt;/p&gt;

&lt;h2 id="mkwsts-policies"&gt;mkw.st&amp;rsquo;s Policies&lt;/h2&gt;

&lt;p&gt;On &lt;a href="https://mkw.st/"&gt;mkw.st&lt;/a&gt;, I&amp;rsquo;m using one stylesheet hosted on &lt;code&gt;mkw.st&lt;/code&gt;, one of Google&amp;rsquo;s web fonts, and a few inlined &lt;code&gt;data:&lt;/code&gt; images. I&amp;rsquo;d like to ensure that that remains the case, and that I don&amp;rsquo;t accidentally load script from my friends at &lt;code&gt;evil.com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;ve configured my server to generate the following headers when loading the site:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ curl -Ik https://mkw.st/
HTTP/1.1 200 OK
Server: nginx/1.0.8
Date: Sat, 08 Oct 2011 10:38:40 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 7940
Last-Modified: Sat, 08 Oct 2011 05:07:16 GMT
Connection: keep-alive
Vary: Accept-Encoding
Strict-Transport-Security: max-age=604800
X-WebKit-CSP: default-src 'self'; img-src 'self' data:; font-src https://themes.googleusercontent.com;
X-Content-Security-Policy: default-src 'self'; img-src 'self' data:; font-src https://themes.googleusercontent.com;
Accept-Ranges: bytes
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The interesting bits are &lt;code&gt;X-Content-Security-Policy&lt;/code&gt; and &lt;code&gt;X-WebKit-CSP&lt;/code&gt;&lt;sup id="fnref:2"&gt;&lt;a href="#fn:2" rel="footnote"&gt;2&lt;/a&gt;&lt;/sup&gt;, both of which contain a simple, semicolon-separated list of policy directives. Each directive consists of a type followed by a set of one or more &amp;ldquo;source expressions&amp;rdquo; that define the policy&amp;rsquo;s limitations. These expressions generally consist of scheme/host/port groupings, but can also contain wildcards and special keywords like &lt;code&gt;'self'&lt;/code&gt; (which expands to the current site&amp;rsquo;s origin) and &lt;code&gt;'none'&lt;/code&gt; (which ought to be self-explanatory). Let&amp;rsquo;s look at each in turn.&lt;/p&gt;

&lt;p&gt;The first directive is of type &lt;code&gt;default-src&lt;/code&gt;, which specifies a catch-all for content types that aren&amp;rsquo;t explicitly listed. I haven&amp;rsquo;t created a policy for objects (&lt;code&gt;object-src&lt;/code&gt;), for example, so any request for video or Flash content would use the policy specified here. In this case, I&amp;rsquo;m specifying a single source: &lt;code&gt;'self'&lt;/code&gt;&lt;sup id="fnref:3"&gt;&lt;a href="#fn:3" rel="footnote"&gt;3&lt;/a&gt;&lt;/sup&gt;. This means that resources that hit &lt;code&gt;default-src&lt;/code&gt; can only be loaded from the same origin as the page itself. You may see references to &lt;code&gt;allow&lt;/code&gt; in older CSP documentation: &lt;code&gt;default-src&lt;/code&gt; replaces that keyword.&lt;/p&gt;

&lt;p&gt;You likely won&amp;rsquo;t be shocked to learn that the next directive,&lt;code&gt;img-src&lt;/code&gt;, whitelists sources for image resources. Here, images are limited to &lt;code&gt;data:&lt;/code&gt; URLs, and to &lt;code&gt;'self'&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Equally unsurprisingly, the directive of type &lt;code&gt;font-src&lt;/code&gt; allows the site to load font resources from &lt;code&gt;https://themes.googleusercontent.com/&lt;/code&gt;, which is taken quite literally and exclusively. Fonts can &lt;em&gt;only&lt;/em&gt; be loaded from &lt;code&gt;themes.googleusercontent.com&lt;/code&gt;, and &lt;em&gt;only&lt;/em&gt; over HTTPS. Any request for a font from a different host or scheme would throw an error. It&amp;rsquo;s important to note here that the value of the &lt;code&gt;font-src&lt;/code&gt; overrides &lt;code&gt;default-src&lt;/code&gt; completely. They aren&amp;rsquo;t merged: I won&amp;rsquo;t be able to load fonts from &lt;code&gt;'self'&lt;/code&gt; unless I explicitly add it to &lt;code&gt;font-src&lt;/code&gt;&amp;rsquo;s definition.&lt;/p&gt;

&lt;h2 id="nothings-free"&gt;Nothing&amp;rsquo;s free.&lt;/h2&gt;

&lt;p&gt;In order to function properly, Content Security Policy imposes a &lt;a href="http://people.mozilla.com/~bsterne/content-security-policy/details.html#restrictions"&gt;few restrictions&lt;/a&gt; on sites that make use of it. Two in particular are worth calling out here.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;CSP enforces a strict separation of behavior and semantics by refusing to execute inline script, and an equally strict separation of presentation and semantics by refusing to apply inline styles. This follows directly in line with the general recommendation of the web standards community, and allows CSP to clearly identify the source of each piece of data on a page. This identification is essential, as without it the whitelisting mechanism is ineffective. In addition, banning inline script and style substantially reduces the effect of cross-site scripting attacks that rely on JavaScript or CSS &lt;a href="http://google-gruyere.appspot.com/part2#2__reflected_xss"&gt;reflection&lt;/a&gt;: attackers will be forced to compromise a whitelisted resource, which is a much higher bar.&lt;/p&gt;

    &lt;p&gt;It&amp;rsquo;s fairly obvious that this restriction will block execution of code contained within &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; blocks, but also note that it prevents event handlers from being written inline (&lt;code&gt;&amp;lt;a … onclick="JAVASCRIPT"&amp;gt;&lt;/code&gt; ought to be rewritten to use &lt;code&gt;addEventListener(…)&lt;/code&gt;). Likewise, &lt;code&gt;javascript:&lt;/code&gt; URLs won&amp;rsquo;t work.&lt;/p&gt;

    &lt;p&gt;It&amp;rsquo;s also the case that &lt;code&gt;data:&lt;/code&gt; URLs are blocked by default, as they can contain arbitrary content that can&amp;rsquo;t be easily verified as being safe, or as really being intentionally written by your server. If you&amp;rsquo;d like to allow &lt;code&gt;data:&lt;/code&gt; URLs, you&amp;rsquo;ll have to do so on a type-by-type basis. See above, for example, where I&amp;rsquo;m explicitly allowing &lt;code&gt;data:&lt;/code&gt; URLs for image resources, but not for any other resource type.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Relatedly, raw strings will not be converted to code. This means that &lt;code&gt;eval&lt;/code&gt; is right out, as are a variety of other &lt;code&gt;eval&lt;/code&gt;-like mechanisms (&lt;code&gt;setTimeout&lt;/code&gt; with a string argument, &lt;code&gt;new Function(…)&lt;/code&gt;, and so on). Since &lt;a href="http://www.jslint.com/lint.html#evil"&gt;&lt;code&gt;eval&lt;/code&gt; is evil&lt;/a&gt;, this isn&amp;rsquo;t a particularly onerous restriction, but it does mean that you&amp;rsquo;ll need to parse JSON content without simply executing it, either with something like &lt;a href="http://www.json.org/js.html"&gt;json.js&lt;/a&gt; or with a built-in JSON object.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id="further-reading"&gt;Further Reading&lt;/h2&gt;

&lt;p&gt;After this introduction to the feature, I hope you&amp;rsquo;re interested enough to want to play around a bit with the headers on your own sites.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Mozilla&amp;rsquo;s developer network has a &lt;a href="https://developer.mozilla.org/en/Introducing_Content_Security_Policy"&gt;great series of articles&lt;/a&gt; that go into a bit more depth, and outline features of CSP that I haven&amp;rsquo;t mentioned at all (&lt;a href="https://developer.mozilla.org/en/Security/CSP/Using_CSP_violation_reports"&gt;violation reporting&lt;/a&gt;, for instance). &lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The list of resource types that Content Security Policy supports is extensive. This example touched on supports images, fonts, and objects, and &lt;a href="https://dvcs.w3.org/hg/content-security-policy/raw-file/tip/csp-specification.dev.html#directives"&gt;a complete list can be found in the specification&lt;/a&gt;. In general, the &lt;a href="https://dvcs.w3.org/hg/content-security-policy/raw-file/tip/csp-specification.dev.html"&gt;draft specification&lt;/a&gt; is quite readable, and is the canonical resource for any question you might have.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;div class="footnotes"&gt;
  &lt;ol&gt;
    &lt;li id="fn:1"&gt;
      &lt;p&gt;Though, since CSP is a bit broken in Chrome 15 and below, Twitter is only serving the header to Firefox (&lt;a href="https://twitter.com/kurrik/status/123837358163496960"&gt;Hi, Arne!&lt;/a&gt;):&lt;/p&gt;

      &lt;pre&gt;&lt;code&gt;$ curl -I -H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:7.0) Gecko/20100101 Firefox/7.0" mobile.twitter.com
HTTP/1.1 200 OK
Date: Tue, 11 Oct 2011 19:09:28 GMT
Server: hi
Status: 200 OK
ETag: "6f812aa05ca092e34fef322867230b3b"
X-Frame-Options: SAMEORIGIN
X-Content-Security-Policy: allow 'self'; img-src *.twitter.com *.twimg.com maps.google.com data:; media-src *.twitter.com *.twimg.com; style-src *.twitter.com *.twimg.com; frame-ancestors *.twitter.com; script-src *.twitter.com *.twimg.com api-secure.recaptcha.net; report-uri http://mobile.twitter.com/csp_violation_report
Content-Language: en
Content-Type: text/html; charset=utf-8
X-Runtime: 6
X-XSS-Protection: 1; mode=block
Content-Length: 3226
Pragma: no-cache
Expires: Mon, 01 Jan 1990 00:00:00 GMT
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Set-Cookie: k=92.230.68.58.1318360167849178; path=/; expires=Tue, 18-Oct-11 19:09:27 GMT; domain=.twitter.com
Set-Cookie: _mobile_sess=BAh7BzoQX2NzcmZfdG9rZW4iGTI4ODY1MDBjZTMxMTFjZmMyOTNmOg9zZXNzaW9uX2lkIiUwYTEwNjE1YjlkNDkzZmFiYzRhMWM4NWI3NTkyNGVhMg%3D%3D--a55f94a4b138aca8618b0bfbaf45bbe96f61450b; path=/; expires=Mon, 05-Dec-2011 22:22:00 GMT
Vary: Accept-Encoding
Connection: close
&lt;/code&gt;&lt;/pre&gt;
      &lt;p&gt;&lt;a href="#fnref:1" rev="footnote"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:2"&gt;
      &lt;p&gt;Firefox is &lt;a href="http://blog.mozilla.com/security/2011/03/22/creating-a-safer-web-with-content-security-policy/"&gt;confident enough&lt;/a&gt; in the draft spec to use the canonical header, WebKit (and therefore Chrome) are a little more cautious, and have prefixed the header just in case: the details are the same. Both teams are working from the same spec, and both are pretty much feature complete. To follow their progress, CC yourself on either &lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=663566"&gt;Bugzilla #663566&lt;/a&gt;, or &lt;a href="https://bugs.webkit.org/show_bug.cgi?id=53572"&gt;WebKit #53572&lt;/a&gt;.&lt;a href="#fnref:2" rev="footnote"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:3"&gt;
      &lt;p&gt;Note the single-quotes around &lt;code&gt;'self'&lt;/code&gt; and &lt;code&gt;'none'&lt;/code&gt;. These are required. Without them, the policy would refer to a server with a hostname of &lt;code&gt;self&lt;/code&gt; or &lt;code&gt;none&lt;/code&gt;, which almost certainly isn&amp;rsquo;t what you mean.&lt;a href="#fnref:3" rev="footnote"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;

&lt;img src="http://feeds.feedburner.com/~r/just_posts/~4/c3cLBxLjJ4c" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://mikewest.org/2011/10/content-security-policy-a-primer</feedburner:origLink></entry>

    
    <entry>
        <title type="text">HTTP Strict Transport Security and You</title>
        <link rel="alternate" href="http://feeds.mikewest.org/~r/just_posts/~3/z-4KSkdTSiM/http-strict-transport-security-and-you" />
        <id>http://mikewest.org/2011/10/http-strict-transport-security-and-you</id>
        <updated>2011-10-07T00:00:00+02:00</updated>
        <published>2011-10-07T00:00:00+02:00</published>
        <content type="html">
&lt;p&gt;With a simple Wi-Fi packet-sniffer, intercepting login cookies over the air is far easier than it ought to be. &lt;a href="http://codebutler.github.com/firesheep/"&gt;Firesheep&lt;/a&gt; demonstrated this vulnerability definitively, showing the public exactly how trivial it is to hijack unencrypted HTTP sessions. So, we learned an important lesson: running HTTPS on your servers mitigates a large chunk of risk, as encrypting the traffic between your site and its users prevents attackers from grabbing cookies, and thus from hijacking a user&amp;rsquo;s session. Encryption also ensures that your content is delivered without modification, which reduces the ability of man-in-the-middle attackers to intercept your users&amp;rsquo; traffic when they&amp;rsquo;re using untrustworthy networks. To whatever extent possible, you should use HTTPS, and ensure that you force encryption for important cookies by marking them as &lt;code&gt;Secure&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Unfortunately, this isn&amp;rsquo;t a complete solution. Users generally don&amp;rsquo;t type &lt;code&gt;https://example.com/&lt;/code&gt; into their browser&amp;rsquo;s address bar. They generally either type &lt;code&gt;example.com&lt;/code&gt; or &lt;code&gt;http://example.com/&lt;/code&gt;, and you&amp;rsquo;re going to have a hard time reminding them to consistently use &lt;code&gt;https&lt;/code&gt; when visiting your site. You can redirect users from HTTP to HTTPS, but that leaves a window of opportunity for attackers: your request to the HTTP site is unencrypted, and potentially vulnerable to attack &lt;em&gt;before&lt;/em&gt; you can be redirected. It would be significantly safer if you could avoid that HTTP request. This is the problem that &lt;a href="http://tools.ietf.org/html/draft-ietf-websec-strict-transport-sec-02"&gt;HTTP Strict Transport Security (HSTS)&lt;/a&gt;&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" rel="footnote"&gt;1&lt;/a&gt;&lt;/sup&gt; is meant to address.&lt;/p&gt;

&lt;p&gt;Adding a &lt;code&gt;Strict-Transport-Security&lt;/code&gt; header to your server&amp;rsquo;s HTTPS responses will inform browsers that your website should &lt;em&gt;only&lt;/em&gt; be accessed via HTTPS. Normal HTTP connections will be rewritten client-side, &lt;em&gt;before&lt;/em&gt; any network traffic is generated. Sending the following header:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Strict-Transport-Security: max-age=31556926; includeSubDomains
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;would instruct a browser that supported the draft standard that it shouldn&amp;rsquo;t touch your site (or any of its subdomains) over HTTP for a year. This substantially reduces the surface exposed to attack: as long as the very first HTTP request went through correctly, your users will never use an insecure connection to your website again, regardless of what they type in the address bar.&lt;/p&gt;

&lt;p&gt;You will need to ensure that you can actually &lt;em&gt;serve&lt;/em&gt; HTTPS responses for every request (on any port) to your host, however, as HTTP simply won&amp;rsquo;t be an option anymore. This is a Good Thing™, even if it might mean a little work for you up front.&lt;/p&gt;

&lt;p&gt;None of this is new (just new to me), so browser support is already relatively good: HSTS is supported in &lt;a href="http://hacks.mozilla.org/2010/08/firefox-4-http-strict-transport-security-force-https/"&gt;Firefox 4+&lt;/a&gt;, and Chrome&lt;sup id="fnref:2"&gt;&lt;a href="#fn:2" rel="footnote"&gt;2&lt;/a&gt;&lt;/sup&gt;. &lt;a href="http://my.opera.com/community/forums/topic.dml?id=838822&amp;amp;t=1317981165&amp;amp;page=1#comment10176262"&gt;Opera appears to be waiting&lt;/a&gt; for &lt;a href="http://trac.tools.ietf.org/wg/websec/trac/report/1?asc=1&amp;amp;sort=ticket"&gt;issues open against the draft standard&lt;/a&gt; to be resolved, and for the draft to move to RFC status. Looking at the list, I don&amp;rsquo;t see any significant upcoming changes to the header structure: I&amp;rsquo;d recommend implementing it for your sites now.&lt;/p&gt;

&lt;h2 id="sound-interesting"&gt;Sound interesting?&lt;/h2&gt;

&lt;p&gt;As an example, I&amp;rsquo;ve just implemented this for &lt;a href="https://mkw.st/"&gt;mkw.st&lt;/a&gt; (where I&amp;rsquo;ll likely be moving this site at some point in the relatively near future). It took about a half-hour, all told, and most of that was waiting for the certificate to be mailed to me. Here&amp;rsquo;s what I needed to do to set things up:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;I generated a certificate request on my server, which also involved creating a new private key. Both were trivial, and &lt;a href="https://knowledge.rapidssl.com/support/ssl-certificate-support/index?page=content&amp;amp;id=SO6506"&gt;RapidSSL&amp;rsquo;s detailed walkthrough&lt;/a&gt; was helpful.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Using the newly generated CSR, I purchased a certificate via &lt;a href="http://www.cheapssls.com/"&gt;CheapSSLs&lt;/a&gt;. They seem a bit… well… cheap, so I&amp;rsquo;m not sure I&amp;rsquo;d recommend them for a high-risk site. For my not particularly valuable site, however, they&amp;rsquo;re brilliant. A 3-year cert (&lt;a href="https://www.cheapssls.com/geotrust-ssl-certificates/rapidssl.html"&gt;from RapidSSL&lt;/a&gt;) was $27 (paid via PayPal), and showed up in my inbox within 20 minutes of purchase.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;I configured my server to use the certificate. For Nginx, this just meant recompiling the server with SSL support, and adding a new server definition that listened on port 443, and had reference to both the private key and certificate generated above. &lt;a href="http://wiki.nginx.org/HttpSslModule"&gt;Nginx&amp;rsquo;s documentation&lt;/a&gt; is better than I remembered it being.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For a single-server site like mine, this is a piece of cake, and certainly worth playing around with.&lt;/p&gt;

&lt;div class="footnotes"&gt;
  &lt;ol&gt;
    &lt;li id="fn:1"&gt;
      &lt;p&gt;Adam Barth co-wrote the HSTS spec, and he&amp;rsquo;s coincidentally just started a cleverly titled web security blog that I suspect will be very much worth reading: &lt;a href="http://www.schemehostport.com/"&gt;Scheme/Host/Port&lt;/a&gt;&lt;a href="#fnref:1" rev="footnote"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:2"&gt;
      &lt;p&gt;Chrome actually attempts to avoid even the initial one-time HTTP request for websites that have requested extra protection. Sites like PayPal and Twitter are hard-coded as requesting HSTS (the complete list is &lt;a href="http://codesearch.google.com/codesearch#OAMlx_jo-ck/src/net/base/transport_security_state.cc&amp;amp;exact_package=chromium&amp;amp;q=kPreloadedSTS"&gt;visible in &lt;code&gt;net/base/transport_security_state.cc&lt;/code&gt;&lt;/a&gt;).&lt;a href="#fnref:2" rev="footnote"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;

&lt;img src="http://feeds.feedburner.com/~r/just_posts/~4/z-4KSkdTSiM" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://mikewest.org/2011/10/http-strict-transport-security-and-you</feedburner:origLink></entry>

    
    <entry>
        <title type="text">Chrome Privacy</title>
        <link rel="alternate" href="http://feeds.mikewest.org/~r/just_posts/~3/mxeIP76jUH4/chrome-privacy" />
        <id>http://mikewest.org/2011/09/chrome-privacy</id>
        <updated>2011-09-24T00:00:00+02:00</updated>
        <published>2011-09-24T00:00:00+02:00</published>
        <content type="html">
&lt;p&gt;Dave Winer ends an &lt;a href="http://scripting.com/stories/2011/09/24/facebookIsScaringMe.html"&gt;otherwise quite reasonable piece&lt;/a&gt; about his concern at
Facebook&amp;rsquo;s &amp;ldquo;frictionless sharing&amp;rdquo; with a non sequitur attack on Chrome for,
as far as I can tell, nothing it&amp;rsquo;s actually doing:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;One more thing. Facebook doesn&amp;rsquo;t have a web browser, yet, but
Google does. It may not be possible to opt-out of Google&amp;rsquo;s 
identity system and all the information gathering it does, if
you&amp;rsquo;re a Chrome user.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="http://brooksreview.net/2011/09/facebook-winer/"&gt;Ben Brooks picked up on that&lt;/a&gt;, adding:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Read Winer’s take on this, it’s pretty creepy of Facebook — 
what’s more scary is the possibility of Google doing this to 
Chrome users.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A direct response to this sort of speculation about Chrome&amp;rsquo;s &lt;em&gt;potential&lt;/em&gt; for
evil, slipped in as a conclusion to a discussion about an unrelated company
&lt;em&gt;being&lt;/em&gt; evil, is difficult, so let me step back a bit. Chrome founded a privacy team
here in Munich back around the release of Chrome 4. I&amp;rsquo;m proud to be a small
part of this clever group of developers who care about making Chrome&amp;rsquo;s use of
data transparent, and giving you control over how it&amp;rsquo;s used to whatever extent
possible. We build APIs that enable privacy-relevant extensions and apps to
fine-tune a browser with an already good set of privacy features, and review
features built by other teams for potential impact on user&amp;rsquo;s private
information. I&amp;rsquo;m biased, but I think we do a decent job.&lt;/p&gt;

&lt;p&gt;So, to Dave, Ben, and everyone else: If you see Chrome doing something you
don&amp;rsquo;t like with your information, or you have specific questions about some
feature or another, send an email to the team at &lt;a href="&amp;#109;&amp;#097;&amp;#105;&amp;#108;&amp;#116;&amp;#111;:&amp;#112;&amp;#114;&amp;#105;&amp;#118;&amp;#097;&amp;#099;&amp;#121;&amp;#064;&amp;#099;&amp;#104;&amp;#114;&amp;#111;&amp;#109;&amp;#105;&amp;#117;&amp;#109;&amp;#046;&amp;#111;&amp;#114;&amp;#103;"&gt;&amp;#112;&amp;#114;&amp;#105;&amp;#118;&amp;#097;&amp;#099;&amp;#121;&amp;#064;&amp;#099;&amp;#104;&amp;#114;&amp;#111;&amp;#109;&amp;#105;&amp;#117;&amp;#109;&amp;#046;&amp;#111;&amp;#114;&amp;#103;&lt;/a&gt;, or
to me directly, &lt;a href="&amp;#109;&amp;#097;&amp;#105;&amp;#108;&amp;#116;&amp;#111;:&amp;#109;&amp;#107;&amp;#119;&amp;#115;&amp;#116;&amp;#064;&amp;#099;&amp;#104;&amp;#114;&amp;#111;&amp;#109;&amp;#105;&amp;#117;&amp;#109;&amp;#046;&amp;#111;&amp;#114;&amp;#103;"&gt;&amp;#109;&amp;#107;&amp;#119;&amp;#115;&amp;#116;&amp;#064;&amp;#099;&amp;#104;&amp;#114;&amp;#111;&amp;#109;&amp;#105;&amp;#117;&amp;#109;&amp;#046;&amp;#111;&amp;#114;&amp;#103;&lt;/a&gt;. You can also file a bug on the public
tracker at &lt;a href="http://new.crbug.com/"&gt;new.crbug.com&lt;/a&gt; and mail me the bug ID. I&amp;rsquo;ll make sure it gets
triaged into the right team.&lt;/p&gt;

&lt;p&gt;With that in mind, here&amp;rsquo;s a direct answer to what I think is being criticized:
The browser doesn&amp;rsquo;t secretly send information about your browsing habits to
Google, nor will it. The feature that comes closest is Sync, which is a)
opt-in, b) encrypted locally before being sent to Google, optionally with a
password separate from your Google account.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Update&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href="http://news.ycombinator.com/item?id=3034155"&gt;Some good discussion is taking place on Hacker News&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;I&amp;rsquo;ve removed an unintentional &lt;a href="http://en.wikipedia.org/wiki/Ad_hominem"&gt;ad hom&lt;/a&gt; that was personally
inflammatory: Sorry Dave, I honestly didn&amp;rsquo;t mean to offend you, just to argue
with you. The focus of my frustration is both the suggestion that Chrome may
at some point in the future start being evil, and the way it was casually
slipped as a conclusion into a discussion of an unrelated company arguably
&lt;em&gt;being&lt;/em&gt; evil. I hope that remains clear. This article&amp;rsquo;s history is &lt;a href="https://github.com/mikewest/mgc/commits/master/mikewest.org/2011/2011-09-24-chrome-privacy.markdown"&gt;available
on GitHub&lt;/a&gt;, so the edits I&amp;rsquo;ve made remain transparent.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;


&lt;img src="http://feeds.feedburner.com/~r/just_posts/~4/mxeIP76jUH4" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://mikewest.org/2011/09/chrome-privacy</feedburner:origLink></entry>

    
    <entry>
        <title type="text">I'm on Technikwürze</title>
        <link rel="alternate" href="http://feeds.mikewest.org/~r/just_posts/~3/wADX6yjxJC8/technikwuerze-wrapup" />
        <id>http://mikewest.org/2011/06/technikwuerze-wrapup</id>
        <updated>2011-06-05T00:00:00+02:00</updated>
        <published>2011-06-05T00:00:00+02:00</published>
        <content type="html">
&lt;p&gt;I sat down with Technikwürze&amp;rsquo;s Marcel Böttcher way back at the beginning of February to talk about the exciting new release of Chrome 9 to the stable channel, and a few other bits and pieces of the Chrome ecosystem. That interview (in German) is just now seeing the light of day as &lt;a href="http://technikwuerze.de/podcast/technikwuerze-178-im-hause-google/"&gt;Technikwürze 178&lt;/a&gt;.  After listening to it last night, I think it generally went pretty well.&lt;/p&gt;

&lt;p&gt;I got a good chance to talk about the (then shiny and new) world of WebGL. It&amp;rsquo;s become hugely popular in the meantime, and is supported with GPU acceleration across the board in modern browsers with generally excellent performance characteristics.  Libraries have sprung up like &lt;a href="http://mrdoob.com/"&gt;Mr.doob&lt;/a&gt;&amp;rsquo;s amazing &lt;a href="https://github.com/mrdoob/three.js"&gt;three.js&lt;/a&gt; that make working with WebGL easy and fun. &lt;a href="http://ro.me/"&gt;ro.me&lt;/a&gt; is a great example of what can be creatively accomplished with the technology, and I&amp;rsquo;m really excited about seeing where the web will take things that it has full-speed access to OpenGL goodness from JavaScript.&lt;/p&gt;

&lt;p&gt;I touched on the &lt;a href="https://chrome.google.com/webstore"&gt;Chrome Web Store&lt;/a&gt;, which has had a very successful launch in the States, and is ramping up (albeit slower than I&amp;rsquo;d like) for a full international release later this year. You can see some of the results of that effort already, as the US store has been fully localized to make it accessible to users no matter what language they speak, and it&amp;rsquo;s only going to get better as the year progresses.&lt;/p&gt;

&lt;p&gt;I was able to highlight the focuses of Google&amp;rsquo;s engineering center in Munich (&lt;a href="http://www.google.de/intl/en/jobs/germanylocations/munich/"&gt;we&amp;rsquo;re hiring!  send me CVs!&lt;/a&gt;), especially those of the Chrome team that&amp;rsquo;s doing exceptional work on privacy and enterprise features of the platform. I touched on some of the thought behind Chrome&amp;rsquo;s release process, autoupdates, and the extension API framework. We dove briefly into some of the privacy-related work Google has done, highlighting &lt;a href="https://chrome.google.com/webstore/detail/hhnjdplhmcnkiecampfdgfjilccfpfoe"&gt;Keep My Opt-outs&lt;/a&gt; which we released in January, and pointing towards some future extension APIs that will enable developers to bring some great privacy protections (think TorButton and NoScript) to the Chrome platform.&lt;/p&gt;

&lt;p&gt;These are all relatively timeless bits and pieces that I&amp;rsquo;m glad I was able to share, and I hope that listeners find it interesting, even if it&amp;rsquo;s all framed in a context that&amp;rsquo;s 4 months too late.  I&amp;rsquo;m a bit disappointed that it&amp;rsquo;s just coming out now rather than back then when it would have been a bit more relevant.  It&amp;rsquo;s amazing to see what&amp;rsquo;s happened in the last 4 months (IE9 and FF4 have both been released in the meantime, we&amp;rsquo;ve pushed two new stable releases of Chrome, I/O happened, etc.), and pushing this interview out four months later simply doesn&amp;rsquo;t reflect the things that I&amp;rsquo;d like to be focusing on now.  It sounds like I&amp;rsquo;m talking about quite old things as though they were new, which is a bit confusing for everyone involved. I&amp;rsquo;m hopeful that we can get together again in the relatively near future to talk about some of the things that are interesting today and tomorrow.&lt;/p&gt;

&lt;h2 id="things-ill-say-differently-next-time"&gt;Things I&amp;rsquo;ll say differently next time.&lt;/h2&gt;

&lt;p&gt;First and foremost, listening to myself speak German is a painful experience. I mean, it&amp;rsquo;s tough to listen to myself speak English; listening to myself try and fail to wrap my tongue around a few phrases (repeatedly) is a bit embarrassing. &lt;em&gt;sigh&lt;/em&gt; I&amp;rsquo;ll get better at it.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;d also like to make two corrections. I&amp;rsquo;m not sure what one would call &amp;ldquo;errata&amp;rdquo; for a podcast, but that&amp;rsquo;s what I&amp;rsquo;ll outline here.  Let&amp;rsquo;s start with the one or two things I said that jumped out at me as being clearly idiotic, even back in February:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;I sold some of my coworkers short: of course Google has lobbyists in Berlin, but that&amp;rsquo;s not at all the extent of our efforts there. Among other things, there&amp;rsquo;s a large cooperation with academic institutes there to &lt;a href="http://www.thelocal.de/sci-tech/20110216-33141.html"&gt;set up a research institute focused on internet and society&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;I talked about Native Client as something that would trigger a review when uploading an item to the Chrome Web Store. I meant to refer to NPAPI plugins that can execute native code on your computer. If you write a Chrome extension or packaged application that relies on an NPAPI plugin, you&amp;rsquo;ll go through a review process to verify that someone&amp;rsquo;s responsible for the code, as there&amp;rsquo;s no practical limit on what such a plugin can do to a user&amp;rsquo;s computer (and we flag it as such in the store as being able to access &amp;ldquo;All data on your computer and the websites you visit&amp;rdquo;). These types of plugins also won&amp;rsquo;t run on ChromeOS, full stop.&lt;/p&gt;

    &lt;p&gt;While Native Client is in your head, however, I&amp;rsquo;ll note that it is right now in Chrome behind a flag, and there are indeed projects written using it (&lt;a href="http://www.naclbox.com/"&gt;NaClBox&lt;/a&gt; being the most recent brilliant example that I&amp;rsquo;m aware of), but it&amp;rsquo;s not something for  the general public at the moment. It&amp;rsquo;s experimental. An amazing piece of technology that&amp;rsquo;s in earnest development, but experimental. The Native Client team gave a talk at I/O (&lt;a href="http://www.google.com/events/io/2011/sessions/beyond-javascript-programming-the-web-with-native-client.html"&gt;&amp;ldquo;Beyond JavaScript: Programming the Web with Native Client&amp;rdquo;&lt;/a&gt;) that&amp;rsquo;s worth watching if you&amp;rsquo;re interested in the current status of the project.&lt;/p&gt;

    &lt;p&gt;I also mentioned casually that Native Client supports not only C/C++ but also Java and maybe Python. Again, I should have referred to NPAPI plugins (which actually &lt;em&gt;do&lt;/em&gt; somewhat support Python via projects like &lt;a href="http://pyplugin.com/"&gt;pyplugin&lt;/a&gt;). Native Client is C/C++ only at the moment. Though there&amp;rsquo;s no theoretical reason the framework &lt;em&gt;couldn&amp;rsquo;t&lt;/em&gt; work foremost other languages, there&amp;rsquo;s no compiler, nor do I know of any effort underway to write one.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id="updates"&gt;Updates.&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;The market share numbers &lt;a href="http://arstechnica.com/web/news/2011/02/chrome-takes-10-usage-share-ie-continues-to-haemorrhage.ars"&gt;from February&lt;/a&gt; which I quoted are, of course, out of date. At I/O we talked about reaching 160 million users, and &lt;a href="http://gs.statcounter.com/"&gt;StatCounter&lt;/a&gt; puts Chrome usage in their slice of the internet at right around 20% at the end of May. What I wish I had mentioned is that these numbers are nice to throw around in conversation, but the most important thing for a particular application is &lt;em&gt;its own&lt;/em&gt; demographics. Look at &lt;em&gt;your own&lt;/em&gt; logs to determine the distribution of browsers in &lt;em&gt;your&lt;/em&gt; audience.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The WebM project has since submitted an update to the bitstream specification (&lt;a href="http://tools.ietf.org/html/draft-bankoski-vp8-bitstream-01"&gt;&amp;ldquo;VP8 Data Format and Decoding Guide&amp;rdquo;&lt;/a&gt;) as an Internet Draft to the &lt;a href="http://www.ietf.org/"&gt;IETF&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;With regard to the application metadata format that the Chrome Web Store uses, Mozilla&amp;rsquo;s implementation of a similar idea &lt;a href="https://developer.mozilla.org/en/OpenWebApps/The_Manifest"&gt;is progressing nicely&lt;/a&gt;, but there&amp;rsquo;s still a gap between the functionality it offers and the model Chrome is running with at the moment. Discussion regarding those differences, and the direction in general, are happening in public on a variety of lists (&lt;a href="https://groups.google.com/forum/#!forum/mozilla-labs"&gt;mozilla-labs&lt;/a&gt; for example).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Chrome&amp;rsquo;s quick, multi-channel release cycle has been more successful than I thought possible. Firefox &lt;a href="http://blog.mozilla.com/blog/2011/04/13/new-channels-for-firefox-rapid-releases/"&gt;has adopted a similar system&lt;/a&gt;, and Microsoft is &lt;a href="http://ie.microsoft.com/testdrive/"&gt;already pushing out &amp;ldquo;platform previews&amp;rdquo; of IE10&lt;/a&gt;. This is just plain good for the web.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id="and-thats-about-it"&gt;And that&amp;rsquo;s about it&amp;hellip;&lt;/h2&gt;

&lt;p&gt;This was the first time I&amp;rsquo;ve participated in a podcast of any sort. It was a good experience, modulo the gap between recording and publication, and I look forward to talking into a microphone at some point again. Thanks for inviting me onto the show, liebe Technikwürzler. Till next time&amp;hellip; :)&lt;/p&gt;


&lt;img src="http://feeds.feedburner.com/~r/just_posts/~4/wADX6yjxJC8" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://mikewest.org/2011/06/technikwuerze-wrapup</feedburner:origLink></entry>

    
    <entry>
        <title type="text">A Quick git/vim Workflow Tip</title>
        <link rel="alternate" href="http://feeds.mikewest.org/~r/just_posts/~3/erdIWO4ep64/a-quick-git-vim-workflow-tip" />
        <id>http://mikewest.org/2011/04/a-quick-git-vim-workflow-tip</id>
        <updated>2011-04-10T00:00:00+02:00</updated>
        <published>2011-04-10T00:00:00+02:00</published>
        <content type="html">
&lt;p&gt;Git makes it incredibly easy to work on a lot of a project&amp;rsquo;s features at once,
hopping quickly back and forth between branches. I love this ability, but I
hate remembering what exactly it was that I was working on in a particular
branch. I know it had something to do with a particular bug, but I&amp;rsquo;ve no idea
anymore which files I was fiddling around with to fix it.&lt;/p&gt;

&lt;p&gt;Enter &lt;code&gt;git vim&lt;/code&gt;. I&amp;rsquo;ve set up two trivial alias in my &lt;code&gt;~/.gitconfig&lt;/code&gt; file to
either show me a list of files effected by a particular revision or range, and
to directly open them in my editor of choice so that I&amp;rsquo;m back to work as
quickly as possible.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[alias]
  ...
  fshow = ! sh -c 'git show --pretty="format:" --name-only $1 | grep -v "^$" | uniq | sed -e "s#^#`git rev-parse --show-toplevel`/#"' -
  vim   = ! sh -c 'vim `git fshow $1`' -
  mate  = ! sh -c 'mate `git fshow $1`' -
  edit  = ! sh -c '$EDITOR `git fshow $1`' -
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The first alias calls &lt;code&gt;git show&lt;/code&gt; to get a list of all the files touched by a
revision or range, filters out empty lines, and ensures that the paths are
absolute after deduplicating the list of files. Any
&lt;a href="http://www.kernel.org/pub/software/scm/git/docs/gitrevisions.html"&gt;valid revision or range&lt;/a&gt; will work: &lt;code&gt;HEAD&lt;/code&gt;, &lt;code&gt;37ad159&lt;/code&gt;, &lt;code&gt;master..&lt;/code&gt;, etc.&lt;/p&gt;

&lt;p&gt;To see a list of files changed over the last four revisions, I could type:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ git fshow HEAD~5..
lib/rocco/layout.rb
lib/rocco/layout.mustache
lib/rocco.rb
rocco.gemspec
test/helper.rb
test/test_reported_issues.rb
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To open those files for editing, I&amp;rsquo;d use the second alias:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ git vim HEAD~5..
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If I wanted to open the files in TextMate instead, I&amp;rsquo;d use the third:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ git mate HEAD~5..
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Or, if I was clever enough to set up an &lt;code&gt;$EDITOR&lt;/code&gt; environment variable (which
I should do, given that it&amp;rsquo;s used all over the place on the shell), I could
use the last alias to open the files in whatever program that was set to:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ git edit HEAD~5..
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I can hop from branch to branch, and open all the relevant files quickly and
easily. It&amp;rsquo;s a small thing, but it&amp;rsquo;s made a big difference in my workflow
over the last week or three. &lt;/p&gt;


&lt;img src="http://feeds.feedburner.com/~r/just_posts/~4/erdIWO4ep64" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://mikewest.org/2011/04/a-quick-git-vim-workflow-tip</feedburner:origLink></entry>

    
    <entry>
        <title type="text">Intro to IndexedDB</title>
        <link rel="alternate" href="http://feeds.mikewest.org/~r/just_posts/~3/5mddrFMxcbM/intro-to-indexeddb" />
        <id>http://mikewest.org/2010/12/intro-to-indexeddb</id>
        <updated>2010-12-14T00:00:00+01:00</updated>
        <published>2010-12-14T00:00:00+01:00</published>
        <content type="html">
&lt;p&gt;Yesterday at the Silicon Valley GTUG meetup, I gave a presentation introducing the IndexedDB API.  I&amp;rsquo;ve thrown the slides on Slideshare, but the transcription there is absolutely miserable.  I&amp;rsquo;ll reproduce it here in a readable format, and add a few notes where appropriate.&lt;/p&gt;

&lt;h2 id="video"&gt;Video&lt;/h2&gt;

&lt;iframe title="'Intro to IndexedDB' on YouTube" class="youtube-player" type="text/html" width="606" height="370" src="http://www.youtube.com/embed/yRo2hVoHWdQ?start=382" frameborder="0" style="margin:0 auto;"&gt;&lt;/iframe&gt;

&lt;h2 id="embedded-slides"&gt;Embedded Slides&lt;/h2&gt;

&lt;div style="width:606px;margin:0 auto;" id="__ss_6162787"&gt;
  &lt;strong style="display:block;margin:12px 0 4px"&gt;
    &lt;a href="http://www.slideshare.net/mikewest/intro-to-indexeddb-beta" title="Intro to IndexedDB (Beta)"&gt;
      Intro to IndexedDB (Beta)
    &lt;/a&gt;
  &lt;/strong&gt;
  &lt;object id="__sse6162787" width="606" height="506"&gt;
    &lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=indexeddb-101214120833-phpapp01&amp;amp;rel=0&amp;amp;stripped_title=intro-to-indexeddb-beta&amp;amp;userName=mikewest" /&gt;&lt;param name="allowFullScreen" value="true" /&gt;&lt;param name="allowScriptAccess" value="always" /&gt;
    &lt;embed name="__sse6162787" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=indexeddb-101214120833-phpapp01&amp;amp;rel=0&amp;amp;stripped_title=intro-to-indexeddb-beta&amp;amp;userName=mikewest" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="606" height="506" /&gt;
  &lt;/object&gt;
&lt;/div&gt;

&lt;h2 id="slide-transcript"&gt;Slide Transcript&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;em&gt;IndexedDB&lt;/em&gt;: Mike West, &lt;a href="http://twitter.com/mikewest"&gt;@mikewest&lt;/a&gt;, &lt;a href="&amp;#109;&amp;#097;&amp;#105;&amp;#108;&amp;#116;&amp;#111;:&amp;#109;&amp;#107;&amp;#119;&amp;#115;&amp;#116;&amp;#064;&amp;#103;&amp;#111;&amp;#111;&amp;#103;&amp;#108;&amp;#101;&amp;#046;&amp;#099;&amp;#111;&amp;#109;"&gt;&amp;#109;&amp;#107;&amp;#119;&amp;#115;&amp;#116;&amp;#064;&amp;#103;&amp;#111;&amp;#111;&amp;#103;&amp;#108;&amp;#101;&amp;#046;&amp;#099;&amp;#111;&amp;#109;&lt;/a&gt;,
&lt;a href="http://sv-gtug.blogspot.com/"&gt;SV GTUG&lt;/a&gt;, 2010.12.14&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;em&gt;Beta&lt;/em&gt;: The IndexedDB API is incredibly beta.  It’s only implemented in
Firefox 4 and Chrome dev channel, so it’s not anything that can be used for
production projects in the near future.  Microsoft and Opera are
contributing to the spec, however, and Google is working on pushing the
code upstream to Webkit itself, so this looks like something that will be
more and more relevant going forward.  &lt;/p&gt;

    &lt;p&gt;Since the spec’s not finished, and everything’s in dev mode, this is a
&lt;em&gt;great&lt;/em&gt; time to examine the API, and experiment.  We need to play around
with this code, and feed our experience back into the standards bodies and
browser vendors: that’s the best way to ensure that things work the way we
want them to when everything’s solidified.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;em&gt;Offline&lt;/em&gt;: One of the most exciting recent realizations in web development
is that the offline bits of the HTML5 suite of specifications are &lt;em&gt;really
ready&lt;/em&gt; for widespread use.  It&amp;rsquo;s possible to store arbitrary amounts of
information on a user&amp;rsquo;s computer without resorting to opaque hacks like
Flash storage, while at the same time making that information available in
useful ways to your program&amp;rsquo;s code.  This opens up a whole new world of
sites and applications which we&amp;rsquo;re only just beginning to appreciate.
Offline&amp;rsquo;s important, and not just because of the Web Store.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;em&gt;Storage Options&lt;/em&gt;: What I&amp;rsquo;d like to do here is take a very brief survey of
the landscape for context, and then dive into one particular feature that I
think will become important in the near future: IndexedDB.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;em&gt;Cookies&lt;/em&gt;:  These aren&amp;rsquo;t offline at all, but they&amp;rsquo;re relevant to the general
context of how web applications store data at the moment.  The image on this
slide is &lt;a href="http://www.flickr.com/photos/ilmungo/65345233/in/photostream/"&gt;Luigi Anzivino&amp;rsquo;s &amp;ldquo;Molasses-Spice cookies&amp;rdquo;&lt;/a&gt; (which look
delicious).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;em&gt;Cookies&lt;/em&gt;&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;
        &lt;p&gt;Simple, key-value pairs, &amp;ldquo;shared&amp;rsquo; between server and client.&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;Excellent for maintaining state, poor for anything else, as they are
unstructured, and incur a signiﬁcant overhead for each HTTP request.&lt;/p&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;em&gt;Local Storage&lt;/em&gt;:  The image on this slide is &lt;a href="http://www.flickr.com/photos/ecstaticist/4743121155/"&gt;Evan Leeson&amp;rsquo;s
&amp;ldquo;Toasters&amp;rdquo;&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;em&gt;Local Storage&lt;/em&gt;&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;
        &lt;p&gt;The simplicity of cookies, tuned for higher-capacity,
client-side-only storage.&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;Dead simple API:&lt;/p&gt;

        &lt;pre&gt;&lt;code&gt;localStorage.setItem( ‘key’, ‘value’ );
localStorage.getItem( ‘key’ ); // ‘value’
&lt;/code&gt;&lt;/pre&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;Values are unstructured strings:&lt;/p&gt;

        &lt;ul&gt;
          &lt;li&gt;
            &lt;p&gt;Filtering and search are &lt;em&gt;O(n)&lt;/em&gt;, unless you layer some indexing
on top.&lt;/p&gt;
          &lt;/li&gt;
          &lt;li&gt;
            &lt;p&gt;Structure requires &lt;code&gt;JSON.stringify&lt;/code&gt; &amp;amp; &lt;code&gt;JSON.parse&lt;/code&gt;&lt;/p&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;em&gt;WebSQL&lt;/em&gt;: The image on this slide is &lt;a href="http://www.flickr.com/photos/nickperez/2569423078/"&gt;Nick P&amp;rsquo;s &amp;ldquo;file cabinet to
heaven&amp;rdquo;&lt;/a&gt;, which is a pretty accurate representation of life with
WebSQL.  Stacking file cabinets on top of each other certainly provides you
with the possibility of well organized storage, but that doesn&amp;rsquo;t mean it&amp;rsquo;s
a good idea.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;em&gt;WebSQL&lt;/em&gt;&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;A real, relational database\n implementation on the client (SQLite)&lt;/li&gt;
      &lt;li&gt;Data can be highly structured, and &lt;code&gt;JOIN&lt;/code&gt; enables quick, ad-hoc
access&lt;/li&gt;
      &lt;li&gt;Big conceptual overhead (&lt;code&gt;SQL&lt;/code&gt;), no finely grained locking&lt;/li&gt;
      &lt;li&gt;Not very JavaScripty, browser support is poor (IE and Firefox won&amp;rsquo;t
implement it), and &lt;a href="http://www.w3.org/TR/webdatabase/"&gt;the spec&lt;/a&gt; has been more or less abandoned.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;em&gt;File API&lt;/em&gt;: The image on this slide is &lt;a href="http://www.flickr.com/photos/daddo83/3406962115/"&gt;Davide Tullio&amp;rsquo;s &amp;ldquo;Hard Disk in
B&amp;amp;W&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;em&gt;File API&lt;/em&gt;: I know nothing about the File API, but Seth does!  And his
presentation is right after mine, so I&amp;rsquo;ll be all ears.  :)&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;em&gt;IndexedDB&lt;/em&gt;: The image on this slide is &lt;a href="http://www.flickr.com/photos/31408547@N06/4671916278/"&gt;Robin Riat&amp;rsquo;s &amp;ldquo;Kanuga library card
catalog&amp;rdquo;&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;em&gt;IndexedDB&lt;/em&gt;:  &lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;Sits somewhere between full-on SQL and unstructured key-value pairs
in localStorage.&lt;/li&gt;
      &lt;li&gt;Values are stored as structured JavaScript objects, and an indexing
system facilitates filtering and lookup.&lt;/li&gt;
      &lt;li&gt;Asynchronous, with moderately granular locking&lt;/li&gt;
      &lt;li&gt;Joining normalized data is a completely manual process.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;em&gt;IndexedDB Concepts&lt;/em&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Practically everything is asynchronous. Callbacks are your friends.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Databases are named, and contain one or more named &lt;em&gt;Object Stores&lt;/em&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;A diagram of how a database might look, containing a single object store
and a set of objects.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Object stores define a property (similar to a primary key) which every
stored object must contain, explicitly or implicitly (autoincremented).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The same diagram as #18, with IDs added.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Values in an Object Store are structured, but don’t have a rigidly defined 
schema.  Think document database, CouchDB.  Not MySQL.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The same diagram as #20, with differing data added for various objects.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Object Stores can contain one or more &lt;em&gt;Indexes&lt;/em&gt; that make filtering and
lookup possible via arbitrary properties.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The same diagram as #22, with a subset highlighted (as though they were
filtered out).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;em&gt;IndexedDB API&lt;/em&gt;: Now we&amp;rsquo;ll dive into some JavaScript.  Lovely, lovely
JavaScript.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;It&amp;rsquo;s beta.  Again.  This is a reminder.  :)&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;em&gt;Vendor Prefixes&lt;/em&gt;:  &lt;code&gt;webkitIndexedDB&lt;/code&gt; &amp;amp; &lt;code&gt;moz_indexedDB&lt;/code&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;em&gt;Code:&lt;/em&gt;&lt;/p&gt;

    &lt;pre&gt;&lt;code&gt;// Deal with vendor prefixes
if ( "webkitIndexedDB" in window ) {
  window.indexedDB      = window.webkitIndexedDB;
  window.IDBTransaction = window.webkitIDBTransaction;
  window.IDBKeyRange    = window.webkitIDBKeyRange;
  // ...
} else if ( "moz_indexedDB" in window ) {
  window.indexedDB = window.moz_indexedDB;
}
if ( !window.indexedDB ) {
  // Browser doesn’t support indexedDB, do something
  // clever, and then exit early.
} 
&lt;/code&gt;&lt;/pre&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;em&gt;Database Creation&lt;/em&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;em&gt;Code:&lt;/em&gt;&lt;/p&gt;

    &lt;pre&gt;&lt;code&gt;var dbRequest = window.indexedDB.open(
  “AddressBook”,        // Database ID
  “All my friends ever” // Database Description
);

// The result of `open` is _not_ the database.
// It’s a reference to the request to open
// the database.  Listen for its `success` and
// `error` events, and respond appropriately.
dbRequest.onsuccess = function ( e ) { ... };
dbRequest.onerror   = function ( e ) { ... };
&lt;/code&gt;&lt;/pre&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;em&gt;Databases are versioned&amp;hellip;&lt;/em&gt; &lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;em&gt;Code:&lt;/em&gt;&lt;/p&gt;

    &lt;pre&gt;&lt;code&gt;// The `result` attribute of the `success` event
// holds the communication channel to the database
dbRequest.onsuccess = function ( e ) {
  var db = e.result;
  // Bootstrapping: if the user is hitting the page
  // for the first time, she won’t have a database.
  // We can detect this by inspecting the database’s
  // `version` attribute:
  if ( db.version === “” ) {
    // Empty string means the database hasn’t been versioned.
    // Set up the database by creating any necessary
    // Object Stores, and populating them with data
    // for the first run experience.
  } else if ( db.version === “1.0” ) {
    // 1.0 is old!  Let’s make changes!
  } else if ( db.version === “1.1” ) {
    // We’re good to go!
  }
  // ...
};
&lt;/code&gt;&lt;/pre&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;em&gt;&amp;hellip; and versioning is asychronous.&lt;/em&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;em&gt;Code:&lt;/em&gt;&lt;/p&gt;

    &lt;pre&gt;&lt;code&gt;dbRequest.onsuccess = function ( e ) {
var db = e.result;
if ( db.version === “” ) {
  // We’re dealing with an unversioned DB.  Versioning is, of
  // course, asynchronous:
  var versionRequest = db.setVersion( “1.0” );
  versionRequest.onsuccess = function ( e ) {
    // Here’s where we’ll set up the Object Stores
    // and Indexes.
  };
}
// ...   };
&lt;/code&gt;&lt;/pre&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;em&gt;Creating Object Stores and Indexes&lt;/em&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;em&gt;Code:&lt;/em&gt;&lt;/p&gt;

    &lt;pre&gt;&lt;code&gt;dbRequest.onsuccess = function ( e ) {
var db = e.result;
if ( db.version === “” ) {
  var versionRequest = db.setVersion( “1.0” );
  // Setting a version creates an implicit Transaction, meaning
  // that either _everything_ in the callback succeeds, or
  // _everything_ in the callback fails.
  versionRequest.onsuccess = function ( e ) {
    // Object Store creation is atomic, but can only take
    // place inside version-changing transaction.
    var store = db.createObjectStore(
      "contacts",  // The Object Store’s name
      "id",        // The name of the property to use as a key
      true         // Is the key auto-incrementing?
    );
    // ...
  };
}
// ...   };
&lt;/code&gt;&lt;/pre&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;em&gt;More code:&lt;/em&gt;&lt;/p&gt;

    &lt;pre&gt;&lt;code&gt;dbRequest.onsuccess = function ( e ) {
  var db = e.result;
  if ( db.version === “” ) {
    var versionRequest = db.setVersion( “1.0” );
    versionRequest.onsuccess = function ( e ) {
      var store = db.createObjectStore( "contacts", "id", true );
      store.createIndex(
        “CellPhone”,  // The index’s name
        “cell”,       // The property to be indexed
        false         // Is this index a unique constraint?
      );
    };
  }
  // ...
};
&lt;/code&gt;&lt;/pre&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;em&gt;Writing Data (is asynchronous)&lt;/em&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;em&gt;Code:&lt;/em&gt;&lt;/p&gt;

    &lt;pre&gt;&lt;code&gt;// Assuming that `db` has been set somewhere in the current
// scope, we use it to create a transaction:
var writeTransaction = db.transaction(
  [ “contacts” ],           // The Object Stores to lock
  IDBTransation.READ_WRITE  // Lock type (READ_ONLY, READ_WRITE)
);
// Open a contact store...
var store = writeTransaction.objectStore( “contacts” );
// ... and generate a write request:
var writeRequest = store.add( {
    “name”:  “Mike West”,
    “email”: “mkwst@google.com”
} );
writeRequest.onerror = function ( e ) {
    writeTransaction.abort();
};
// Transactions are “complete” (not “committed”?) either when
// they fall out of scope, or when all activities in the
// transaction have finished (whichever happens last)
writeTransaction.oncomplete = function ( e ) { ... };
&lt;/code&gt;&lt;/pre&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;em&gt;Reading Data (is asynchronous)&lt;/em&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;em&gt;Code:&lt;/em&gt;&lt;/p&gt;

    &lt;pre&gt;&lt;code&gt;// Assuming that `db` has been set somewhere in the current
// scope, we use it to create a transaction:
var readTransaction = db.transaction(
  [ “contacts” ],           // The Object Stores to lock
  IDBTransation.READ_ONLY   // Lock type (READ_ONLY, READ_WRITE)
);
// Open the `contact` store...
var store = readTransaction.objectStore( “contacts” );
// ... and generate a cursor to walk the complete list:
var readCursor = store.openCursor();
// Setup a handler for the cursor’s `success` event:
readCursor.onsuccess = function ( e ) {
  if ( e.result ) {
    // You now have access to the key via `e.result.key`, and
    // the stored object via `e.result.value`.  For example:
    console.log( e.result.value.email ); // mkwst@google.com
  } else {
    // If the `success` event’s `result` is null, you’ve reached
    // the end of the cursor’s list.
  }
};
&lt;/code&gt;&lt;/pre&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;em&gt;Querying (is asynchronous)&lt;/em&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;em&gt;Code:&lt;/em&gt;&lt;/p&gt;

    &lt;pre&gt;&lt;code&gt;var t = db.transaction( [ “contacts” ], IDBTransation.READ_ONLY );
var s = t.objectStore( “contacts” );
// ... and generate a cursor to walk a bounded list, for example
// only those names between M and P (inclusive)
var bounds = new IDBKeyRange.bound(
  “M”,  // Lower bound
  “Q”,  // Upper bound
  true, // Include lower bound?
  false // Include upper bound?
);
var readCursor = store.openCursor( bounds );
// Setup a handler for the cursor’s `success` event:
readCursor.onsuccess = function ( e ) {
  // process `e.result`
};
&lt;/code&gt;&lt;/pre&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;em&gt;Further Reading:&lt;/em&gt;&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;&lt;a href="http://www.w3.org/TR/IndexedDB/"&gt;The IndexedDB Spec&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="http://hacks.mozilla.org/2010/06/comparing-indexeddb-and-webdatabase/"&gt;Firefox 4: An Early Walkthrough of IndexedDB&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="https://developer.mozilla.org/en/IndexedDB"&gt;Mozilla Developer Docs&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;em&gt;Questions?&lt;/em&gt;, Mike West, &lt;a href="http://twitter.com/mikewest"&gt;@mikewest&lt;/a&gt;, &lt;a href="&amp;#109;&amp;#097;&amp;#105;&amp;#108;&amp;#116;&amp;#111;:&amp;#109;&amp;#107;&amp;#119;&amp;#115;&amp;#116;&amp;#064;&amp;#103;&amp;#111;&amp;#111;&amp;#103;&amp;#108;&amp;#101;&amp;#046;&amp;#099;&amp;#111;&amp;#109;"&gt;&amp;#109;&amp;#107;&amp;#119;&amp;#115;&amp;#116;&amp;#064;&amp;#103;&amp;#111;&amp;#111;&amp;#103;&amp;#108;&amp;#101;&amp;#046;&amp;#099;&amp;#111;&amp;#109;&lt;/a&gt;,
http://mikewest.org/&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;


&lt;img src="http://feeds.feedburner.com/~r/just_posts/~4/5mddrFMxcbM" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://mikewest.org/2010/12/intro-to-indexeddb</feedburner:origLink></entry>

    
    <entry>
        <title type="text">projects.mikewest.org</title>
        <link rel="alternate" href="http://feeds.mikewest.org/~r/just_posts/~3/avUoZqvL11w/projects-mikewest-org" />
        <id>http://mikewest.org/2010/11/projects-mikewest-org</id>
        <updated>2010-11-02T00:00:00+01:00</updated>
        <published>2010-11-02T00:00:00+01:00</published>
        <content type="html">
&lt;p&gt;&amp;ldquo;What &lt;em&gt;has&lt;/em&gt; Mike West been up to recently?&amp;rdquo;  This is one question that you almost certainly haven&amp;rsquo;t been asking yourself recently.  That&amp;rsquo;s a shame, really, as I&amp;rsquo;ve got a few small projects floating around that I think you might be interested in paying attention to.&lt;/p&gt;

&lt;p&gt;If you&amp;rsquo;ll indulge me, I&amp;rsquo;ll run through them in no particular order:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://projects.mikewest.org/vimroom/"&gt;VimRoom&lt;/a&gt; is a Vim plugin that replicates the best features of &lt;a href="http://www.hogbaysoftware.com/products/writeroom"&gt;WriteRoom&lt;/a&gt; in my favorite editor.  I do most of my writing (code and otherwise) in Vim, as the keyboard shortcuts I&amp;rsquo;ve &lt;a href="http://github.com/mikewest/homedir/blob/master/.vimrc"&gt;painstakingly assembled&lt;/a&gt; are hardwired into my fingers (and, I suppose, because I&amp;rsquo;m a huge nerd).  Combined with &lt;a href="http://sites.google.com/site/iterm2home/"&gt;iTerm2&lt;/a&gt;&amp;rsquo;s brilliant fullscreen mode, VimRoom offers a great way to shut out the myriad distractions floating around my iMac, and focus on actually getting words onto the screen: I&amp;rsquo;m pretty pleased with how it&amp;rsquo;s turned out, and I hope it might be useful for others.&lt;/li&gt;
&lt;/ul&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://projects.mikewest.org/static_gettext/"&gt;&lt;code&gt;static_gettext&lt;/code&gt;&lt;/a&gt; is a (tiny) internationalization framework that makes it possible to generate arbitrary localizations of static source documents.  Dynamic frameworks like Django or Rails have good systems in place to deal with the tough problems of removing hard-coded strings from source code and templates.  Less complex, static websites aren&amp;rsquo;t going away, however, and &lt;code&gt;static_gettext&lt;/code&gt; has solved the problem for me nicely, generating industry-standard &lt;code&gt;*.po&lt;/code&gt; files that can be easily handed off to translators.  The framework is currently seeing active use on the &lt;a href="http://html5boilerplate.com/"&gt;HTML5 Boilerplate&lt;/a&gt; site for the &lt;a href="http://de.html5boilerplate.com/"&gt;German translation&lt;/a&gt; (which I helped out with), and a few other localizations &lt;a href="http://github.com/nimbupani/html5boilerplate-site/issues#issue/3"&gt;are in the pipe&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://projects.mikewest.org/jslint_utils/"&gt;JSLint Utils&lt;/a&gt; is a command-line wrapper for JSLint that makes it possible to quickly lint your JavaScript and CSS files via the magic of either Node.js (fast!) or Rhino (not so fast!).  Lint results can be output as XUnit-style XML files, making it possible to cleanly integrate into a variety of continuous integration systems (&lt;a href="http://hudson-ci.org/"&gt;Hudson&lt;/a&gt;, for example), meaning that you don&amp;rsquo;t even have to think about it: you just get friendly emails after every commit you screw up.  It&amp;rsquo;s a lifesaver!&lt;/li&gt;
&lt;/ul&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://projects.mikewest.org/pyplaceholder/"&gt;PyPlaceholder&lt;/a&gt; is a command-line Python script that generates placeholder PNGs for use in&amp;hellip; well&amp;hellip; wherever you might use placeholder PNGs.  It&amp;rsquo;s made my life a little simpler while putting together mockups, and it has a few tiny features that I didn&amp;rsquo;t see on any of the surprisingly numerous alternatives.  I&amp;rsquo;ve additionally wrapped it up in a &lt;a href="http://flask.pocoo.org/"&gt;Flask&lt;/a&gt; application, &lt;a href="http://github.com/mikewest/flask-pyplaceholder"&gt;&lt;code&gt;flask-pyplaceholder&lt;/code&gt;&lt;/a&gt;, to generate images on the fly via &lt;a href="http://placeholder.mikewest.org/"&gt;placeholder.mikewest.org&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://chrome.google.com/extensions/detail/liamajdghafnpofaconeimppimbdbhgi/"&gt;Send To Instapaper&lt;/a&gt; is a stunningly well-named Chrome extension that has no purpose other than to replicate the standard Instapaper-bookmarklet functionality with two small additions: it adds a keyboard shortcut, and it&amp;rsquo;s streamlined, clean, and pretty.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="and-now-the-point"&gt;And now, the point&amp;hellip;&lt;/h2&gt;

&lt;p&gt;I read Jesper&amp;rsquo;s &lt;a href="http://waffle.wootest.net/2010/11/01/doc-robot/"&gt;Doc Robot&lt;/a&gt; this morning, and found myself nodding vigorously.  I disagree about the inherent valuelessness of &lt;em&gt;all&lt;/em&gt; autogenerated documentation (as I&amp;rsquo;ve also been doing a good bit of work on Ryan Tomayko&amp;rsquo;s &lt;a href="http://github.com/rtomayko/rocco"&gt;Rocco&lt;/a&gt;, which autogenerates lovely documentation if you do the work of coding in a literate fashion), but I think he makes a great point about the way we generally treat documentation as an afterthought.  I&amp;rsquo;d like to share the solution I&amp;rsquo;ve come up with for my code.&lt;/p&gt;

&lt;p&gt;You&amp;rsquo;ll notice that these projects that I&amp;rsquo;ve linked to above all have landing pages that more or less clearly explain what the project is, how it works, and what your next steps might be, should you be interested enough to want to try it out for yourself.  Each of those landing pages also has a clear changelog, and an RSS feed that you can subscribe to, should you be interested in keeping yourself up to date.  There&amp;rsquo;s even an &lt;a href="http://projects.mikewest.org/atom.xml"&gt;RSS feed for the site&lt;/a&gt;, in case you&amp;rsquo;d just like to have a good handle on what it is that I&amp;rsquo;m up to.&lt;/p&gt;

&lt;p&gt;I think this is the bare minimum a project needs to offer in order to begin to serve an audience.  I&amp;rsquo;ve put together &lt;a href="http://projects.mikewest.org/"&gt;projects.mikewest.org&lt;/a&gt; in order to have a clear place to put any and all documentation I generate for the projects I&amp;rsquo;d like to present to the public.  The ever so clever &lt;a href="http://projects.timhuegdon.com"&gt;Tim Huegdon&lt;/a&gt; has put together a similar project listing with good documentation, and I&amp;rsquo;d like to encourage &lt;em&gt;you&lt;/em&gt; to do so as well.&lt;/p&gt;

&lt;p&gt;GitHub pages makes the process of putting together a basic website hassle-free, and you can take a look at the &lt;a href="http://github.com/mikewest/mikewest.github.com/"&gt;project page repository&lt;/a&gt; to see how I&amp;rsquo;ve bent Jekyll to the task of generating RSS feeds and embedded changelogs.  It&amp;rsquo;s not rocket science, but it took a bit of experimenting that you can spare yourself.  Use the repo as a template.  There&amp;rsquo;s nothing there I wouldn&amp;rsquo;t gladly share.&lt;/p&gt;


&lt;img src="http://feeds.feedburner.com/~r/just_posts/~4/avUoZqvL11w" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://mikewest.org/2010/11/projects-mikewest-org</feedburner:origLink></entry>

    
    <entry>
        <title type="text">JSLint needs some Bad Parts</title>
        <link rel="alternate" href="http://feeds.mikewest.org/~r/just_posts/~3/plagaIdm0UY/jslint-needs-some-bad-parts" />
        <id>http://mikewest.org/2010/05/jslint-needs-some-bad-parts</id>
        <updated>2010-05-16T00:00:00+02:00</updated>
        <published>2010-05-16T00:00:00+02:00</published>
        <content type="html">
&lt;p&gt;One of the few tools that I consider truly indispensable when developing
websites is &lt;a href="http://www.jslint.com/"&gt;JSLint&lt;/a&gt;.  A marvel of applied compiler theory, the program
has saved me from stupid mistakes more times than I care to remember.  I
have it set up to automatically sanity-check my code &lt;a href="http://github.com/mikewest/jslint-utils"&gt;every time I push a
commit to SVN&lt;/a&gt;, and it&amp;rsquo;s generally my best friend in the whole
wide world.&lt;/p&gt;

&lt;p&gt;JSLint isn&amp;rsquo;t always perfect, however, especially when used to check CSS
files.  I think &lt;a href="http://www.crockford.com/"&gt;Douglas Crockford&lt;/a&gt; is a JavaScript wizard, but I&amp;rsquo;m
somewhat less blindly acquiescent when it comes to his take on the Good
Parts of style sheets.  For better or worse, browsers are &lt;em&gt;much&lt;/em&gt; less
similar in their interpretation of what I mean when I write a particular
style, and certain hacks and workarounds are par for the course when
putting together a layout of any complexity.  JSLint&amp;rsquo;s CSS checks do a
good job warning about certain types of errors (missing semicolons, for
instance), but a relatively terrible job when it comes to some of the
necessary evils of practical development.  In short, JSLint&amp;rsquo;s CSS mode
needs some &lt;a href="http://github.com/mikewest/jslint/raw/master/CHANGELOG.markdown"&gt;Bad Parts&lt;/a&gt; to be really &lt;em&gt;usable&lt;/em&gt; for me.&lt;/p&gt;

&lt;p&gt;In itself, this wouldn&amp;rsquo;t be an issue.  Crockford has kindly released 
JSLint as open source (under a unique (to say the least) &amp;ldquo;Do no evil&amp;rdquo;
license), and I&amp;rsquo;m generally able to puzzle out how to go about adding
support for the features that I believe are necessary.  Getting those
patches into the mainline JSLint project is, unfortunately, often a
miserable process.  I have two issues with the current process:&lt;/p&gt;

&lt;p&gt;First, there&amp;rsquo;s no public repository (that I&amp;rsquo;ve come across).  Crockford
is pretty good about announcing changes on &lt;a href="http://tech.groups.yahoo.com/group/jslint_com/"&gt;the JSLint mailing list&lt;/a&gt;,
and he keeps a timestamp in the current &lt;code&gt;fulljslint.js&lt;/code&gt; file, but that&amp;rsquo;s
hardly a solid basis for contributing patches.  This isn&amp;rsquo;t a show stopper,
it just makes things harder to follow than they could be, and more
difficult to give back to the project than it should be.  I asked about
this &lt;a href="http://tech.groups.yahoo.com/group/jslint_com/message/476"&gt;in May 2009&lt;/a&gt;, and was met with silence.  Ah well.&lt;/p&gt;

&lt;p&gt;Second, the aforementioned list is easily the most (passive-)aggressive
I&amp;rsquo;ve been on recently.  The (true) warning that &amp;ldquo;JSLint will hurt your
feelings&amp;rdquo; goes double for posting questions or suggestions, especially
as a newbie.  I almost fell off my chair when I saw &lt;a href="http://tech.groups.yahoo.com/group/jslint_com/message/1168"&gt;this question&lt;/a&gt;
(&amp;ldquo;I have this problem, and I&amp;rsquo;ve found this workaround.  Why is it a
problem in the first place?&amp;rdquo;) received &lt;a href="http://tech.groups.yahoo.com/group/jslint_com/message/1170"&gt;this response&lt;/a&gt; (&amp;ldquo;Thanks for
the report.  JSLint now no longer accepts your workaround.&amp;rdquo;)  Crockford
is a &lt;em&gt;smart&lt;/em&gt; guy, and he&amp;rsquo;s opinionated in the best possible way, but he
couples that with a periodic lack of tact that&amp;rsquo;s really influenced the
way the list as a whole works.  It&amp;rsquo;s simply not a fun place to
contribute ideas or code, and that&amp;rsquo;s a shame.  &lt;a href="http://tech.groups.yahoo.com/group/jslint_com/message/1280"&gt;Arguing about the
validity of suggestions&lt;/a&gt; is simply not something I&amp;rsquo;m willing to do
&lt;em&gt;every single time&lt;/em&gt; I make a suggestion, especially when the suggestions
are quite often met with silence from the one guy who actually has 
commit access to the mainline trunk.&lt;/p&gt;

&lt;p&gt;So, to resolve these issues for myself, I&amp;rsquo;m forking JSLint.  I fully
expect this to be of interest to almost exclusively myself, but I&amp;rsquo;ll
find it useful, and I&amp;rsquo;ll hold out hope that some of the patches will
eventually make it back into JSLint proper.&lt;/p&gt;

&lt;p&gt;To resolve the issue of a base &amp;ldquo;official&amp;rdquo;  repository, I&amp;rsquo;ll pull down
a copy of the current iteration of JSLint on a daily basis, and
mirror it on GitHub (&lt;a href="http://github.com/mikewest/jslint/tree/mirror"&gt;jslint/mirror&lt;/a&gt;).  My patches will be pushed
to &lt;a href="http://github.com/mikewest/jslint/"&gt;jslint/master&lt;/a&gt; (along with QUnit-based regression tests), and
I&amp;rsquo;ll do my best to keep &lt;code&gt;master&lt;/code&gt; merged with the latest from &lt;code&gt;mirror&lt;/code&gt;,
and the changes continually rebased on top of &lt;code&gt;mirror&lt;/code&gt; into
&lt;a href="http://github.com/mikewest/jslint/tree/rebased"&gt;jslint/rebased&lt;/a&gt; for ease of application (in the unlikely event
that Crockford pays attention :) ).&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;ll keep the &lt;a href="http://github.com/mikewest/jslint/raw/master/CHANGELOG.markdown"&gt;changelog&lt;/a&gt; up to date as I add the functionality
I find that I need to do my job.  If you find the idea useful, I hope
you&amp;rsquo;ll help me out.  Reasonable patches most humbly accepted (although
&lt;em&gt;my&lt;/em&gt; arbitration of &amp;ldquo;reasonable&amp;rdquo; might hurt your feelings too).&lt;/p&gt;


&lt;img src="http://feeds.feedburner.com/~r/just_posts/~4/plagaIdm0UY" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://mikewest.org/2010/05/jslint-needs-some-bad-parts</feedburner:origLink></entry>

    
    <entry>
        <title type="text">A JavaScript Detection Pattern</title>
        <link rel="alternate" href="http://feeds.mikewest.org/~r/just_posts/~3/XrPKdimg6Dk/javascript-detection-pattern" />
        <id>http://mikewest.org/2010/03/javascript-detection-pattern</id>
        <updated>2010-03-06T00:00:00+01:00</updated>
        <published>2010-03-06T00:00:00+01:00</published>
        <content type="html">
&lt;p&gt;Progressive enhancement of our sites and applications has become a relatively well accepted best practice for web development.  It simply makes sense to implement core functionality in a universally accessible way before layering new behaviors and possibilities for interaction on top via JavaScript.&lt;/p&gt;

&lt;p&gt;This implementation model has one drawback that we need to consider.  If we render a basic version of a module before reworking it with JavaScript, it&amp;rsquo;s possible that visitors would briefly be exposed to the unenhanced module, only to see it morph into something new before their eyes.  This distraction is especially likely when we consider the &lt;a href="http://developer.yahoo.com/performance/rules.html#js_bottom"&gt;well-known performance benefits&lt;/a&gt; associated with loading JavaScript at the very bottom of a page.  The page as a whole will load well before JavaScript is completely parsed and executed, leaving a space of time during which the raw versions of your modules are visible.&lt;/p&gt;

&lt;p&gt;To avoid this issue, I&amp;rsquo;d suggest inserting the following code directly after opening your page&amp;rsquo;s &lt;code&gt;body&lt;/code&gt; element:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;script&amp;gt;document.documentElement.className += " js";&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When a visitor comes to the site with JavaScript enabled, this snippet will add a &lt;code&gt;js&lt;/code&gt; class to the document&amp;rsquo;s root node (in most cases, the &lt;code&gt;html&lt;/code&gt; element).  This gives us a styling hook that allows us to generate CSS rules that only take effect when JavaScript is present.  Prefixing rules with a &lt;code&gt;.js&lt;/code&gt; selector ensures that they only apply when this script has executed, meaning that the visitor must have JavaScript enabled in her browser.  We can use this information to pre-style the widgets in preparation for the JavaScript manipulations we&amp;rsquo;ll do later on.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;ve put together a &lt;a href="http://mikewest.org/static_content/2010-03-javascript-detection.html"&gt;demonstration of this JavaScript detection technique&lt;/a&gt; in action.  It&amp;rsquo;s worth visiting that demonstration both with and without JavaScript enabled, simply to get a feel for what&amp;rsquo;s possible.  It&amp;rsquo;s not a perfect solution (JavaScript could error out somewhere in the middle of the page, for instance), but I find it to be a reasonable compromise that avoids distracting flashes of incompletely styled content.&lt;/p&gt;

&lt;p&gt;That demonstration, however, is pretty abstract.  Let&amp;rsquo;s look at a more practical example of how this could improve a site&amp;rsquo;s usability.  Take &lt;a href="http://twitter.com/"&gt;Twitter&lt;/a&gt;, for instance: with JavaScript enabled, clicking on the &amp;ldquo;Sign in&amp;rdquo; button in the top right-hand corner of the page exposes the login form, which is otherwise hidden away.  Without JavaScript, the form doesn&amp;rsquo;t show up at all, users are instead directed to a separate page that just displays this form.&lt;/p&gt;

&lt;p&gt;This is a reasonable fallback, all things considered (and certainly better than sites like CNN, whose login link goes nowhere without JavaScript).  Still, I see it as a missed opportunity as the login form&amp;rsquo;s HTML code is delivered to the user on the homepage regardless, it&amp;rsquo;s simply hidden by default.  I think a better decision would have been to design the page such that the login form shows up for all users, and is simply presented differently for users with JavaScript.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;ve implemented a &lt;a href="http://mikewest.org/static_content/2010-03-javascript-detection-twitter.html"&gt;demonstration of how this might work&lt;/a&gt; by copying down the Twitter homepage&amp;rsquo;s code, adding the JavaScript detection snippet from above, moving the login form HTML lower down on the page, and adding a few lines of CSS to make things halfway usable (a caveat: &lt;a href="http://mikewest.org/static_content/2010-03-javascript-detection-twitter.html"&gt;the twitter demo&lt;/a&gt; looks good in Chrome/Webkit, decent in Firefox, and miserable in IE: Twitter&amp;rsquo;s HTML is dependent upon server-side browser detection, which I&amp;rsquo;m not going to attempt to recreate here.).  I&amp;rsquo;m no designer, but it seems like a step in the right direction to me, and adds a bit of bulletproofing with next to no effort expended.&lt;/p&gt;

&lt;p&gt;With this in your toolkit, I don&amp;rsquo;t think there&amp;rsquo;s any excuse for mandating a hard requirement for JavaScript for most interactive widgets.  Certainly complex applications would be hard-pressed to come up with ways of presenting the same functionality to all users, but I think we can all agree that &amp;ldquo;simple&amp;rdquo; functionality (like logging in) should be equally available to everyone, and we should absolutely take that into account when building websites.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: &lt;a href="http://timhuegdon.com/"&gt;Tim Huegdon&lt;/a&gt; mentioned, rightly, that &lt;code&gt;class&lt;/code&gt; isn&amp;rsquo;t actually a valid attribute on the &lt;code&gt;html&lt;/code&gt; element, and that it might be better to set the &lt;code&gt;js&lt;/code&gt; class on the document&amp;rsquo;s &lt;code&gt;body&lt;/code&gt; element instead.  It&amp;rsquo;s a valid point, one which ought not be ignored out of hand.  I&amp;rsquo;m sticking with &lt;code&gt;document.documentElement&lt;/code&gt; for a simple reason: I know it works stably in every browser I&amp;rsquo;ve tested (IE6+, FF2+, Safari 2+, Opera 9.5+).  I&amp;rsquo;ve heard anecdotal evidence of problems in IE caused by manipulating the document&amp;rsquo;s &lt;code&gt;body&lt;/code&gt; while it&amp;rsquo;s loading (&amp;ldquo;Operation Aborted&amp;rdquo;, and the like), which I&amp;rsquo;ve never experienced with this technique, and which I&amp;rsquo;d like to avoid.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update to the Update&lt;/strong&gt;:   &lt;a href="http://vanderven.se/martijn/"&gt;Martijn van der Ven&lt;/a&gt; notes, also rightly, that HTML5 allows &lt;code&gt;class&lt;/code&gt; attributes (as well as all other &lt;a href="http://dev.w3.org/html5/spec/dom.html#global-attributes"&gt;global attributes&lt;/a&gt;) on the &lt;code&gt;html&lt;/code&gt; element.  One more reason to switch over to the &lt;a href="http://diveintohtml5.org/semantics.html#the-doctype"&gt;HTML5 doctype&lt;/a&gt;, if you ask me.&lt;/p&gt;


&lt;img src="http://feeds.feedburner.com/~r/just_posts/~4/XrPKdimg6Dk" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://mikewest.org/2010/03/javascript-detection-pattern</feedburner:origLink></entry>

</feed>

