<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><atom:link rel="hub" href="http://tumblr.superfeedr.com/" xmlns:atom="http://www.w3.org/2005/Atom"/><description>Wasting time and examining more pointless web 2.0 technology.</description><title>crad on tumblr</title><generator>Tumblr (3.0; @crad)</generator><link>http://crad.tumblr.com/</link><item><title>My Nexus One Battery Adventure</title><description>&lt;p&gt;As I&amp;#8217;ve tweeted about, probably all too much, I&amp;#8217;ve been having issues with my new Nexus One.  I love the phone and it has yet to leave me wanting, if it weren&amp;#8217;t for one thing, the battery.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve been having issues where the phone&amp;#8217;s battery is well charged and then without notice, the charge drops to zero.  A few days go it went one worse, after falling off the power cliff, it would not charge.  It just stuck at 2%.  I went to sleep figuring I always had my iPhone to fall back on in the morning.  When I woke up it was at 100% charged.&lt;/p&gt;
&lt;p&gt;Just prior to this happening I decided to get an application to see if I can find out any information about what&amp;#8217;s going on.  After a bit of poking about in the Android Marketplace, I found the excellent Battery Graph app.  After letting it run around for a few days I exported the data and made this graph in Excel:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://media.tumblr.com/tumblr_kx8qgp0VBR1qzn6yk.png"/&gt;&lt;/p&gt;
&lt;p&gt;You can see the event I described above on the left side of the graph, showing the cliff happening sometime around 8&amp;#160;pm on January 31st and sometime around 5:30 am where it decided to go from 2% to 100% charge.  You can then see a full days normal use for yesterday, without incident.  The graph looks a little odd because I was sampling at 1 minute and then slowed the sample rate to 5 minutes.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve been trying all sorts of different things with the phone to see if it was related to changing cell modes between 2G and 3G, some sort of background application running, or what not, with no success.  I went as far as to call HTC support about this last week.&lt;/p&gt;
&lt;p&gt;I had only contacted HTC after I opened a ticket with Google.  The Google support email, which came in two or three days after I sent in the request, told me to contact HTC and get a warranty replacement.  I went to the HTC site to begin the process and noticed that for HTC warranty replacement of the Nexus One, they send you a new phone without a battery.  You are to use the battery that came with the original phone.&lt;/p&gt;
&lt;p&gt;HTC support had acted as if they had never heard of such an issue before and told me they needed to bump it up to the next support level and that someone from HTC would contact me within a few days.  It&amp;#8217;s now been a few days, and as you can see from the graph above, my Nexus One had another battery event this afternoon.  Fortunately it decided after 10-15 minutes of charging that it was 100% charged, so I&amp;#8217;m guessing at this point the problem is either in the battery charge sensor itself or in the Android firmware.  Here&amp;#8217;s hoping the next revision of the firmware, just announced, will fix my issue.&lt;/p&gt;</description><link>http://crad.tumblr.com/post/367812183</link><guid>http://crad.tumblr.com/post/367812183</guid><pubDate>Tue, 02 Feb 2010 20:07:00 -0500</pubDate><category>android</category><category>nexus one</category><category>battery</category></item><item><title>Web Application Development with Tornado</title><description>&lt;p&gt;I recently finished a rewrite of &lt;a target="_blank" href="http://privatepaste.com"&gt;privatepaste.com&lt;/a&gt; in python using &lt;a title="Tornado Website" target="_blank" href="http://tornadoweb.org"&gt;Tornado&lt;/a&gt; as the web framework. There are multiple reasons why I decided to use Tornado instead of something like Django, cherry.py or web.py, all of which I’ve previously used.  One of the main reasons for my choice to switch to Tornado was due of its feature-rich yet light-weight nature. In addition, the benchmarks and asynchronous http server were intriguing.&lt;/p&gt;
&lt;p&gt;Tornado is distributed as a set of loosely coupled python modules. It’s up to the developer to decide which aspects of Tornado you’d like to use. It’s also up to the developer to write the core application which is responsible for running your web application as a daemon. To create a base level application, all that is required is using tornado.httpserver and tornado.web. If you’ve ever programmed with using web.py, many of the conventions should be similar to you.&lt;/p&gt;
&lt;p&gt;The base principle in writing an application is to map a URI to a class. In that class you provide functions for the HTTP methods you intend to support. Because Tornado at its core is a HTTP server, you must implement every HTTP method you intend on supporting for a URI. For example, if you are writing a CMS, you would not only implement the GET function, but you’d want to implement a HEAD function for returning browsers with cache information for your content.&lt;/p&gt;
&lt;p&gt;Being loosely-coupled, it is up to the developer to implement everything from session handling and authentication to localization and the data layer.  Some may consider this an issue, but not to worry, Tornado includes modules to help.  There are &lt;a title="Third Party Authentication" target="_blank" href="http://www.tornadoweb.org/documentation#third-party-authentication"&gt;authentication mix-ins&lt;/a&gt; for Google, Twitter, Facebook and Friendfeed.  To achieve authentication with Tornado, you would extend the tornado.web.RequestHandler class and extend the get_current_user() to handle the authentication functionality.&lt;/p&gt;
&lt;p&gt;&lt;a title="Localization Documentation" target="_blank" href="http://www.tornadoweb.org/documentation#localization"&gt;Localization&lt;/a&gt; is handled in a similar fashion.  While there is some magic under the covers, it generally leaves localization implementation up to the developer.  By extending get_user_locale(), the developer returns a locale object which has been initialized with the appropriate language.  As with other modules, the meat of the documentation is in the locale and web classes.&lt;/p&gt;
&lt;p&gt;&lt;a title="Tornado Documentation" target="_blank" href="http://www.tornadoweb.org/documentation"&gt;Documentation&lt;/a&gt; is one of the key drawbacks of using Tornado.  If you can not dive in to other peoples code to find what you need, you’re going to have a difficult time with Tornado.  Much of the initial time that I spent with Tornado was in the Tornado code itself, figuring out how to access different parts of data within the http request, templating system and the application class.  The documentation provided is deceivingly simple, and indeed, for a Hello World application the documentation is sufficient and accurate.  It’s when you’re knee deep in code that you’ll find yourself having to go beyond the documentation to get what you need.&lt;/p&gt;
&lt;p&gt;The&lt;a title="Template documentation" target="_blank" href="http://www.tornadoweb.org/documentation#templates"&gt; template engine&lt;/a&gt; is full-featured and has yet to leave me wanting.  While there has been some back and forth on the mailing lists about the speed of the template engine, it has proven important to turn off debug mode when comparing template engines.  I have found the template engine to be very fast, even when extending other templates and including modules.&lt;/p&gt;
&lt;p&gt;The biggest hurdle, which isn’t uncommon in any web application, is right-sizing processes to serve your application.  Because your tornado app runs as a stand-alone HTTP server that is directly coupled to your application classes, you need to run multiple processes to serve multiple requests.  Like FriendFeed, I use Tornado behind a web server using a reverse proxy module.  However, instead of Nginx, I am using Cherokee.  I use Python’s multiprocessing module to spawn multiple HTTPServer instances with my application.  Each instance has its own port number and the reverse proxy server uses these backends in a round-robin pool to provision requests.&lt;/p&gt;
&lt;p&gt;When coming from a CGI based backend, one has to think a bit more about how you size your backends.  Because your web server front-end can’t spawn new backends on demand, you’ll need to make sure that you have enough backends to provision your maximum number of simultaneous requests.  There are changes in the master branch of Tornado on github to make Tornado fork on its own, spawning a thread per CPU core, but this will not change the scaling concern, as the same principles apply.&lt;/p&gt;
&lt;p&gt;&lt;a title="Documentation about Asynchronous Request Handling" target="_blank" href="http://www.tornadoweb.org/documentation#non-blocking-asynchronous-requests"&gt;Asynchronous request handling&lt;/a&gt; is one of the more often touted features of Tornado.  It’s important to understand exactly how async requests fit into your application development model.  Because each Tornado back end is single threaded it is important to think about the blocking areas of your application, such as database calls, to determine if you can benefit from the async functionality.  To truly benefit from the async server, you’ll need to use a fully async model for any type of operation that would normally be blocking.&lt;/p&gt;
&lt;p&gt;An example where the async functionality shines is the &lt;a title="auth module with mixins" target="_blank" href="http://github.com/facebook/tornado/blob/master/tornado/auth.py"&gt;Authentication Mix-in’s&lt;/a&gt; for Google, Facebook, FriendFeed and Twitter.   When you use these mix-ins, you specify a callback function to call once the &lt;a title="HTTPClient Code" target="_blank" href="http://github.com/facebook/tornado/blob/master/tornado/httpclient.py#L32"&gt;HTTPClient&lt;/a&gt; class has returned a result from your call.&lt;/p&gt;
&lt;p&gt;Because I use &lt;a title="Psycopg2 Git Repository" target="_blank" href="https://dndg.it/cgi-bin/gitweb.cgi?p=public/psycopg2.git"&gt;psycopg2&lt;/a&gt;, a blocking PostgreSQL driver, for my database access, I generally do not use the async functionality.  For me this is not an issue, as in full featured applications I still see performance as fast as 1ms from start to finish of request.  Of course your own application has as much, if not more impact on performance than Tornado itself.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re just getting started with Tornado, be sure to check out the &lt;a title="Tornado Demos" target="_blank" href="http://github.com/facebook/tornado/tree/master/demos/"&gt;demo code&lt;/a&gt;.  If you&amp;#8217;re looking for a little more structure in getting started, check out &lt;a title="Tinman" target="_blank" href="http://github.com/gmr/Tinman"&gt;Tinman&lt;/a&gt;, a meta-framework on top of Tornado.&lt;/p&gt;
&lt;p&gt;Edit: Changed to reflect a misstatement about the new forking changes coming up for 0.3.&lt;/p&gt;</description><link>http://crad.tumblr.com/post/351142148</link><guid>http://crad.tumblr.com/post/351142148</guid><pubDate>Sun, 24 Jan 2010 14:17:00 -0500</pubDate><category>tornado</category><category>python</category><category>web-development</category></item><item><title>On Net Neutrality</title><description>&lt;p&gt;The Internet as you know it is about to change.  If you live in the United States and pay for Broadband Internet access, there is a good chance your Internet Service Provider is looking to discriminate against you and what you do on the Internet.  Using network management tools and high-tech equipment they watch what you do on the Internet with the intention to block activities and in some cases, selectively slow down things you are doing.  In addition, if legislation in the works is passed, you could be charged more based upon what technology you are using or even what content you&amp;#8217;re looking at.&lt;/p&gt;
&lt;p&gt;&lt;img height="310" width="400" src="http://gavinroy.com/Graphics/net_neutrality.jpg" align="right"/&gt;When I first started accessing the Internet back in the first half of the 90’s, I had my trusty modem and an account at Cerfnet.  At the time, the web was barely in its infancy.  It was not the Internet of Google or Yahoo.  In fact, the operating system I used at the time didn’t even come with a commercial TCP/IP stack.  For the non-geek, that means you couldn’t just connect to the Internet like you could now.  I had a commercial “winsock” library that had to be installed before the browser of the time, NCSA Mosiac would run.&lt;/p&gt;
&lt;p&gt;While the web was itself a revolutionary concept, it was not the most revolutionary thing about the Internet.  For the first time, I was not dialing up a private computer with my modem, I was connecting to a large scale network of interconnected computers.  The possibilities were endless.  With these interconnected computers you could connect to a “finger server” to see what your friends were up to, play text-based role-playing games called MUD’s, send and receive messages via email, log in to multiple remote systems and much, much more.  What was revolutionary about this was unlike the previous paradigm of using a modem to connect to a Bulletin Board System or other single remote system, one was able to do all of these things at one time, independently of each other, to any other systems, all on the same Internet connection. I would imagine everyone takes this for granted these days.&lt;/p&gt;
&lt;p&gt;When cable modems started to show up in the mid-nineties, the Internet was about to change.  Soon the average consumer would connect to the Internet with speeds and capacity that was once reserved for Internet companies and universities.  T1 Internet connections reigned supreme for non-university level corporate connectivity and they were expensive.  I was fortunate enough to be in a test rollout for the cable provider in my area who was testing the new Broadband system which boasted T1 level speed.  Broadband connectivity would ultimately change how people connect to the Internet and what we would do on it.&lt;/p&gt;
&lt;p&gt;There was one problem with the the way Broadband was being rolled out to consumers: math.  These companies were rolling out cable modems with speeds that when used in aggregate, exceeded the capacity of the cable company’s connection to the Internet.  To use an analogy, they were promising everyone a gallon of water to drink, when they themselves only had a gallon of water.  For this to work they bet that not everyone would drink the full gallon, or use all of the connectivity.&lt;/p&gt;
&lt;p&gt;This is a model that has proven itself to work well in the telecommunications industry.  From corporate telephone systems, all the way to national telecommunications infrastructure, systems are over-subscribed.  If everyone decided to use the phone at the same time, the system falls apart.  This is one of the main reasons why it’s difficult to make calls during a disaster.&lt;/p&gt;
&lt;p&gt;The Internet Service Providers took a known, working model and then something really bad happened.  People started using that connectivity.  The Internet exploded, websites became bigger. People started streaming video and sharing files.  The whole scaffolding that their business model was based upon, selling connectivity that in aggregate exceeds their own capacity, became an issue.  To combat the issue, they had to buy more and more expensive connectivity.&lt;/p&gt;
&lt;p&gt;The Internet continued to grow.  Broadband Internet connectivity started to blur the lines of commercial Internet connectivity with consumer connectivity.  Commercial companies purchased connectivity at a premium, not only because they needed more connectivity to service consumers but because there was an expectation that they would use the bandwidth they purchased.  Consumers were never expected to use the full capacity of what they were purchasing.&lt;/p&gt;
&lt;p&gt;Then file-sharing became a phenomenon that not only concerned the property rights owners but the ISP’s as well.  Consumers started leaving computers on 24x7, much in the way a commercial server would  be available.  These computers were sending files to other consumers at a rate and duration that causes the over-subscription model to falter.  It’s important to note that while I’ve mentioned cable companies, big-telco faced these same issues as well.&lt;/p&gt;
&lt;p&gt;While all this continued to escalate, technology improved, the Internet became even more bandwidth intensive and consumer connection speeds have continued to increase.  My personal Internet connection has 3,555% more capacity than it had 15 years ago.  In the commercial space, I pay roughly the the same for 410% more commercial capacity than I did 10 years ago.  Yet with all of these technological advances, in essence the Internet Service Providers still have the same problem.&lt;/p&gt;
&lt;p&gt;Here comes the nefarious part. How are they trying to solve this problem?  By providing consumers with selective access to the Internet, discriminating against applications and services that directly contribute to the over-subscription of their bandwidth. Where at one time, a consumer connection to the Internet could be compared to pipelines of various capacities, ISP’s are now looking to selectively control what their customers have access to and how fast they can access it.&lt;/p&gt;
&lt;p&gt;By watching what you do and how you do it on the Internet, ISP’s can selectively throttle or limit what you do.  What this means is that while you may be able to download your email at 20Mb/s (a very fast rate), you may be limited to download YouTube videos at 2Mb/s.&lt;/p&gt;
&lt;p&gt;In another twist on this subject, ISP’s have proposed charging companies like YouTube to not be rate-limited when going to your home connection.  This means that not only are you paying to have 20Mb/s of YouTube in this example, but your ISP is going to charge YouTube to be able to send you data at 20Mb/s even though both you and YouTube already pay to have that much capacity to the Internet. They don’t intend on stopping there. These concepts are so contrarian to what had established the Internet as such a large part of our society and lives.&lt;/p&gt;
&lt;p&gt;The freedom to share information is the conceptual cornerstone upon which the Internet was built.  We are at the precipice of shift in those freedoms as the consumer facing foundation of the Internet looks to censorship and discrimination in an effort to solve their engineering issues.&lt;/p&gt;
&lt;p&gt;There is an urgency with this issue as there is an ongoing national debate which is shaping up to be very partisan.  Recently John McCain has introduced legislation to block the FCC from mandating that ISP&amp;#8217;s do not selectively discriminate against specific applications, protocols or activity on the Internet.  In addition, John McCain’s bill would block FCC rules that would require ISP’s to provide transparency to consumers with regard to network management and congestion management techniques.  Senator McCain incorrectly sees Net-Neutrality as a government takeover of the Internet industry as opposed to the government ensuring non-discriminatory access and transparency to the Internet for all consumers and companies.&lt;/p&gt;
&lt;p&gt;While I am generally for less government regulation in every aspect of our lives, the Internet is international infrastructure that supports multiple industries and has a direct impact on the global economy.  Much like the Interstate Highway System, the phone system and Postal Service, the Internet is much more than the corporations who wish to change the landscape of what users can access and how they can access it.&lt;/p&gt;
&lt;p&gt;I highly recommend you find out more about the subject and let your politicians know how you feel about it.  The decisions being made today at the Federal level will impact the Internet industry and how we use the Internet for many, many years to come.&lt;/p&gt;</description><link>http://crad.tumblr.com/post/224037241</link><guid>http://crad.tumblr.com/post/224037241</guid><pubDate>Mon, 26 Oct 2009 14:50:00 -0400</pubDate></item><item><title>Running Playlist #1</title><description>&lt;p&gt;I&amp;#8217;ve been working on a good playlist to keep me going as I&amp;#8217;m running.  I&amp;#8217;m hoping the playlist can be a good motivational tool to keep running longer.  This playlist is 41 minutes which should work out just about right for my current goals:&lt;/p&gt;
&lt;ol&gt;&lt;li&gt;One Of These Days - Pink Floyd (Meddle) 5:58&lt;/li&gt;
&lt;li&gt;Ringfinger - Nine Inch Nails (Pretty Hate Machine) 5:41&lt;/li&gt;
&lt;li&gt;Stinkfist - Tool (&lt;i&gt;Æ&lt;/i&gt;nima) 5:11&lt;/li&gt;
&lt;li&gt;Du Hast - Rammstein (Muttertag) 2:05&lt;/li&gt;
&lt;li&gt;Waiting Room - Fugazi (13 Songs) 2:55&lt;/li&gt;
&lt;li&gt;Parabola - Tool (Lateralus) 6:04&lt;/li&gt;
&lt;li&gt;Dead Souls - Nine Inch Nails (The Crow Soundtrack) 4:54&lt;/li&gt;
&lt;li&gt;My Apocalypse - Metallica (Death Magnetic) 5:01&lt;/li&gt;
&lt;li&gt;Mutter - Rammstein (Muttertag) 1:54&lt;/li&gt;
&lt;li&gt;Walk Together, Rock Together (7 Seconds) 2:05&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;Now I know it&amp;#8217;s a bit of a genre mix-up, but I think it should work good.  What would you add or remove?&lt;/p&gt;</description><link>http://crad.tumblr.com/post/213293540</link><guid>http://crad.tumblr.com/post/213293540</guid><pubDate>Wed, 14 Oct 2009 20:35:12 -0400</pubDate></item><item><title>The Attention Deficit Disorder Guide to RabbitMQ</title><description>&lt;p&gt;RabbitMQ has been one of my interests of late, as I’ve identified it as part of our technology path at work. There are other very good resources that dive pretty deep in RabbitMQ and how to use it.  The goal of this guide is to help you get on your feet quickly and easily.  It assumes a couple of things:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;You already know about message queues and have some experience or knowledge on the subject.&lt;/li&gt;
&lt;li&gt;You know what &lt;a title="AMQP" target="_blank" href="http://www.google.com/url?q=http://www.amqp.org/&amp;amp;ei=0lC9SsDUHYPuswODzLgf&amp;amp;sa=X&amp;amp;oi=spellmeleon_result&amp;amp;resnum=1&amp;amp;ct=result&amp;amp;usg=AFQjCNHhaiGqE-z1vwGB_Ml_3k2p-PXjfg"&gt;AMQP&lt;/a&gt; &lt;a title="AMQP @ Wikipedia" target="_blank" href="http://en.wikipedia.org/wiki/Advanced_Message_Queuing_Protocol"&gt;is&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;You are already interested in RabbitMQ enough to try it out.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;If you’re good on those things, let’s get started&amp;#8230;&lt;/p&gt;
&lt;p&gt;RabbitMQ is written in erlang.  As such, you should have already &lt;a title="erlang Website" target="_blank" href="http://www.erlang.org/"&gt;downloaded&lt;/a&gt; and installed erlang as a first step.&lt;/p&gt;
&lt;p&gt;&lt;a title="RabbitMQ Server Download" target="_blank" href="http://www.rabbitmq.com/server.html"&gt;Download RabbitMQ&lt;/a&gt; and install it, which is pretty easy.  I like to setup RabbitMQ in an /opt/rabbitmq directory.  To do that, I set some environment variables before compiling (bash assumed):&lt;/p&gt;
&lt;blockquote&gt;export TARGET_DIR=/opt/rabbitmq&lt;br/&gt;export SBIN_DIR=/opt/rabbitmq/sbin&lt;br/&gt;export MAN_DIR=/opt/rabbitmq/man&lt;/blockquote&gt;
&lt;p&gt;Then I compile and install with “make install.”  Because I like to run as my own user or a service user, I’ll chown -R myuser /opt/rabbitmq as appropriate.&lt;/p&gt;
&lt;p&gt;There are a few other things we need to do including make the log directory and the directory RabbitMQ will use to store its data:&lt;/p&gt;
&lt;blockquote&gt;mkdir /var/log/rabbitmq&lt;br/&gt;chown myuser /var/log/rabbitmq &lt;br/&gt;mkdir /var/lib/rabbitmq&lt;br/&gt;chown myuser /var/lib/rabbitmq&lt;/blockquote&gt;
&lt;p&gt;Now as &amp;#8220;myuser&amp;#8221; we can &amp;#8220;cd /opt/rabbitmq/sbin&amp;#8221; and run &amp;#8220;./rabbitmq-server&amp;#8221; and what you should see is:&lt;/p&gt;
&lt;blockquote&gt;RabbitMQ 1.6.0 (AMQP 8-0)&lt;br/&gt;Copyright (C) 2007-2009 LShift Ltd., Cohesive Financial Technologies LLC., and Rabbit Technologies Ltd.&lt;br/&gt;Licensed under the MPL.  See &lt;a href="http://www.rabbitmq.com/"&gt;http://www.rabbitmq.com/&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;node       &amp;#160;: rabbit@binti&lt;br/&gt;log        &amp;#160;: /var/log/rabbitmq/rabbit.log&lt;br/&gt;sasl log   &amp;#160;: /var/log/rabbitmq/rabbit-sasl.log&lt;br/&gt;database dir: /var/lib/rabbitmq/mnesia/rabbit&lt;br/&gt;&lt;br/&gt;starting database             &amp;#8230;done&lt;br/&gt;starting core processes       &amp;#8230;done&lt;br/&gt;starting recovery             &amp;#8230;done&lt;br/&gt;starting persister            &amp;#8230;done&lt;br/&gt;starting guid generator       &amp;#8230;done&lt;br/&gt;starting builtin applications &amp;#8230;done&lt;br/&gt;starting TCP listeners        &amp;#8230;done&lt;/blockquote&gt;
&lt;p&gt;If you have the hang of starting RabbitMQ and now want to run it in the background, instead do: &amp;#8220;./rabbitmq-server -detached&amp;#8221;.&lt;/p&gt;
&lt;p&gt;Once we’ve gotten this far, we’ve got our broker up and running and now we’ll need some way to talk to it.  For the purposes of this article, I’m going to talk about amqplib and Python. There are AMQP libraries for just about every relevant language at this point.  RabbitMQ 1.6.0 implements the AMQP 0.8 standard.  The easiest way to install amqplib is a simple “easy_install amqplib”.&lt;/p&gt;
&lt;p&gt;But before we dive into code, there are a few key concepts we need to talk about:&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Queues&lt;/b&gt;: You should get these already, one puts a message in a queue and a consumer app receives it somewhere else.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Exchanges&lt;/b&gt;: These are a little more tricky than queues.  I like to think of them as namespaces.  One of the keen things about RabbitMQ exchanges is that different exchanges will get a different erlang process which should help make better use your available hardware resources.  There are three types of exchanges that we need to talk about:&lt;/p&gt;
&lt;blockquote&gt;&lt;b&gt;&lt;i&gt;Direct&lt;/i&gt;&lt;/b&gt;: a direct exchange means when you put a message in, it goes to one consumer and he’s all that will get that message routed through the exchange.&lt;br/&gt;&lt;b&gt;&lt;i&gt;&lt;br/&gt;Fanout&lt;/i&gt;&lt;/b&gt;: a fanout exchange sends your message to every consumer that listening to a particular exchange / queue combination.&lt;br/&gt;&lt;b&gt;&lt;br/&gt;&lt;i&gt;Topic Exchange&lt;/i&gt;&lt;/b&gt;: this type of exchange allows you to do neat things like listen to the same queue across exchanges on one consumer, multiple queues in one namespace in a consumer and other wildcard type trickery.&lt;/blockquote&gt;
&lt;p&gt;&lt;b&gt;Bindings&lt;/b&gt;: In RabbitMQ you bind your exchanges and queues together in unique combinations which determine how messages are routed to what consumers.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Memory&lt;/b&gt;: As of RabbitMQ 1.6.0 all messages are kept in memory. If you have nothing consuming your messages and you send too many of them, you’ll run out of memory.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Monitoring&lt;/b&gt;: The main install has the app rabbitmq_ctl which you can use to inspect the various parts of RabbitMQ.  This isn’t very good for remote monitoring or visualization.  For that there’s a great project called &lt;a title="Alice" target="_blank" href="http://github.com/auser/alice"&gt;Alice&lt;/a&gt; which is also erlang based.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Speed&lt;/b&gt;: There are two ways to get messages from RabbitMQ: basic_get and basic_consume.&lt;/p&gt;
&lt;blockquote&gt;&lt;i&gt;&lt;b&gt;basic_get&lt;/b&gt;&lt;/i&gt; is where your app, on a message by message basis, asks RabbitMQ for a message.  This is the slower of the two methods and will not allow single consumer applications to scale to a very high transaction rate.  Note that RabbitMQ will not register these connections as a consumer and you will not see them in list_queues or in Alice as such.&lt;br/&gt;&lt;i&gt;&lt;b&gt;&lt;br/&gt;basic_consume&lt;/b&gt;&lt;/i&gt; is where your app registers itself with RabbitMQ as a consumer and RabbitMQ will send messages to you as fast as you’re able to consume them.&lt;/blockquote&gt;
&lt;p&gt;&lt;b&gt;Durability&lt;/b&gt;: If you want to have the definitions of your queues and exchanges hang around if you have to restart RabbitMQ you need to define them as durable.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Auto-Delete&lt;/b&gt;: If you want your queues and exchanges to exist even when there are no consumers waiting for messages on them, you need to turn auto-delete off.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Persistence&lt;/b&gt;: If you do not tell RabbitMQ that you want it to hang on to your messages if it reboots, it will not do so.  You must set the delivery mode of a message to “2” to tell it to persist it until it is consumed.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Auto-Ack&lt;/b&gt;: You can tell RabbitMQ to automatically acknowledge receipt of a message, or you can do it yourself.  This is a boolean setting that you use when you’re consuming messages via basic_get or basic_consume.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Queue and Exchange definitions&lt;/b&gt;: By default, queues and exchanges do not exist until you connect a consumer to them.  You can cheat and do this in your code that enqueues your messages.&lt;/p&gt;
&lt;p&gt;Now that we have that out of the way, here&amp;#8217;s some sample Consumer code:&lt;/p&gt;
&lt;blockquote&gt;
&lt;pre&gt;#!/bin/env python
""" Sample Consumer Code """

