<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:posterous="http://posterous.com/help/rss/1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:media="http://search.yahoo.com/mrss/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">
  <channel>
    <title>Parcell's Posts</title>
    <link>http://blog.edparcell.com</link>
    <description>Most recent posts at Parcell's Posts</description>
    <generator>posterous.com</generator>
    <link xmlns="http://www.w3.org/2005/Atom" href="http://posterous.com/api/sup_update#0a893d0c2" type="application/json" rel="http://api.friendfeed.com/2008/03#sup" />
    
    
    <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/ParcellsPosts" /><feedburner:info uri="parcellsposts" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://posterous.superfeedr.com/" /><item>
      <pubDate>Sat, 17 Sep 2011 14:27:00 -0700</pubDate>
      <title>Thoughts on If this, then that</title>
      <link>http://feedproxy.google.com/~r/ParcellsPosts/~3/5Z4Swk9AFgg/thoughts-on-if-this-then-that</link>
      <guid isPermaLink="false">http://blog.edparcell.com/thoughts-on-if-this-then-that</guid>
      <description>&lt;p&gt;
	&lt;p&gt;&lt;span style="font-family: Arial, sans-serif; line-height: 18px;"&gt;My friend George pointed out a link to an &lt;a href="http://www.infoworld.com/t/cloud-computing/the-great-dropbox-twitter-facebook-mashup-arrives-173341?page=0,1" target="_blank"&gt;Infoworld article&lt;/a&gt; about a new startup, If this then that&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;I've been looking at internet-wide event processing for a little while. My feeling is that messaging and event-processing have been big and useful in enterprise IT for a while, but that so far there hasn't been much on the wider web ecosystem. And we are increasingly generating and consuming events - facebook status updates, google+ updates, location data, share prices, real-time sports data. So my hope has been that this is an area that can grow up and offer us some great new capabilities in the next few years.&lt;/p&gt;
&lt;p&gt;So if this then that looks interesting. Unfortunately, it appears their site is down right now, so I need to follow up further, but my initial impressions from the infoworld article are&lt;/p&gt;
&lt;p&gt;&lt;span style="font-family: Arial, sans-serif; line-height: 18px;"&gt;&lt;ol&gt;
&lt;li&gt;This is cool, and not too far from the lines I was thinking - I hope it generates some interest.&lt;/li&gt;
&lt;li&gt;It reminds me a little of Yahoo's pipes, which was cool, but never really went anywhere. Albeit an event-based version, so as SQL is to CEP, pipes is to this I guess, in my mind.&lt;/li&gt;
&lt;li&gt;That it relies on ifttt people hooking into your site. I hope I am wrong about this - it would be a shame for me to have to build a userbase of tens of millions of users before it's worth their while hooking into my API.&lt;/li&gt;
&lt;li&gt;That it's proprietary, and that's reasonable given the amount of IP in those integrations. But then it depends on their integration with various APIs, and your event-processing remains locked in their system. This is a shame, and that's why I hope that underlying protocols for event dissemination get standardized, so that systems like this can become&amp;nbsp;commoditized.&lt;/li&gt;
&lt;/ol&gt;In my mind, what is needed is a standard for events, as RSS standardized blog data etc. So that just as google reader doesn't have to have different processing for wordpress vs blogger vs slashdot vs xkcd vs ... then a given event processing program, library, add-in or extension wouldn't have to speak facebook, google+, twitter, yahoo finance, google finance, betfair, formula 1, etc.. Given that I think there is scope for event processing in the cloud, on the desktop as a stand-alone application, on the desktop integrated with the OS, on the desktop as an add-in/extension to various programs eg Excel add-in, a notification programme, and integrated with the OS on mobile, the sheer number of data sources and consumers, tends to suggest to me that events won't really reach their full potential until there is a common protocol in the middle.&lt;p /&gt;Anyway, these are just my thoughts, and ifttt seems like an exciting step increasing general excitement around events, and hopefully a baby-step to a brave new world where consuming, processing and emitting events across sites seems as commonplace as looking at a blog in google reader.&lt;/span&gt;&lt;/p&gt;
	
&lt;/p&gt;

&lt;p&gt;&lt;a href="http://blog.edparcell.com/thoughts-on-if-this-then-that"&gt;Permalink&lt;/a&gt; 

	| &lt;a href="http://blog.edparcell.com/thoughts-on-if-this-then-that#comment"&gt;Leave a comment&amp;nbsp;&amp;nbsp;&amp;raquo;&lt;/a&gt;

&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ParcellsPosts/~4/5Z4Swk9AFgg" height="1" width="1"/&gt;</description>
      <posterous:author>
        <posterous:userImage>http://posterous.com/images/profile/missing-user-75.png</posterous:userImage>
        <posterous:profileUrl>http://posterous.com/users/5erKH0kcdaeZ</posterous:profileUrl>
        <posterous:firstName>Ed</posterous:firstName>
        <posterous:lastName>Parcell</posterous:lastName>
        <posterous:nickName>edparcell</posterous:nickName>
        <posterous:displayName>Ed Parcell</posterous:displayName>
      </posterous:author>
    <feedburner:origLink>http://blog.edparcell.com/thoughts-on-if-this-then-that</feedburner:origLink></item>
    <item>
      <pubDate>Wed, 15 Sep 2010 10:23:00 -0700</pubDate>
      <title>How I added my Hacker News saved stories to my Posterous sidebar</title>
      <link>http://feedproxy.google.com/~r/ParcellsPosts/~3/EHk5VmJbiWI/how-i-added-my-hacker-news-saved-stories-to-m</link>
      <guid isPermaLink="false">http://blog.edparcell.com/how-i-added-my-hacker-news-saved-stories-to-m</guid>
      <description>&lt;p&gt;
	&lt;p&gt;I acknowledge that adding something to the sidebar of my Posterous blog is not going to set the world on fire. The real meat here is that I have created a nascent library to pull data from the Hacker News website and I'm interested to see what all the creative people that hang out over there do with it. &lt;a href="http://github.com/edparcell/HNScraper"&gt;The code is available on github&lt;/a&gt;&amp;nbsp;- help yourselves.&lt;/p&gt;
