<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Elf Sternberg</title>
	<atom:link href="http://www.elfsternberg.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.elfsternberg.com</link>
	<description>Done, and gets things smart.</description>
	<lastBuildDate>Fri, 27 Jan 2012 04:50:27 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Scientific Progress!</title>
		<link>http://www.elfsternberg.com/2012/01/26/scientific-progress/</link>
		<comments>http://www.elfsternberg.com/2012/01/26/scientific-progress/#comments</comments>
		<pubDate>Fri, 27 Jan 2012 04:50:27 +0000</pubDate>
		<dc:creator>Elf Sternberg</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.elfsternberg.com/?p=1224</guid>
		<description><![CDATA[&#8220;The most exciting phrase to hear in science, the one that heralds new discoveries, is not &#8216;Eureka!&#8216; (&#8216;I found it!&#8217;) but rather &#8216;hmm&#8230;.that&#8217;s funny&#8230;&#8217;&#8221; &#8211; Isaac Asimov I had that very experience this evening.  It&#8217;s funny what gives you insight, what makes you understand.  I&#8217;ve been trying to wrap my head around the whole idea [...]]]></description>
			<content:encoded><![CDATA[<p>&#8220;The most exciting phrase to hear in science, the one that heralds new discoveries, is not &#8216;<em>Eureka!</em>&#8216; (&#8216;I found it!&#8217;) but rather &#8216;<em>hmm&#8230;.that&#8217;s funny&#8230;&#8217;&#8221; &#8211; </em>Isaac Asimov</p>
<p>I had that very experience this evening.  It&#8217;s funny what gives you insight, what makes you <em>understand</em>.  I&#8217;ve been trying to wrap my head around the whole idea of Haskell&#8217;s type, typeclass, data, and instance, and just not getting it.  It wasn&#8217;t clicking for me at all.  I went back to chapter 2 (!) of <em><a href="http://book.realworldhaskell.org/read/types-and-functions.html">Real World Haskell</a> </em>and started working through the problems again, and I hit this example:</p>
<pre>ghci&gt; lines "the quick\nbrown fox\njumps"["the quick","brown fox","jumps"]</pre>
<p>And being a good little student I meant to type:</p>
<pre>ghci&gt; :t lines</pre>
<p>But being a <em>lazy</em> student I used keyboard shortcuts to summon the previous example. I ended up with this:</p>
<pre>ghci&gt; :t lines "the quick\nbrown fox\njumps"
lines "the quick\nbrown fox\njumps" :: [String]</pre>
<p>And the lights totally went on. Because I realized that the expression to the left of the <tt>::</tt> symbol is not &#8220;an lvalue&#8221;, it&#8217;s just a <em>value</em>. If you don&#8217;t understand Haskell, why that&#8217;s a big deal might not make sense to you. But I get some of it now.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.elfsternberg.com/2012/01/26/scientific-progress/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ghost of Done: How Backbone and RDFa are incompatible, and a Grand Unified Theory thereof.</title>
		<link>http://www.elfsternberg.com/2012/01/25/ghost-backbone-rdfa-incompatible-grand-unified-theory-thereof/</link>
		<comments>http://www.elfsternberg.com/2012/01/25/ghost-backbone-rdfa-incompatible-grand-unified-theory-thereof/#comments</comments>
		<pubDate>Wed, 25 Jan 2012 17:24:06 +0000</pubDate>
		<dc:creator>Elf Sternberg</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.elfsternberg.com/?p=1221</guid>
		<description><![CDATA[Last night, I was working on a little demonstration project, teaching myself the intricacies of Backbone/CouchDB interaction. I wrote my first CouchDB views and figured out what they&#8217;re for, which is a massive step toward world domination and all that. I was working on the retrieval layer, and thinking about the create/update features, when I [...]]]></description>
			<content:encoded><![CDATA[<p>Last night, I was working on a little demonstration project, teaching myself the intricacies of <a href="http://documentcloud.github.com/backbone/">Backbone</a>/<a href="http://couchdb.apache.org/">CouchDB</a> interaction. I wrote my first CouchDB views and figured out what they&#8217;re for, which is a massive step toward world domination and all that. I was working on the retrieval layer, and thinking about the create/update features, when I said to myself, &#8220;Hey, Self, can you use that sexy new <a href="http://bergie.iki.fi/blog/using_rdfa_to_make_a_web_page_editable/">RDFa stuff</a> to handle the create/update feature?&#8221;</p>
<p>I&#8217;ve been thinking about this because I have a different project that&#8217;s very RDFa-heavy, and the details of implementation have been challenging. But no, I had to come to a different conclusion:</p>
<p>RDFa and Backbone.js are incompatible.</p>
<p>RDF is a framework for self-describing data, such that the data carries along with itself tokenized indicators for how it is to be organized, presented, and edited. The idea is simple: the browser requests a page, the server sends it all: the HTML represents the structured data, the CSS the visual depiction, and the javascript detects the RDFA (the &#8216;A&#8217; stands for &#8216;attributes&#8217;, HTML attributes) and decorates these islands of content with controls to make the content editable and saveable back to the server.  The data itself is kept in a representative semantic form of (X)HTML trees.</p>
<p>Backbone, in contrast, is a software framework in which the data is represented in a tree-like structure in Javascript itself, in the models and collections. The data does not come down with the page, but is requested after the fact by Backbone.  The HTML is rendered as a side-effect (my Haskell classes are rubbing off on me): it is a <em>representation</em> of the data-state on the client. Backbone works hard under the covers to keep the client and server state in sync, but in all cases the HTML is just a representation of the data; it is not the data itself.  The data itself is kept in Javascript trees.</p>
<p>These are two completely different approaches to managing data on the client. Both are valid. And both have their uses, but for the moment they don&#8217;t mesh well.</p>
<p><strong>&#8220;If you have an idea and publish it on the internet, it counts <a href="http://www.brepettis.com/blog/2009/3/3/the-cult-of-done-manifesto.html">as the ghost of done</a>.&#8221;</strong></p>
<p>So here&#8217;s my ghost:</p>
<p>We need a Backbone-like for RDFa. RDFa cannot easily be coerced into working with Backbone, but let&#8217;s face it: there are only a few things we work with on the internet: text and inputs, and lists and trees of text and inputs.</p>
<p>It ought to be possible to formalize a backbone-like collection of Views, Schemas and Rules, such that the transition from presentation to revision is seamless and perhaps not even distinct, and synchronization for a range of RDFa-enabled articles, forms, fieldsets, and the like is automagical. In other works, make Models and Views &#8220;know&#8221; about their data because it&#8217;s already present in the HTML, and not the other way around.  It&#8217;s the transition from page-format to server-side format that&#8217;s the pain point.</p>
<p>Hmm. This needs more thinking.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.elfsternberg.com/2012/01/25/ghost-backbone-rdfa-incompatible-grand-unified-theory-thereof/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>ToneMatrix for HTML5</title>
		<link>http://www.elfsternberg.com/2012/01/22/tonematrix-html5/</link>
		<comments>http://www.elfsternberg.com/2012/01/22/tonematrix-html5/#comments</comments>
		<pubDate>Sun, 22 Jan 2012 21:19:44 +0000</pubDate>
		<dc:creator>Elf Sternberg</dc:creator>
				<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://www.elfsternberg.com/?p=1219</guid>
		<description><![CDATA[This morning, I had an attack of SRMD, aka &#8220;Mad Scientist&#8217;s Disease.&#8221; Many moons ago, I admired a lovely little program called ToneMatrix by Andre Michelle. I had Flash envy hard after seeing it, and I wanted to figure out if it was possible to make such a thing using only HTML. Well, with the [...]]]></description>
			<content:encoded><![CDATA[<p>This morning, I had an attack of SRMD, aka &#8220;Mad Scientist&#8217;s Disease.&#8221; Many moons ago, I admired a lovely little program called <a href="http://lab.andre-michelle.com/tonematrix">ToneMatrix</a> by Andre Michelle. I had Flash envy hard after seeing it, and I wanted to figure out if it was possible to make such a thing using only HTML.</p>
<p>Well, with the latest <a href="https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html">audio standard</a> from the W3C (note that that&#8217;s a &#8220;Raw Tip&#8221; specification, meaning that it&#8217;s completely vaporware), it is now possible. Chrome supports much of the WebAudio specification, so this in what I hacked together in the past, oh, four hours or so: <a href="http://elfsternberg.com/projects/tonematrix">HTML5 Tone Matrix</a>.</p>
<p>Compared to the original, it&#8217;s not very pretty at all. I don&#8217;t understand audio. But it&#8217;s a start, and like all experiments, won&#8217;t suffer from further experimentation and understanding.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.elfsternberg.com/2012/01/22/tonematrix-html5/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Coffeescript is a gateway drug to Haskell</title>
		<link>http://www.elfsternberg.com/2012/01/15/coffeescript-gateway-drug-haskell/</link>
		<comments>http://www.elfsternberg.com/2012/01/15/coffeescript-gateway-drug-haskell/#comments</comments>
		<pubDate>Mon, 16 Jan 2012 01:17:54 +0000</pubDate>
		<dc:creator>Elf Sternberg</dc:creator>
				<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://www.elfsternberg.com/?p=1204</guid>
		<description><![CDATA[So, I&#8217;ve been working my way through Learn You A Haskell For Great Good, and in chapter five there&#8217;s a quicksort example that reads: quicksort [] = [] quicksort (x:xs) =            let smallerOrEqual = [a &#124; a]]></description>
			<content:encoded><![CDATA[<p>So, I&#8217;ve been working my way through <em>Learn You A Haskell For Great Good, </em>and in chapter five there&#8217;s a quicksort example that reads:</p>
<pre>
quicksort [] = []
quicksort (x:xs) =
           let smallerOrEqual = [a | a <- xs, a <= x]
               larger = [a | a <- xs, a > x]
           in quicksort smallerOrEqual ++ [x] ++ quicksort larger
</pre>
<p>I wondered what it would be like in Coffeescript.  Frighteningly enough, other than moving the guard condition into the function itself, they look remarkably similar:</p>
<pre>
quicksort = (x) ->
    return [] if x.length == 0
    h = x.pop()
    smallerOrEqual = (a for a in x when a <= h)
    larger = (a for a in x when a > h)
    (quicksort smallerOrEqual).concat([h]).concat(quicksort larger)
</pre>
<p>Coffescript is a gateway drug to Haskell.  If you don&#8217;t want to learn Haskell, turn back now.  (On the other hand, I think learning Haskell will be a hell of a good thing for me.  My brain needs the exercise.)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.elfsternberg.com/2012/01/15/coffeescript-gateway-drug-haskell/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Thinking In Haskell is harder than Thinking In Portals</title>
		<link>http://www.elfsternberg.com/2011/12/21/thinking-haskell-harder-thinking-portals/</link>
		<comments>http://www.elfsternberg.com/2011/12/21/thinking-haskell-harder-thinking-portals/#comments</comments>
		<pubDate>Wed, 21 Dec 2011 22:57:24 +0000</pubDate>
		<dc:creator>Elf Sternberg</dc:creator>
				<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.elfsternberg.com/?p=1202</guid>
		<description><![CDATA[I used to joke that, sometimes, when someone in my family comes down and sees a mess of code up in Emacs on my screen that &#8220;No, really, I&#8217;m playing a video game. It just looks like work.&#8221; Because I find coding fun. But the fact is that I also play games, and Portal 2 [...]]]></description>
			<content:encoded><![CDATA[<p>I used to joke that, sometimes, when someone in my family comes down and sees a mess of code up in Emacs on my screen that &#8220;No, really, I&#8217;m playing a video game.  It just looks like work.&#8221;  Because I find coding fun.  But the fact is that I also play games, and <i>Portal 2</i> was definitely a brain-bender.</p>
<p>But not as brain-bending as Haskell.</p>
<p>That said, I just finished the first exercise in <i>Seven Languages in Seven Weeks</i>, although really I&#8217;d think it&#8217;s more like <i>Seven Languages in Seven Days</i>, given my ferocious language consumption&#8211; I just skipped right to the Haskell part, because I have a project that requires Haskell at the moment.  Still, this was pretty cool.  Don&#8217;t read further if you don&#8217;t want the answer.</p>
<p><span id="more-1202"></span><br />
The problem was &#8220;Write a function that reverses a list.&#8221;  In most languages, that&#8217;s pretty simple.  In Haskell, not so much.  This problem requires three leaps: First, to understand that &#8220;strings are lists of characters&#8221; means exactly what it says, so the thing introduced earlier as a &#8220;String concatenation infix operator&#8221; is in fact a <i>list</i> concatenation infix operator, and finally take the Fibonacci example, with its helper functions and patterns, and apply that idea to this problem.</p>
<pre>
    reverseSub :: ([x], [x]) -> ([x], [x])
    reverseSub (xs, []) = (xs, [])
    reverseSub (xs, (h:t)) = reverseSub([h] ++ xs, t)

    reverse1 :: [x] -> [x]
    reverse1 [] = []
    reverse1 xs = (fst . reverseSub) ([], xs)
</pre>
<p>The function I&#8217;m defining I&#8217;m defining takes a list and returns a list.  If the list is empty, return an empty list.  Otherwise, return the first item in the tuple returned by reverseSub, to which I provide an empty list and my initial list.  </p>
<p>reverseSub, in turn, takes a tuple of two lists, and returns a tuple of two lists.  The first pattern says &#8220;If the second list is empty, return the tuple unchanged.&#8221;  The second pattern means &#8220;<i>Otherwise</i>, reverseSub of two lists is &#8220;the head of the second list concatenated with the first list, and the tail of the second list,&#8221; applied recursively.  It still feels totally weird to me that Haskell would automatically apply the second operation again and again until the first is met; I <i>understand</i> it intellectually, in a super-cool, I-love-recursion way, but it doesn&#8217;t quite resonate yet.  </p>
<p>Still, this is way fun.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.elfsternberg.com/2011/12/21/thinking-haskell-harder-thinking-portals/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Is backbone.js important enough to warrant its own recruitment category?</title>
		<link>http://www.elfsternberg.com/2011/12/02/backbonejs-important-warrant-recruitment-category/</link>
		<comments>http://www.elfsternberg.com/2011/12/02/backbonejs-important-warrant-recruitment-category/#comments</comments>
		<pubDate>Fri, 02 Dec 2011 19:01:21 +0000</pubDate>
		<dc:creator>Elf Sternberg</dc:creator>
				<category><![CDATA[chat]]></category>
		<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://www.elfsternberg.com/?p=1192</guid>
		<description><![CDATA[I got a call last night from a recruiter who was looking for &#8220;A front end guy: Javascript, HTML, CSS.  But the real kicker is they need someone with experience in Backbone.  Do you know anyone with that?&#8221; I said, &#8220;Sure. Me.&#8221; I told him about the tutorials I had written for Backbone, the current [...]]]></description>
			<content:encoded><![CDATA[<p>I got a call last night from a recruiter who was looking for &#8220;A front end guy: Javascript, HTML, CSS.  But the real kicker is they need someone with experience in Backbone.  Do you know anyone with that?&#8221;</p>
<p>I said, &#8220;Sure. <a href="http://www.elfsternberg.com/2011/08/22/backbone-store-version-20-backbonejs-coffeescript-haml-stylus-edition/">Me</a>.&#8221; I told him about the tutorials I had written for Backbone, the current use of Backbone at ${DAY_JOB}, the stuff I had contributed to Backbone-relational, and for a while we talked about the difference between Backbone and Knockout on the one hand, and then those versus do-everything frameworks like Cappucino and Sproutcore.</p>
<p>But here&#8217;s what gets me wondering: is Backbone.js, a fairly small and smart library, by itself difficult enough to warrant its own recruitment category? Any competent Javascript programmer who&#8217;s had any experience writing enterprise-level code, working with any of the above frameworks (along with JavascriptMVC and Batman and&#8230; did Amber ever make it into the wild?  I can&#8217;t follow <em>everything</em>, you know!), should be able to get up-to-speed on Backbone within a week or so of using it.  Just write a tutorial, like I did, then re-write to figure out how silly your original try was.</p>
<p>Is &#8220;We need Backbone experience&#8221; even a reasonable request at this point?</p>
]]></content:encoded>
			<wfw:commentRss>http://www.elfsternberg.com/2011/12/02/backbonejs-important-warrant-recruitment-category/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>I&#8217;m an idiot.  Ignore &#8220;Switchboard&#8221;</title>
		<link>http://www.elfsternberg.com/2011/11/30/idiot-ignore-switchboard/</link>
		<comments>http://www.elfsternberg.com/2011/11/30/idiot-ignore-switchboard/#comments</comments>
		<pubDate>Wed, 30 Nov 2011 20:16:14 +0000</pubDate>
		<dc:creator>Elf Sternberg</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.elfsternberg.com/?p=1184</guid>
		<description><![CDATA[The other day, I posted a chunk of code called Switchboard, which was all about using Nodejitsu&#8217;s node-http-proxy. I turns out there&#8217;s a much easier way. HttpProxy.createServer will create an empty routing proxy, and when you ask for a backend handler that isn&#8217;t present, node-http-proxy will automagically build one using internal defaults. So, really, your [...]]]></description>
			<content:encoded><![CDATA[<p>The other day, I posted a chunk of code called <a href="http://www.elfsternberg.com/2011/11/23/switchboard-reverse-proxy-handler-urlbased-namespacing/">Switchboard</a>, which was all about using Nodejitsu&#8217;s <a href="https://github.com/nodejitsu/node-http-proxy">node-http-proxy</a>. I turns out there&#8217;s a much easier way. <tt>HttpProxy.createServer</tt> will create an empty routing proxy, and when you ask for a backend handler that isn&#8217;t present, node-http-proxy will automagically build one using internal defaults.</p>
<p>So, really, your code looks like this:</p>
<pre>backends = [
    {
        name: 'Event Hub'
        host: 'http://127.0.0.1:8024'
        paths: ['^/socket.io/']
    },
    {
        name: 'Django Server'
        host: 'http://127.0.0.1:8022'
        paths: ['^/api/']
    }
]

standard_options = (t) -&gt;
    target:
        host: t.hostname
        port: t.port
        https: (t.protocol == 'https:')
    enable:
        xforward: true

for backend in backends
    backend.paths = (new RegExp(i) for i in backend.paths)
    backend.options = standard_options(url.parse(backend.host))

find_backend = (req) -&gt;
    pathname = url.parse(req.url).pathname
    for backend in backends
        for path in backend.paths
            m = path.exec(pathname)
            if m
                return backend
    null

proxyserver = httpProxy.createServer (req, res, proxy) -&gt;
    backend = find_backend(req)
    if backend
        proxy.proxyRequest(req, res, backend.options)
        return @

    # Clean up if no backend found
    try
        res.writeHead 404
        res.end()
    catch error
        console.error("res.writeHead/res.end error: %s", error.message)
    undefined

proxyserver.listen(80)</pre>
<p>Instead of all that silliness in the original, here I define my routes in a fairly standard human-readable format, and then translate them into the <tt>target</tt> style preferred by node-http-proxy. I have a simple function for looking up the back-end depending upon URL components and returning the first match. I let node-http-proxy do all the work of creating a connection to the back-end if it doesn&#8217;t work.</p>
<p>All that crud from last week reduced to a couple of list comprehensions and translations. Sad, isn&#8217;t it?</p>
<p>I should add that there&#8217;s a bug in the current version of node-http-proxy that will cause the code above to fail. Node-http-proxy has an internal call, <tt>_getKey()</tt>, to look up that host to which it will route a request, that it should use, but does not, for the ad-hoc proxy creation. Until that bug is fixed (and yes, I have a <a href="https://github.com/nodejitsu/node-http-proxy/pull/164">patch submitted</a> in), you&#8217;ll have to patch the server by hand.</p>
<p>There is some additional magic not shown in this example.  The rewriters is a trivial add-in, and neither example handles the case where a back-end issues an <tt>http://</tt> re-direct, but that has to be mangled to read <tt>https://</tt> before being forwarded to the client. Again, there&#8217;s a bug in the original that prevents this from working right, and I have a <a href="https://github.com/nodejitsu/node-http-proxy/pull/165">patch in for that</a> as well.</p>
<p>Finally, the code as checked out of <tt>npm</tt> has a bug that prevents websocket upgrades from working properly. My work-around was to disable that in the code and do it myself, but that&#8217;s not a satisfactory hack and I haven&#8217;t sent that forward to the nodejitsu team yet.</p>
<p>I will say that with all of these fixes in place, I have a working solution for replacing Nginx. It proxies nicely, it proxies websockets nicely, <em>and</em> it proxies large-file uploads without using hideously huge memory or file buffers on the proxy server, all through SSL. We will be evaluating its performance, stability, and cross-browser issues over the next couple of weeks to ensure it&#8217;s a good solution.</p>
<p>I will also say that reading the Nginx source code was an eye-opening experience. The <tt>core</tt> and <tt>http</tt> modules are very well-written, clear and concise, and learning from their comments and code examples has made a big difference in how I&#8217;m approaching this proxying issue.</p>
<p>In theory, I could reduce Switchboard down to my routines for defining backends and frontends, add the rewriter and ad-hoc websocket upgrader.  Maybe I will.  It&#8217;ll be a heck of a lot shorter than the current edition.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.elfsternberg.com/2011/11/30/idiot-ignore-switchboard/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>I should stop reading magazines.</title>
		<link>http://www.elfsternberg.com/2011/11/28/stop-reading-magazines/</link>
		<comments>http://www.elfsternberg.com/2011/11/28/stop-reading-magazines/#comments</comments>
		<pubDate>Tue, 29 Nov 2011 01:24:51 +0000</pubDate>
		<dc:creator>Elf Sternberg</dc:creator>
				<category><![CDATA[chat]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[Design]]></category>
		<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://www.elfsternberg.com/?p=1180</guid>
		<description><![CDATA[I have to say that I&#8217;m really disappointed with .net magazine this month. .Net is a popular magazine for web designer and developers, and frequently has great articles and tutorials. For someone in my class of developer it&#8217;s not always that useful, but there&#8217;s always one or two tutorials worth perusing&#8211; and reading the tutorials [...]]]></description>
			<content:encoded><![CDATA[<p>I have to say that I&#8217;m really disappointed with <a href="http://netmagazine.com">.net</a> magazine this month. .Net is a popular magazine for web designer and developers, and frequently has great articles and tutorials. For someone in my class of developer it&#8217;s not always that useful, but there&#8217;s always one or two tutorials worth perusing&#8211; and reading the tutorials is what I buy it for.</p>
<p>I don&#8217;t do much with Cold Fusion, Flash, and obviously a beginners&#8217; article on Coffeescript just isn&#8217;t going to impress me, so those tutorials were out. On the other hand, the central article was on <a href="http://webdesignerwall.com/trends/inspiration-fluid-responsive-design">responsive design</a>, and a badge graphically associated with the &#8220;responsive design&#8221; part of the cover art promised &#8220;16 pages of how-to guides and advice!&#8221;</p>
<p>Which there wasn&#8217;t. Other than one article on using Drupal&#8217;s server-side client detection facility (Drupal? Server-side user agent detection? I mean, <em>really?</em>), there wasn&#8217;t anything in this issue that really corresponded as actionable advice.</p>
<p>If you want a real looksee at responsive design, <a href="http://www.alistapart.com/articles/responsive-web-design/">Ethan Marcotte&#8217;s original article</a> is where you start, Smashing Magazine <a href="http://coding.smashingmagazine.com/2011/01/12/guidelines-for-responsive-web-design/">has a decent article</a>, and once you understand the basics, DesignModo&#8217;s <a href="http://designmodo.com/responsive-design-examples/">50 Examples</a> is definitely where you see how the rubber meets the road.</p>
<p>Maybe I&#8217;m just done reading magazines.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.elfsternberg.com/2011/11/28/stop-reading-magazines/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Switchboard: A Reverse Proxy Handler for URL-based Namespacing</title>
		<link>http://www.elfsternberg.com/2011/11/23/switchboard-reverse-proxy-handler-urlbased-namespacing/</link>
		<comments>http://www.elfsternberg.com/2011/11/23/switchboard-reverse-proxy-handler-urlbased-namespacing/#comments</comments>
		<pubDate>Thu, 24 Nov 2011 03:31:55 +0000</pubDate>
		<dc:creator>Elf Sternberg</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.elfsternberg.com/?p=1158</guid>
		<description><![CDATA[tl;dr version: We recently replaced our Nginx with an HTTP reverse proxy written entirely in Node.js. We leveraged Nodejitsu&#8217;s node-http-proxy, and added our own logic to provide a useful switchboard for several small HTTP servers, each of which &#8220;does one thing well,&#8221; in the Coffeescript programming language. There are three scenarios where a reverse proxy [...]]]></description>
			<content:encoded><![CDATA[<blockquote><p>tl;dr version: We recently replaced our Nginx with an HTTP reverse proxy written entirely in Node.js. We leveraged Nodejitsu&#8217;s node-http-proxy, and added our own logic to provide a useful switchboard for several small HTTP servers, each of which &#8220;does one thing well,&#8221; in the Coffeescript programming language.</p></blockquote>
<p>There are three scenarios where a reverse proxy is useful. The first is when you have several back-end servers that all do the same thing, and you want to distribute the load across those servers; the second is when you have several different back-end servers on the same box, one per hostname, and you want to dispatch the packet to the correct handler.</p>
<p>The last is when you have several different services that are deployed from several different kinds of webservers, and you want all of those to be fed out of the same address/port combination. For a real-world example, we at Spiral Genetics have our core application server; an authentication and accounting server (&#8220;Who are you and do you have any money?&#8221;); a media server; an import handler for customer uploads; and a pub/sub/hub that coordinates among these, and publishes events to our web-based UI as events happen on the back-end.</p>
<p>Ngnix buffers requests before passing them on to the back-end service, and it doesn&#8217;t speak HTTP/1.0 natively to its back-ends, a requirement for websockets. Both of these limitations needed to be overcome.</p>
<p>My initial research led me to <a href="https://github.com/nodejitsu/node-http-proxy">Node-HTTP-Proxy</a>, which did about 90%of what I wanted it to do. The request-response cycle within Node-HTTP-Proxy&#8217;s HttpProxy object was exactly what I wanted, with non-buffering of the body of the HTTP request, and automatic upgrading to both HTTP/1.1 and the Websocket protocol as needed.</p>
<p>Node-HTTP-Proxy&#8217;s examples came in two flavors: a single route to a single back-end, multiple-routes to hostname-related back-ends, and a how-to example that showed how to route to different back-ends based on URL fragments.</p>
<p>It was this last example, <a href="https://github.com/dominictarr/proxy-by-url">route-by-proxy</a>, that provided the bulk of the intelligence needed for our solution.</p>
<h2><a name="toc2"></a><br />
Segmentation</h2>
<p>There were two things that needed to be addressed: first, since we had multiple back-end servers that would be addressed through a single hostname, segmenting those back-end servers would have to be done on a URL basis. Fortunately, Node 0.6&#8242;s request/response cycle pauses when the head of the request has been processed and allows us to process the inbound data in chunks, the same way we&#8217;d handle outbound data.</p>
<p>The second problem was that one of our services was &#8220;macros of <a name="NWD3ORUn8-1"></a>instructions to the data server,&#8221; which was easier to store as a set of procedural steps somewhere other than the data server. So we needed a URL re-writer that <em>looked like</em> it was part of the data server&#8217;s namespace, but was actually in its own little application.</p>
<p>Node-HTTP-Proxy&#8217;s &#8220;proxy-by-url&#8221; example demonstrates how to do this, for the most part, but here&#8217;s what we wanted:</p>
<pre><a name="NW3ORUn8-2rlFOF-1" href="#NWD3ORUn8-1"></a><dfn>&lt;configure and run the application&gt;=</dfn> <strong>(<a href="#NWD3ORUn8-E">U-&gt;</a>)</strong> <strong>[D<a href="#NWD3ORUn8-2">-&gt;</a>]</strong>
routes = [
    ['http://127.0.0.1:80', ['^/AnimatedSkills/', '^/180minutes/'], "Event Hub"],
    ['http://127.0.0.1:8002', '^/soundpodcast/', "Auth Server"]
]</pre>
<p>This is the base configuration: For each destination, we have a list of URLs that we want to go to that destination. You&#8217;ll note that the last one in &#8220;Auth Server&#8221; goes to the home page; it&#8217;s a Django application that&#8217;s perfectly capable of figuring out if you&#8217;re logged in and serving you the application, or demanding you log in if you <a name="NWD3ORUn8-2"></a>aren&#8217;t.</p>
<p>You&#8217;ll also note that the path to &#8220;Auth Server&#8221; comes before the &#8220;Data Server.&#8221; It&#8217;s a more precise path, and we want it to be analyzed first.</p>
<p>We also wanted to do URL rewrites <em>after</em> the path had been determined. So we&#8217;re going to pass that to our switchboard:</p>
<pre><a name="NW3ORUn8-2rlFOF-2" href="#NWD3ORUn8-1"></a><dfn>&lt;configure and run the application&gt;+=</dfn> <strong>(<a href="#NWD3ORUn8-E">U-&gt;</a>)</strong> <strong>[<a href="#NWD3ORUn8-1">&lt;-</a>D<a href="#NWD3ORUn8-3">-&gt;</a>]</strong>
switchboard_options =
    rewrites: [['^/soundpodcast/', '/']]</pre>
<p><a name="NWD3ORUn8-3"></a>And finally we start the application, passing our switchboard to node-http-proxy&#8217;s <code>httpProxy.createServer</code> function:</p>
<pre><a name="NW3ORUn8-2rlFOF-3" href="#NWD3ORUn8-1"></a><dfn>&lt;configure and run the application&gt;+=</dfn> <strong>(<a href="#NWD3ORUn8-E">U-&gt;</a>)</strong> <strong>[<a href="#NWD3ORUn8-2">&lt;-</a>D]</strong>
server_options = {}
console.log("Listening on port 8120")
proxy = httpProxy.createServer(server_options, Connect.logger(), switchboard(routes, switchboard_options))
proxy.listen(8120)</pre>
<h2>The Switchboard</h2>
<p>I&#8217;m asking three things of the switchboard: efficient look-ups based on the URL&#8217;s content, efficient rewrite of the URL to be passed to the <a name="NWD3ORUn8-4"></a>back-end server, and a minimal number of proxy handlers to be configured in the meantime.</p>
<p>What I want, ultimately, is to create an array of routes that I will search, in order, for a match. First match wins, and to associate those routes with the appropriate proxy.</p>
<p>Using Coffeescript, let&#8217;s put that into a constructor.</p>
<pre><a name="NW3ORUn8-8NqEs-1" href="#NWD3ORUn8-4"></a><dfn>&lt;Switchboard constructor&gt;=</dfn> <strong>(<a href="#NWD3ORUn8-B">U-&gt;</a>)</strong> <strong>[D<a href="#NWD3ORUn8-5">-&gt;</a>]</strong>
constructor: (routes, routing_options = {}) -&gt;
    @rewrites = []
    @routes = []

    for route in routes
        target = url.parse(route[0])

        options = {}
        options.target = {}
        options.target.host = target.hostname
        options.target.port = target.port
        options.target.https = (target.protocol == 'https:')

        proxy = new HttpProxy(options)
        proxy.on 'start', (req, res, target) =&gt; @emit('start', req, res, target)
        proxy.on 'end', (req, res) =&gt; @emit('end', req, res)</pre>
<p>Here, for a given back-end, we&#8217;re creating a new <code>HttpProxy</code> object <a name="NWD3ORUn8-5"></a>that knows the basic information needed to contact the back-end. That information won&#8217;t be needed until we make a request, but now it&#8217;s cached in the proxy object.</p>
<p>Now, for each route, the second item in each routing table object, we&#8217;re going to create a RegExp object for matching, a reference to the proxy we just created, and we&#8217;ll keep the comment. (We don&#8217;t actually do anything smart with the comment right now.) <!--'--></p>
<pre><a name="NW3ORUn8-8NqEs-2" href="#NWD3ORUn8-4"></a><dfn>&lt;Switchboard constructor&gt;+=</dfn> <strong>(<a href="#NWD3ORUn8-B">U-&gt;</a>)</strong> <strong>[<a href="#NWD3ORUn8-4">&lt;-</a>D<a href="#NWD3ORUn8-6">-&gt;</a>]</strong>
        for r in (if (route[1] instanceof Array) then route[1] else [route[1]])
            @routes.push
                match: new RegExp(r)
                proxy: proxy
                comment: route[2]</pre>
<p><a name="NWD3ORUn8-6"></a>A little syntactic sugar there allows you to pass in plain paths rather than arrayed ones, but that&#8217;s about it.</p>
<p>And finally, we need to remember the rewriting options. Again, we care about a regexp for the inbound path.</p>
<pre><a name="NW3ORUn8-8NqEs-3" href="#NWD3ORUn8-4"></a><dfn>&lt;Switchboard constructor&gt;+=</dfn> <strong>(<a href="#NWD3ORUn8-B">U-&gt;</a>)</strong> <strong>[<a href="#NWD3ORUn8-5">&lt;-</a>D]</strong>
    if routing_options and routing_options.rewrites?
        @rewrites = ({match: new RegExp(r[0]), rewrite: r[1]} for r in routing_options.rewrites)</pre>
<p><a name="NWD3ORUn8-7"></a>You can&#8217;t tell me that Coffeescript&#8217;s comprehension&#8217;s aren&#8217;t cool.</p>
<p>Next, we want to be able to determine if a given request matches our switchboard. That&#8217;s a fairly straightforward RegExp match. When we get a hit, we want to return the route object associated with the match. If we don&#8217;t get a hit, return null</p>
<pre><a name="NW3ORUn8-3BSKFO-1" href="#NWD3ORUn8-7"></a><dfn>&lt;Switchboard URL matcher&gt;=</dfn> <strong>(<a href="#NWD3ORUn8-B">U-&gt;</a>)</strong>
match: (path) -&gt;
    for route in @routes
        m = route.match.exec(path)
        if m
            return route
    null</pre>
<p><a name="NWD3ORUn8-8"></a>And finally, now that we&#8217;ve had a match, we want to proxy that match. The handler has all the context information we need.</p>
<pre><a name="NW3ORUn8-30uFhy-1" href="#NWD3ORUn8-8"></a><dfn>&lt;Switchboard proxy dispatch&gt;=</dfn> <strong>(<a href="#NWD3ORUn8-B">U-&gt;</a>)</strong>
proxy: (handler, req, res) -&gt;
    path = url.parse(req.url)
    req.url = @rewrite(req.url)
    p = handler.proxy.proxyRequest req, res, null</pre>
<p>Rewrites are probably more complicated than the proxy itself. We have to get the URL right, but we can&#8217;t afford to confuse the <code>HttpProxy</code>, which has its own needs about URLs. The popular convention is to replace <code>\$1</code> with the first match of the RegExp, <code><a name="NWD3ORUn8-9"></a>\$2</code> with the second and so on. Here, we use Node&#8217;s <!--'--><br />
<code>url.parse()</code> method to create a URL object, perform a match against our list of rewrites, and if we get a hit, we make a new URL object, copying those from the original, and then mangling the pathname. We transform this new object back into a standard URL for <code>HttpProxy</code> to make sense of, and return it. Otherwise, we return the original URL unchanged. <!--'--></p>
<pre><a name="NW3ORUn8-i56fS-1" href="#NWD3ORUn8-9"></a><dfn>&lt;Switchboard URL rewriter&gt;=</dfn> <strong>(<a href="#NWD3ORUn8-B">U-&gt;</a>)</strong>
rewrite: (ourl) -&gt;
    path = url.parse(ourl)
    for check in @rewrites
        m = check.match.exec(path.pathname)
        if m
            resp = {}
            for i of path
                if path.hasOwnProperty(i)
                    resp[i] = path[i]
            resp.pathname = check.rewrite
            for i in [1..m.length - 1]
                resp.pathname = resp.pathname.replace(@substitutions[i], m[i])
            return url.format(resp)
    return ourl</pre>
<p><a name="NWD3ORUn8-A"></a>The <code>@substitutions</code> are pre-cached regular expressions for <code>$1</code> through <code>$9</code>:</p>
<pre><a name="NW3ORUn8-VR3nf-1" href="#NWD3ORUn8-A"></a><dfn>&lt;Substitution regexps for URL rewriting&gt;=</dfn> <strong>(<a href="#NWD3ORUn8-B">U-&gt;</a>)</strong>
substitutions: (new RegExp('\\$' + i) for i in [0..10])</pre>
<p><!--$--><br />
<a name="NWD3ORUn8-B"></a>And our class looks like:</p>
<pre><a name="NW3ORUn8-V3qPy-1" href="#NWD3ORUn8-B"></a><dfn>&lt;Class Switchboard&gt;=</dfn> <strong>(<a href="#NWD3ORUn8-D">U-&gt;</a>)</strong>
class Switchboard extends events.EventEmitter
      <a name="NW3ORUn8-V3qPy-1-u1" href="#NWD3ORUn8-A"></a><em>&lt;Substitution regexps for URL rewriting&gt;</em>

      <a name="NW3ORUn8-V3qPy-1-u2" href="#NWD3ORUn8-4"></a><em>&lt;Switchboard constructor&gt;</em>

      <a name="NW3ORUn8-V3qPy-1-u3" href="#NWD3ORUn8-7"></a><em>&lt;Switchboard URL matcher&gt;</em>

      <a name="NW3ORUn8-V3qPy-1-u4" href="#NWD3ORUn8-9"></a><em>&lt;Switchboard URL rewriter&gt;</em>

      <a name="NW3ORUn8-V3qPy-1-u5" href="#NWD3ORUn8-8"></a><em>&lt;Switchboard proxy dispatch&gt;</em></pre>
<p><a name="NWD3ORUn8-C"></a>It&#8217;s nice and all that we have this class, but for our purposes we&#8217;re going to create a single function that pulls it all together, and handles the case where there is no match. And then we&#8217;ll export this <!--'--><br />
function so other people can use it:</p>
<pre><a name="NW3ORUn8-6UM0B-1" href="#NWD3ORUn8-C"></a><dfn>&lt;export the switchboard function&gt;=</dfn> <strong>(<a href="#NWD3ORUn8-D">U-&gt;</a>)</strong>
module.exports = (routes, options) -&gt;
    switchboard = new Switchboard routes, options
    (req, res, next) -&gt;
        path = url.parse(req.url)
        handler = switchboard.match(path.pathname)
        if handler
            return switchboard.proxy handler, req, res, next
        try
            res.writeHead 404
            res.end()
        catch error
            console.error("res.writeHead/res.end error: %s", er.message)
        undefined</pre>
<p><a name="NWD3ORUn8-D"></a>So now our programs become, first, our library:</p>
<pre><a name="NW3ORUn8-2RyBE4-1" href="#NWD3ORUn8-D"></a><dfn>&lt;switchboard.coffee&gt;=</dfn>
events = require('events')
HttpProxy = require('http-proxy').HttpProxy
url = require('url')

<a name="NW3ORUn8-2RyBE4-1-u1" href="#NWD3ORUn8-B"></a><em>&lt;Class Switchboard&gt;</em>

<a name="NW3ORUn8-2RyBE4-1-u2" href="#NWD3ORUn8-C"></a><em>&lt;export the switchboard function&gt;</em></pre>
<p><a name="NWD3ORUn8-E"></a>And secondly, our example:</p>
<pre><a name="NW3ORUn8-TdXYj-1" href="#NWD3ORUn8-E"></a><dfn>&lt;dispatchexample.coffee&gt;=</dfn>
Connect = require('connect')
httpProxy = require('http-proxy')
switchboard = require('./switchboard')

<a name="NW3ORUn8-TdXYj-1-u1" href="#NWD3ORUn8-1"></a><em>&lt;configure and run the application&gt;</em></pre>
<p>As always, this code, in both the Literate Programming original and a fully functional NodeJS/Coffeescript library, is available at my github under <a href="https://github.com/elfsternberg/node-http-proxy-switchboard">elfsternberg/node-http-proxy-switchboard</a>.</p>
<ul>
<li><a href="#NWD3ORUn8-B"><em>&lt;Class Switchboard&gt;</em></a>: <a href="#NWD3ORUn8-B">D1</a>, <a href="#NWD3ORUn8-D">U2</a></li>
<li><a href="#NWD3ORUn8-1"><em>&lt;configure and run the application&gt;</em></a>: <a href="#NWD3ORUn8-1">D1</a>, <a href="#NWD3ORUn8-2">D2</a>, <a href="#NWD3ORUn8-3">D3</a>, <a href="#NWD3ORUn8-E">U4</a></li>
<li><a href="#NWD3ORUn8-E"><em>&lt;dispatchexample.coffee&gt;</em></a>: <a href="#NWD3ORUn8-E">D1</a></li>
<li><a href="#NWD3ORUn8-C"><em>&lt;export the switchboard function&gt;</em></a>: <a href="#NWD3ORUn8-C">D1</a>, <a href="#NWD3ORUn8-D">U2</a></li>
<li><a href="#NWD3ORUn8-A"><em>&lt;Substitution regexps for URL rewriting&gt;</em></a>: <a href="#NWD3ORUn8-A">D1</a>, <a href="#NWD3ORUn8-B">U2</a></li>
<li><a href="#NWD3ORUn8-4"><em>&lt;Switchboard constructor&gt;</em></a>: <a href="#NWD3ORUn8-4">D1</a>, <a href="#NWD3ORUn8-5">D2</a>, <a href="#NWD3ORUn8-6">D3</a>, <a href="#NWD3ORUn8-B">U4</a></li>
<li><a href="#NWD3ORUn8-8"><em>&lt;Switchboard proxy dispatch&gt;</em></a>: <a href="#NWD3ORUn8-8">D1</a>, <a href="#NWD3ORUn8-B">U2</a></li>
<li><a href="#NWD3ORUn8-7"><em>&lt;Switchboard URL matcher&gt;</em></a>: <a href="#NWD3ORUn8-7">D1</a>, <a href="#NWD3ORUn8-B">U2</a></li>
<li><a href="#NWD3ORUn8-9"><em>&lt;Switchboard URL rewriter&gt;</em></a>: <a href="#NWD3ORUn8-9">D1</a>, <a href="#NWD3ORUn8-B">U2</a></li>
<li><a href="#NWD3ORUn8-D"><em>&lt;switchboard.coffee&gt;</em></a>: <a href="#NWD3ORUn8-D">D1</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.elfsternberg.com/2011/11/23/switchboard-reverse-proxy-handler-urlbased-namespacing/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Making Backbone-Relational work with deep namespaces</title>
		<link>http://www.elfsternberg.com/2011/11/09/making-backbonerelational-work-deep-namespaces/</link>
		<comments>http://www.elfsternberg.com/2011/11/09/making-backbonerelational-work-deep-namespaces/#comments</comments>
		<pubDate>Wed, 09 Nov 2011 19:14:47 +0000</pubDate>
		<dc:creator>Elf Sternberg</dc:creator>
				<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://www.elfsternberg.com/?p=1149</guid>
		<description><![CDATA[It&#8217;s no secret that I&#8217;m a Backbone.js fan, along with everything else. One of my other preferences is for Backbone-Relational, a nifty hack on top of Backbone that allows you to create, manage, and maintain simple relationships between objects. If you have a CouchDB or other JSON-oriented database, and you want to manipulate a record [...]]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s no secret that I&#8217;m a Backbone.js fan, along with everything else. One of my other preferences is for <a href="https://github.com/PaulUithol/Backbone-relational">Backbone-Relational</a>, a nifty hack on top of Backbone that allows you to create, manage, and maintain simple relationships between objects. If you have a CouchDB or other JSON-oriented database, and you want to manipulate a record with Backbone on the client and then write it back, Backbone-Relational will let you define how child records get encoded into JSON, and when you write the parent object the backbone <tt>toJSON()</tt> call will automatically encapsulate your record in a DB-ready format. Very good.</p>
<p>I&#8217;m also fond of namespaces, and have started using the <a href="https://github.com/jashkenas/coffee-script/wiki/Easy-modules-with-coffeescript">easy modules hack</a> to manage namespaces with Coffeescript. It&#8217;s just a layer of abstraction on top of simply allocating yourself a namespace hanging off the root (in the client case, the traditional DOM <tt>window</tt> object). But it&#8217;s a nice, clear, self-documenting abstraction.</p>
<p>I discovered, however, that Backbone-Relational doesn&#8217;t like this idea. Since it&#8217;s an ORM, it needs to keep references to the models used for relationships, and it stores these as strings. The introspection layer is fairly dumb and not sure where to stop, so it assumes all of the names hang off the root namespace.</p>
<p>Bad idea. The following will not work:</p>
<pre>@module "MyModule", -&gt;
    class @AClass
        relations: [
            type: Backbone.HasMany
            key: 'children'
            relatedModel: @TheOtherClass
            includeInJSON: false
            reverseRelation:
                type: Backbone.HasOne
                key: 'parent'
        ]</pre>
<p>However, because Backbone-Relational is working off string namespaces, specifying the relationships a  string works wonders:</p>
<pre>@module "MyModule", -&gt;
    MyModule = @
    class MyModule.AClass
        relations: [
            type: Backbone.HasMany
            key: 'children'
            relatedModel: "MyModule.TheOtherClass"
            includeInJSON: false
            reverseRelation:
                type: Backbone.HasOne
                key: 'parent'
        ]</pre>
<p>In some respects, this is fairly ugly. You&#8217;re losing some of the shorthand advantages of using the Module hack by repetitiously (if you&#8217;re using the namespace in more than one file) re-assigning the module&#8217;s <tt>this</tt> object to a local name.  In other respects, it&#8217;s self-documenting, allows Backbone-Relational to work well, and is well-behaved.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.elfsternberg.com/2011/11/09/making-backbonerelational-work-deep-namespaces/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