import amqplib.client_0_8 as amqp&lt;br/&gt;
# This is the function that basic_consume will send messages to                               
def process_message( message ):
    """ Callback function used by channel.basic_consume """
    print 'Received: %s' % message.body

# Rabbit Server to connect to
host = '127.0.0.1'
port = 5672

# Exchange and queue information
exchange_name = 'test'
exchange_type = 'direct'
queue_name = 'messages'
routing_key = 'test.messages'

# Let's set this up by default, we'll use it later
process_messages = True

# Connect to Rabbit
connection= amqp.Connection( host ='%s:%s' % ( host, port ),
                        userid = 'guest',
                        password = 'guest',
                        ssl = False,
                        virtual_host = '/' )

# Create a channel to talk to Rabbit on
channel = connection.channel()

# Create our exchange
channel.exchange_declare( exchange = exchange_name, 
                          type = exchange_type, 
                          durable = True,
                          auto_delete = False )
                                       
# Create our Queue
channel.queue_declare( queue = queue_name , 
                       durable = True,
                       exclusive = False, 
                       auto_delete = True )
            
# Bind to the Queue / Exchange
channel.queue_bind( queue = queue_name, 
                    exchange = exchange_name,
                    routing_key = routing_key )

# Let AMQP know to send us messages
consumer_tag = channel.basic_consume( queue = queue_name, 
                                      no_ack = True,
                                      callback = process_message )