&lt;p&gt;If you interested in software, or startups and don't already read &lt;a href="http://news.ycombinator.com/news"&gt;Hacker News&lt;/a&gt;, you should. It's what reddit was before it got big, and what slashdot was before it got big before that. Fortunately, Paul Graham know what's what, so Hacker News has proved more robust.&lt;/p&gt;
&lt;p&gt;I've spent quite a bit of time following articles on Hacker News, upvoting the ones that I like, and know I'll want to read again one day. It occurred to me that it would be awesome to make the stories I've upvoted available as a side-bar on this site. In this day of RSS that should be easy right? Wrong. Hacker News is deliberately basic, partly due to PG's time-constraints, and partly I suspect because keeping it basic means only people actively interested in the subject matter go there. As a result, it doesn't have an RSS feed for the list of your saved stories that it maintains. And Posterous doesn't seem to have any option to add an RSS feed to a side-bar anyway.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;span style="font-size: large;"&gt;Architecting and building this little monstrosity&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I have a couple of virtual private servers that I keep around to perform tasks like this. The plan here was to have a VPS periodically scrape the Hacker News site, and generate a static HTML file, which could then be included in the Posterous sidebar.&lt;/p&gt;
&lt;p&gt;My choice of language for tasks like this is Python. There are a stunning number of libraries built into it, and it's easy to augment its power using packages from the PyPI repository. I'm sure that Ruby and Perl would be similarly capable, but this is definitely a task best suited for a scripting language.&lt;/p&gt;
&lt;p&gt;I chose to use the &lt;a href="http://wwwsearch.sourceforge.net/mechanize/"&gt;Mechanize librar&lt;/a&gt;y to control interaction with the Hacker News site. Mechanize provides you with a 'browser' object that can be easily told how to fill in forms, or to click a link with particular text. This relieves the strain of having to keep track of state between calls to an HTTP library, and having to parse the returned HTML. This made it a lot easier to handle the stream of hidden forms and clicks that have to be done to log in to Hacker News using clickpass.&lt;/p&gt;
&lt;p&gt;The library wraps around the Mechanize browser object, allowing the library user to easily log in to Hacker News (currently only available using a google login - patches/pull requests welcome if you'd like to contribute). Once logged in, the user uses the nav_* functions to navigate to the appropriate page, and the get_current_page_stories function to get a list of dictionaries, each item representing a story. An example interactive session might look like this:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;
&amp;gt;&amp;gt;&amp;gt; import hnscraper &amp;nbsp; &amp;nbsp; &amp;nbsp;
&amp;gt;&amp;gt;&amp;gt; h=hnscraper.HNScraper()
&amp;gt;&amp;gt;&amp;gt; h.login_with_google('USERNAMEGOESHERE','PASSWORDGOESHERE')
&amp;gt;&amp;gt;&amp;gt; h.nav_saved_stories()
&amp;gt;&amp;gt;&amp;gt; stories=h.get_current_page_stories()
&amp;gt;&amp;gt;&amp;gt; list(stories)[0]
{'score': 254, 'link': u'http://adgrok.com/why-founding-a-three-person-startup-with-zero-revenue-is-better-than-working-for-goldman-sachs', 'user': u'cjg', 'title': u'Founding a startup with zero revenue is better than working for Goldman Sachs', 'ord': 1, 'comhead': u' (adgrok.com) '}
&amp;gt;&amp;gt;&amp;gt; h.nav_more()
&amp;gt;&amp;gt;&amp;gt; stories=h.get_current_page_stories()
&amp;gt;&amp;gt;&amp;gt; list(stories)[0]
{'score': 61, 'link': u'http://www.aaronstannard.com/post/2010/06/12/The-Myth-of-the-Single-Person-Startup.aspx', 'user': u'Aaronontheweb', 'title': u'The Myth of the Single-Person Startup', 'ord': 31, 'comhead': u' (aaronstannard.com) '}
&lt;/code&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;The get_current_page_stories function uses the BeautifulSoup library to parse the currently open web page. BeautifulSoup provides a pragmatic interface for pulling data out of HTML pages, allowing access through the tree of tags using dictionaries and lists, which allows you to quickly drill down to the data you need. For example, to get all the &amp;lt;td&amp;gt; tags for a particular row:&lt;/p&gt;
&lt;div&gt;&lt;code&gt;
&amp;gt;&amp;gt;&amp;gt; s.findAll('tr')[49].findAll('td')&amp;lt;/div&amp;gt;
&amp;lt;div&amp;gt;
&amp;lt;div&amp;gt;[&amp;lt;td align="right" valign="top" class="title"&amp;gt;16.&amp;lt;/td&amp;gt;,&amp;lt;/div&amp;gt;
&amp;lt;div&amp;gt;&amp;nbsp;&amp;lt;td&amp;gt;&amp;lt;center&amp;gt;&amp;lt;img src="http://ycombinator.com/images/s.gif" height="1" width="14" /&amp;gt;&amp;lt;/center&amp;gt;&amp;lt;/td&amp;gt;,&amp;lt;/div&amp;gt;
&amp;lt;div&amp;gt;&amp;nbsp;&amp;lt;td class="title"&amp;gt;&lt;a href="http://www.businessballs.com/cold_calling.htm"&gt;Cold Calling Techniques&lt;/a&gt;&amp;lt;span class="comhead"&amp;gt; (businessballs.com) &amp;lt;/span&amp;gt;&amp;lt;/td&amp;gt;]&amp;lt;/div&amp;gt;
&amp;lt;div&amp;gt;&lt;/code&gt;&lt;/div&gt;
&lt;p&gt;As there is no class assigned to indicate which table rows represent stories, the get_current_page function naively looks through all table rows in a page, trying to build story dictionaries for those that are in a plausible format. This works pretty reliably in practice.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;span style="font-size: large;"&gt;Building a page for Posterous to include&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Martin Ruiz has a great &lt;a href="http://www.martinruiz.com/posterous-sidebar-flair-hack"&gt;blog post on how he uses a similar technique to add items to the sidebar of his blog&lt;/a&gt;. He uses a dynamicly generated webpage, whereas I build a static webpage to serve - in the event that I hit slashdot, maybe this saves my server from melting.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;The page itself is included in Posterous using an iframe added to my custom Posterous template:&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;&lt;code&gt;
&amp;lt;section id="hackernews"&amp;gt;
&amp;lt;h1&amp;gt;Articles I've liked on Hacker News&amp;lt;/h1&amp;gt;
&amp;lt;div class="sidebar-block"&amp;gt;
&amp;nbsp;&lt;iframe marginheight="0" marginwidth="0"&gt;
&amp;nbsp;&amp;nbsp;&lt;/iframe&gt;
&amp;lt;/div&amp;gt;
&amp;lt;/section&amp;gt;
&amp;nbsp;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The key thing to remember is that the included page does not inherit any of the CSS from the page importing it. To get the look and feel right, I opened up my posterous home page in Chrome, and fired up the Developer Tools. I can use this to see what CSS is getting applied to each element on a page, and replicate that in the page I will be generating.&lt;/p&gt;
&lt;p&gt;I used the mako template library to build the final output - this is very similar to using a templating engine to dynamically generate content. I built a script, make-html.py, to drive the HNScraper, pass the scraped data to Mako, and save down the output ready to be served.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;span style="font-size: large;"&gt;The End Result&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You can hopefully now see the items I've found interesting in the sidebar on my blog. The fantastic libraries available for Python meant that I just had to write a bit of glue code to get this working - 170 lines in total. Working out how to get Mechanize to push through clickpass took a little time, as did getting the parsing right on anonymous-looking tables using BeautfulSoup, but all-told, I've probably spent longer on this blog post than writing code.&lt;/p&gt;
&lt;p&gt;As I said, I've &lt;a href="http://github.com/edparcell/HNScraper"&gt;made the code available on github&lt;/a&gt;. I hope you find it useful,&amp;nbsp;and I'd love to see what mash-ups people can use it for.&lt;/p&gt;

	
&lt;/p&gt;

&lt;p&gt;&lt;a href="http://blog.edparcell.com/how-i-added-my-hacker-news-saved-stories-to-m"&gt;Permalink&lt;/a&gt; 

	| &lt;a href="http://blog.edparcell.com/how-i-added-my-hacker-news-saved-stories-to-m#comment"&gt;Leave a comment&amp;nbsp;&amp;nbsp;&amp;raquo;&lt;/a&gt;

&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ParcellsPosts/~4/EHk5VmJbiWI" height="1" width="1"/&gt;</description>
      <posterous:author>
        <posterous:userImage>http://posterous.com/images/profile/missing-user-75.png</posterous:userImage>
        <posterous:profileUrl>http://posterous.com/users/5erKH0kcdaeZ</posterous:profileUrl>
        <posterous:firstName>Ed</posterous:firstName>
        <posterous:lastName>Parcell</posterous:lastName>
        <posterous:nickName>edparcell</posterous:nickName>
        <posterous:displayName>Ed Parcell</posterous:displayName>
      </posterous:author>
    <feedburner:origLink>http://blog.edparcell.com/how-i-added-my-hacker-news-saved-stories-to-m</feedburner:origLink></item>
    <item>
      <pubDate>Mon, 06 Sep 2010 09:32:00 -0700</pubDate>
      <title>Only a moron would use a SQL database in 2010</title>
      <link>http://feedproxy.google.com/~r/ParcellsPosts/~3/gUIK487Bmy4/only-a-moron-would-use-a-sql-database-in-2010</link>
      <guid isPermaLink="false">http://blog.edparcell.com/only-a-moron-would-use-a-sql-database-in-2010</guid>
      <description>&lt;p&gt;
	&lt;p&gt;There you go: in time-honoured blogging fashion, I've used a highly inflammatory title to get your attention. Hopefully now I'll have got that out of my system, and the rest of this post can be reasoned and insightful.&lt;/p&gt;
&lt;p&gt;A friend drew my attention to &lt;a href="http://nosql.mypopescu.com/post/1016320617/mongodb-is-web-scale#"&gt;this animation&lt;/a&gt;&amp;nbsp;at Alex Popescu's excellent &lt;a href="http://nosql.mypopescu.com/"&gt;myNoSQL&lt;/a&gt;&amp;nbsp;blog. It features a pig and bear (?) arguing the merits of relational versus NoSQL databases. The bear is a NoSQL fan-boy, parroting lines such as "shards are the secret ingredient in the web-scale sauce - they just work". The pig condescendingly suggests /dev/null may be a better place to store data, performance-wise, and rants that he will move to farm rather than work in the same industry as the bear. The debate is not moved forward.&lt;/p&gt;
&lt;p&gt;Now, the relative merits of relational and NoSQL databases is well trodden ground by now. Relational databases are&amp;nbsp;reliable and proven&amp;nbsp;versus the scalability and flexibility offered by schema-less NoSQL databases. Each has their place. There are some situations where reliability, and transactions, and all the other relational goodness is important - bank accounts are the standard example. Conversely, if you need to scale cheaply, and no-one cares all that much about a few missing tweets, likes or status updates, then NoSQL is the obvious solution. There are gray areas in the middle, where either or neither may be appropriate. But it is hard to argue that there is no place for one or the other, and you'd have to be a moron to make that choice (regardless of title of this blog post).&lt;/p&gt;
&lt;p&gt;So why the animosity between the relational database crowd and the NoSQL crowd?&lt;/p&gt;
&lt;p&gt;After all, there are plenty of areas where there is more than one solution. No one argues vociferously that I must use Google or Bing for all my searches - sometimes one is better, sometimes the other. Sometimes Excel is a more convenient tool for analysis, sometimes Matlab would be a better choice, and everyone seems happy with that.&lt;/p&gt;
&lt;p&gt;Although the argument is often framed in terms of facts - "MongoDB is web scale", "You might as well write to /dev/null" - I think it is more telling to look at the interests of those making the arguments.&amp;nbsp;Well, one difference between the examples above and database technologies is that there is a group of people with a vested interest in relational databases: DBAs.&lt;/p&gt;
&lt;p&gt;I suspect that DBAs, en masse, think that NoSQL databases will ruin their livelihoods with their lack of schemas and tables to CREATE and UPDATE.&amp;nbsp;On the other side of that, web developers think they would like to cut out the bureaucracy of endless CREATE and SELECT statements as they make web applications, and as extension of that, not having to defer to a DBA on matters of database style, and schema-less databases seem to promise that.&lt;/p&gt;
&lt;p&gt;I understand the defensiveness, and I understand the desire to make dealing with data easy. But I think both of these arguments are wrong.&lt;/p&gt;
&lt;p&gt;Dealing with large amounts of data has never been easy. DBAs are valuable not because they now they know every clause a SELECT statement can have, but because they understand data, and particularly the data under their care. They know what indexes are going to help performance. They know how to defend against the application layer inserting junk rows with inappropriate NULLs, or against application programmers who want to make a column called "COL_1" to contain comma-separated data because it would just be convenient. A good DBA can free developers from thinking about data-quality issues, and act as a multiplier on development productivity.&lt;/p&gt;
&lt;p&gt;This is not going to go away just because some applications run against a MongoDB back-end, rather than a MySQL back-end. Sure, the commands will be different, but the skills will not, and much of the knowledge and experience transfers.&lt;/p&gt;
&lt;p&gt;In short, I think data volumes are exploding, both for relational and non-relational databases, and the DBA skill set will be in higher and higher demand over the next few years.&amp;nbsp;Hopefully, when this comes to pass, we can stop the defensiveness, stop the fan-boyishness, and just use the best tool for whatever job we need to do.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://thedailywtf.com/Articles/Enterprise-Level-Access.aspx"&gt;Or we can use CSVs and VBA.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt;&amp;nbsp;My friend George has written a &lt;a href="http://shortcontrolledbursts.blogspot.com/2010/09/on-babies-bathwater-and-databases.html"&gt;thoughtful response&lt;/a&gt; to this post, arguing that NoSQL solutions will benefit from standardized query languages, and query planners, and that it may be as easy to adapt existing solutions to be distributed as it is to re-invent the wheel.&amp;nbsp;&lt;/p&gt;
	
&lt;/p&gt;

&lt;p&gt;&lt;a href="http://blog.edparcell.com/only-a-moron-would-use-a-sql-database-in-2010"&gt;Permalink&lt;/a&gt; 

	| &lt;a href="http://blog.edparcell.com/only-a-moron-would-use-a-sql-database-in-2010#comment"&gt;Leave a comment&amp;nbsp;&amp;nbsp;&amp;raquo;&lt;/a&gt;

&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ParcellsPosts/~4/gUIK487Bmy4" height="1" width="1"/&gt;</description>
      <posterous:author>
        <posterous:userImage>http://posterous.com/images/profile/missing-user-75.png</posterous:userImage>
        <posterous:profileUrl>http://posterous.com/users/5erKH0kcdaeZ</posterous:profileUrl>
        <posterous:firstName>Ed</posterous:firstName>
        <posterous:lastName>Parcell</posterous:lastName>
        <posterous:nickName>edparcell</posterous:nickName>
        <posterous:displayName>Ed Parcell</posterous:displayName>
      </posterous:author>
    <feedburner:origLink>http://blog.edparcell.com/only-a-moron-would-use-a-sql-database-in-2010</feedburner:origLink></item>
    <item>
      <pubDate>Fri, 13 Aug 2010 02:35:00 -0700</pubDate>
      <title>A new low (number of bytes in your program)?</title>
      <link>http://feedproxy.google.com/~r/ParcellsPosts/~3/FrJfzj3A8oM/a-new-low-number-of-bytes-in-your-program</link>
      <guid isPermaLink="false">http://blog.edparcell.com/a-new-low-number-of-bytes-in-your-program</guid>
      <description>&lt;p&gt;
	&lt;p&gt;Occasionally it's fun to get away from "serious" programming and do something just for fun. Serious programming these days tends to require using several, possibly tens of external frameworks and libraries. That's fine, and you get a lot more bang per line of code that way. But it can be fun to go back to basics, and make something from scratch.&lt;/p&gt;
&lt;p&gt;With that in mind, I've been looking at the &lt;a href="http://js1k.com/"&gt;JS1k competition&lt;/a&gt;. The idea is to do something interesting in under a kilobyte of&amp;nbsp;JavaScript. The great thing about this is that you can get started with just notepad and a browser. The new canvas element in HTML5 makes it surprisingly easy to do interesting graphical effects in JavaScript. But it requires some ingenuity to get the size down, particularly any data you might want to use is probably better generated procedurally.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://js1k.com/demo/225"&gt;My effort&lt;/a&gt; is a spinning tetrahedron. I enjoyed &lt;a href="http://acko.net/blog/js1k-demo-the-making-of"&gt;Steven Wittens description of making his demo&lt;/a&gt;, so I thought I might describe one aspect of mine here.&lt;/p&gt;
&lt;p&gt;My initial effort ran to over 2k, so I looked at a few techniques to get the size down. Some were pretty obvious: changing variable names to be single letters helped. Inlining functions further reduced the size to 1.3k - each function requires you use at least "function" and "return", but you also get quite a lot of redundancy assigning the results to a local variable for example.&lt;/p&gt;
&lt;p&gt;One method that helped, and is a bit more interesting, was to generate the data, rather than store it. The data in the case are the vertices and the line list [lines from vertex 0 to vertices 1, 2, 3, from 1 to 2 and 3, and from 2 to 3]. Taking the vertex list first, one way to represent it would be as a list of lists, with each inner list having 3 items representing the x,y and z coordinates, using 65 bytes:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;
P=[[-0.5,-0.5,-0,5],[-0.5,0.5,0.5],[0.5,-0.5,0.5],[0.5,0.5,-0.5]]
&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Accessing a coordinates using something similar to "P[i][0]" uses 7 bytes, and this will be done once for each of the x, y and z coordinates for a total cost of 86 bytes - a not insubstantial portion of the 1024 allowed.&lt;/p&gt;
&lt;p&gt;A better way is to not explicitly store the data, but to try and use bitwise operators to calculate it. Looking at the first coordinate, we can see that it is that it is -0.5 for the 0th and 1st vertices, and 0.5 for the 2nd and 3rd. I notice that 0, 1, 2 and 3 in binary are 00, 01, 10 and 11, and that the second digit, less a half, would be precisely what I want. So I can replace "P[i][0]" with "(i/2&amp;amp;1)-0.5". Similarly, the second coordinate is the first digit, minus a half, and so "P[i][1]" can be replaced with "(i%2)-0.5". The final digit is a little harder - it is 0.5 when i is 1 or 2. One way to think of this, is that it is 0.5 when precisely one of the binary digits is 1 - so this sounds like a job for xor. Sure enough, the final coordinate can be represented by "((i/2^i)&amp;amp;1)-0.5". Each of these expressions is longer than using the indexing operator on P, but it is now possible to throw away P. In fact, using this representation uses 34 bytes rather than the 86 used by explicitly creating the vertex data.&lt;/p&gt;
&lt;p&gt;Similarly, the line list does need to be stored explicitly. In a pyramid, every vertex is connected directly to every other vertex, so it is sufficient to use a double-loop over the vertices "for(i=0;i&amp;lt;4;++i)for(j=i;j&amp;lt;4;++j)".&lt;/p&gt;
&lt;p&gt;With a tetrahedron, these savings a relatively small. For a cube, with twice as many vertices, they are larger: the vertex list can be stored by using the jth binary digit to represent the jth coordinate, and the line list can be represented by double-looping over each pair of vertices again, but only drawing those where exactly one binary digit differs [ie vertex a and b are connected if a^b is a power of 2, which is true if (a^b)&amp;amp;((a^b)-1) - check &lt;a href="http://graphics.stanford.edu/~seander/bithacks.html"&gt;bit-twiddling hacks for more bitwise goodness&lt;/a&gt;]. For an icosahedron, it is not immediately clear what a good representation&amp;nbsp;&lt;/p&gt;
	
&lt;/p&gt;

&lt;p&gt;&lt;a href="http://blog.edparcell.com/a-new-low-number-of-bytes-in-your-program"&gt;Permalink&lt;/a&gt; 

	| &lt;a href="http://blog.edparcell.com/a-new-low-number-of-bytes-in-your-program#comment"&gt;Leave a comment&amp;nbsp;&amp;nbsp;&amp;raquo;&lt;/a&gt;

&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ParcellsPosts/~4/FrJfzj3A8oM" height="1" width="1"/&gt;</description>
      <posterous:author>
        <posterous:userImage>http://posterous.com/images/profile/missing-user-75.png</posterous:userImage>
        <posterous:profileUrl>http://posterous.com/users/5erKH0kcdaeZ</posterous:profileUrl>
        <posterous:firstName>Ed</posterous:firstName>
        <posterous:lastName>Parcell</posterous:lastName>
        <posterous:nickName>edparcell</posterous:nickName>
        <posterous:displayName>Ed Parcell</posterous:displayName>
      </posterous:author>
    <feedburner:origLink>http://blog.edparcell.com/a-new-low-number-of-bytes-in-your-program</feedburner:origLink></item>
    <item>
      <pubDate>Wed, 11 Aug 2010 06:58:00 -0700</pubDate>
      <title>Thoughts on the Barclays Cycle Hire scheme</title>
      <link>http://feedproxy.google.com/~r/ParcellsPosts/~3/uhV7ZO6gPns/thoughts-on-the-barclays-cycle-hire-scheme</link>
      <guid isPermaLink="false">http://blog.edparcell.com/thoughts-on-the-barclays-cycle-hire-scheme</guid>
      <description>&lt;p&gt;
	&lt;p&gt;I just had my first ride on a Barclays Cycle Hire bike. Here are some random thoughts on it:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I think they should be called Barcycles.&lt;/strong&gt;&amp;nbsp;I like &lt;a href="http://www.xkcd.com/739/"&gt;portmanteaux&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It's less scary riding in London than I thought.&lt;/strong&gt;&amp;nbsp;I used to ride occasionally in Cambridge, but mostly on back-roads, so I always found the thought of cycling in London pretty terrifying. While I chickened out of joining 3 lanes of traffic on Euston Road on my first ride, cycling with traffic wasn't as scary as I expected - I expect that traffic is more wary than usual of people on.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The bikes themselves are pretty good.&lt;/strong&gt;&amp;nbsp;Perfectly pleasant to ride for half an hour or so. I've never driven a carbon-fibre featherweight bike, so I don't know what I'm missing, but I have walked a long way in London, and these bikes are definitely faster than that.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="http://itunes.apple.com/gb/app/london-cycle-maps-routes/id383292875?mt=8"&gt;FipLab's London Cycle: Maps &amp;amp; Routes app&lt;/a&gt;&amp;nbsp;is cool.&amp;nbsp;&lt;/strong&gt;I looked at a few contenders, and all seemed reasonable. FipLab's effort seemed best. I just sent an email to the company, and they responded in a minute, letting me know that they are looking at colour-coding the pins based on bike/space availability in the near future. Awesome.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;There are a few organization teething problems.&lt;/strong&gt;&amp;nbsp;I couldn't find a docking space at the dock nearest my work. I understand that there is a large inward flow of bikes in the morning, and and a large outward flow in the evening. I hope that this will get dealt with in time, as demand stabilizes, and TfL can better plan how much redistribution is needed. In the meantime, it's a little frustrating to have to walk back from a distant cycle station.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Very positive for cycling in London.&lt;/strong&gt;&amp;nbsp;This makes it a lot easier to cycle in London. No need to find somewhere to keep a bike now. More importantly, I think it stands a good chance of creating a virtuous circle which fixes the lack of cycle routes in London. More people cycle, so more cycle routes are created, so more people cycle.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Barclays got themselves a good deal.&lt;/strong&gt;&amp;nbsp;Put in &amp;pound;25m over 5 years, &lt;a href="http://mqt.london.gov.uk/mqt/public/question.do?id=27803"&gt;less than half the estimated cost for the first year of the scheme&lt;/a&gt;, but get their logo and colouring plastered all over London. I've no objection to the corporate sponsorship - if anything it's positive - but Boris's team could have pushed for a better price.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cycle shops could take better advantage. &lt;/strong&gt;I went to a couple of shops to look at buying a helmet. I asked the very helpful guy at Cycle Surgery if there had been many people using the Barclays Cycle Hire scheme coming in for helmets - he didn't know. With 32,000 members in the first week, that has to be the biggest upsurge in cycling the capital has ever seen. Ok, so not many of these people are going to spend &amp;pound;1,000 on a bike frame, but I would expect that most of these people would value the contents of their skulls at more the &amp;pound;50 a reasonable helmet costs.&amp;nbsp;The cycle stores could pushing this. Stick a board outside the store proclaiming that you sell helmets for people using the scheme. Pay people to hand out flyers by cycle stations offering a discount on helmets, or even just describing what you have. But it seems like they are blithely ignoring it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Be interested to hear of your experiences, or any hints and tips to get the most out of the scheme.&lt;/strong&gt;&lt;/p&gt;
	
&lt;/p&gt;

&lt;p&gt;&lt;a href="http://blog.edparcell.com/thoughts-on-the-barclays-cycle-hire-scheme"&gt;Permalink&lt;/a&gt; 

	| &lt;a href="http://blog.edparcell.com/thoughts-on-the-barclays-cycle-hire-scheme#comment"&gt;Leave a comment&amp;nbsp;&amp;nbsp;&amp;raquo;&lt;/a&gt;

&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ParcellsPosts/~4/uhV7ZO6gPns" height="1" width="1"/&gt;</description>
      <posterous:author>
        <posterous:userImage>http://posterous.com/images/profile/missing-user-75.png</posterous:userImage>
        <posterous:profileUrl>http://posterous.com/users/5erKH0kcdaeZ</posterous:profileUrl>
        <posterous:firstName>Ed</posterous:firstName>
        <posterous:lastName>Parcell</posterous:lastName>
        <posterous:nickName>edparcell</posterous:nickName>
        <posterous:displayName>Ed Parcell</posterous:displayName>
      </posterous:author>
    <feedburner:origLink>http://blog.edparcell.com/thoughts-on-the-barclays-cycle-hire-scheme</feedburner:origLink></item>
    <item>
      <pubDate>Mon, 02 Aug 2010 11:22:00 -0700</pubDate>
      <title>How to pick a product name</title>
      <link>http://feedproxy.google.com/~r/ParcellsPosts/~3/CFHD4mCHFeQ/how-to-pick-a-product-name</link>
      <guid isPermaLink="false">http://blog.edparcell.com/how-to-pick-a-product-name</guid>
      <description>&lt;p&gt;
	&lt;p&gt;I just read &lt;a href="http://blog.asmartbear.com/pick-company-name-brand.html"&gt;Jason Cohen's advice on the Smart Bear blog about how to pick a company name&lt;/a&gt;. It's excellent advice, and I wish that article had been written before I was trying to come up with a name for Cobalt Quantware last year. It also reminded me that I wanted to write a blog post about the process of coming up with a product name, which I have just been through.&lt;/p&gt;
&lt;p&gt;The core of Jason's advice is that the name is a lot less important than what the company does. I hope that is true, and I think it is. It is good advice, because it takes the pressure off you to think of the perfect name. Nonetheless, when you fire up your IDE or editor of choice to create the new project or solution that will be your product, it will ask you for a name. &lt;strong&gt;So you shouldn't put pressure on yourself to come up with a perfect name, but you do need a name.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;span style="font-size: medium;"&gt;Don't: Use a half-assed Product Name&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;My first instinct was to use the first name that came into my head, and hope that I thought of something better later. I spent about 3 minutes coming up with the name. This was a mistake for several reasons, and so I'd advise you to avoid doing that.&lt;/p&gt;
&lt;p&gt;I was never really keen on the name. This reduced my engagement with the project. Not by a huge amount, just marginally. Nonetheless, trying to bootstrap a new business and create a product is hard. It is not wise to throw away motivation.&lt;/p&gt;
&lt;p&gt;Customers and advisors were not keen on the name. One of the repeated comments I would get is that the product looked useful, but the name wasn't great. Customer and advisor feedback is invaluable. It is a waste of both your time for you to explain why you have a crappy name that you intend to change. Worse, it is a wasted opportunity if they are telling you something that you already know. Far better to fix it, and hear about the feature that they really wish was there that hadn't even occurred to you.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;span style="font-size: medium;"&gt;Do: Use a codename if you can't come up with a Product Name&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size: small;"&gt;Later, I adopted a codename for the project. A codename is just a cool-sounding word that is a temporary placeholder for the final name.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size: small;"&gt;I decided to use names of British railway stations for codenames, using a station with a cool-sounding name beginning with "A" for the first codename, "B" for the second codename, and so on. There are a hundred themes you could use: cool-sounds birds, cool-sounding cities, cool-sounding metals etc.. This can be done pretty well without getting others involved, and without taking a large amount of time.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size: small;"&gt;When I did this, I started getting better quality feedback. Customers knew that this wasn't the final name, so it wasn't up for discussion. We could move on to discussing important topics, like what they wished the product would do.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;span style="font-size: medium;"&gt;Do: Come up with a Product Name as early as possible&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As well as a solution/project name for the codebase, you may also need a name for JIRA, or other bug tracking software, for a wiki, for documentation. Some of those places can be easily changed. Some less so: you can't easily change the project code used by JIRA for emails, for example. The sooner you come up with a final product name, the fewer places you will need to change, and the fewer headaches you will have making those changes.&lt;/p&gt;
&lt;p&gt;Later, but before release, you will need to start creating marketing materials - a document describing your product to send to potential customers, for example. At this point, you pretty much need a final product name. Your product name will be in large type at the top of that document. You don't want an asterisk next to it.&lt;/p&gt;
&lt;p&gt;Eventually you will release your product, and at that point you will be pretty irrevocably committed to the name you have used. Yes, products change their name, but they lose a lot of brand recognition when they do.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;span style="font-size: small;"&gt;&lt;span style="font-size: medium;"&gt;Do: Get a group together to brain-storm for Product Name candidates&lt;/span&gt;&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size: small;"&gt;I naturally tend to gravitate towards solving problems on my own, rather than in a group. I tried to do that with the problem of coming up with a product name. That worked badly. I partially filled a whiteboard with suggestions that I wasn't happy with. One of my advisors suggested than in a large company she had worked for, they would typically gather a group to brain-storm for product names. That was great advice - this is a type of problem that screams out for group brain-storming.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size: small;"&gt;In brain-storming, you have two aims: to suggest ideas that could be good solutions, and to suggest things that could trigger ideas in others. It's important to create a positive environment where people feel free to suggest anything, no matter how off-the-wall, and it's important not to criticize or evaluate ideas at this point. There are plenty of good resources on brain-storming on the web. I'd recommend &lt;a href="http://www.businessballs.com/brainstorming.htm"&gt;businessballs.com&lt;/a&gt;&amp;nbsp;for this and other topics.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size: small;"&gt;One problem for me was that I'm a sole-founder, so I didn't have anyone to brainstorm with. I solved this by gathering a group of friends in a meeting room I hired for a couple of hours over a weekend. I traded with them the promise that I would owe each of them a couple of hours (but that I'd appreciate it if they didn't choose tasks that would make me cry).&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size: small;"&gt;I decided on a group size of 6, as being large enough to bounce around ideas, but small enough not to be intimidating. I deliberately chose friends that didn't know each other. This helped us focus on the task, rather than pal around, and it maximized the variation in suggestions. We also had lunch together afterwards. I think everybody had a good time. Common friends, unsurprisingly, got on well, and people enjoyed the unusual exercise.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size: small;"&gt;We generated several hundred suggestions, many of which I was very happy with, and all it has cost me so far is building a barbeque and helping a friend move.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size: small;"&gt;&lt;strong&gt;&lt;span style="font-size: medium;"&gt;Do: Filter down to a shortlist&lt;/span&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size: small;"&gt;I transferred the several hundred suggestions from flipcharts to a word document. From the several hundred suggestion, I filtered through several times, first down to about 100 names, and then to a shorter list of around 25, and finally to 10 or so names. I did this at different times, to ensure that the names that made it through weren't purely based on a particular whim at the time.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size: small;"&gt;I also found that some suggestions were fragments - either a good descriptive name for the product, or a cool-sounding adjective that could be incorporated into a product name. I tried to save these as I filtered, and combined them to form a few extra names for the shortlist.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size: small;"&gt;I checked the shortlist to ensure that I wasn't infringing on trademarks, and that the names were not already in use, ideally for any product, but certainly for similar products, or other products that our customers might already use.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size: small;"&gt;In the final filter, from 25 to 10, I did not filter purely on quality - I was pretty happy with most of the 25 - but as well to ensure some variation in the final set. I would rather get feedback on more variable set of names, than a higher-quality set of very similar names.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size: medium;"&gt;&lt;strong&gt;&lt;span&gt;Do: Get feedback on the shortlist&lt;/span&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size: medium;"&gt;&lt;span style="font-size: small;"&gt;I gathered feedback from about 50 people over the course of a week or so, including customers and potential customers, advisors, friends, family, people I had just met, and so on. Everyone has an opinion on your shortlist, and most people are happy to give it.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size: medium;"&gt;&lt;span style="font-size: small;"&gt;The easiest way is just to ask if they'd like to see the shortlist of names for your product (you were talking about your product anyway, right?), present them with the list, shut up and make notes. Do shut up, because people will often volunteer things like liking one part of one name, and one part of another, which they won't if you just ask them which their favourite is. Do make notes, because you won't remember what someone said about 10 different names over dinner. In a pinch, I have recorded people on my phone, but people are generally a little more reticent to be recorded.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size: medium;"&gt;&lt;span style="font-size: small;"&gt;When you get back to base, systematically organize the feedback. Hopefully, it should quickly become apparent that there are a few names that people are responding positively to. Remember, these are being positively evaluated with respect to the names that you preferred out of a large set.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size: medium;"&gt;&lt;strong&gt;&lt;span&gt;Final Thoughts&amp;nbsp;&lt;/span&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size: small;"&gt;The process of coming up with a name was not actually that time-consuming. In hindsight, it is pretty obvious too. But coming up with a process that worked well for me was a little trickier. In particularly, the key realization was that as a sole-founder I would need, and could get, others to help on this task. I hope that if other people are stuck on this task, or on other tasks, they can use my "mini-crowdsourcing" experiment as inspiration.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size: small;"&gt;For me, having a final product name that I was happy with, and my customers liked, was a big punch-the-air happy moment. There was a huge contrast: Not having a product name was an increasing source of anxiety as we moved towards launch. Having a product name really renewed my energy and engagement towards the project.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size: small;"&gt;I'm really excited about Cobalt Quantware again, and about our first product. We currently in stealth mode, but I look forward to filling you in later, at an appropriate time.&lt;/span&gt;&lt;/p&gt;
	
&lt;/p&gt;

&lt;p&gt;&lt;a href="http://blog.edparcell.com/how-to-pick-a-product-name"&gt;Permalink&lt;/a&gt; 

	| &lt;a href="http://blog.edparcell.com/how-to-pick-a-product-name#comment"&gt;Leave a comment&amp;nbsp;&amp;nbsp;&amp;raquo;&lt;/a&gt;

&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ParcellsPosts/~4/CFHD4mCHFeQ" height="1" width="1"/&gt;</description>
      <posterous:author>
        <posterous:userImage>http://posterous.com/images/profile/missing-user-75.png</posterous:userImage>
        <posterous:profileUrl>http://posterous.com/users/5erKH0kcdaeZ</posterous:profileUrl>
        <posterous:firstName>Ed</posterous:firstName>
        <posterous:lastName>Parcell</posterous:lastName>
        <posterous:nickName>edparcell</posterous:nickName>
        <posterous:displayName>Ed Parcell</posterous:displayName>
      </posterous:author>
    <feedburner:origLink>http://blog.edparcell.com/how-to-pick-a-product-name</feedburner:origLink></item>
    <item>
      <pubDate>Thu, 01 Jul 2010 08:01:00 -0700</pubDate>
      <title>NRN: How about a convention for emails that don't require responses?</title>
      <link>http://feedproxy.google.com/~r/ParcellsPosts/~3/WNxhjYZYqDw/nrn-how-about-a-convention-for-emails-that-do</link>
      <guid isPermaLink="false">http://blog.edparcell.com/nrn-how-about-a-convention-for-emails-that-do</guid>
      <description>&lt;p&gt;
	&lt;p&gt;&lt;span style="font-size: medium;"&gt;&lt;strong&gt;NRN = No Response Necessary&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;A few years back, I was thinking about learning to fly. Other things got in the way, and it didn't happen, but it's something I may go back to in the future. That didn't stop me massively geeking out around flying though. One of the things I liked to do was listen to air traffic control online. It's actually quite relaxing as background noise, in the same way that listening to the shipping forecast is. I highly recommend &lt;a href="http://www.atcmonitor.com/"&gt;http://www.atcmonitor.com/&lt;/a&gt;, where you can see live radar around Atlanta as well as listen to the air traffic controllers.&lt;/p&gt;
&lt;p&gt;One of the things I've noticed is that air traffic controllers and pilots don't waste a lot of time when talking on the radio. They need to say what needs to be said, and then stop talking. They are busy, and need to focus on flying and directing planes, and there is probably another person who needs to transmit a message.&lt;/p&gt;
&lt;p&gt;It's quite common for them to finish a transmission with "Good day". The implication is that they have nothing further to say, and aside from the other party repeating what they have just said to confirm, they do not expect to speak again. They are not being rude, but busy, and considerate of the next guy who needs to speak.&lt;/p&gt;
&lt;p&gt;In a lot of ways, it would be nice to have a similar convention in other avenues of life. Sometimes emails seem to bounce politely backwards and forwards, long after everyone has run out of things to say.&lt;/p&gt;
&lt;p&gt;So I'd like to propose inserting "&lt;strong&gt;NRN:&lt;/strong&gt;" in the subject line of an email to indicate that the other party is not obliged to respond. It's short for &lt;strong&gt;&lt;span style="font-weight: normal;"&gt;"&lt;/span&gt;NO RESPONSE NECESSARY&lt;/strong&gt;". The idea is that I won't be offended if you don't respond.&lt;/p&gt;
&lt;p&gt;So if I you send me an email asking a question, and I give you an answer, I could stick "NRN:" in the subject line. You are relieved from any duty you might have perceived to send me a thank you email. And you don't have to flag the email for further response. You can if you want, or have something else you need to say, but don't feel obliged. &lt;strong&gt;Don't worry - we are done here and everything is fine.&lt;/strong&gt;&lt;/p&gt;
	
&lt;/p&gt;

&lt;p&gt;&lt;a href="http://blog.edparcell.com/nrn-how-about-a-convention-for-emails-that-do"&gt;Permalink&lt;/a&gt; 

	| &lt;a href="http://blog.edparcell.com/nrn-how-about-a-convention-for-emails-that-do#comment"&gt;Leave a comment&amp;nbsp;&amp;nbsp;&amp;raquo;&lt;/a&gt;

&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ParcellsPosts/~4/WNxhjYZYqDw" height="1" width="1"/&gt;</description>
      <posterous:author>
        <posterous:userImage>http://posterous.com/images/profile/missing-user-75.png</posterous:userImage>
        <posterous:profileUrl>http://posterous.com/users/5erKH0kcdaeZ</posterous:profileUrl>
        <posterous:firstName>Ed</posterous:firstName>
        <posterous:lastName>Parcell</posterous:lastName>
        <posterous:nickName>edparcell</posterous:nickName>
        <posterous:displayName>Ed Parcell</posterous:displayName>
      </posterous:author>
    <feedburner:origLink>http://blog.edparcell.com/nrn-how-about-a-convention-for-emails-that-do</feedburner:origLink></item>
    <item>
      <pubDate>Wed, 30 Jun 2010 11:43:00 -0700</pubDate>
      <title>Getting started with RabbitMQ in Windows using C#</title>
      <link>http://feedproxy.google.com/~r/ParcellsPosts/~3/514qnMOhV-U/getting-started-with-rabbitmq-in-windows-usin</link>
      <guid isPermaLink="false">http://blog.edparcell.com/getting-started-with-rabbitmq-in-windows-usin</guid>
      <description>&lt;p&gt;
	&lt;p&gt;In a &lt;a href="http://edparcell.posterous.com/excited-by-zeromq"&gt;previous blog&lt;/a&gt;, I wrote how excited I was by ZeroMQ, a very lightweight brokerless messaging system. I wanted to also try RabbitMQ using C# on my Windows development machine, but couldn't find any step-by-step introduction to get me to the point of running my first program. I'm there now, so I thought it would be good to remedy that.&lt;/p&gt;
&lt;p&gt;I'd like to note that I'm not a RabbitMQ or messaging whiz. What you see here may or may not be best practice. If it's not, hopefully someone will chime in with some comments to put me back on the right path.&lt;/p&gt;
&lt;p&gt;Here are the steps I took to install RabbitMQ and create a couple of simple C# clients to check that everything was working.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Download the Windows bundle zip file from the &lt;a href="http://www.rabbitmq.com/download.html"&gt;RabbitMQ download page&lt;/a&gt;. The current version at the time of writing is &lt;a href="http://www.rabbitmq.com/releases/bundles/v1.8.0/complete-rabbitmq-bundle-1.8.0.zip"&gt;1.8.0&lt;/a&gt;. It contains the Erlang installer, the RabbitMQ server, and bindings for Java and C#.&lt;/li&gt;
&lt;li&gt;Unzip the bundle.&lt;/li&gt;
&lt;li&gt;Install Erlang using the OTP installer by running otp_win32_R13B03.exe from the unzipped bundle.&lt;/li&gt;
&lt;li&gt;Create a subdirectory "RabbitMQ" in "C:\Program Files". (Or "C:\Program Files (x86)" if you are running on 64-bit).&lt;/li&gt;
&lt;li&gt;Unzip the rabbitmq-server-windows-1.8.0 zipfile in the bundle to a directory rabbitmq-server-windows-1.8.0. &lt;/li&gt;
&lt;li&gt;Copy the rabbitmq-server-windows-1.8.0 directory you just unzipped to the RabbitMQ directory you just created. Copy the rabbitmq-server-windows-1.8.0 directory itself rather than its contents. ie You should have a directory "C:\Program Files\RabbitMQ\rabbitmq_server-1.8.0" when you have done this.&lt;/li&gt;
&lt;li&gt;You need to add ERLANG_HOME to the environment variables for your system so RabbitMQ can find Erlang. I can't remember precisely how to do this in XP - I think it's in Control Panel...System... somewhere, and I don't have Windows 7 yet. Perhaps someone could comment for these versions of Windows. In Vista, this is done by:&lt;ol&gt;
&lt;li&gt;Open the control panel.&lt;/li&gt;
&lt;li&gt;Search "environment". As you type, the option to "Edit the system environment variables" should present itself. Click this - you will be asked for permission to take this action.&lt;/li&gt;
&lt;li&gt;In the System Properties...Advanced tab which appears, click the "Environment Variables..." button.&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;bottom&lt;/strong&gt; "New..." button to add a &lt;strong&gt;system&lt;/strong&gt; variable.&lt;/li&gt;
&lt;li&gt;Enter "ERLANG_HOME" as the variable name.&lt;/li&gt;
&lt;li&gt;Enter "C:\Program Files\erl5.7.4" as the variable value for 32-bit systems. Use "C:\Program Files (x86)\erl5.7.4" for 64-bit systems.&lt;/li&gt;
&lt;li&gt;Click Ok, Ok, Ok and close the control panel.&lt;/li&gt;
&lt;/ol&gt; &lt;/li&gt;
&lt;li&gt;Run the server by running "C:\Program Files\RabbitMQ\rabbitmq_server-1.8.0\sbin\rabbitmq-server.bat". A command-line window should appear. When it says "broker running" the server is running ok.&lt;/li&gt;
&lt;li&gt;Install the .Net libraries by running the rabbitmq-dotnet-client-1.8.0.msi installer in the unzipped bundle.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You can also install RabbitMQ as a service. The RabbitMQ documentation has more details on this.&lt;/p&gt;
&lt;p&gt;Ok, so now you've installed RabbitMQ, and you have a RabbitMQ broker running (that's the server that all your message producers and message consumers will connect to). Before going any further, it's worth taking a little time to come up to speed with the concepts behind RabbitMQ. Dmitriy Samovskiy has an excellent, and quick, set of introduction slides which should tell you what you need to know (when I clicked publish, I saw that Posterous automatically embedded this - kudos, Posterous crew):&lt;/p&gt;
&lt;p&gt;&lt;iframe marginheight="0" scrolling="no" src="http://www.slideshare.net/slideshow/embed_code/8833888" marginwidth="0" frameborder="0" height="417" width="500"&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;p&gt;In case you are too impatient to read through that, the gist is that a &lt;strong&gt;publisher&lt;/strong&gt; application sends messages to an &lt;strong&gt;exchange&lt;/strong&gt;, which sits on the server. &lt;strong&gt;Message queues&lt;/strong&gt; sit on the server and filter messages from exchanges. Finally a &lt;strong&gt;consumer&lt;/strong&gt; application consumes messages from a message queue.&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size: small;"&gt;&lt;span style="font-size: medium;"&gt;&lt;strong&gt;A simple publisher&lt;/strong&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Let's start by writing an application that publishes a message each second which contains "Hello World":&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Start a new project in Visual C#, called "RabbitMQPub".&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Add a reference to "RabbitMQ Client Library for .Net"&lt;/strong&gt;, by right-clicking the "References" entry in the Solution Explorer, clicking "Add Reference...", selecting the ".NET" tab, and double-clicking the "RabbitMQ Client Library for .Net" entry.&lt;/li&gt;
&lt;li&gt;In the program you will want to add using statements to bring in the appropriate RabbitMQ namespaces:&lt;br /&gt;&lt;span style="font-size: small;"&gt;&lt;code&gt;using RabbitMQ.Client;using RabbitMQ.Client.Framing.v0_8;
&amp;lt;/span&amp;gt;&lt;/code&gt; &lt;/span&gt;&lt;/li&gt;
&lt;li&gt;The first step is to create a &lt;strong&gt;ConnectionFactory&lt;/strong&gt;, and configure it:&lt;br /&gt;&lt;code&gt;
ConnectionFactory factory = new ConnectionFactory();
factory.Protocol = Protocols.FromEnvironment();
factory.HostName = "localhost";         
&lt;/code&gt;&lt;br /&gt;There are other configuration items, which are taking default values here. This will work on a virgin RabbitMQ instance, but in production you should look at setting up access control and VHosts.&lt;/li&gt;
&lt;li&gt;Then from the ConnectionFactory, create a Connection object:&lt;br /&gt;&lt;code&gt;
IConnection conn = factory.CreateConnection();
&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;And from the connection, create a Channel object:&lt;br /&gt;&lt;code&gt;
IModel ch = conn.CreateModel();
&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;We need to create an exchange to publish our messages to:&lt;br /&gt;&lt;code&gt;
ch.ExchangeDeclare("exch", ExchangeType.Direct);
&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;And a queue to filter messages from the exchange. A queue is made to filter messages from a particular exchange by "binding" it to that exchange:&lt;br /&gt;&lt;code&gt; 
ch.QueueDeclare("queue");
ch.QueueBind("queue", "exch", "key", false, null);
&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;Then we loop, using the Channel object's BasicPublish method to publish a new message every second, and printing a message to the display to indicate we have done so.&lt;br /&gt;&lt;code&gt; 
            while (true)
            {
                Console.WriteLine("Sending message.");
                byte[] messageBody = Encoding.UTF8.GetBytes("Hello world");
                ch.BasicPublish("exch", "key", null, messageBody);
                Thread.Sleep(1000);
            }
&lt;/code&gt; &lt;br /&gt;Note that we are expected to present byte arrays to send in a message. When sending strings, it's a good idea to use UTF-8 encoding as shown. &lt;/li&gt;
&lt;li&gt;Finally, we close the channel and the connection. This will never execute in this case, and the channel and connection will be shutdown by program termination instead, but if you are writing a client that isn't guaranteed to loop forever, this is how you should terminate the connection:&lt;br /&gt;&lt;code&gt; 
ch.Close(Constants.ReplySuccess, "Closing the channel");
conn.Close(Constants.ReplySuccess, "Closing the connection");
&lt;/code&gt; &lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;span style="font-size: medium;"&gt;&lt;strong&gt;A simple consumer&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size: small;"&gt;We now need to create a simple application to listen for these messages, and print them.&lt;/span&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;span style="font-size: small;"&gt;Create a new project Follow steps 2-6 and 10 above. This should connect to the RabbitMQ broker, but otherwise is inactive.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-size: small;"&gt;Add code to consume messages from a queue:&lt;br /&gt;&lt;code&gt;
QueueingBasicConsumer consumer = new QueueingBasicConsumer(ch); ch.BasicConsume("queue", null, consumer);
&lt;/code&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-size: small;"&gt;In an infinite loop, listen for messages, decoding each one, and printing its body&lt;br /&gt;&lt;code&gt;
            while (true)
            {
                BasicDeliverEventArgs e = (BasicDeliverEventArgs)consumer.Queue.Dequeue();
                IBasicProperties props = e.BasicProperties;
                byte[] body = e.Body;
                Console.WriteLine("Received message: " + Encoding.UTF8.GetString(body));
                ch.BasicAck(e.DeliveryTag, false);
            }