# Loop while process_messages is True
while process_messages:

    # Wait for a message
    channel.wait()            
            
# Close the channel
channel.close()

# Close our connection
connection.close()
            
# This might go somewhere like a signal handler
def cancel_processing():
    """ Stop consuming messages from RabbitMQ """
    global channel, consumer_tag, process_messages
    
    # Do this so we exit our main loop
    process_message = False          
    
    # Tell the channel you dont want to consume anymore  
    channel.basic_cancel( consumer_tag )
&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;Note that a lot of what is in that example is commented code and whitespace for ease of reading, the actual implementation is pretty darn simple.&lt;/p&gt;
&lt;p&gt;Now that we have a consumer going let&amp;#8217;s send some messages in:&lt;/p&gt;
&lt;blockquote&gt;
&lt;pre&gt;#!/bin/env python
import amqplib.client_0_8 as amqp

# Connect
connection = amqp.Connection( host = "localhost:5672", 
                              userid = "guest", 
                              password = "guest", 
                              virtual_host = "/", 
                              insist = False )

# Create our channel
channel = connection.channel()

""" We've already declared our queue, exchange and binding in &lt;br/&gt;our consumer so just send the messages """&lt;/pre&gt;
&lt;pre&gt;for i in range(0, 10):
	message = amqp.Message("Test message %i!" % i)
	message.properties["delivery_mode"] = 2
	channel.basic_publish( message, 
	                       exchange = "test", 
	                       routing_key = "test.messages")   