&lt;/code&gt;&lt;br /&gt;Note that messages must be acknowledged using BasicAck, or the broker will resend them.&lt;br /&gt; &lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;span style="font-size: medium;"&gt;&lt;strong&gt;Source code&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size: small;"&gt;I have made the source code for these projects, as well as other sample projects, through GitHub: &lt;/span&gt;&lt;a href="http://github.com/edparcell/Samples-CS"&gt;http://github.com/edparcell/Samples-CS&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;span style="font-size: medium;"&gt;Where's the Fudge?&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In a &lt;a href="http://edparcell.posterous.com/excited-by-zeromq"&gt;previous post&lt;/a&gt;, I mentioned that I would like to give an example of using &lt;a href="http://wiki.fudgemsg.org:8080/display/FDG/Fudge+Messaging+Home"&gt;Fudge&lt;/a&gt; to encode messages. That is still my intention. However, I thought this blog post had become long enough already, so I'd like to defer that to another post.&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size: medium;"&gt;&lt;strong&gt;Comments&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Some random comments on RabbitMQ so far:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The bundle seems quite large. I know the bulk of this is the OTP installer, but it makes it quite hard to consider embedding RabbitMQ in a lot of small-scale cases, such as deploying to a single end-user machine. Not a problem for an enterprise perhaps, but this is the case I have right now.&lt;br /&gt;[Update: I'd like to clarify that 80 megs is not a huge download by modern standards, especially for such a useful and full-featured product. Just that it would look odd to my end-users if I replace the named pipes in a few programs with embedded RabbitMQ, and the installer balloons from 1 meg to 80 megs].&lt;/li&gt;
&lt;li&gt;Would be nice to create an installer to automate these steps, so installation is simply clicking "Next" a few times.&lt;/li&gt;
&lt;li&gt;The .Net user guide seems a little out-of-sync with the latest library in places. Not terribly, but it throws you a curveball sometimes, such as suggesting that ConnectionFactory.CreateConnection takes 3 parameters, when in the latest version you should set some member variables on the factory and call the method with no parameters.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Overall, RabbitMQ seems like a great application, albeit a little tough to get started in on .Net. Hopefully this short tutorial will help with that.&lt;/p&gt;
&lt;p&gt;I'd gratefully welcome any corrections - as I said, I'm no messaging guru, so if I've met any errors, let me know and I'll correct them.&lt;/p&gt;
	
&lt;/p&gt;

&lt;p&gt;&lt;a href="http://blog.edparcell.com/getting-started-with-rabbitmq-in-windows-usin"&gt;Permalink&lt;/a&gt; 

	| &lt;a href="http://blog.edparcell.com/getting-started-with-rabbitmq-in-windows-usin#comment"&gt;Leave a comment&amp;nbsp;&amp;nbsp;&amp;raquo;&lt;/a&gt;

&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ParcellsPosts/~4/514qnMOhV-U" height="1" width="1"/&gt;</description>
      <posterous:author>
        <posterous:userImage>http://posterous.com/images/profile/missing-user-75.png</posterous:userImage>
        <posterous:profileUrl>http://posterous.com/users/5erKH0kcdaeZ</posterous:profileUrl>
        <posterous:firstName>Ed</posterous:firstName>
        <posterous:lastName>Parcell</posterous:lastName>
        <posterous:nickName>edparcell</posterous:nickName>
        <posterous:displayName>Ed Parcell</posterous:displayName>
      </posterous:author>
    <feedburner:origLink>http://blog.edparcell.com/getting-started-with-rabbitmq-in-windows-usin</feedburner:origLink></item>
    <item>
      <pubDate>Tue, 29 Jun 2010 01:42:00 -0700</pubDate>
      <title>Excited by ZeroMQ</title>
      <link>http://feedproxy.google.com/~r/ParcellsPosts/~3/G87dlH5YQis/excited-by-zeromq</link>
      <guid isPermaLink="false">http://blog.edparcell.com/excited-by-zeromq</guid>
      <description>&lt;p&gt;
	&lt;p&gt;ZeroMQ looks like an interesting project. It's a light-weight messaging stack, supporting point-to-point, publish-subscribe and other topologies, without a broker.&lt;/p&gt;
&lt;p&gt;ZeroMQ aims to sit at a slightly higher level than raw sockets. It's easy to write a socket "Hello World" server and client. The server prints whatever it receives, and the client connects to the server and emits "Hello World". Scaling up to real world needs is hard though. Sockets tend to fall over. Messages certainly will be fragmented. Your socket may be handling several clients at the same time. Messaging layers such as ZeroMQ aim to provide an abstraction, so you can put a string or an object in one end, and have it come out the other with minimal fuss.&lt;/p&gt;
&lt;p&gt;In the past, I've looked at ActiveMQ, and RabbitMQ. Both seemed interesting, although as I understand it, both require a broker i.e. a server. This is fine for enterprises, the main target of messaging systems to date, but a little trickier for an individual - sure you can run a broker on your machine, but it's just something to be down at inopportune moments.&lt;/p&gt;
&lt;p&gt;As far as I can see ZeroMQ is to Active/RabbitMQ as SQLite is to MySQL or PostgreSQL. You can embed ZeroMQ in your applications, and get the benefit, but the user doesn't have to care, and critically, doesn't have to run a server on their desktop.&lt;/p&gt;
&lt;p&gt;And I think that having personal message systems on the desktop is exciting. I already have one, sort of, kind of. Growl is an application that sits in the background listening for "messages". Various applications support growl to pop up status messages. So when a friend comes online, Growl pops up a bubble to notify me. Or when various things update. It's a nice and useful program, but it's not really a messaging system - the "messages" are one-way, and do one thing: pop up on the screen.&lt;/p&gt;
&lt;p&gt;A real messaging system goes further. One program could listen for a certain type of message to pass on to Growl. My servers could send messages detailing their status. A third could monitor those messages to check whether limits were breached, and send messages for Growl if so. A library for Excel could monitor messages, and give the latest value for various things, even updating in real-time, allowing quick-and-easy status board. Messages could be sent for stock and other financial data.&lt;/p&gt;
&lt;p&gt;People are already doing all of this, of course. But you need to be an enterprise, or prepared to act like one, to use an enterprise messaging system. ZeroMQ will bring the bar down, and in the past, when that's happened, there have always been exciting new products. I hope I've given some, but, as usual, I expect the most exciting new uses will be the ones that we can't even see at the outset.&lt;/p&gt;
&lt;p&gt;I've been playing a little with ZeroMQ at weekends, and in a future post, I'll describe how to install ZeroMQ, and give some simple examples of how to use it.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;While I'm talking about messaging, I'd like to give a quick mention to the &lt;a href="http://wiki.fudgemsg.org:8080/display/FDG/Fudge+Messaging+Home"&gt;Fudge messaging project&lt;/a&gt; who are building libraries to support a slick binary format for encoding messages.&lt;/p&gt;
	
&lt;/p&gt;

&lt;p&gt;&lt;a href="http://blog.edparcell.com/excited-by-zeromq"&gt;Permalink&lt;/a&gt; 

	| &lt;a href="http://blog.edparcell.com/excited-by-zeromq#comment"&gt;Leave a comment&amp;nbsp;&amp;nbsp;&amp;raquo;&lt;/a&gt;

&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ParcellsPosts/~4/G87dlH5YQis" height="1" width="1"/&gt;</description>
      <posterous:author>
        <posterous:userImage>http://posterous.com/images/profile/missing-user-75.png</posterous:userImage>
        <posterous:profileUrl>http://posterous.com/users/5erKH0kcdaeZ</posterous:profileUrl>
        <posterous:firstName>Ed</posterous:firstName>
        <posterous:lastName>Parcell</posterous:lastName>
        <posterous:nickName>edparcell</posterous:nickName>
        <posterous:displayName>Ed Parcell</posterous:displayName>
      </posterous:author>
    <feedburner:origLink>http://blog.edparcell.com/excited-by-zeromq</feedburner:origLink></item>
    <item>
      <pubDate>Sat, 26 Jun 2010 01:15:00 -0700</pubDate>
      <title>I've put some C# code samples on github</title>
      <link>http://feedproxy.google.com/~r/ParcellsPosts/~3/toNwgL7uFws/ive-put-some-c-code-samples-on-github</link>
      <guid isPermaLink="false">http://blog.edparcell.com/ive-put-some-c-code-samples-on-github</guid>
      <description>&lt;p&gt;
	&lt;p&gt;When I have to use a new library or functionality, I tend to build a minimal console application to check that I can get something working in isolation from the codebase it will eventually be integrated into. My &lt;a href="http://edparcell.posterous.com/using-jquery-and-couchdb-to-build-a-simple-we"&gt;first blog post&lt;/a&gt; grew out of a sample I was building to try out JQuery and CouchDb. Often, there's good sample code out there on the web, but sometimes not. In any case, I often need to do something different to the other guy, so it's as well to make my own sample.&lt;/p&gt;
&lt;p&gt;In the past, I've tended to throw away these samples once they are working, for lack of anywhere reasonable to put them. Recently though, I've noticed that often, great working code samples are available on github, so I've decided to join the crowd there.&lt;/p&gt;
&lt;p&gt;My first github repository - &lt;a href="http://github.com/edparcell/Samples-CS"&gt;Samples-CS&lt;/a&gt; - is set of code samples for various things in C#. Currently there are simple console applications to encipher and decipher using AES, convert a PNG to an ICO, and a simple system tray application. They are released under an MIT licence. I'll be adding more as things come up, as well as repositories for other languages.&lt;/p&gt;
&lt;p&gt;Hopefully they will be useful to someone who needs to do the same things as me. If not, I lose nothing, and I can refer back to my code samples later if I need to.&lt;/p&gt;
	
&lt;/p&gt;

&lt;p&gt;&lt;a href="http://blog.edparcell.com/ive-put-some-c-code-samples-on-github"&gt;Permalink&lt;/a&gt; 

	| &lt;a href="http://blog.edparcell.com/ive-put-some-c-code-samples-on-github#comment"&gt;Leave a comment&amp;nbsp;&amp;nbsp;&amp;raquo;&lt;/a&gt;

&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ParcellsPosts/~4/toNwgL7uFws" height="1" width="1"/&gt;</description>
      <posterous:author>
        <posterous:userImage>http://posterous.com/images/profile/missing-user-75.png</posterous:userImage>
        <posterous:profileUrl>http://posterous.com/users/5erKH0kcdaeZ</posterous:profileUrl>
        <posterous:firstName>Ed</posterous:firstName>
        <posterous:lastName>Parcell</posterous:lastName>
        <posterous:nickName>edparcell</posterous:nickName>
        <posterous:displayName>Ed Parcell</posterous:displayName>
      </posterous:author>
    <feedburner:origLink>http://blog.edparcell.com/ive-put-some-c-code-samples-on-github</feedburner:origLink></item>
    <item>
      <pubDate>Wed, 19 May 2010 16:42:00 -0700</pubDate>
      <title>Mockup of EasyInstaller - an "App Store for Excel"</title>
      <link>http://feedproxy.google.com/~r/ParcellsPosts/~3/sipqwDB1J4g/mockup-of-easyinstaller-an-app-store-for-exce</link>
      <guid isPermaLink="false">http://blog.edparcell.com/mockup-of-easyinstaller-an-app-store-for-exce</guid>
      <description>&lt;p&gt;
	&lt;p&gt;In my previous &lt;a href="http://edparcell.posterous.com/how-about-an-app-store-for-excel"&gt;blog post&lt;/a&gt;, I talked about an "App Store for Excel", allowing Excel users to download extensions from a central repository on the web. A picture being worth a thousand words (and more likely to get looked at), I thought I'd put together a mock-up of how this might actually look:&lt;/p&gt;
&lt;p&gt;&lt;div class='p_embed p_image_embed'&gt;
&lt;a href="http://posterous.com/getfile/files.posterous.com/temp-2010-05-19/vjpycrkthppifprgqCzstrvHupjsfEzobckCuxeHlgxgHElqaBqhypflqzxn/EasyInstaller_Mockup.png.scaled1000.png"&gt;&lt;img alt="Easyinstaller_mockup" height="391" src="http://posterous.com/getfile/files.posterous.com/temp-2010-05-19/vjpycrkthppifprgqCzstrvHupjsfEzobckCuxeHlgxgHElqaBqhypflqzxn/EasyInstaller_Mockup.png.scaled500.png" width="500" /&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/p&gt;
&lt;p&gt;I also coined the name EasyInstaller. Let me know what you think of the idea and the name.&lt;/p&gt;
&lt;p&gt;On a separate note, I used &lt;a href="http://www.balsamiq.com/"&gt;Balsamiq&lt;/a&gt; to create this mock-up. I recommend it, in that it's very easy to use. I'm currently weighing up whether I want to spend $79 on it. It's a great piece of software, and I love that I can do application interfaces as well as websites, but I rarely mock up interfaces. In the meantime, does anyone have any recommendations for other mock-up software I should look at?&lt;/p&gt;
	
&lt;/p&gt;

&lt;p&gt;&lt;a href="http://blog.edparcell.com/mockup-of-easyinstaller-an-app-store-for-exce"&gt;Permalink&lt;/a&gt; 

	| &lt;a href="http://blog.edparcell.com/mockup-of-easyinstaller-an-app-store-for-exce#comment"&gt;Leave a comment&amp;nbsp;&amp;nbsp;&amp;raquo;&lt;/a&gt;

&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ParcellsPosts/~4/sipqwDB1J4g" height="1" width="1"/&gt;</description>
      <posterous:author>
        <posterous:userImage>http://posterous.com/images/profile/missing-user-75.png</posterous:userImage>
        <posterous:profileUrl>http://posterous.com/users/5erKH0kcdaeZ</posterous:profileUrl>
        <posterous:firstName>Ed</posterous:firstName>
        <posterous:lastName>Parcell</posterous:lastName>
        <posterous:nickName>edparcell</posterous:nickName>
        <posterous:displayName>Ed Parcell</posterous:displayName>
      </posterous:author>
      <media:content type="image/png" height="631" width="807" url="http://getfile3.posterous.com/getfile/files.posterous.com/temp-2010-05-19/vjpycrkthppifprgqCzstrvHupjsfEzobckCuxeHlgxgHElqaBqhypflqzxn/EasyInstaller_Mockup.png">
        <media:thumbnail height="391" width="500" url="http://getfile1.posterous.com/getfile/files.posterous.com/temp-2010-05-19/vjpycrkthppifprgqCzstrvHupjsfEzobckCuxeHlgxgHElqaBqhypflqzxn/EasyInstaller_Mockup.png.scaled500.png" />
      </media:content>
    <feedburner:origLink>http://blog.edparcell.com/mockup-of-easyinstaller-an-app-store-for-exce</feedburner:origLink></item>
    <item>
      <pubDate>Fri, 07 May 2010 10:41:11 -0700</pubDate>
      <title>How about... an "App Store for Excel"</title>
      <link>http://feedproxy.google.com/~r/ParcellsPosts/~3/2AuVaimX1ww/how-about-an-app-store-for-excel</link>
      <guid isPermaLink="false">http://blog.edparcell.com/how-about-an-app-store-for-excel</guid>
      <description>&lt;p&gt;
	&lt;i&gt;In my &lt;a href="http://edparcell.posterous.com/the-tortoise-the-hare-and-the-problems-of-the"&gt;previous blog post&lt;/a&gt;, I looked at the complementary roles of open- and closed-source development in a software ecosystem. In particular, I focused on how the lack of a fully interoperable alternative to Excel is hurting innovation in the spreadsheet ecosystem. In this post, I&amp;#39;d like to look at a way of stimulating that ecosystem.&lt;/i&gt;&lt;p /&gt;&lt;div&gt;&lt;b&gt;I&amp;#39;d like to propose an &amp;quot;App Store for Excel&amp;quot;&lt;/b&gt;. That is, an equivalent of Apple&amp;#39;s App Store for iPhones, but built to integrate with, and to provide extensions for Excel.&lt;/div&gt;&lt;p /&gt;&lt;div&gt;This is something that I&amp;#39;m personally excited about. It would be incredibly useful, and I would love this to exist. At the moment, most of my time is going into iterating for Cobalt Quantware&amp;#39;s initial release of our product. Cobalt Quantware is currently in stealth mode, and I hope to talk about both the experience of creating a start-up and our product more later. In the meantime, I&amp;#39;m putting this idea out there, because I don&amp;#39;t have the spare capacity to execute on it. If someone wants to build it, great, and I&amp;#39;ll provide whatever support I can. If not, I may pick up on it later. In the meantime, consider this an A-to-B test of stealth mode vs loudly talking about an idea. &lt;b&gt;I want to provoke debate, and I would love to hear feedback on this idea - if you love it, if you hate it, or if you think it needs to work differently. Please email me, or comment below.&lt;/b&gt;&lt;/div&gt; &lt;p /&gt;&lt;div&gt;I&amp;#39;ll deal later with how I think this would improve the spreadsheet ecosystem, but first, I&amp;#39;ll outline the mechanics of how the &amp;quot;App Store for Excel&amp;quot; might work.&lt;/div&gt;&lt;p /&gt; &lt;div&gt; &lt;b&gt;&lt;span style="font-size: large;"&gt;How might an &amp;quot;App Store for Excel&amp;quot; work&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;p /&gt;&lt;div&gt;I imagine that the &amp;quot;App Store for Excel&amp;quot; would be accessible through a menu item. It would show a dialog that would list extensions that are available from a central repository. One could search for a particular extension using a search bar. Clicking on an extension would give a detailed description, and &lt;b&gt;double-clicking would download and install the extension&lt;/b&gt;.&lt;/div&gt; &lt;p /&gt;&lt;div&gt;&lt;div&gt;An extension may offer additional functions to be used in formulae - for example, a simple extension may offer a version of doing linear interpolation, or a way to access data from web pages in a spreadsheet. It may offer additional menu items - for example, a better alternative to manage named ranges.&lt;/div&gt; &lt;/div&gt;&lt;p /&gt;&lt;div&gt;An extension could be packaged in one of several ways. Immediate possibilities that spring to mind are that an extension could be a VBA module, or an XLL file, or it could be a ZIP file that contains many file resources, including a file that describes how the extension could be installed. I&amp;#39;ll discuss advantages and disadvantages later.&lt;/div&gt; &lt;p /&gt;&lt;div&gt;The central repository itself might simply be a single XML or JSON file served by a webserver over HTTP, listing the available extensions, together with download URLs, descriptions, release dates, version information and other metadata. In the case of ZIP file extensions, it could even be compiled from the information file in the ZIP itself.&lt;/div&gt; &lt;p /&gt;&lt;div&gt;The &amp;quot;App Store for Excel&amp;quot; may support using several repositories simultaneously - I may have access to a global central repository of good stuff, but also to a repository specific for my company, or my group.&lt;/div&gt; &lt;p /&gt;&lt;div&gt;This is a broad brush-strokes overview of how an &amp;quot;App Store for Excel&amp;quot; may work. You may agree with what I&amp;#39;ve sketched out, or you may feel it needs some changing. In any case, there are a lot of details that would need to be filled out and specified more precisely between this description, and even a working prototype.&lt;/div&gt; &lt;p /&gt;&lt;div&gt;&lt;b&gt;&lt;span style="font-size: large;"&gt;What an &amp;quot;App Store for Excel&amp;quot; offers&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;p /&gt;&lt;div&gt;&lt;b&gt;The promise is of a global central repository, packed with functions that allow you to access data from the web, from databases, and to do high quality analysis&lt;/b&gt; of it, right in Excel. Instead of cutting and pasting several tables from web pages and emails to Excel, pull it in using a function from the central repository. Data changed, no problem, and no need to manually recopy the data - just recalculate.&lt;/div&gt; &lt;p /&gt;&lt;div&gt;The examples I gave before - linear interpolation, pulling data from the web, and managing named ranges - are functions that I have built recently. I&amp;#39;m pretty sure that many people have built functions to do these things. The duplication of effort is crazy! It would save years of effort, is if they were written once, and available centrally.&lt;/div&gt; &lt;p /&gt;&lt;div&gt;There are two other nice side-effects. First, Excel users would be better able to interoperate between companies, if they were using common functions for linear interpolation, and all the other things. Second, these common functions would see much more use, than the versions in existence at even the largest companies do currently. The more these functions are pounded, the more bugs are shaken out; and &lt;b&gt;the functions in a central repository are likely to be very high quality&lt;/b&gt;.&lt;/div&gt; &lt;p /&gt;&lt;div&gt;Above all, what I hope you do feel, if you are an Excel user is that you listen to this, and think &amp;quot;&lt;b&gt;I want this to exist&lt;/b&gt;&amp;quot;. I know I do.&lt;/div&gt;&lt;p /&gt;&lt;div&gt;&lt;b&gt;&lt;span style="font-size: large;"&gt;Why this improves the spreadsheet ecosystem&lt;/span&gt;&lt;/b&gt;&lt;/div&gt; &lt;p /&gt;&lt;div&gt;The most obvious way this improves the spreadsheet ecosystem is by putting more capabilities in the hands of users. Want to pull a stock quote from Yahoo Finance - there&amp;#39;s an extension for that. Want to pull analytics data on who is visiting your blog into Excel - you can do that too.&lt;/div&gt; &lt;p /&gt;&lt;div&gt;For me, there is an even closer analogy than Apple&amp;#39;s amazingly successful App Store, and that is the repositories that have sprung up around various programming languages in the last 10 years. Perl has CPAN, Python has PyPI, Ruby has RubyGems, Java has Maven, and so on. To my mind, these repositories have been one of the two huge production-boosts for programmers in the 2000s (the other is that lists and dictionaries have become first-class data structures in most languages). With a single command, I can extend Python with a world class numerical library, or an industrial-strength web framework, or a web scraping library, or ... All things that would require a huge amount of effort for me to create from scratch. In fact, due to the success of these libraries, &lt;a href="http://reprog.wordpress.com/2010/03/03/whatever-happened-to-programming/"&gt;the nature of programming itself has changed from creating from scratch, to glueing together libraries and systems&lt;/a&gt;.&lt;/div&gt; &lt;p /&gt;&lt;div&gt;But this post is meant to be about improving the spreadsheet ecosystem, rather than simply improving the Excel ecosystem, and there is a second, more subtle way that this central repository could help achieve that, and that harks back to the power of formal written standard that I discussed in my &lt;a href="http://edparcell.posterous.com/the-tortoise-the-hare-and-the-problems-of-the"&gt;previous post&lt;/a&gt;. By having a specification, it allows other spreadsheets to interoperate. The same extension that accesses BetFair from Excel, could be made available in OpenOffice, and in Apple&amp;#39;s Numbers, and so on. This would be tricky for extensions written in VBA, but should be achievable for other forms of extension. For example, extensions written in C#, and exposed to Excel through ExcelDna, could be compiled using Mono, and exposed automatically to other sheets.&lt;/div&gt; &lt;p /&gt;&lt;div&gt;This would provide a key interoperability step. As the central repository grows, it would become more and more attractive to build spreadsheets using only built in functions, and those available in the &amp;quot;App Store for Excel&amp;quot;. There would be no dependence on custom-built VBA, and those spreadsheets would be portable. And once this happens, the stage is set for several commercial vendors to compete by adding value, with  open-source competitors keeping them innovating.&lt;/div&gt; &lt;p /&gt;&lt;div&gt;As I said before, Excel has 400 million users, versus Java&amp;#39;s 9 million. To me, the thought of &lt;b&gt;creating a software ecosystem to hugely empower nearly 6% of the world&amp;#39;s population is very exciting&lt;/b&gt;.&lt;/div&gt; &lt;p /&gt;&lt;div&gt;&lt;b&gt;&lt;span style="font-size: large;"&gt;Monetization&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;p /&gt;&lt;div&gt;As I said before, I do not currently have the capacity to pursue creating this &amp;quot;App Store for Excel&amp;quot;. But I have thought a little about how it might be monetized. To me, the importance of this is that it provides sustainability, rather than dot-com riches. If it can be monetized, it can support a population of permanent developers, who can maintain, support and extend it. Although more power to you if you can make dot-com riches as well.&lt;/div&gt; &lt;p /&gt;&lt;div&gt;The obvious way to obtain revenue from an &amp;quot;App Store for Excel&amp;quot; is the same way that Apple do: by providing the facility for authors to charge for add-ins, and to take a percentage of this. In that case, this had a very strong stimulative effect on the community of developers, especially considering that development for Apple systems beforehand would be considered nichey, at best. I would hope that providing authors with a simple way to charge for Excel extensions would provoke a similar effect on development around the Excel ecosystem.&lt;/div&gt; &lt;p /&gt;&lt;div&gt;Another way to obtain revenue might be by providing a certification scheme, charging to certify that extensions meet certain criteria. &lt;/div&gt;&lt;p /&gt;&lt;div&gt;A third way might be to provide a product targeting the corporate market, allowing easy distribution, authentication, and access control within a company. I understand this is the route chosen by the makers of the repository software used in the Java ecosystem.&lt;/div&gt; &lt;p /&gt;&lt;div&gt;I haven&amp;#39;t thought too deeply about this aspect, but these are just some initial thoughts that spring to mind on how to make an &amp;quot;App Store for Excel&amp;quot; pay for itself. I&amp;#39;d be interested in any comments or further thoughts people have.&lt;/div&gt; &lt;p /&gt;&lt;div&gt;&lt;b&gt;&lt;span style="font-size: large;"&gt;Conclusion&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;p /&gt;&lt;div&gt;&lt;b&gt;In this post, and the previous one, I&amp;#39;ve looked at the dynamic of open- and closed-source software working together for the best pace of innovation. My particular focus has been the spreadsheet ecosystem, the largest software development ecosystem by number of users, which has been dominated for many years by a single closed-source commercial solution, Excel. I&amp;#39;ve put forward a proposal of a central repository for extensions to Excel, and other spreadsheets - an &amp;quot;App Store for Excel&amp;quot;. I think that this would be immediately useful, and exciting in itself. More importantly, longer term, I hope this would hope to stimulate the existence of open- and closed-source solutions competing in the spreadsheet ecosystem, and to restore a high pace of innovation.&lt;/b&gt;&lt;/div&gt;
	