&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;That&amp;#8217;s it!  If we did this right, you&amp;#8217;ve now setup RabbitMQ, sent some messages and consumed them on the other end of the pipe.&lt;/p&gt;
&lt;p&gt;If I&amp;#8217;ve kept you this long and you&amp;#8217;re still interested, but still have questions, I highly recommend &lt;a title="Rabbits and Warrens" target="_blank" href="http://blogs.digitar.com/jjww/2009/01/rabbits-and-warrens/"&gt;this article&lt;/a&gt; which goes much more in depth and has been a valuable guide for me.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re into both python and RabbitMQ, you might want to check out my consumer framework &amp;#8220;&lt;a title="Rejected" target="_blank" href="http://github.com/gmr/rejected.py"&gt;rejected.py&lt;/a&gt;,&amp;#8221; it&amp;#8217;s on GitHub.&lt;/p&gt;
&lt;p&gt;I hope you enjoyed the first of my A.D.D. Guides. I&amp;#8217;d be happy to answer any questions and would appreciate feedback so I may improve this and future articles to come.&lt;/p&gt;</description><link>http://crad.tumblr.com/post/196979154</link><guid>http://crad.tumblr.com/post/196979154</guid><pubDate>Fri, 25 Sep 2009 19:57:00 -0400</pubDate></item><item><title>1984</title><description>&lt;p&gt;I don&amp;#8217;t know exactly how I got out of reading 1984 in school. Had I read it, I am sure it  would not have done much but reinforce my anti-establishment teen angst.&lt;/p&gt;
&lt;p&gt;I recently took the opportunity to read the book, finishing it last night. I am still trying to formulate my feelings about the book, but ultimately I think it was a very good book, moving in its brutality. I&amp;#8217;m not speaking about the physical brutality toward the protagonist, nor the very anti-climatic, yet bitterly disappointing ending, though I think both reinforced the cold and harsh atmosphere of the book. It&amp;#8217;s rare that I find a book strike such an emotional chord, even if they&amp;#8217;re about the not so distant distopian future.&lt;/p&gt;
&lt;p&gt;Perhaps it was the complete loneliness that Winston was content in, only to find love and companionship thrust upon him, then to be utterly betrayed by all that he trusted. The level of betrayal, as it was outlined in the book was devastatingly cruel.&lt;/p&gt;</description><link>http://crad.tumblr.com/post/185794392</link><guid>http://crad.tumblr.com/post/185794392</guid><pubDate>Fri, 11 Sep 2009 23:06:06 -0400</pubDate></item><item><title>What an amazing video, a must see!
Playing For Change | Song...</title><description>&lt;iframe src="http://player.vimeo.com/video/2539741" width="400" height="266" frameborder="0"&gt;&lt;/iframe&gt;&lt;br/&gt;&lt;br/&gt;&lt;p&gt;What an amazing video, a must see!&lt;/p&gt;
&lt;p&gt;Playing For Change | Song Around The World “Stand By Me” on Vimeo (via &lt;a href="http://vimeo.com/2539741#comment"&gt;Vimeo&lt;/a&gt;)&lt;/p&gt;</description><link>http://crad.tumblr.com/post/101476756</link><guid>http://crad.tumblr.com/post/101476756</guid><pubDate>Wed, 29 Apr 2009 11:02:51 -0400</pubDate></item><item><title>jQuery Tip: How to break out of .each()</title><description>&lt;p&gt;I’m working on a dynamic page using jQuery where I have an unordered list of 12 items, one of which will randomly have the class “selected.”  My goal was to find out the position in the list of the “selected” item.  I hunted around the various properties I could get from a jQuery selector and didn’t find what I was looking for so I ended up with the following solution as illustrated by the following HTML and JavaScript.&lt;/p&gt;
&lt;blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;"&gt;&amp;lt;ul id=&amp;#8221;mylist&amp;#8221;&amp;gt;&lt;br/&gt;&lt;blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;"&gt;&amp;lt;li&amp;gt;Item #1&amp;lt;/li&amp;gt;&lt;br/&gt;&amp;lt;li&amp;gt;Item #2&amp;lt;/li&amp;gt;&lt;br/&gt;&amp;lt;li class=&amp;#8221;selected&amp;#8221;&amp;gt;Item #3&amp;lt;/li&amp;gt;&lt;br/&gt; &amp;#8230;&lt;br/&gt;&amp;lt;li&amp;gt;Item #12&amp;lt;/li&amp;gt;&lt;br/&gt;&lt;/blockquote&gt;
&amp;lt;/ul&amp;gt;&lt;/blockquote&gt;
&lt;p&gt;Using the following JavaScript, I was able to determine the position of the li with the selected class:&lt;/p&gt;
&lt;blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;"&gt;// Default values&lt;br/&gt; var selected = 0;&lt;br/&gt; // Iterate through item in the list.  If we find the selected item, return false to break out of the loop&lt;br/&gt; $(&amp;#8216;ul#mylist li&amp;#8217;).each(function(index){&lt;br/&gt;&lt;blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;"&gt;if ( $(this).hasClass(&amp;#8216;selected&amp;#8217;) )&lt;br/&gt; {&lt;br/&gt;&lt;blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;"&gt;selected = index;&lt;br/&gt; return false;&lt;br/&gt;&lt;/blockquote&gt;
}&lt;br/&gt;&lt;/blockquote&gt;
});&lt;br/&gt; console.debug(&amp;#8216;Selected position is: &amp;#8217; + selected);&lt;/blockquote&gt;
&lt;p&gt;I had spent so much time looking for a function or selector to help me with this issue, I overlooked the obvious, I could keep a counter of my position in the .each() function and then break out from there.  But I was faced with a problem, I didn’t know how to break out of an each.  The context of it is fairly odd, from a procedural standpoint.  Thankfully, Rey Bango had the solution: returning false.&lt;/p&gt;
&lt;p&gt;As illustrated in the above code snippet, returning false from an .each() will act like a traditional loop break.  If you have any solutions for solving my original problem, I’d love to hear them.&lt;/p&gt;</description><link>http://crad.tumblr.com/post/85523431</link><guid>http://crad.tumblr.com/post/85523431</guid><pubDate>Wed, 11 Mar 2009 10:09:00 -0400</pubDate><category>jQuery</category></item><item><title>Dropped IE support for Instapaper</title><description>&lt;a href="http://www.marco.org/82950480"&gt;Dropped IE support for Instapaper&lt;/a&gt;: &lt;p&gt;A great blog post illustrating why IE is a pain to code for. Marco Arment mirrors my sentiment on the subject.&lt;/p&gt;</description><link>http://crad.tumblr.com/post/83021303</link><guid>http://crad.tumblr.com/post/83021303</guid><pubDate>Mon, 02 Mar 2009 22:44:19 -0500</pubDate></item><item><title>Found this picture of my old Commodore Vic-20 when cleaning out...</title><description>&lt;img src="http://24.media.tumblr.com/pRHTXKqkEjx7phovtKrsN17Mo1_500.jpg"/&gt;&lt;br/&gt;&lt;br/&gt;&lt;p&gt;Found this picture of my old Commodore Vic-20 when cleaning out my desk tonight.&lt;/p&gt;</description><link>http://crad.tumblr.com/post/78173129</link><guid>http://crad.tumblr.com/post/78173129</guid><pubDate>Fri, 13 Feb 2009 21:26:34 -0500</pubDate></item><item><title>Google Apps for Domains Utils</title><description>&lt;a href="http://github.com/gmr/google-apps-for-domains-utilities/tree/master"&gt;Google Apps for Domains Utils&lt;/a&gt;: &lt;p&gt;GitHub.com Repository for a suite of command line python scripts for maintaining my Google Apps for Domains account.  I figured other people might find these useful.&lt;/p&gt;</description><link>http://crad.tumblr.com/post/73327011</link><guid>http://crad.tumblr.com/post/73327011</guid><pubDate>Mon, 26 Jan 2009 17:17:03 -0500</pubDate></item><item><title>gdata Python Client Mappings</title><description>&lt;p&gt;I had a little bit of an issue today finding out that Google&amp;#8217;s gdata Python library changes attribute names for the UserEntity class to match with the PEP8 naming conventions.  Here&amp;#8217;s a quick rundown:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;userName becomes user_name&lt;/li&gt;
&lt;li&gt;changePasswordAtNextLogin becomes change_password&lt;/li&gt;
&lt;li&gt;ipWhitelisted becomes ip_whitelisted&lt;/li&gt;
&lt;li&gt;agreedToTerms becomes agreed_to_terms&lt;/li&gt;
&lt;li&gt;hashFunctionName becomes hash_function_name&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;Notice that changePasswordAtNextLogin is shortened to just change_password.  Frankly I&amp;#8217;m surprised by the lack of consistency by the part of the gdata Python authors, and the lack of documentation of such in the &lt;a href="http://code.google.com/apis/apps/gdata_provisioning_api_v2.0_reference_python.html"&gt;Google Apps Provisioning API Developer&amp;#8217;s Guide: Python&lt;/a&gt;.&lt;/p&gt;</description><link>http://crad.tumblr.com/post/73308257</link><guid>http://crad.tumblr.com/post/73308257</guid><pubDate>Mon, 26 Jan 2009 15:54:00 -0500</pubDate></item><item><title>YES WE CAN (Side with the Bush Administration)!</title><description>&lt;a href="http://blog.wired.com/27bstroke6/2009/01/obama-sides-wit.html"&gt;YES WE CAN (Side with the Bush Administration)!&lt;/a&gt;: &lt;p&gt;Obama Sides With Bush in Spy Case | Threat Level from Wired.com&lt;/p&gt;</description><link>http://crad.tumblr.com/post/72664914</link><guid>http://crad.tumblr.com/post/72664914</guid><pubDate>Fri, 23 Jan 2009 17:22:13 -0500</pubDate></item><item><title>Chicago Style Q&amp;A: One Space or Two?</title><description>&lt;a href="http://www.chicagomanualofstyle.org/CMS_FAQ/OneSpaceorTwo/OneSpaceorTwo03.html"&gt;Chicago Style Q&amp;A: One Space or Two?&lt;/a&gt;: &lt;p&gt;I’ve not thought too much about this, but it makes sense. Now to break the double-space habit after a period.&lt;/p&gt;</description><link>http://crad.tumblr.com/post/70335410</link><guid>http://crad.tumblr.com/post/70335410</guid><pubDate>Tue, 13 Jan 2009 22:14:19 -0500</pubDate></item><item><title>An amazing tilt-lens video</title><description>&lt;a href="http://keithloutit.com/2008/11/23/metal-skin/"&gt;An amazing tilt-lens video&lt;/a&gt;: &lt;p&gt;Keith Loutit’s amazing tilt-lens video at a monster truck rally.&lt;/p&gt;</description><link>http://crad.tumblr.com/post/68608902</link><guid>http://crad.tumblr.com/post/68608902</guid><pubDate>Mon, 05 Jan 2009 20:30:21 -0500</pubDate></item><item><title>You can’t make this stuff up!</title><description>&lt;img src="http://24.media.tumblr.com/pRHTXKqkEgxtipqqlnI7nFlco1_400.png"/&gt;&lt;br/&gt;&lt;br/&gt;&lt;p&gt;You can’t make this stuff up!&lt;/p&gt;</description><link>http://crad.tumblr.com/post/62314104</link><guid>http://crad.tumblr.com/post/62314104</guid><pubDate>Sun, 30 Nov 2008 17:38:03 -0500</pubDate></item><item><title>via i36.tinypic.com
I love you Dilbert.</title><description>&lt;img src="http://25.media.tumblr.com/pRHTXKqkEge2p2qz2kQ6c7A3o1_500.jpg"/&gt;&lt;br/&gt;&lt;br/&gt;&lt;p&gt;via &lt;a href="http://i36.tinypic.com/11jq5nm.jpg"&gt;i36.tinypic.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I love you Dilbert.&lt;/p&gt;</description><link>http://crad.tumblr.com/post/60041591</link><guid>http://crad.tumblr.com/post/60041591</guid><pubDate>Sun, 16 Nov 2008 21:59:32 -0500</pubDate></item><item><title>New Website</title><description>&lt;p&gt;I&amp;#8217;ve decided it&amp;#8217;s too much work to keep up my own instance of blogging software and such so I have changed my site to work completely based off the content I publish on various sites.  I use twitter fairly heavily, so I figured that it would be a good &amp;#8220;first view&amp;#8221; of what&amp;#8217;s going on with me.  For my photos, I&amp;#8217;ve decided I like Flickr over Picasaweb and Smugmug.  And for my blogging, tumblr is simple, has an RSS feed I can use to power my main site and gives me lots of functionality. &lt;/p&gt;
&lt;p&gt;Even though Tumblr provides a JSONP javascript app to embed tumblr into ones site, I decided to go around it because it did not format the content in a way that I liked.  I might play around with it again in the future, but for now I am proxying the RSS file from tumblr using a small python script.&lt;/p&gt;</description><link>http://crad.tumblr.com/post/56228290</link><guid>http://crad.tumblr.com/post/56228290</guid><pubDate>Fri, 24 Oct 2008 23:00:00 -0400</pubDate></item><item><title>More Filter</title><description>&lt;img src="http://24.media.tumblr.com/pRHTXKqkEcrn9f98j5DvFzjr_500.jpg"/&gt;&lt;br/&gt;&lt;br/&gt;&lt;p&gt;More Filter&lt;/p&gt;</description><link>http://crad.tumblr.com/post/46322886</link><guid>http://crad.tumblr.com/post/46322886</guid><pubDate>Sun, 17 Aug 2008 16:17:25 -0400</pubDate></item><item><title>Taken at the Filter concert aboard the USS New Jersey</title><description>&lt;img src="http://24.media.tumblr.com/pRHTXKqkEcrn7yil8Gv9dFgc_500.jpg"/&gt;&lt;br/&gt;&lt;br/&gt;&lt;p&gt;Taken at the Filter concert aboard the USS New Jersey&lt;/p&gt;</description><link>http://crad.tumblr.com/post/46322812</link><guid>http://crad.tumblr.com/post/46322812</guid><pubDate>Sun, 17 Aug 2008 16:16:17 -0400</pubDate></item></channel></rss>