&lt;/p&gt;

&lt;p&gt;&lt;a href="http://blog.edparcell.com/how-about-an-app-store-for-excel"&gt;Permalink&lt;/a&gt; 

	| &lt;a href="http://blog.edparcell.com/how-about-an-app-store-for-excel#comment"&gt;Leave a comment&amp;nbsp;&amp;nbsp;&amp;raquo;&lt;/a&gt;

&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ParcellsPosts/~4/2AuVaimX1ww" height="1" width="1"/&gt;</description>
      <posterous:author>
        <posterous:userImage>http://posterous.com/images/profile/missing-user-75.png</posterous:userImage>
        <posterous:profileUrl>http://posterous.com/users/5erKH0kcdaeZ</posterous:profileUrl>
        <posterous:firstName>Ed</posterous:firstName>
        <posterous:lastName>Parcell</posterous:lastName>
        <posterous:nickName>edparcell</posterous:nickName>
        <posterous:displayName>Ed Parcell</posterous:displayName>
      </posterous:author>
    <feedburner:origLink>http://blog.edparcell.com/how-about-an-app-store-for-excel</feedburner:origLink></item>
    <item>
      <pubDate>Wed, 28 Apr 2010 23:29:45 -0700</pubDate>
      <title>The tortoise, the hare and the problems of the Excel ecosystem</title>
      <link>http://feedproxy.google.com/~r/ParcellsPosts/~3/CdpslgX0tgA/the-tortoise-the-hare-and-the-problems-of-the</link>
      <guid isPermaLink="false">http://blog.edparcell.com/the-tortoise-the-hare-and-the-problems-of-the</guid>
      <description>&lt;p&gt;
	Chris Dixon has a great &lt;a href="http://cdixon.org/2010/04/25/the-tradeoff-between-open-and-closed/" target="_blank"&gt;post about the tradeoff between open and closed&lt;/a&gt;. One thing that I found particularly interesting was the quote from Professor Eisenmann that &amp;quot;markets may evolve in directions that favor[sic] the presence of one strong closed player and one strong open player&amp;quot;.&lt;p /&gt;&lt;div&gt;&lt;b&gt;The tortoise and the hare&lt;/b&gt;&lt;/div&gt;&lt;p /&gt;&lt;div&gt;I agree with the thinking. It&amp;#39;s like Aesop&amp;#39;s tortoise and hare exploring an unknown continent. The hare goes scampering off to the near distance, and starts napping, while the tortoise plods along, slowly and continuously, catching up to the hare, and then passing it. Eventually the hare wakes up, and again runs ahead of the tortoise. They are going to run a long way.&lt;/div&gt; &lt;p /&gt;&lt;div&gt;Without the tortoise, the hare is going to run off in the distance once, fall asleep, and never bother to explore the rest of the continent. You can see this after the first set of browser wars. Internet Explorer had become dominant, and Mozilla took a long sabbatical to be redeveloped from scratch as an open-source product. Microsoft didn&amp;#39;t release a version of Internet Explorer for five years. So the job of the tortoise is to make sure that the hare doesn&amp;#39;t nap.&lt;/div&gt; &lt;p /&gt;&lt;div&gt;The job of the hare is more subtle. The hare runs faster, and can explore the area near them both in less time. I would argue that companies with closed source products tend to innovate faster, and that open source products tend to take their lead from closed source products where possible. To pick 3 examples I can see on my desktop right now, Linux/BSD came from the commercial UNIXes, Firefox was built to compete with IE, Thunderbird with Outlook, and so on. Without the hare, the tortoise will get there, eventually, but it will take far longer to explore the possibilities. The hare helps give the tortoise direction.&lt;/div&gt; &lt;p /&gt;&lt;div&gt;Now I would hardly argue that this is hardly a complete analysis of the distinctive aspects of open- and closed-source cultures, and the various ways they compete and co-operate. But it does help cast some light on where this innovation process is failing. And for me, the prime example has to be Excel.&lt;/div&gt; &lt;p /&gt;&lt;div&gt;&lt;b&gt;Excel&lt;/b&gt;&lt;/div&gt;&lt;p /&gt;&lt;div&gt;Excel is used by 400 million people worldwide, to build what are to all intents and purposes simple business applications. And yet from 1995 to 2007, we have seen the following innovations in Excel:&lt;/div&gt; &lt;div&gt;&lt;ul&gt;&lt;li&gt;a clipboard that can hold multiple items&lt;/li&gt;&lt;li&gt;a talking paper-clip&lt;/li&gt;&lt;li&gt;the ability to have more the 65,536 rows&lt;/li&gt;&lt;li&gt;an arguably improved menu-system&lt;/li&gt;&lt;/ul&gt;I don&amp;#39;t think I&amp;#39;m missing too much in that list. I haven&amp;#39;t used 2010 yet, but I&amp;#39;m not holding my breath. And Microsoft is acting perfectly rationally in failing to innovate. Say they could spend $1 million developing a new feature, then for them that&amp;#39;s $1 million of lost profit. They won&amp;#39;t gain a single customer, because what else were you going to do than buy Excel?&lt;/div&gt; &lt;p /&gt;&lt;div&gt;Now, there are open-source spreadsheets - OpenOffice and Gnumeric spring to mind. And there are commercial alternatives, such as iWork. And if you prefer the cloud, there&amp;#39;s Google Documents. But year after year, they fail to make a significant dent in Excel&amp;#39;s dominance. Why is that?&lt;/div&gt; &lt;p /&gt;&lt;div&gt;What none of them have, properly, is interoperability. Sure, if I make a simple table in Excel, I can port that around. If I start using the more fancy functions in Excel, I start running into trouble. If I make my own functions in VBA, fairly quickly I end up unable to use my spreadsheet, even on Mac Excel.&lt;/div&gt; &lt;p /&gt;&lt;div&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;Where do we go from here&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;p /&gt; &lt;div&gt;The internet, and the web in particular, have always had interoperability. While Internet Explorer may be closed source, it is based on open standards. And in a lot of ways, IE has done a good job as the hare, exploring possibilities - ActiveX for example, was expedient, and gave use-cases which set targets for later web standards to do properly.&lt;/div&gt; &lt;p /&gt;&lt;div&gt;If I&amp;#39;m asked to imagine what the web would be like if the entire ecosystem was closed, I think of Lotus Notes. I first used Notes in 1997, eight years after its first release, and it still seemed innovative at that time. But in 2010, I would not consider it for a new deployment. It&amp;#39;s clunky, and has been largely eclipsed by web technologies, improving slowly over time.&lt;/div&gt; &lt;p /&gt;&lt;div&gt;The spreadsheet ecosystem needs to take this lesson to heart. Standards allow interoperability. And interoperability allows real competition. And that makes better products for end-users.&lt;/div&gt;&lt;p /&gt;&lt;div&gt;So one possibility is to start defining standards based on what already exists in Excel and other spreadsheets. One standard may define allowable worksheet functions, another may define the core of a scripting language, another a standard file format for interchange and so on. There is a lot of work here, no doubt. In fact, I would say it is an impractical amount of work, amounting in effect to reverse engineering Excel.&lt;/div&gt; &lt;p /&gt;&lt;div&gt;This blog post is already long enough, so in a future blog post, I&amp;#39;d like to outline an alternative direction, based on the creation of a repository for VBA modules, XLLs and other extensions. Think CPAN/PyPI/CRAN/App Store for Excel. The aim is to create something of immediate utility, with a view to allowing proper interoperability.&lt;/div&gt; &lt;p /&gt;&lt;div&gt;In the mean time, especially if you&amp;#39;re a keen Excel user, I&amp;#39;d be interested in any feedback you have on this post.&lt;/div&gt;
	
&lt;/p&gt;

&lt;p&gt;&lt;a href="http://blog.edparcell.com/the-tortoise-the-hare-and-the-problems-of-the"&gt;Permalink&lt;/a&gt; 

	| &lt;a href="http://blog.edparcell.com/the-tortoise-the-hare-and-the-problems-of-the#comment"&gt;Leave a comment&amp;nbsp;&amp;nbsp;&amp;raquo;&lt;/a&gt;

&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ParcellsPosts/~4/CdpslgX0tgA" height="1" width="1"/&gt;</description>
      <posterous:author>
        <posterous:userImage>http://posterous.com/images/profile/missing-user-75.png</posterous:userImage>
        <posterous:profileUrl>http://posterous.com/users/5erKH0kcdaeZ</posterous:profileUrl>
        <posterous:firstName>Ed</posterous:firstName>
        <posterous:lastName>Parcell</posterous:lastName>
        <posterous:nickName>edparcell</posterous:nickName>
        <posterous:displayName>Ed Parcell</posterous:displayName>
      </posterous:author>
    <feedburner:origLink>http://blog.edparcell.com/the-tortoise-the-hare-and-the-problems-of-the</feedburner:origLink></item>
    <item>
      <pubDate>Thu, 22 Apr 2010 12:15:00 -0700</pubDate>
      <title>Tutorial: Numerical Analysis in Excel using C# with ExcelDna and AlgLib</title>
      <link>http://feedproxy.google.com/~r/ParcellsPosts/~3/_RiUGewbM-s/tutorial-numerical-analysis-in-excel-using-c</link>
      <guid isPermaLink="false">http://blog.edparcell.com/tutorial-numerical-analysis-in-excel-using-c</guid>
      <description>&lt;p&gt;
	&lt;p&gt;Quite often, I need to use numerical techniques more advanced than those that ship with Excel. Sometimes this involves writing my own algorithms from scratch, but when possible, I prefer to make use of existing libraries. Tens or hundreds of thousands of open source developers have worked to make great libraries - not only for numerical analysis, but for messaging, web scraping, and a jillion other tasks. Exposing this functionality to Excel makes it far more powerful. With that in mind, I'd like to share the workflow I use to access an open source numerical library, AlgLib using C#.&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size: large;"&gt;C#&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;So why C# rather than VBA?&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;C# lets me use version control. Once you've used version control, you can't go back.&lt;/li&gt;
&lt;li&gt;C# is more maintainable than VBA. Even with the best of intentions, VBA code tends to become a bit of a mess - functions grow to several pages, algorithms become enmeshed with code to manipulate the sheet. C# is a well-designed modern object-oriented language. It's the easiest language I've ever come across to just bash code out in, and be pretty sure that you will be able to understand it when you come back in 6 months.&lt;/li&gt;
&lt;li&gt;A C# library is more manageable than VBA modules. When I start a new spreadsheet, I have one add-in to load, rather than 20 separate VBA modules.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You can download Visual C# 2010 Express from Microsoft at &lt;a href="http://www.microsoft.com/express/Downloads/#2010-Visual-CS"&gt;http://www.microsoft.com/express/Downloads/#2010-Visual-CS&lt;/a&gt;, which will be sufficient for this article. Standard or Professional editions are recommended for more serious work.&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size: large;"&gt;AlgLib&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;In this article, I'll be looking at accessing numerical routines from the AlgLib library. AlgLib is a neat project run by Sergey Bochkanov and Vladimir Bystritsky, aiming to provide robust implementations of numerical algorithms for several languages, including C#. This is great for several reasons. Having code in the language you are familiar with makes it very easy to integrate into your project or existing codebase. But more importantly, at a deeper level than that, it encourages you to look at the code, to play with it, and to adapt it to your own needs. Numerical algorithms are intrinsically hard - you need a lot of maths to come up with an efficient solver or integration routine - and I'm not anticipating that every one who looks at the code will be able to do that. Nonetheless, the most important property of numerical routines is that they be robust. There is nothing worse than running a solver for a day, just to find it has crashed, or given you, very precisely, the wrong solution. And the way numerical routines become robust is by people pounding on them, and fixing edge cases. And for this, AlgLib is a much better base for the 2010s, than JPL's excellent, but nearly dead, Fortran routines - code may not decay, but code ecosystems seem to, and there aren't so many Fortran programmers left.&lt;/p&gt;
&lt;p&gt;I should mention the other open source numerical libraries. GSL is robust, mainly written in C, which can make it a challenge to integrate, memory-management-wise. Boost (C++) now has some mathematical libraries, although fewer, and less advanced, but its coverage of statistical distributions is quite complete. On the commercial side, IMSL and NAG are well recognized as robust numerical libraries, with hefty price tags. If there is interest, I can cover how I expose C++ libraries to Excel in another post.&lt;/p&gt;
&lt;p&gt;You can download the latest version of AlgLib from their website at &lt;a href="http://www.alglib.net/"&gt;http://www.alglib.net/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size: large;"&gt;ExcelDna&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;I'll be using ExcelDna to expose C# functions to Excel. ExcelDna is a magical, but under-publicized library, which can be used to automatically expose all public static functions in a .NET assembly to Excel through an xll addin. Everyone I have recommended ExcelDna to has either immediately switched to using it, or lamented (hard) the fact that for one reason or another they were unable to immediately switch to it.&lt;/p&gt;
&lt;p&gt;You can download the latest version of ExcelDna from &lt;a href="http://exceldna.codeplex.com/"&gt;http://exceldna.codeplex.com/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size: large;"&gt;How to put it all together&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size: small;"&gt;The first thing to do is to expose C# functions to Excel. To do that, follow these instructions:&lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span style="font-size: large;"&gt;&lt;span style="font-size: small;"&gt;Open Visual C# 2010 Express, and select start a new project from the start page. In the new project dialog box, select the Class Library template and enter "AwesomeNumericalLibrary" as the name at the bottom of the dialog.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-size: small;"&gt;Put the cursor in the name of the class, "Class1", and hit F2 to rename the class to "ExcelFunctions". You should also rename the files. This is personal choice, but my preference is to have the functions I expose to Excel to be in a single file, which only contains functions exposed to Excel, rather than intermingled with other code. As the library grows, I tend to split the file based on categories of function eg statistical distributions in one file, interpolation routines in another.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-size: small;"&gt;Add a simple function, so we can test that we can expose functions to Excel. Again, as a personal choice I tend to begin all Excel functions in a single library with a common prefix. This allows them to be easily found using Excel's Insert Function dialog or intellitype.&lt;br /&gt;&lt;code&gt;
        public static double AwesomeLifeUniverseEverything()
        {
            return 42;
        }
&lt;/code&gt; &lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-size: small;"&gt;From the ExcelDna zip file, add ExcelDna-0.25\Distribution\ExcelDna.xll to your project. You should add it to the project root itself, rather than a sub-folder. This can be done by dragging the ExcelDna.xll file from a Windows Explorer window onto the text AwesomeNumericalLibrary in the Visual C# Solution Explorer.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-size: small;"&gt;In the solution explorer, rename ExcelDna.xll to AwesomeNumericalLibrary.xll.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-size: small;"&gt;Add a new text file to the project root, and rename it to AwesomeNumericalLibrary.dna. The xll file looks for a dna file with a similar name to tell it what .NET assemblies it should load and expose functions to Excel from. In our case, there will be a single dll, so add the following text to AwesomeNumericalLibrary.dna:&lt;br /&gt;&lt;code&gt;
&amp;lt;DnaLibrary&amp;gt;
  &amp;lt;ExternalLibrary Path="AwesomeNumericalLibrary.dll" /&amp;gt;
&amp;lt;/DnaLibrary&amp;gt;
&lt;/code&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span style="font-size: small;"&gt; &lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;You must tell Excel to copy the .dna and .xll files to the output directory when it builds the project. To do this, select the two files in the solution explorer. Then right click and select properties from the context menu. In the properties dock, change the Copy To Output Directory setting from "Do not copy" to "Copy always".&lt;/li&gt;
&lt;li&gt;At the time of writing, ExcelDna does not support .NET 4.0 assemblies. To fix this, right click on the project in the solution explorer and hit properties. In the properties window, change Target Framework to ".NET Framework 3.5". There will be a warning message about the CSharp reference. Expand the References section for the project in the solution explorer, and remove the reference to CSharp.&lt;/li&gt;
&lt;li&gt;Now we are ready to test whether our function is accessible from Excel, so save the project (easiest way seems to be to close and re-open it!) and build the project (by hitting F6).&lt;/li&gt;
&lt;li&gt;Fire up Excel, and open the Add-Ins dialog box. In Excel 2003 and older, it is Tools..Addins. If you are using Excel 2007 or newer, the menus are hidden - the magic key combo to get to the Add-Ins dialog box is "Alt-T, I" (it is also available through Excel options).&lt;/li&gt;
&lt;li&gt;Click Browse, and then navigate to where you saved the project, and then within the "bin\Release" directory, select AwesomeNumericalRecipes.xll and hit Open.&lt;/li&gt;
&lt;li&gt;In a cell in the sheet, type "&lt;strong&gt;=AwesomeLifeUniverseEverything(10)&lt;/strong&gt;" and verify that you get the result 42.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p&gt;&lt;span style="font-size: small;"&gt;Well done! You have just exposed your first C# function to Excel.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size: small;"&gt;Now to incorporate AlgLib into our project, and expose a function to Excel:&lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span style="font-size: small;"&gt;Unfortunately AlgLib does not have a project file, so we have to create our own. Right click the solution in the solution explorer, and click Add..New Project. In the Add New Project dialog, select Class Library and enter the name "AlgLib".&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-size: small;"&gt;Delete the class file, Class1.cs, that is created by default.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-size: small;"&gt;From the AlgLib zip file, add all the .cs files in the csharp\src directory to the AlgLib project. You can do this by selecting the files in Windows Explorer and dragging them to the AlgLib project in the Visual Studio Solution Explorer.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-size: small;"&gt;Again, you must tell Visual Studio you want a .NET Framework 3.5 library, using the steps above on the AlgLib project.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-size: small;"&gt;Add a reference to the AlgLib project in the AwesomeNumericalLibrary project. In the Solution Explorer, expand the AwesomeNumericalLibrary project. Right-click References, and click Add Reference. In the Add Reference dialog, select the Projects tab, select the AlgLib project and click OK.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-size: small;"&gt;Add a function to the ExcelFunctions class in the AwesomeNumericalLibrary project. I've chosen here to expose Dawson's integral:&lt;br /&gt;&lt;code&gt;
        public static double AwesomeDawson(double x)
        {
            return alglib.dawson.dawsonintegral(x);
        }
&lt;/code&gt; &lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-size: small;"&gt;Build the solution (hit F6). The AlgLib project may generate many warnings. You may get an error that AwesomeNumericalLibrary.dll is open by another process and cannot be written. If this is the case, then open up the Add-Ins dialog in Excel, and remove the tick from by "AwesomeNumericalLibrary" to unload the dll from Excel. Occasionally you may also have to restart Excel.&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-size: small;"&gt;Go back to Excel and reload the library. It should remain in the Addins dialog, so you can just re-select it. Then in a cell, type "&lt;strong&gt;=AwesomeDawson(2)&lt;/strong&gt;". It should give you the result 0.30134.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span style="font-size: small;"&gt;Congratulations! You have just exposed a numerical routine from AlgLib to Excel.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size: small;"&gt;AlgLib has a large number of functions, so I'll let you expose the rest as you need. I've chosen a pretty simple function to expose here, but ExcelDna also makes it possible to take ranges as inputs, and give ranges as outputs using array formulae. This can be useful for linear algebra, or generating large amounts of random data. Error handling is another issue - this function takes one number and always returns a result, but not so with all functions. If you're interested, let me know, and I'll cover these issues in a future blog post.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size: large;"&gt;How to Distribute&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size: small;"&gt;To distribute an Excel add-in you have made using ExcelDna you must distribute the (renamed) ExcelDna.dll file, your .dna file, and any .dll files that your add-in is using directly or indirectly.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size: small;"&gt;AlgLib is distributed under a GPL license, so if you distribute your add-in, you must also make the source code available under the GPL license. ExcelDna is distributed under a more permissive license. Please check for yourself that you are complying with the respective projects' license terms.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size: small;"&gt;&lt;span style="font-size: large;"&gt;Further steps&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size: small;"&gt;There are several directions you can take from this quick tutorial. I'd recommend looking through the ExcelDna documentation a little. ExcelDna is able to take object arrays and other types as parameters, and to return them as results, which can be powerful. You can also use attributes on your functions to better control how they work, and how they appear in Excel.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size: small;"&gt;You might want to look at exposing other libraries or functionality to Excel. Some things I've done that were quite fun and useful were a web scraper, which allows me to suck out values from a live web page using XPath right in the Excel formula, and more targetted add-ins for Yahoo finance and Betfair.&lt;/span&gt;&lt;/p&gt;
	
&lt;/p&gt;

&lt;p&gt;&lt;a href="http://blog.edparcell.com/tutorial-numerical-analysis-in-excel-using-c"&gt;Permalink&lt;/a&gt; 

	| &lt;a href="http://blog.edparcell.com/tutorial-numerical-analysis-in-excel-using-c#comment"&gt;Leave a comment&amp;nbsp;&amp;nbsp;&amp;raquo;&lt;/a&gt;

&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ParcellsPosts/~4/_RiUGewbM-s" height="1" width="1"/&gt;</description>
      <posterous:author>
        <posterous:userImage>http://posterous.com/images/profile/missing-user-75.png</posterous:userImage>
        <posterous:profileUrl>http://posterous.com/users/5erKH0kcdaeZ</posterous:profileUrl>
        <posterous:firstName>Ed</posterous:firstName>
        <posterous:lastName>Parcell</posterous:lastName>
        <posterous:nickName>edparcell</posterous:nickName>
        <posterous:displayName>Ed Parcell</posterous:displayName>
      </posterous:author>
    <feedburner:origLink>http://blog.edparcell.com/tutorial-numerical-analysis-in-excel-using-c</feedburner:origLink></item>
    <item>
      <pubDate>Wed, 14 Apr 2010 19:10:07 -0700</pubDate>
      <title>Book review: Influence: The Psychology of Persuasion by Robert Cialdini</title>
      <link>http://feedproxy.google.com/~r/ParcellsPosts/~3/1yeOl6EiLSs/book-review-influence-the-psychology-of-persu-0</link>
      <guid isPermaLink="false">http://blog.edparcell.com/book-review-influence-the-psychology-of-persu-0</guid>
      <description>&lt;p&gt;
	&lt;div&gt;I initially came across Cialdini&amp;#39;s &amp;quot;Influence: The Psychology of Persuasion&amp;quot; as a recommendation by Charlie Munger in his excellent speech &amp;quot;The Psychology of Human Misjudgement&amp;quot;, and with my reading pile near empty, ordered it from Amazon on a whim. You can (and if you&amp;#39;ve got time, should) read a transcript of that speech at &lt;a href="http://vinvesting.com/docs/munger/human_misjudgement.html"&gt;http://vinvesting.com/docs/munger/human_misjudgement.html&lt;/a&gt;. Here is my review of that book:&lt;/div&gt; &lt;p /&gt;In Influence, Cialdini looks at some of the universal principles used by what he calls compliance professionals. This includes salesmen and estate agents, looking to make you compliant so that you might buy a fridge, a car or a house, but also includes more extreme examples - cult leaders and Chinese POW guards are two of the more colourful examples.&lt;p /&gt;&lt;div&gt;The book naturally targets two groups of people. First, those who want to put these principles into action. I would expect this would naturally include sales and marketing professionals, but I&amp;#39;m hard-pressed to imagine who wouldn&amp;#39;t want the magic power to make others do their bidding. The audience also includes those who want to know more about these principles, how they are susceptible to them, and how to defend against them. I suspect this group also includes pretty much everybody. There is a natural tension between these audiences. It would be easy to alienate the general public with a barrage of ways they are naive, or to go the other way and turn off sales people looking for concrete techniques. The author successfully diffuses this tension, identifying himself in the first sentence of the book as a life-long patsy for all these techniques, but not shying away from giving details on how they can be used to best effect.&lt;/div&gt; &lt;p /&gt;&lt;div&gt;The author Robert Cialdini, is an expert researcher in this field, and this book builds upon his years of research. Nonetheless, while it is backed by high quality research and thinking, this book is no research paper. The book is deliberately approachable, outlining ideas with a minimum of fuss, and giving plenty of concrete examples from the author&amp;#39;s own experience, and interpreting well-known events or situations.&lt;/div&gt; &lt;p /&gt;&lt;div&gt;The book is organized into seven chapters. The first is an introductory chapter which provides motivation for the reader by giving a taste of the power of the sort of techniques outlined in the book. Each of the subsequent chapters deals with a specific principle which can be used to motivate an intended action. The principles covered are Reciprocation, Commitment and Consistency, Social Proof, Liking, Authority and Scarcity. Within each chapter, the author uses a number of examples to drive the message, outlining the general principle at work, looking at when they are most effective, and how to say no when you are on the receiving end.&lt;/div&gt; &lt;p /&gt;&lt;div&gt;For example, in the chapter on Reciprocation, the author looks at the facet of human nature that causes us to feel indebted when someone does something for us, or gives us something. Examples given include Hare Krishnas handing out flowers at airports, and various political careers. He goes on to describe how this effect works even when the gift is unreciprocated, to the point where people will try to avoid receiving unsolicited gifts to avoid the burden of reciprocation. He uses the example of a boy scout initially offering circus tickets at 5 dollars a piece, but when rejected, backing off to offering cookies at 1 dollar a piece to illustrate how reciprocal concessions can be used to make a sale. Finally, he covers how to avoid being trapped into an action by the principle of reciprocation, without resorting to rudeness that may itself be counter-productive.&lt;/div&gt; &lt;p /&gt;&lt;div&gt;The most severe criticism I can level at the book is that occasionally it veers towards becoming a succession of anecdotes, with less attention paid to explicitly describing the principle under consideration. These colourful examples do all have a point, illustrating some aspect of a principle or a way it can be more or less effective, but it is possible to lose track of the higher level view, and just start reading the book as a series of interesting stories.&lt;/div&gt; &lt;p /&gt;&lt;div&gt;And that would be a great shame, because this is one of those books, that once you have read it, you cannot help but view the world through the prism of the ideas in this book. Apple delaying the iPad internationally yet again, and me wanting one even more - perfect example of the principle of scarcity. In hindsight, the credit bubble leading to the financial crisis of 2007 onwards seems pretty much a perfect storm of all the principles from all the parties.&lt;/div&gt; &lt;p /&gt;&lt;div&gt;One might think that in the 26 years since it was first published, it would have aged. Certainly, advertising and marketing techniques have evolved hugely in that time, to the point where modern consumers could be expected to be pretty immune to say, a television advert from the early 80s. Nonetheless, underlying the principles examined in the book are fundamental aspects of human behaviour, and these do not change so quickly.&lt;/div&gt; &lt;p /&gt;&lt;div&gt;In any case, it is useful to explicitly list, describe and examine how it is that people come to make decisions, both to be aware of where our own decision-making can be taken advantage of, and to help others come to decisions that we would prefer them to.&lt;/div&gt; &lt;p /&gt;&lt;div&gt;The author abstains from comment on the desirability of using the powers of influence it describes, although it deals with examples from the positive (increasing racial integration in schools, effectively promoting environmental causes) to the strongly negative (propaganda in North Korean POW camps). Like any tools, the author&amp;#39;s principles can be used for good or evil, but are inherently neither.&lt;/div&gt; &lt;p /&gt;&lt;div&gt;In many cases, the principles are based on shortcuts that we could reasonably expect to work; a more expensive or more in demand item  is likely to be a better item. Furthermore, with the vast choice of actions and purchases available to us in the modern world, we need these shortcuts. It would take a long time to complete a supermarket shopping trip if one was to calculate the cost per gram of every item in the shopping cart, and take into account the subjective quality differences - far easier to just go by the shiny packaging. The author recognizes this, and to his credit does not recommend attempting to totally avoid these signals. Instead, he adopts an approach of recognizing when the signals are being used in a deliberately manipulative way, giving mental tricks to flip the manipulation around, and negate its effect.&lt;/div&gt; &lt;p /&gt;&lt;div&gt;The author leaves it to you to decide whether you want to try to influence others, or simply to shield yourself from their undue influence. Nonetheless, he does on occasion advocate a course of trying to disrupt those who use these techniques in a dishonest way. For example, social proof is too useful a tool in deciding what to do to allow it to be subverted.&lt;/div&gt; &lt;p /&gt;&lt;div&gt;In the end, I found this an interesting book. The subject matter, how people try to influence other people, was always going to be good, and its handled at a good pace. Simple enough that it&amp;#39;s approachable for anyone, but with deep enough ideas to make it worth reading. More than that, the book is likely to be useful reading whichever camp you primarily fall into, a manipulator or a manipulatee.&lt;/div&gt; &lt;p /&gt;&lt;div&gt;&lt;b&gt;Recommendation&lt;/b&gt;: At £5.50 on Amazon, this book is a steal. &lt;b&gt;BUY IT! &lt;/b&gt;&lt;/div&gt;
	
&lt;/p&gt;

&lt;p&gt;&lt;a href="http://blog.edparcell.com/book-review-influence-the-psychology-of-persu-0"&gt;Permalink&lt;/a&gt; 

	| &lt;a href="http://blog.edparcell.com/book-review-influence-the-psychology-of-persu-0#comment"&gt;Leave a comment&amp;nbsp;&amp;nbsp;&amp;raquo;&lt;/a&gt;

&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ParcellsPosts/~4/1yeOl6EiLSs" height="1" width="1"/&gt;</description>
      <posterous:author>
        <posterous:userImage>http://posterous.com/images/profile/missing-user-75.png</posterous:userImage>
        <posterous:profileUrl>http://posterous.com/users/5erKH0kcdaeZ</posterous:profileUrl>
        <posterous:firstName>Ed</posterous:firstName>
        <posterous:lastName>Parcell</posterous:lastName>
        <posterous:nickName>edparcell</posterous:nickName>
        <posterous:displayName>Ed Parcell</posterous:displayName>
      </posterous:author>
    <feedburner:origLink>http://blog.edparcell.com/book-review-influence-the-psychology-of-persu-0</feedburner:origLink></item>
    <item>
      <pubDate>Tue, 13 Apr 2010 17:21:00 -0700</pubDate>
      <title>Tutorial: Using JQuery and CouchDb to build a simple AJAX web application</title>
      <link>http://feedproxy.google.com/~r/ParcellsPosts/~3/0kqRJ9DV5Rk/using-jquery-and-couchdb-to-build-a-simple-we</link>
      <guid isPermaLink="false">http://blog.edparcell.com/using-jquery-and-couchdb-to-build-a-simple-we</guid>
      <description>&lt;p&gt;
	&lt;p&gt;I initially wrote this post a couple of months ago, while trying out writing a blog on wordpress. That blog didn't go anywhere, but I thought this tutorial on writing an AJAX web application with JQuery and CouchDb might still be of interest to developers playing with CouchDb. Certainly I couldn't find anything similar at the time&lt;/p&gt;
&lt;p&gt;It also gives me a chance to see what the code formatting facilities on posterous are like. I enjoyed using CouchDb, but ultimately found that MongoDb better met my needs. That said, I was very impressed with CouchDb as a light, stand-alone solution, and look forward to seeing how it progresses. I hope that CouchDb hasn't moved so far forward in the intervening time that this tutorial is out of date.&lt;/p&gt;
&lt;p&gt;I could not find too much on the web about using jQuery and CouchDb together, so I decided to put together a little "Hello World" couch app of my own. Having done that, I thought I'd put together a little step-by-step instruction in case it's of use to others.&lt;/p&gt;
&lt;p&gt;I should warn that I'm not too familiar with jQuery, so I may be doing things in odd ways - please let me know if you see something that could be done better.&lt;/p&gt;
&lt;p&gt;I assume that you have CouchDb 0.10 and CouchApp 0.5 installed. Later versions may work, but no guarantees.&lt;/p&gt;
&lt;p&gt;First, go to &lt;a href="http://127.0.0.1:5984/_utils"&gt;http://127.0.0.1:5984/_utils&lt;/a&gt; and create a database called "addressbook". Because we'll be making the functionality to display data before the functionality to create or update it, it's a good idea to use the built-in CouchDb web interface to add a couple of documents. The initial version of our webapp will let us store a mobile number for each person, so add the following 2 documents:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;
{"type": "address", "name": "Fred", "mobile": "555-0001"}
{"type": "address", "name": "Barney", "mobile": "555-0002"}
&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;CouchDb uses design documents to expose the database to the world, but editing design documents directly gets a little painful. Couchapp eases this pain, by breaking design documents out into a set of directories and files on the local filesystem representing shows, views, and so on, which can be pushed to the CouchDb server at will. We need to create a couchapp design document, and also a view to retrieve the phone numbers, which we can do using couchapp at the command-line:&lt;/p&gt;
&lt;p&gt;couchapp generate app addressbook&lt;br /&gt;couchapp generate view addressbook phonenumbers&lt;/p&gt;
&lt;p&gt;The first line creates a directory called addressbook with a skeleton design document set up, and the second creates a view in the design document.&lt;/p&gt;
&lt;p&gt;We can push this to the server using:&lt;/p&gt;
&lt;p&gt;couchapp push addressbook &lt;a href="http://127.0.0.1:5984/addressbook"&gt;http://127.0.0.1:5984/addressbook&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you look at the database using the web interface now, you should see the design document "_design/addressbook" in addition to the documents representing the two phone numbers.&lt;/p&gt;
&lt;p&gt;The view we will need simply gives each name and mobile number, with name as key, so the view is sorted by name. No reduce function is required, so delete addressbook/views/phonenumbers/reduce.js, and put the following in addressbook/views/phonenumbers/map.js&lt;/p&gt;
&lt;p&gt;&lt;code&gt;
function(doc) {
  if (doc.type &amp;amp;amp;&amp;amp;amp; doc.type == "address" &amp;amp;amp;&amp;amp;amp; doc.name &amp;amp;amp;&amp;amp;amp; doc.mobile) {
    emit(doc.name, doc.mobile);
  }
}
&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Push the couchapp to the server using&lt;/p&gt;
&lt;p&gt;couchapp push addressbook &lt;a href="http://127.0.0.1:5984/addressbook"&gt;http://127.0.0.1:5984/addressbook&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;and check that you can see the view at http://127.0.0.1:5984/addressbook/_design/addressbook/_view/phonenumbers&lt;/p&gt;
&lt;p&gt;Couchapp has set up an initial index.html for us, which we can edit at addressbook/_attachments/index.html, and view at http://127.0.0.1:5984/addressbook/_design/addressbook/index.html. Make sure that you can view the file ok. You should then alter index.html to contain:&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;&lt;code&gt;
&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;title&amp;gt;Simple address book&amp;lt;/title&amp;gt;
    &amp;lt;link rel="stylesheet" href="style/main.css" type="text/css"&amp;gt;
&amp;lt;span style="white-space: pre;"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;script src="/_utils/script/json2.js"&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;span style="white-space: pre;"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;script src="/_utils/script/jquery.js?1.3.1"&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;span style="white-space: pre;"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;script src="/_utils/script/jquery.couch.js?0.9.0"&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;span style="white-space: pre;"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;script type="text/javascript"&amp;gt;
&amp;lt;span style="white-space: pre;"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;h1&amp;gt;Simple address book&amp;lt;/h1&amp;gt;
&amp;lt;span style="white-space: pre;"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;div id="add"&amp;gt;&amp;lt;button type="button" id="add"&amp;gt;Add&amp;lt;/button&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;div id="addressbook"&amp;gt;&amp;lt;/div&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt; &lt;/p&gt;
&lt;p&gt;The head contains a title, a link to a stylesheet, imports jQuery and jQuery Couch. These are used by the CouchDb web interface, and included with CouchDb by default. It then has a space for our own javascript to go - more on this later. The body contains an add button within a div, and an empty div called addressbook. The app will display address book entries in the addressbook div.&lt;/p&gt;
&lt;p&gt;We use javascript to access data in the CouchDb, and to process events from the browser, such as buttons and links being clicked. Conceptually, we can think of CouchDb as the Model, the DOM representing the HTML shown to the user as being the view, and our javascript as being the Controller, albeit with relatively little separation in this example.&lt;/p&gt;
&lt;p&gt;Javascript typically uses a continuation-style to process events. For example, we call asynchronous functions, for example to request data from CouchDb, and pass them a function to call when they return, eg to update the view with the data we receive. A simple example:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;
$.couch.db("addressbook").saveDoc(
  {type: "address", name: "Wilma", mobile: "555-003"},
  {success: function() { alert("Saved ok."); }}
);
&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This example saves a new document to the Couch database, and if successful, pops up an alert.&lt;/p&gt;
&lt;p&gt;Another example is jQuery, which calls functions when links or buttons are clicked. The following example will trigger an alert whenever an "a" element is clicked (ie a hyperlink):&lt;/p&gt;
&lt;p&gt;&lt;code&gt;
$("a").click(function() { alert("Click"); })
&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;jQuery uses selectors to control what elements of an HTML document will trigger functions. In the above example, the selector applied to all "a" elements. We can use "a#blah" to select all "a" elements with an id attribute of "blah", or "a.blah" to select all "a" elements with a class of blah. Selectors form a mini-language and the jQuery documentation gives more details.&lt;/p&gt;
&lt;p&gt;The first javascript we add is called when the base document has finished loading. It retrieves the JSON object of the phonenumbers view from CouchDb. When the JSON object is retrieved a continuation iterates over each row in the view, adding a div for each row containing the name, phonenumber and links to edit and delete it:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;
  $db = $.couch.db("addressbook");

  function refreshAddressbook() {
   $("div#addressbook").empty();
   $db.view("addressbook/phonenumbers", {
    success: function(data) {
     for (i in data.rows) {
      id = data.rows[i].id;
      name = data.rows[i].key;
      phonenumber = data.rows[i].value;
      html = '&amp;lt;div class="address"&amp;gt;' +
       '&amp;lt;span class="name"&amp;gt;' + name + '&amp;lt;/span&amp;gt; ' +
       '&amp;lt;span class="phonenumber"&amp;gt;' + phonenumber + '&amp;lt;/span&amp;gt; ' +
       '&lt;a href="#" class="edit"&gt;edit&lt;/a&gt; '+
       '&lt;a href="#" class="delete"&gt;delete&lt;/a&gt; '+
       '&amp;lt;/div&amp;gt;';
      $("div#addressbook").append(html);
     }
   }});
  }

  $(document).ready(function() { 
   refreshAddressbook();
  });
&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;A few things to note:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We have created a variable $db to access the CouchDb database. If we change the name of the database, this means we only have to change one place.&lt;/li&gt;
&lt;li&gt;The function called on success(ful retrieval of data from CouchDb) takes a parameter, data, which is the data returned fromt the view.&lt;/li&gt;
&lt;li&gt;We call the function from a continuation passed to $(document).ready(). This ensures that we won't request data until the HTML document is fully loaded.&lt;/li&gt;
&lt;li&gt;The links have an id, which is the id of the document representing the address book entry.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If we push to the server now, using&lt;/p&gt;
&lt;p&gt;couchapp push addressbook &lt;a href="http://127.0.0.1:5984/addressbook"&gt;http://127.0.0.1:5984/addressbook&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;and refresh in the browser, we should see the page load and then populate with phone numbers from the database. The add button and the edit and delete links will be inactive, but at least the R part of our CRUD app works.&lt;/p&gt;
&lt;p&gt;The next thing to focus on is deleting entries. A nice way for this to work is for the delete link, when clicked, to pop up further links to confirm or cancel deletion. We can use jQuery to insert these links in the div for the address book entry when the delete links are created.&lt;/p&gt;
&lt;p&gt;But this poses a problem - jQuery binds functions to the DOM elements that exist at the time. The links we are proposing adding do not exist when the $(document).ready continuation is called, so we cannot bind functions to them until they are created. Fortunately, there is a trick we can use. Events such as clicks propogate up the DOM tree if they are not processed - so a click will first be processed by the a element, if a handler exists, else it will be processed by the containing div, for example, if a handler exists, all the way up to the document itself. The continuation takes a parameter, which can be used to determine the exact element that was clicked.&lt;/p&gt;
&lt;p&gt;In our example, we can bind a function to the click event of div#addressbook, and then check whether the click came from an edit link, a delete link, or the confirm or delete links we will create. Add the following to the $(document).ready continuation:&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;&lt;code&gt;
$("div#addressbook").click(function(event) {
  var $tgt = $(event.target);
  if ($tgt.is('a')) {
     id = $tgt.attr("id");
     if ($tgt.hasClass("edit")) {
      // TODO: implement edit functionality   
     }
     if ($tgt.hasClass("delete")) {
      html = '&amp;lt;span class="deleteconfirm"&amp;gt;Sure? &lt;a href="#" class="dodelete"&gt;Yes&lt;/a&gt; &lt;a href="#" class="canceldelete"&gt;No&lt;/a&gt;&amp;lt;/span&amp;gt;';
      $tgt.parent().append(html);
     }
     if ($tgt.hasClass("dodelete")) {
      $db.openDoc(id, { success: function(doc) {
       $db.removeDoc(doc, { success: function() {
        $tgt.parents("div.address").remove();     
       }})
      }});      
     }
     if ($tgt.hasClass("canceldelete")) {
      $tgt.parents("span.deleteconfirm").remove();
     }
    }
   });
&lt;/code&gt; &lt;/p&gt;
&lt;p&gt;This code runs when any element in the addressbook div is clicked. It gets the clicked element, the id of that target element (which we set above to be the relevant CouchDb document's id), and then runs different code depending on the class of the clicked element. If the link with class "delete" is clicked, we append two new links - "Yes" with class "dodelete", and "No" with class "canceldelete" - within a span with class deleteconfirm. Then, if a link with class "canceldelete" is clicked, we remove the relevent "confirmdelete" span from the DOM to delete the confirm message. On the other hand, if a link with class "dodelete" is clicked, we call $db.openDoc to retrieve the document to delete from CouchDb, and pass it, using a success continuation to $db.removeDoc. We need to retrieve the document prior to deletion in CouchDb, to avoid deleting from an older version than the most current in the database. If this is successful, we remove the parent address div from the DOM, to match the database. Take a deep breath, and read that again.&lt;/p&gt;
&lt;p&gt;If you push this design document to CouchDb, you should be able to delete entries from the address book. However, you will have to use the CouchDb built-in interface to re-add them at this point.&lt;/p&gt;
&lt;p&gt;We adopt a similar approach for editing or creating new entries - clicking the button or link exposes a form to enter new details. CouchDb allows us to save a document with an id to indicate an update, or without an id to indicate that one should be generated, and a new document created. Consequently, we can use the same form for creating and editing if we are careful.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Add the following function between the refreshAddressbook function and the $(document).ready&lt;/p&gt;
&lt;p&gt;&lt;code&gt;
function addUpdateForm(target, existingDoc) {
  html = '&amp;lt;form name="update" id="update" action=""&amp;gt;&amp;lt;table&amp;gt;' +
    '&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;Name&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Number&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;' +
    '&amp;lt;tr&amp;gt;' +
      '&amp;lt;td&amp;gt;&amp;lt;input type="text" name="name" id="name" value="' +
&amp;lt;span style="white-space: pre;"&amp;gt; &amp;lt;/span&amp;gt;    (existingDoc ? existingDoc.name : "") + '"/&amp;gt;&amp;lt;/td&amp;gt;' +
      '&amp;lt;td&amp;gt;&amp;lt;input type="text" name="mobile" id="mobile"/ value="' + 
&amp;lt;span style="white-space: pre;"&amp;gt; &amp;lt;/span&amp;gt;    (existingDoc ? existingDoc.mobile : "") + '"&amp;gt;&amp;lt;/td&amp;gt;' + 
      '&amp;lt;td&amp;gt;&amp;lt;input type="submit" name="submit" class="update" value="' + 
&amp;lt;span style="white-space: pre;"&amp;gt; &amp;lt;/span&amp;gt;    (existingDoc?"Update":"Add") + '"/&amp;gt;&amp;lt;/td&amp;gt;' + 
      '&amp;lt;td&amp;gt;&amp;lt;input type="submit" name="cancel" class="cancel" value="Cancel"/&amp;gt;&amp;lt;/td&amp;gt;' + 
    '&amp;lt;/tr&amp;gt;' +
  '&amp;lt;/table&amp;gt;&amp;lt;/form&amp;gt;';
  target.append(html);
  target.children("form#update").data("existingDoc", existingDoc);
}
&lt;/code&gt; &lt;/p&gt;
&lt;p&gt;Apologies for the inelegant table. I would love to hear a better way for laying out forms. In the meantime, this does the job. And the job is that it appends a form to the target element. If existingDoc is provided, its name and mobile values are used to populate the form, else blanks are used. Further, the existing document is attached to the form, so it can be updated with new values provided by the user to save data later.&lt;/p&gt;
&lt;p&gt;To display the form when an edit link is clicked, add the following in place of the edit TODO above:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;
     if ($tgt.hasClass("edit")) {
      $("button#add").show();
      $("form#update").remove();
      $db.openDoc(id, { success: function(doc) {
        addUpdateForm($tgt.parent(), doc);
      }});      
    }
&lt;/code&gt;&lt;/p&gt;
&lt;p&gt; And to display the form when the add button is clicked, add a continuation to the bottom of the $(document).ready continuation:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;
   $("button#add").click(function(event) {   
    $("form#update").remove();
    $("button#add").hide();
    addUpdateForm($("div#add"));
   }); 
&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Note that we hide the add button when it is clicked, and show it otherwise. We also remove any existing forms, so only one form shows at any time.&lt;/p&gt;
&lt;p&gt;Finally, we need to process the events when the update(/add) button is hit, or the cancel button. We could adopt the same approach as above, of binding to an element up the hierarchy, but I've chosen to demonstrate a different approach. The .live method can be used to bind to a selector, and to any future elements that selector applies to. That is, as new DOM elements are created, the continuation will apply to them also. Here is an example to bind the click events, of input elements of class "cancel", which hides the form and shows the add button when the cancel button is pressed:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;
    $("input.cancel").live('click', function(event) {
    $("button#add").show();
    $("form#update").remove();
    return false;
   });  
&lt;/code&gt;&lt;/p&gt;
&lt;p&gt; You should add this to the end of the $(document).ready continuation.&lt;/p&gt;
&lt;p&gt;Finally, we need to process the update/add event. The key here is to pick up the existing CouchDb document, if it exists, from the form DOM element we attached it to. This ensures we are updating a CouchDb document with the appropriate id and revision. If there is no existing document, we can populate an empty JSON object, and CouchDb will save it as a new document with a uniquely generated id. Here is the continuation and binding to add to $(document).ready:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;
   $("input.update").live('click', function(event) {
    var $tgt = $(event.target);
    var $form = $tgt.parents("form#update");
    var $doc = $form.data('existingDoc') || {};
    $doc.type = "address";
    $doc.name = $form.find("input#name").val();
    $doc.mobile = $form.find("input#mobile").val();
    $db.saveDoc(
     $doc,
     {success: function() {
      $("button#add").show();
      $("form#update").remove();
      refreshAddressbook();
    }});
    return false;
   });
&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Note that we remove the form and show the button when the document has been saved.&lt;/p&gt;
&lt;p&gt;Ok, that's it. Push this to CouchDb, and reload the page. You should find that you have a perfectly working, albeit minimal, CRUD webapp.&lt;/p&gt;
&lt;p&gt;There are a few other things that you would want to do in production code, which I have left out here for clarity and brevity. Verification functions should be added to the design document, to avoid badly formed data being passed to CouchDb. Errors should be handled, as well as successes. Also, you might want slightly more from an address book webapp. Nonetheless, I hope this is a useful example of using CouchDb and jQuery to make an AJAX webapp.&lt;/p&gt;
	
&lt;/p&gt;

&lt;p&gt;&lt;a href="http://blog.edparcell.com/using-jquery-and-couchdb-to-build-a-simple-we"&gt;Permalink&lt;/a&gt; 

	| &lt;a href="http://blog.edparcell.com/using-jquery-and-couchdb-to-build-a-simple-we#comment"&gt;Leave a comment&amp;nbsp;&amp;nbsp;&amp;raquo;&lt;/a&gt;

&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/ParcellsPosts/~4/0kqRJ9DV5Rk" height="1" width="1"/&gt;</description>
      <posterous:author>
        <posterous:userImage>http://posterous.com/images/profile/missing-user-75.png</posterous:userImage>
        <posterous:profileUrl>http://posterous.com/users/5erKH0kcdaeZ</posterous:profileUrl>
        <posterous:firstName>Ed</posterous:firstName>
        <posterous:lastName>Parcell</posterous:lastName>
        <posterous:nickName>edparcell</posterous:nickName>
        <posterous:displayName>Ed Parcell</posterous:displayName>
      </posterous:author>
    <feedburner:origLink>http://blog.edparcell.com/using-jquery-and-couchdb-to-build-a-simple-we</feedburner:origLink></item>
  </channel>
</rss>

