<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-2368086490179632165</id><updated>2012-02-27T15:10:24.650-08:00</updated><category term='Python'/><category term='Flask-Principal'/><category term='Twitter'/><category term='SPARQL'/><category term='MVC'/><category term='NPM'/><category term='cache'/><category term='MapReduce'/><category term='Pip and VirtualEnv'/><category term='perl'/><category term='Flas-Coffee'/><category term='VirtualEnvWrapper'/><category term='Semantic Web'/><category term='Authorization'/><category term='Security'/><category term='Mongoose'/><category term='Postgres'/><category term='Web2py'/><category term='Node.js'/><category term='Git'/><category term='Tipfy'/><category term='Twitter Streaming API'/><category term='Flask'/><category term='email'/><category term='work'/><category term='Facebook'/><category term='IM'/><category term='database'/><category term='humor'/><category term='flask-script'/><category term='flask-lesscss'/><category term='business'/><category term='PostGIS'/><category term='office'/><category term='RDF'/><category term='Shell Script'/><category term='Backbone.js'/><category term='zappa'/><category term='Javascript'/><category term='Weblayer'/><category term='Pidgin'/><category term='GAE'/><category term='Java'/><category term='mongodb'/><category term='Pyramid'/><category term='contractors'/><category term='GAE Framework'/><category term='Development'/><category term='Frameworks'/><category term='Smart HTTP'/><category term='CoffeeScript'/><category term='CubicWeb'/><category term='Flask-Login'/><category term='Django'/><category term='flask-zen'/><category term='Nagare'/><category term='Authentication'/><category term='Ubuntu'/><category term='Bottle'/><category term='model'/><category term='satire'/><category term='Micro frameworks'/><category term='Repositories'/><title type='text'>Terse Words</title><subtitle type='html'>Getting stuff done using open source tools.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://terse-words.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://terse-words.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Terse Col</name><uri>http://www.blogger.com/profile/07607140110549407614</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>28</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-2368086490179632165.post-7579212372824523687</id><published>2012-02-27T15:10:00.000-08:00</published><updated>2012-02-27T15:10:24.662-08:00</updated><title type='text'>Generating Gibberish in Python - Markov Chains</title><content type='html'>&lt;b&gt;Markov Chains allow us to generate letter&amp;nbsp;sequences&amp;nbsp;which can contain sensible keywords and bulk up your blog.&amp;nbsp;&lt;/b&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I was once taught to speed read. A sham, a party trick, but interesting too. Essentially you just have to practice gliding over pages in a book or whatever and pick out key information (as opposed to just words). You do this by focusing on starts of paragraphs, which tend to be information rich, and capitalized words which tent to be names and useful information and ignore the rest.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;What I'm suggesting here is almost the opposite, generating key words which are beefed up by noise in such a way that, I believe, most search engines will not see the join.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://en.wikipedia.org/w/index.php?title=Markov_chain&amp;amp;oldid=477343426" target="_blank"&gt;Markov Chains&lt;/a&gt; have been around for the most of a&amp;nbsp;hundred&amp;nbsp;years and work by splitting a text into groups of letters of a fixed length and record which groups follow that group anywhere in the text. To generate gibberish all you have to do is choose any group of letters and randomly pick one of the other groups that you know can follow that group; loop until you get enough text. If you use short groups of letters (say two) the text contains less information from the&amp;nbsp;original&amp;nbsp;text than if you use longer groups (say six), because with short groups there are more choices available. You should try this yourself to see what I mean, but I find that a group&amp;nbsp;length&amp;nbsp;of about four is a good start.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Now to the code. Firstly I would love to see your improvements, so please let me know or branch it from &lt;a href="http://github.com/colwilson/Gibberish" target="_blank"&gt;GitHub&lt;/a&gt;. And don't forget to read the extra information at the bottom of this page to understand how it works.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;script src="https://gist.github.com/1927802.js?file=gibberish.py"&gt;&lt;/script&gt;&lt;br /&gt;&lt;div&gt;&lt;div&gt;Essentially you just have to practice gliding over pages in a book or whatever and pick out key information (as opposite, generate gibberish all you use short groups of letters of the join. Firstly ins have been around for the most of a hundred years and use longer groups (say six), because obviously there are more choices available. Essentially you just have to do is choose any group of letters and randomly pick one of the other groups that you know can follow that groups of letters of a fixed length and randomly pick one of a fixed length and randomly pick one of a fixed length and randomly pick one of the code.&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Chains have been around for the most of a hundred years and words which are beefed up by noise in such a way that, I believe, most the join. GitHub op until you have to do is choose any group of letter sequences which can contain sensible keywords and capitalized words which groups follow that groups of letters (say two) the text contains less information from the original text that you know can follow that groups of letters (say two) the text contains less information from the original text.&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;What up by noise in such a way that, I believe, most the other groups than if you get enough text than if you use short group anywhere information rich, and capitalized words which tent to the opposed to just words which tent to be names and work by splitting a text into groups of paragraphs, which tend to be information from the original text than if you use short group anywhere in the most of a hundred years and words which are been around for the most of a hundred years and work by splitting a text into group; loop until you have to do is choose any group of letter sequences which can contain sensible keywords and bulk up your blog. Chains have beefed up by noise in such a way that, I believe, most the opposed to just words which groups (say six), because obviously there are more choices available.&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2368086490179632165-7579212372824523687?l=terse-words.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://terse-words.blogspot.com/feeds/7579212372824523687/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://terse-words.blogspot.com/2012/02/generating-gibberish-in-python-markov.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/7579212372824523687'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/7579212372824523687'/><link rel='alternate' type='text/html' href='http://terse-words.blogspot.com/2012/02/generating-gibberish-in-python-markov.html' title='Generating Gibberish in Python - Markov Chains'/><author><name>Terse Col</name><uri>http://www.blogger.com/profile/07607140110549407614</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2368086490179632165.post-7987854245772416555</id><published>2012-01-22T15:14:00.000-08:00</published><updated>2012-01-22T15:24:54.487-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Semantic Web'/><category scheme='http://www.blogger.com/atom/ns#' term='SPARQL'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>Get Real Data from the Semantic Web - Finding Resources</title><content type='html'>&lt;b&gt;In my &lt;a href="http://terse-words.blogspot.com/2012/01/get-real-data-from-semantic-web.html" target="_blank" title="Get Real Data from the Semantic Web"&gt;last article&lt;/a&gt;, I briefly explained how to get data from a resource using python and SPARQL. This article explains how to find the resource in the first place.&lt;/b&gt;&lt;br /&gt;Have you ever been taught how to knit? I you have, then you'll know that you are not usually taught how to &lt;em&gt;cast on&lt;/em&gt;&amp;nbsp;(or start off) on your first lesson. That's because it much easier to learn how to knit than it is to cast on.&lt;br /&gt;&lt;br /&gt;So it is with the Semantic Web. Once you have a resource URL, it's reasonably easy to extract information linked to that resource, but finding the starting resource is a bit trickier.&lt;br /&gt;So let's just recap how we might get the abstract description for &lt;a href="http://dbpedia.org/page/London" target="_blank"&gt;London from DBpedia&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;If we know the URL then that's pretty straight forward:&lt;br /&gt;&lt;script src="https://gist.github.com/1659179.js"&gt; &lt;/script&gt;(If you want to follow this tutorial, then you had better copy the sparql.py file from &lt;a href="http://terse-words.blogspot.com/2012/01/get-real-data-from-semantic-web.html" target="_blank" title="Get Real Data from the Semantic Web"&gt;there&lt;/a&gt;.)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-uhghWhwymbU/TxyXZ4N3oQI/AAAAAAAAAJY/oGkez8ggqsw/s1600/types.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="183" src="http://1.bp.blogspot.com/-uhghWhwymbU/TxyXZ4N3oQI/AAAAAAAAAJY/oGkez8ggqsw/s400/types.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;RDF types for the DBpedia entry for London&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;b&gt;&lt;/b&gt;&lt;/div&gt;If you don't however, then you'll have to search for it. According to the dbpedia entry, London is many things, including a &lt;b&gt;owl:Thing&lt;/b&gt;, there are a lot of Things out there, probably enough to make even the DBpdia&amp;nbsp;&amp;nbsp;endpoint&amp;nbsp;time out, so let's choose something more restrictive such as &lt;b&gt;yago:Locations&lt;/b&gt;&amp;nbsp;but not too restrictive, for example &lt;b&gt;yago:BritishCapitals&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1659199.js"&gt; &lt;/script&gt;&lt;br /&gt;Just to be a smart ass as I&amp;nbsp;finish&amp;nbsp;off, you can get both at the same time by doing this, but don't forget that doing this will stress the SPARQL endpoint more than is probably&amp;nbsp;necessary. Be kind.&lt;script src="https://gist.github.com/1659213.js"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2368086490179632165-7987854245772416555?l=terse-words.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://terse-words.blogspot.com/feeds/7987854245772416555/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://terse-words.blogspot.com/2012/01/get-real-data-from-semantic-web-finding.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/7987854245772416555'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/7987854245772416555'/><link rel='alternate' type='text/html' href='http://terse-words.blogspot.com/2012/01/get-real-data-from-semantic-web-finding.html' title='Get Real Data from the Semantic Web - Finding Resources'/><author><name>Terse Col</name><uri>http://www.blogger.com/profile/07607140110549407614</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-uhghWhwymbU/TxyXZ4N3oQI/AAAAAAAAAJY/oGkez8ggqsw/s72-c/types.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2368086490179632165.post-8390623197484207528</id><published>2012-01-19T13:53:00.001-08:00</published><updated>2012-01-19T14:24:11.644-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Semantic Web'/><category scheme='http://www.blogger.com/atom/ns#' term='SPARQL'/><category scheme='http://www.blogger.com/atom/ns#' term='RDF'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>Get Real Data from the Semantic Web</title><content type='html'>&lt;p&gt;&lt;strong&gt;Semantic Web this, Semantic Web that, what actual use is the Semantic Web in the real world? I mean how can you actually use it?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;If you haven't heard the term "Semantic Web" over the last couple of years then you must have been in... well somewhere without this interweb they're all talking about.&lt;/p&gt;&lt;p&gt;Basically, by using metadata (see &lt;a title="RDF" href="http://en.wikipedia.org/wiki/Resource_Description_Framework" target="_blank"&gt;RDF&lt;/a&gt;), disparate bits of data floating around the web can be joined up. In otherwords they stop being disparate. Better than that, theoretically you can query the connections between the data and get lots of lovely information back. This last bit is done via &lt;a title="SPARQL" href="http://en.wikipedia.org/wiki/SPARQL" target="_blank"&gt;SPARQL&lt;/a&gt;, and yes, the QL does stand for Query Language.&lt;/p&gt;&lt;p&gt;I say &lt;em&gt;theoretically&lt;/em&gt; because in reality it's a bit of a pain. I may be an &lt;em&gt;intelligent agent&lt;/em&gt; capable of finding linked bits of data through the web, but how exactly would you do that in python.&lt;/p&gt;&lt;p&gt;It is possible to use &lt;a title="rdflib" href="http://code.google.com/p/rdflib/" target="_blank"&gt;rdflib&lt;/a&gt; to find information, but it's very long winded. It's much easier to use &lt;a title="SPARQLWrapper" href="http://sparql-wrapper.sourceforge.net/" target="_blank"&gt;SPARQLWrapper&lt;/a&gt;&amp;nbsp;andin fact in the simple example below, I've used a SPARQLWrapperWrapper to make asking for lots of similarly sourced data, in this case DBPedia, even easier.&lt;/p&gt;&lt;p&gt;&lt;script src="https://gist.github.com/1643191.js"&gt; &lt;/script&gt;&lt;/p&gt;&lt;p&gt;To use this try importing the DBpediaEndpoint and feeding it some SPARQL:&lt;/p&gt;&lt;p&gt;&lt;script src="https://gist.github.com/1643199.js"&gt; &lt;/script&gt;&lt;/p&gt;&lt;p&gt;Your homework is - How do you identify the resource_uri in the first place?&lt;/p&gt;&lt;p&gt;That's for another evening.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2368086490179632165-8390623197484207528?l=terse-words.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://terse-words.blogspot.com/feeds/8390623197484207528/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://terse-words.blogspot.com/2012/01/get-real-data-from-semantic-web.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/8390623197484207528'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/8390623197484207528'/><link rel='alternate' type='text/html' href='http://terse-words.blogspot.com/2012/01/get-real-data-from-semantic-web.html' title='Get Real Data from the Semantic Web'/><author><name>Terse Col</name><uri>http://www.blogger.com/profile/07607140110549407614</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2368086490179632165.post-2118443853778476406</id><published>2012-01-17T14:13:00.001-08:00</published><updated>2012-01-17T14:46:51.584-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Shell Script'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>Github: Who needs it?</title><content type='html'>&lt;p&gt;&lt;strong&gt;Do you ever think that you just don't want all your code on Github? I mean it's only a quick hack right?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Truth is, once you start using git you probably use it automatically for all your code, but you don't always want all your code floating around the net. What about those hard-coded email addresses and API tokens, or those references to your private net servers?&lt;/p&gt;&lt;p&gt;The answer is probably so simple that you have just overlooked it. You don't need to set up a local git server or hire one from Amazon. All you need to do is use &lt;strong&gt;DropBox&lt;/strong&gt; or &lt;strong&gt;Ubuntu One&lt;/strong&gt; as your &lt;em&gt;remote&lt;/em&gt; origin repository.&lt;/p&gt;&lt;p&gt;Here's how, using Ubuntu One on Ubuntu:&lt;/p&gt;&lt;p&gt;Write a short shell script something like this and save it on your path as &lt;strong&gt;repo.sh&lt;/strong&gt;.&lt;/p&gt;&lt;p&gt;&lt;script src="https://gist.github.com/1629349.js"&gt; &lt;/script&gt;&lt;/p&gt;&lt;p&gt;Now when you want to create a new repository all you have to do is:&lt;/p&gt;&lt;p&gt;&lt;script src="https://gist.github.com/1629359.js"&gt; &lt;/script&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;If you use Python and virtualenv you may be interested in the slightly extended script at &lt;a title="this post" href="http://pythonic-apis.blogspot.com/2012/01/using-ubuntu-one-as-git-repository.html" target="_blank"&gt;http://pythonic-apis.blogspot.com/2012/01/using-ubuntu-one-as-git-repository.html&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2368086490179632165-2118443853778476406?l=terse-words.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://terse-words.blogspot.com/feeds/2118443853778476406/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://terse-words.blogspot.com/2012/01/github-who-needs-it.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/2118443853778476406'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/2118443853778476406'/><link rel='alternate' type='text/html' href='http://terse-words.blogspot.com/2012/01/github-who-needs-it.html' title='Github: Who needs it?'/><author><name>Terse Col</name><uri>http://www.blogger.com/profile/07607140110549407614</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2368086490179632165.post-6215633495336510096</id><published>2011-12-15T08:20:00.000-08:00</published><updated>2011-12-15T08:21:10.410-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Twitter Streaming API'/><category scheme='http://www.blogger.com/atom/ns#' term='Twitter'/><title type='text'>Twitter Streaming API - Almost Useful</title><content type='html'>&lt;b&gt;&lt;a href="https://dev.twitter.com/docs/streaming-api" target="_blank"&gt;Twitter's Streaming API&lt;/a&gt; is a splendid idea. It gives developer's access to a good splodge of Tweets and let's us filter them in different ways.&amp;nbsp;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;However it has a few flaws.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;For Twitter, the benefit of a Streaming API is probably one of scalability. Instead of us using the old REST API to ask for specific data and causing tens of thousands of data look ups, all they do is give us the end of their own data stream once it has been used in house and is now halfway across the back garden. All they have to do is allow us to filter the stream a bit to make it a bit more relevant to our needs and put an absolute cap on the throughput (about 1% for most of us.)&lt;br /&gt;&lt;br /&gt;This looks good. 1% is enough for most development needs and streams down your connection like a low bandwidth radio station. I don't really know what the bandwidth or download is, but it's not much. Once we've developed our new and wonderful website, then we can ask, or possibly pay, Twitter to turn up the pressure a bit.&lt;br /&gt;&lt;br /&gt;So, now let's look at the filters.&lt;br /&gt;&lt;br /&gt;There are several ways that the stream can be filtered&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;follow&lt;/b&gt; - filter by userid&lt;/li&gt;&lt;li&gt;&lt;b&gt;track&lt;/b&gt; - filter by keyword&lt;/li&gt;&lt;li&gt;&lt;b&gt;location&lt;/b&gt; - filter by geographic location&lt;/li&gt;&lt;li&gt;&lt;b&gt;retweets&lt;/b&gt; - just the retweets ma'am&lt;/li&gt;&lt;li&gt;&lt;b&gt;links&lt;/b&gt; - only tweets containing a link&lt;/li&gt;&lt;li&gt;&lt;b&gt;random&lt;/b&gt; - I think they just mean unfiltered&lt;/li&gt;&lt;/ul&gt;On the face of it this is pretty useful. You could filter the stream by adding the location of your home town so that you can get the jist of what is important to your townsfolk. You could filter the stream by the keyword 'Elvis' to see who has spotted Elvis lately and plot the results on a map.&lt;br /&gt;&lt;br /&gt;My own first idea was inspired by the &lt;a href="http://www.bbc.co.uk/news/uk-15607476" target="_blank"&gt;M5 motorway accident&lt;/a&gt; just a few miles from where I live and astounded that even in this day and age, the scale of the incident was only uncovered somewhat slowly. Surely what the quantity and content of the tweets from the people who were NOT in the incident itself, would help scale the incident? So what I wanted to do was:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Listen to what people Tweet at known traffic jam locations.&lt;/li&gt;&lt;li&gt;Identify some fingerprint of common words, maybe "traffic, jam, standstill, miles" or whatever.&lt;/li&gt;&lt;li&gt;Look for clusters of these words near to motorways.&lt;/li&gt;&lt;li&gt;Plot the clusters based on the location of the phones that made the tweets.&lt;/li&gt;&lt;/ol&gt;So I get an updating list of current traffic incidents from the &lt;a href="http://www.trafficengland.com/trafficalerts.aspx" target="_blank"&gt;Traffic England&lt;/a&gt; RSS feed and start listening within 5 kms of the stated location using a bounding box centred on the location. The first thing I notice is that some of the tweets are in the bounding box, some are around it and some, quite a few are far away, sometimes 200km away or more!&lt;br /&gt;&lt;br /&gt;I don't know how Twitter do the filtering, but evidently it's based on something fairly broad brushed. I can live with that maybe, all I have to do is check the Tweets &lt;i&gt;geo&lt;/i&gt; location, which is added if you tweet by most modern phones. I was expecting most of the useful tweets to be from a mobile anyway, so that would work if I can just get used to maybe 2% of the tweets actually being in the bounding box. 2% 0f 1% is after all only 0.02% of all Tweets or 1 Tweet in 5000.&lt;br /&gt;&lt;br /&gt;So what happens if I assume that the word "traffic" will occur in the most useful Tweets? This is either bad science or common sense data filtering depending on how you look at it.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Alas, it appears that the Streaming API does not allow you to filter by location AND keyword! All you can do is do an OR filter, so I can filter the stream to include certain areas OR certain keywords, but not certain keywords within a certain location.&lt;br /&gt;&lt;br /&gt;To me this just renders the API all but useless, but no doubt you lot are much smarter than I and will dazzle me with your great ideas.&lt;br /&gt;&lt;br /&gt;Please let me know.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2368086490179632165-6215633495336510096?l=terse-words.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://terse-words.blogspot.com/feeds/6215633495336510096/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://terse-words.blogspot.com/2011/12/twitter-streaming-api-almost-useful.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/6215633495336510096'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/6215633495336510096'/><link rel='alternate' type='text/html' href='http://terse-words.blogspot.com/2011/12/twitter-streaming-api-almost-useful.html' title='Twitter Streaming API - Almost Useful'/><author><name>Terse Col</name><uri>http://www.blogger.com/profile/07607140110549407614</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2368086490179632165.post-478008538447631712</id><published>2011-11-06T15:07:00.000-08:00</published><updated>2011-11-07T01:14:09.771-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GAE'/><category scheme='http://www.blogger.com/atom/ns#' term='VirtualEnvWrapper'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>Google App Engine Python2.5 Development in Ubuntu 11.10</title><content type='html'>How to set up a development environment for Google App Engine, Python2.5 in Ubuntu 11.10.&lt;br /&gt;Firstly, sorry if the code below is badly formatted, but there's a clearer copy of the code at the bottom. &lt;br /&gt;&lt;br /&gt;Python2.5 isn't in the Ubuntu 11.10 sources by default so in a console:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;sudo add-apt-repository ppa:fkrull/deadsnakes&lt;br /&gt;sudo apt-get update&lt;/pre&gt;&lt;br /&gt;and install python2.5 and some other stuff:&lt;br /&gt;&lt;pre&gt;sudo apt-get install python2.5 python-virtualenv&amp;nbsp;virtualenvwrapper python-pip&lt;/pre&gt;&lt;br /&gt;Next for project 'oinkyoinker':&lt;br /&gt;&lt;pre&gt;export CURRENT=oinkyoinker&lt;br /&gt;mkvirtualenv --no-site-packages --distribute --python python2.5 ${CURRENT}&lt;br /&gt;workon ${CURRENT}&lt;br /&gt;cdvirtualenv&lt;br /&gt;pip install fabric yolk ipython readline&lt;/pre&gt;&lt;br /&gt;Now download GAE and fix the path:&lt;br /&gt;&lt;pre&gt;wget -O /tmp/gae.zip http://googleappengine.googlecode.com/files/google_appengine_1.5.5.zip&lt;br /&gt;unzip /tmp/gae.zip&lt;br /&gt;echo "../../../google_appengine" &amp;gt; lib/python2.5/site-packages/gae.pth&lt;/pre&gt;and create a simple file server app:&lt;br /&gt;&lt;pre&gt;mkdir -p application/static&lt;br /&gt;&lt;br /&gt;echo """application: oinkyoinker&lt;br /&gt;version: 1&lt;br /&gt;runtime: python&lt;br /&gt;api_version: 1&lt;br /&gt;default_expiration: "7d"&lt;br /&gt;handlers:&lt;br /&gt;- url: /&lt;br /&gt;  static_dir: static&lt;br /&gt;""" &amp;gt; application/app.yaml&lt;/pre&gt;and run it:&lt;br /&gt;&lt;pre&gt;./google_appengine/dev_appserver.py application/&lt;/pre&gt;Hope this helped you too.&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1344513.js?file=some.bash"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2368086490179632165-478008538447631712?l=terse-words.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://terse-words.blogspot.com/feeds/478008538447631712/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://terse-words.blogspot.com/2011/11/google-app-engine-python25-development.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/478008538447631712'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/478008538447631712'/><link rel='alternate' type='text/html' href='http://terse-words.blogspot.com/2011/11/google-app-engine-python25-development.html' title='Google App Engine Python2.5 Development in Ubuntu 11.10'/><author><name>Terse Col</name><uri>http://www.blogger.com/profile/07607140110549407614</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2368086490179632165.post-745389102196136137</id><published>2011-11-06T13:14:00.000-08:00</published><updated>2011-11-06T15:37:13.535-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MapReduce'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>MapReduce in Python</title><content type='html'>Over the last while I've been using NodeJS, MongoDB and Google's App Engine. Everything seems to have MapReduce functionality and frankly I was missing it when I went back to do some work in plain old Python. This is a nice short example of how it can be done.&lt;br /&gt;&lt;br /&gt;The basic format that you need is something like this:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1343468.js?file=skelmr.py"&gt;&lt;/script&gt;Now, a simple working example using the usual MapReduce example:&lt;script src="https://gist.github.com/1343474.js?file=pymr.py"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;The output will look something like this:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1343491.js?file=outs.txt"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;I got most of this from the following blog:&amp;nbsp;&lt;a href="http://goo.gl/nW8iA"&gt;http://goo.gl/nW8iA&lt;/a&gt;&amp;nbsp;.&lt;/li&gt;&lt;li&gt;Docs are here:&amp;nbsp;&lt;a href="http://docs.python.org/library/multiprocessing.html"&gt;http://docs.python.org/library/multiprocessing.html&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2368086490179632165-745389102196136137?l=terse-words.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://terse-words.blogspot.com/feeds/745389102196136137/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://terse-words.blogspot.com/2011/11/mapreduce-in-python.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/745389102196136137'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/745389102196136137'/><link rel='alternate' type='text/html' href='http://terse-words.blogspot.com/2011/11/mapreduce-in-python.html' title='MapReduce in Python'/><author><name>Terse Col</name><uri>http://www.blogger.com/profile/07607140110549407614</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2368086490179632165.post-4393601194711034970</id><published>2011-10-19T06:32:00.000-07:00</published><updated>2011-10-21T23:23:34.729-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='CoffeeScript'/><category scheme='http://www.blogger.com/atom/ns#' term='Mongoose'/><category scheme='http://www.blogger.com/atom/ns#' term='mongodb'/><title type='text'>MapReduce with Mongoose and CoffeeScript</title><content type='html'>&lt;span class="Apple-style-span" style="font-size: large;"&gt;After searching the InterWeb for a decent MapReduce example coded in CoffeeScript I came up blank and decided to write my own. This one uses Mongoose too - well why use anything else?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;I haven't written a whole lot of explanation in the text, but commented the code quite heavily so you can copy and paste and still have it with you. &lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;/span&gt;Load Mongoose and connect to your database.Describe your schema and model and then load up some dummy data.&lt;br /&gt;&lt;script src="https://gist.github.com/1298226.js"&gt; &lt;/script&gt;&lt;br /&gt;Now for the MapReduce stuff. If you still don't get MapReduce then you will once you read this &lt;a href="http://www.snailinaturtleneck.com/blog/2010/03/15/mapreduce-the-fanfiction/"&gt;Star Trek based article&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;Define a Map function. &lt;br /&gt;&lt;script src="https://gist.github.com/1298237.js"&gt;&lt;/script&gt;&lt;br /&gt;Define a Reduce function.&lt;br /&gt;&lt;script src="https://gist.github.com/1298238.js"&gt;&lt;/script&gt;&lt;br /&gt;Get some output &lt;br /&gt;&lt;script src="https://gist.github.com/1298241.js"&gt;&lt;/script&gt;&lt;br /&gt;The results will now be in a collection called "results" which you can look at with JMongoBrowser or whatever.&lt;br /&gt;&lt;br /&gt;I hope this is of some use to you. If there are any corrections or improvements then please post something below.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2368086490179632165-4393601194711034970?l=terse-words.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://terse-words.blogspot.com/feeds/4393601194711034970/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://terse-words.blogspot.com/2011/10/mapreduce-with-mongoose-and.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/4393601194711034970'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/4393601194711034970'/><link rel='alternate' type='text/html' href='http://terse-words.blogspot.com/2011/10/mapreduce-with-mongoose-and.html' title='MapReduce with Mongoose and CoffeeScript'/><author><name>Terse Col</name><uri>http://www.blogger.com/profile/07607140110549407614</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2368086490179632165.post-7194620845477930471</id><published>2011-10-18T05:23:00.000-07:00</published><updated>2011-11-05T00:31:52.924-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='work'/><category scheme='http://www.blogger.com/atom/ns#' term='office'/><category scheme='http://www.blogger.com/atom/ns#' term='humor'/><category scheme='http://www.blogger.com/atom/ns#' term='satire'/><category scheme='http://www.blogger.com/atom/ns#' term='business'/><title type='text'>Six Ways to Have a Lazy Day at the Office</title><content type='html'>&lt;span style="font-size: large;"&gt;Sometimes you just need a lazy day at the Office. Now I'm not saying that I am lazy, but I have built up a certain amount of useful expertise in this area. Sometimes it's tiredness, sometimes I'm hungover, but mostly I'm just still drunk.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Either way I hope these are of use to you.&lt;/span&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-S_MkUdceu28/TpymJTjtMVI/AAAAAAAAAHA/qJOOTSRdQuM/s1600/709419_75939502.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="213" src="http://3.bp.blogspot.com/-S_MkUdceu28/TpymJTjtMVI/AAAAAAAAAHA/qJOOTSRdQuM/s320/709419_75939502.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Leave a Post-it saying that you have gone for a meeting with your new boss. If your current boss asks where you were just say you 've been asked not to say until "things are sorted out". They'll be too worried about their own job to worry about what you've been up to.&lt;/li&gt;&lt;li&gt;Sit in a café all day sending the occasional email from your smart phone letting people know you are meeting a client.&lt;/li&gt;&lt;li&gt;Sit in the smoker's shed smoking one of those electronic cigarettes. Occasionally switch sheds; smokers are people of habit and always use the same shed.&lt;/li&gt;&lt;li&gt;When you need to have a lie down, then just go ahead and lie on the floor complaining of "the old slipped disk". Don't snore.&lt;/li&gt;&lt;li&gt;Book a meeting room and send an invite to a manager that you know isn't in today. Take some paperwork along and if asked just say that you thought you'd use the time while waiting to catch up on some documents.&lt;/li&gt;&lt;li&gt;Before you disappear from your desk tell your neighbours that your having an affair with the bosses partner. They will do all the lying for you.&lt;/li&gt;&lt;/ol&gt;&lt;ol&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2368086490179632165-7194620845477930471?l=terse-words.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://terse-words.blogspot.com/feeds/7194620845477930471/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://terse-words.blogspot.com/2011/10/six-ways-to-have-lazy-day-at-office.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/7194620845477930471'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/7194620845477930471'/><link rel='alternate' type='text/html' href='http://terse-words.blogspot.com/2011/10/six-ways-to-have-lazy-day-at-office.html' title='Six Ways to Have a Lazy Day at the Office'/><author><name>Terse Col</name><uri>http://www.blogger.com/profile/07607140110549407614</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-S_MkUdceu28/TpymJTjtMVI/AAAAAAAAAHA/qJOOTSRdQuM/s72-c/709419_75939502.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2368086490179632165.post-3056848984635932291</id><published>2011-10-17T12:14:00.000-07:00</published><updated>2011-10-19T02:23:37.995-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='work'/><category scheme='http://www.blogger.com/atom/ns#' term='office'/><category scheme='http://www.blogger.com/atom/ns#' term='humor'/><category scheme='http://www.blogger.com/atom/ns#' term='satire'/><category scheme='http://www.blogger.com/atom/ns#' term='contractors'/><title type='text'>Ten Annoying Things About IT Contractors</title><content type='html'>&lt;span style="font-size: large;"&gt;OK, so I'm bitter and twisted. I've never been brave enough to leave my long term job and take the risk. Even bumbling along like I do, you eventually end up working alongside; hiring, and managing IT contractors and you spot&amp;nbsp;some&amp;nbsp;peculiarities. Strange scary (or at least annoying)&amp;nbsp;peculiarities.&lt;/span&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-C-vOHPyyMUk/TpyFdNVnZiI/AAAAAAAAAG4/xl-qDKkoLD8/s1600/464669_56783139.jpg" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="200" src="http://4.bp.blogspot.com/-C-vOHPyyMUk/TpyFdNVnZiI/AAAAAAAAAG4/xl-qDKkoLD8/s200/464669_56783139.jpg" width="150" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Suits&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;ol&gt;&lt;li&gt;Nobody needs a suit that sharp to meet our customers and certainly not to go to internal meetings. It's just not fair to show up my Hawaii shirt.&amp;nbsp;It&amp;nbsp;deserves&amp;nbsp;respect.&amp;nbsp;You seem to forget that once it still fitted and had all the buttons.&amp;nbsp;&lt;/li&gt;&lt;li&gt;Your code is shit.&lt;/li&gt;&lt;li&gt;I'm signing your damn hours so please stop calling me a "management overhead".&lt;/li&gt;&lt;li&gt;If you want to read a morning publication, read Dilbert like the rest of us, not the broad sheets and not that one in particular. Even more than that, reading the Financial Times/Wall Street Journal is just plain wrong.&lt;/li&gt;&lt;li&gt;You don't need to park your BMW next to my Rover. I'll have you know that Rover were the last great British car manufacturer and you can still find parts. Mostly in scrapyards admittedly, but all cheap.&lt;/li&gt;&lt;li&gt;It's just rude to send your CV to another company using our email system. I don't care if it is&amp;nbsp;lunch-time.&lt;/li&gt;&lt;li&gt;Stop bringing your own laptop. Yes, it's nice and slim, but the company laptops improve your muscle tone and can store loads of stuff if you use a USB stick.&lt;/li&gt;&lt;li&gt;On doughnut Wednesday you just can't bring fruit and carrot sticks unless you want to be&amp;nbsp;ridiculed. Gym-boy!&lt;/li&gt;&lt;li&gt;Dress down Friday doesn't mean wear a slightly cheaper suit, it means you don't need to wear pants at all.&lt;/li&gt;&lt;li&gt;Your code is still shit, but don't worry we'll fix it and write the documentation too.&amp;nbsp;Enjoy&amp;nbsp;your new job.&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;Comment below as you will.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2368086490179632165-3056848984635932291?l=terse-words.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://terse-words.blogspot.com/feeds/3056848984635932291/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://terse-words.blogspot.com/2011/10/ten-annoying-things-about-it.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/3056848984635932291'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/3056848984635932291'/><link rel='alternate' type='text/html' href='http://terse-words.blogspot.com/2011/10/ten-annoying-things-about-it.html' title='Ten Annoying Things About IT Contractors'/><author><name>Terse Col</name><uri>http://www.blogger.com/profile/07607140110549407614</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-C-vOHPyyMUk/TpyFdNVnZiI/AAAAAAAAAG4/xl-qDKkoLD8/s72-c/464669_56783139.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2368086490179632165.post-5130250030320577586</id><published>2011-10-17T07:17:00.000-07:00</published><updated>2011-10-17T10:54:13.370-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='CoffeeScript'/><category scheme='http://www.blogger.com/atom/ns#' term='Micro frameworks'/><category scheme='http://www.blogger.com/atom/ns#' term='Frameworks'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><category scheme='http://www.blogger.com/atom/ns#' term='Node.js'/><category scheme='http://www.blogger.com/atom/ns#' term='zappa'/><title type='text'>Staying Up Late - CoffeeScript and Zappa</title><content type='html'>Over the last couple of years NodeJS has become the darling of "coding for pleasure" crowd. All that cross fertilization from the client side buffs into the server side and the server side coders ranting about the whole event-driveness of NodeJS.&lt;br /&gt;&lt;br /&gt;Yes, it's the next big thing. Well, it's probably not, but it's certainly "A" next big thing or maybe we'll all get bored dream up something else with a catchy name... "perl for parallelism" or "Friendly Java (without the memory leaks)", or what about "C+=3" or "Oil for Android", "Lube for Palm OS". Well you know what I mean.&lt;br /&gt;&lt;br /&gt;We see something; we explore it and once it starts getting a bit boring we convince ourselves and then our customers that we need to use some new technology or other. It's all true of course, or partly true, or lies.&lt;br /&gt;&lt;br /&gt;Anyway, I'm not here to rant about that, after all I as guilty as anyone else.&lt;br /&gt;&lt;br /&gt;&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-dUjAzLVM_6A/TpxrjUQ1rUI/AAAAAAAAAGw/QkzNpP1fICc/s1600/handring.jpg" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="212" src="http://1.bp.blogspot.com/-dUjAzLVM_6A/TpxrjUQ1rUI/AAAAAAAAAGw/QkzNpP1fICc/s320/handring.jpg" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;A Messy Affair&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;What I want to rant about is Zappa which is my own personal cure for technical disfunction at the moment. Well that sounds real bad, but I've been doing this job for years and it's only these little affairs over the years that keep me coming home; "Assembler", "C", "C++", "Ruby", "Python", how I remember their sweet names, but sooner or later they all start to look like their mother and have to go.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://zappajs.org/"&gt;Zappa&lt;/a&gt; is a young virgin of a technology, only now reaching a pubescent version 0.3. Essentially it's a lightweight framework built on top of known technologies such like NodeJS, CoffeeScript, Express and Socket.IO in much the same way as Python's Flask is built on top of Werkzeug, Jinja 2 and so on. &lt;br /&gt;&lt;br /&gt;It's that Socket.IO bit that makes this one so sexy (I'm overdoing the procreation metaphors aren't I?). Socket.IO provides cross-browser &lt;a href="http://en.wikipedia.org/wiki/WebSocket"&gt;WebSocket&lt;/a&gt; goodness which means you can do stuff like stop using the &lt;a href="http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller"&gt;Model-View-Controller paradigm&lt;/a&gt; and start thinking outside the cubical with your "Model-View-Controller-View-Controller-Controller-View Paradigm" or whatever. Mind you, that's when you'll realise that MVC wasn't about limiting your options, it was about simplifying them.&lt;br /&gt;&lt;br /&gt;Anyway, back to &lt;a href="http://zappajs.org/"&gt;Zappa&lt;/a&gt; itself. Go and have a look, there are great examples that will get your inventive juices flowing (stop it!) and inspire you to spend a little time alone locked it the bathroom... I mean office. The community is starting to grow and the &lt;a href="http://groups.google.com/group/zappajs?pli=1"&gt;mailing list&lt;/a&gt; is big enough to be useful, but not so big as to be faceless and scarey.&lt;br /&gt;&lt;br /&gt;Have fun but take precautions.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2368086490179632165-5130250030320577586?l=terse-words.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://terse-words.blogspot.com/feeds/5130250030320577586/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://terse-words.blogspot.com/2011/10/staying-up-late-coffeescript-and-zappa.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/5130250030320577586'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/5130250030320577586'/><link rel='alternate' type='text/html' href='http://terse-words.blogspot.com/2011/10/staying-up-late-coffeescript-and-zappa.html' title='Staying Up Late - CoffeeScript and Zappa'/><author><name>Terse Col</name><uri>http://www.blogger.com/profile/07607140110549407614</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-dUjAzLVM_6A/TpxrjUQ1rUI/AAAAAAAAAGw/QkzNpP1fICc/s72-c/handring.jpg' height='72' width='72'/><thr:total>0</thr:total><georss:featurename>Exeter, Devon, UK</georss:featurename><georss:point>50.7218 -3.533617</georss:point><georss:box>50.68159 -3.612581 50.762010000000004 -3.454653</georss:box></entry><entry><id>tag:blogger.com,1999:blog-2368086490179632165.post-7992409973185172276</id><published>2011-07-13T08:09:00.000-07:00</published><updated>2011-07-27T05:16:12.820-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='MVC'/><category scheme='http://www.blogger.com/atom/ns#' term='Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Node.js'/><title type='text'>Back of an Envelope Node.js Framework - Discuss</title><content type='html'>I had a quiet afternoon today and while "keeping up with recent developments in my field" or as you might call it "wasting my afternoon googling" I got to thinking what I'd like a Node.js MVC framework should or could contain.&lt;br /&gt;&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; text-align: left;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-F3n8LxO9DL0/Th2ri1XmDBI/AAAAAAAAAFw/FW2Qi6lM3hU/s1600/node-framework.GIF" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="400" src="http://1.bp.blogspot.com/-F3n8LxO9DL0/Th2ri1XmDBI/AAAAAAAAAFw/FW2Qi6lM3hU/s400/node-framework.GIF" width="353" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;How design shouldn't be done&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;Firstly, I've been playing with Node.js for about three weeks now and I'm impressed, but I can't seem to find a framework that I'm happy with. &lt;a href="http://documentcloud.github.com/backbone/"&gt;Backbone &lt;/a&gt;looked good, but I wasted three days on it and it was too much like hard work. Similarly &lt;a href="http://www.blogger.com/"&gt;Spine &lt;/a&gt;which tried to be less complicated, but eventually failed. Finally I really wanted &lt;a href="http://brunchwithcoffee.com/"&gt;Brunch &lt;/a&gt;to work but it was a release behind backbone (which is a major component of it) and I didn't want to get lost in the mismatching documentation (the Backbone release was pretty major).&lt;br /&gt;&lt;br /&gt;I have spent a whole lot of time over the last couple of years using python frameworks, especially &lt;a href="http://flask.pocoo.org/docs/"&gt;Flask &lt;/a&gt;and I like their approach of starting with a good foundation (in their case &lt;a href="http://werkzeug.pocoo.org/documentation/"&gt;Werkzeug&lt;/a&gt;) and adding the bits that are still needed. Could that work with Node? I mean writing a basic HTTP server looks pretty straight forward and there are tons of modules to add the other functionality.&lt;br /&gt;&lt;br /&gt;So with this possibly naive starting position I grabbed my pen and scribble down some stuff I thought I'd need. Now bear in mind that I haven't much used any of these modules yet, and I pinched several of them from the bits that go to make up Brunch. &lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;I'd appreciate any feedback, suggestions and so on that those more learned than I might care to offer. Few of you will be less learned I imagine.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Here are the transcribed notes with some links:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Server&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Simple Node.js &lt;/li&gt;&lt;li&gt;&lt;a href="http://expressjs.com/index.html"&gt;Express &lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;b&gt;Routing&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://github.com/joyent/node/wiki/modules#web-frameworks-routers"&gt;choose a module&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Express?&lt;/li&gt;&lt;/ul&gt;&lt;b&gt;Data Store&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.mongodb.org/"&gt;Mongo&lt;/a&gt;? &lt;/li&gt;&lt;li&gt;&lt;a href="http://couchdb.apache.org/"&gt;CouchDB&lt;/a&gt;?&lt;/li&gt;&lt;li&gt;&lt;a href="https://github.com/chrisdew/barricane-db"&gt;Barricane-db &lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;b&gt;Models&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;JS Object/JSON?&lt;/li&gt;&lt;li&gt;ORM?&lt;/li&gt;&lt;/ul&gt;&lt;b&gt;Views&lt;/b&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; -CSS&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://lesscss.org/"&gt;lesscss &lt;/a&gt;? &lt;/li&gt;&lt;li&gt;&lt;a href="https://github.com/LearnBoost/stylus"&gt;Stylus &lt;/a&gt;? &lt;/li&gt;&lt;/ul&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; -Templating&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://mustache.github.com/"&gt;mustache&lt;/a&gt;(js) ? &lt;/li&gt;&lt;li&gt;&lt;a href="https://github.com/sstephenson/eco"&gt;Eco &lt;/a&gt;(coffeescript) &lt;/li&gt;&lt;/ul&gt;&lt;b&gt;Controllers&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Plain Old JS&lt;/li&gt;&lt;li&gt;&lt;a href="http://jashkenas.github.com/coffee-script/"&gt;CoffeeScript&lt;/a&gt;? &lt;/li&gt;&lt;li&gt;&lt;a href="http://jquery.com/"&gt;jQuery &lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://documentcloud.github.com/underscore/"&gt;Underscore.js &lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://github.com/caolan/quip"&gt;Quip &lt;/a&gt;(responses) ? &lt;/li&gt;&lt;/ul&gt;&lt;b&gt;Middleware&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;how? Express&lt;/li&gt;&lt;/ul&gt;&lt;b&gt;Other Stuff&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://github.com/robrighter/node-boilerplate"&gt;node-boilerplate&lt;/a&gt;?&lt;/li&gt;&lt;li&gt;&lt;a href="https://github.com/sstephenson/stitch"&gt;Stitch &lt;/a&gt;(glue) &lt;/li&gt;&lt;li&gt;&lt;a href="http://jashkenas.github.com/coffee-script/"&gt;Cake &lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;b&gt;If you spot any typos, inaccuracies or just plain lies then please let me know.&lt;/b&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2368086490179632165-7992409973185172276?l=terse-words.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://terse-words.blogspot.com/feeds/7992409973185172276/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://terse-words.blogspot.com/2011/07/back-of-envelope-nodejs-framework.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/7992409973185172276'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/7992409973185172276'/><link rel='alternate' type='text/html' href='http://terse-words.blogspot.com/2011/07/back-of-envelope-nodejs-framework.html' title='Back of an Envelope Node.js Framework - Discuss'/><author><name>Terse Col</name><uri>http://www.blogger.com/profile/07607140110549407614</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-F3n8LxO9DL0/Th2ri1XmDBI/AAAAAAAAAFw/FW2Qi6lM3hU/s72-c/node-framework.GIF' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2368086490179632165.post-8452329286870314581</id><published>2011-06-27T14:37:00.000-07:00</published><updated>2011-06-27T14:37:24.634-07:00</updated><title type='text'>Binding Updates to Model Changes in Backbone/CoffeeScript</title><content type='html'>My &lt;a href="http://terse-words.blogspot.com/2011/06/simplest-ever-backbonejscoffeescript.html"&gt;previous post&lt;/a&gt; showed a View that looked like this:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1047896.js?file=4.coffee"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;But what happens if we have a more complicated app and something else changes the Model?&lt;br /&gt;&lt;br /&gt;Well as I said I'm just learning myself here, co the correct way that should be handled is to bind Model changes to the Views render function which looks like this:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1049890.js?file=6.coffee"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;Note the bind instruction which means that every time the counter changes, it calls the render function. You might also notice the fat arrow now on the render which make "this" still mean the View rather than the caller (which would be the Model otherwise.)&lt;br /&gt;&lt;br /&gt;The explanation for all this is at &lt;a href="http://jashkenas.github.com/coffee-script"&gt;http://jashkenas.github.com/coffee-script&lt;/a&gt; under "Function Binding".&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2368086490179632165-8452329286870314581?l=terse-words.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://terse-words.blogspot.com/feeds/8452329286870314581/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://terse-words.blogspot.com/2011/06/binding-updates-to-model-changes-in.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/8452329286870314581'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/8452329286870314581'/><link rel='alternate' type='text/html' href='http://terse-words.blogspot.com/2011/06/binding-updates-to-model-changes-in.html' title='Binding Updates to Model Changes in Backbone/CoffeeScript'/><author><name>Terse Col</name><uri>http://www.blogger.com/profile/07607140110549407614</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2368086490179632165.post-1448449050408923123</id><published>2011-06-26T13:01:00.000-07:00</published><updated>2011-06-27T14:38:16.868-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='Backbone.js'/><category scheme='http://www.blogger.com/atom/ns#' term='CoffeeScript'/><title type='text'>Simplest Ever Backbone.js/CoffeeScript Example</title><content type='html'>I'm teaching myself to use &lt;a href="http://documentcloud.github.com/backbone/#"&gt;Backbone&lt;/a&gt; because after having done quite a lot of&amp;nbsp;JavaScript&amp;nbsp;in work lately, it has become obvious to me that I need a framework.&lt;br /&gt;&lt;br /&gt;I'm also learning how to use &lt;a href="http://jashkenas.github.com/coffee-script/"&gt;CoffeeScript&lt;/a&gt;, which is close enough to python/ruby for me to understand.&lt;br /&gt;&lt;br /&gt;First thing that I noticed is that most of the examples for Backbone out there are in pure JavaScript, so I thought I'd do my bit by providing something in CoffeeScript.&lt;br /&gt;&lt;br /&gt;To that end, here is a very simple app which displays a number. You can increase or decrease the count by clicking buttons.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;The app.coffee code:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1047624.js"&gt; &lt;/script&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;and the html to go with that:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1047622.js?file=gistfile1.txt"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;In detail&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;At the top, we set up global hashes to store our objects. In a bigger app this would make referencing bits and pieces much easier, although we don't really need it in this example.&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1047659.js?file=1.coffee"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;Next the controller. This one is almost empty except it has two routes both taking you to the home control which is also part of the controller. The route with no reference (the empty string) and the one for #home tagged on the end of your URL (by way of an example) both call the home function in this case.&lt;br /&gt;&lt;br /&gt;The home control just tells the view to render itself.&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1047663.js?file=2.coffee"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;Next the Counter model which has one attribute called count which defaults to zero. In reality I think you would want to synchronize your models with a database, but we'll do that in another post soon.&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1047670.js?file=3.coffee"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;And now for the View. The View is obviously what you are seeing in the browser. In our trivial example we only have one view, but a real app would probably have several. A view lumps together a unit of the app, sometimes nowadays we call these widgets, or blocks or display regions or whatever. You get the idea.&lt;br /&gt;&lt;br /&gt;In the initialize function, we just connect the view to the model that backs it. The events connect the button to the functions that they call. The render function draws the result into the #count div; the @ symbol at the end is shorthand for this. In CoffeeScript (like Ruby) the last line of a function gets returned even if you don't specifically say "return". So in other words it means "return this". This is handy since it lets us chain together functions.&lt;br /&gt;&lt;br /&gt;The inc and dec functions increase and decrease the count in the model and then update the display. &lt;b&gt;Please see the update &lt;a href="http://terse-words.blogspot.com/2011/06/binding-updates-to-model-changes-in.html"&gt;here&lt;/a&gt;.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1047896.js?file=4.coffee"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;Finally the equivalent of the main() function which instaniates the bits and bobs and then starts the history. I've no idea why they called it history, but basically it starts up all the listeners.&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1047908.js?file=5.coffee"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;That's all for now. Next time I'll show you how to connect all this to your database using python and Flask.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;If you see anything wrong with what I've written here or if you spot spelling or other mistakes then please let me know.&lt;/b&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2368086490179632165-1448449050408923123?l=terse-words.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://terse-words.blogspot.com/feeds/1448449050408923123/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://terse-words.blogspot.com/2011/06/simplest-ever-backbonejscoffeescript.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/1448449050408923123'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/1448449050408923123'/><link rel='alternate' type='text/html' href='http://terse-words.blogspot.com/2011/06/simplest-ever-backbonejscoffeescript.html' title='Simplest Ever Backbone.js/CoffeeScript Example'/><author><name>Terse Col</name><uri>http://www.blogger.com/profile/07607140110549407614</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2368086490179632165.post-7820963367430896811</id><published>2011-06-25T12:15:00.000-07:00</published><updated>2011-11-19T07:44:48.997-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Git'/><category scheme='http://www.blogger.com/atom/ns#' term='Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Repositories'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>Set Up Your Own Git Repository Hosting Service in Three Minutes</title><content type='html'>You might have seen my earlier post "A Review of Free Code Repositories".&lt;br /&gt;&lt;br /&gt;Well I forgot about hosting your own. Really handy for hobbyist development.I have one of those free developer servers from Amazon out there somewhere. I don't use it much except to demo the occasional site and so on.&lt;br /&gt;&lt;br /&gt;I decided that it was a good idea to set it up as a git repository and i show you here how to do this.If you are using something Ubuntu-ish remotely then this should take about three minutes.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;A Word of Explanation&lt;/span&gt;&lt;br /&gt;This is the simple setup, it avoids creating 'git' user on the remote server, but you DO need to use a seperate key for using the git service and I show you that first.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;On your local machine:&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="Apple-style-span"&gt;&lt;br /&gt;# echo "Host gitserver&lt;br /&gt;  Hostname ec2-XXX-XXX-XXX-XXX.compute-1.amazonaws.com&lt;br /&gt;  User git-col&lt;/span&gt;&lt;span class="Apple-style-span"&gt;&lt;br /&gt;  PreferredAuthentications publickey&lt;br /&gt;  IdentityFile ~/keys/&lt;/span&gt;git-col.pub&lt;br /&gt;&lt;span class="Apple-style-span"&gt;" &amp;gt;&amp;gt; ~/.ssh/config&lt;br /&gt;&lt;br /&gt;# mkdir ~/keys&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="Apple-style-span"&gt;# ssh-keygen&lt;br /&gt;Generating public/private rsa key pair.&lt;br /&gt;Enter file in which to save the key (/home/col/.ssh/id_rsa): &lt;/span&gt;git-col.pub # do NOT accept the default&lt;/pre&gt;&lt;pre&gt;# cp git-col* ~/keys&lt;br /&gt;&lt;span class="Apple-style-span"&gt;# scp git-col.pub &lt;/span&gt;ec2-XXX-XXX-XXX-XXX.compute-1.amazonaws.com:&lt;br /&gt;&lt;span class="Apple-style-span"&gt;# ssh &lt;br /&gt;&lt;/span&gt;ec2-XXX-XXX-XXX-XXX.compute-1.amazonaws.com&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;On your remote host you are now logged in as 'ubuntu':&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="Apple-style-span"&gt;# sudo apt-get install git&lt;br /&gt;# git clone git://github.com/sitaramc/gitolite&lt;br /&gt;# ./gitolite/src/gl-system-install &lt;br /&gt;# gl-setup -q ~/&lt;/span&gt;git-col.pub &lt;br /&gt;&lt;span class="Apple-style-span"&gt;# exit&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;On your local machine:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="Apple-style-span"&gt;# git config --global user.name "Your Name"&lt;br /&gt;&lt;/span&gt;&lt;span class="Apple-style-span"&gt;# git config --global user.email your@email.address&lt;br /&gt;&lt;/span&gt;&lt;span class="Apple-style-span"&gt;# git clone gitserver:gitolite-admin&lt;br /&gt;&lt;/span&gt;&lt;span class="Apple-style-span"&gt;# exit&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;That's it really.To create a new repository called dummy and initialize it, you can do something like this.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;On your local machine:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;# set the new repository name&lt;br /&gt;export repo=dummy&lt;br /&gt;&lt;br /&gt;# update the gitolite conf file with your new repository&lt;br /&gt;cd ~/gitolite-admin&lt;br /&gt;echo "        repo    ${repo}" &amp;gt;&amp;gt; conf/gitolite.conf&lt;br /&gt;echo "                RW+     =   @all" &amp;gt;&amp;gt; conf/gitolite.conf&lt;br /&gt;&lt;br /&gt;# push the config to your server&lt;br /&gt;git commit -m "added new repository ${repo}" conf/gitolite.conf&lt;br /&gt;git push &lt;br /&gt;&lt;br /&gt;# make sure you cd to an existing directory!&lt;br /&gt;mkdir ~/Projects&lt;br /&gt;cd ~/Projects&lt;br /&gt;&lt;br /&gt;# pull back the new empty repository&lt;br /&gt;git clone gitserver:${repo}&lt;br /&gt;&lt;br /&gt;# go to repository and make any change&lt;br /&gt;cd ${repo}&lt;br /&gt;echo "*.pyc" &amp;gt;&amp;gt; .git/info/exclude # I use python&lt;br /&gt;touch README&lt;br /&gt;&lt;br /&gt;# do your first push back to master&lt;br /&gt;git add .&lt;br /&gt;git commit -am "repository ${repo} pushed to origin on gitserver"&lt;br /&gt;git push origin master&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;You'll be using that last code section again, so you might want to make it into a script.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Never type anything you don't understand.&amp;nbsp;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;If I've made any mistakes then please let me know.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2368086490179632165-7820963367430896811?l=terse-words.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://terse-words.blogspot.com/feeds/7820963367430896811/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://terse-words.blogspot.com/2011/06/set-up-your-own-git-repository-hosting.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/7820963367430896811'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/7820963367430896811'/><link rel='alternate' type='text/html' href='http://terse-words.blogspot.com/2011/06/set-up-your-own-git-repository-hosting.html' title='Set Up Your Own Git Repository Hosting Service in Three Minutes'/><author><name>Terse Col</name><uri>http://www.blogger.com/profile/07607140110549407614</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2368086490179632165.post-736615424246384862</id><published>2011-06-21T15:42:00.000-07:00</published><updated>2011-06-21T15:43:40.531-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='flask-script'/><category scheme='http://www.blogger.com/atom/ns#' term='flask-lesscss'/><category scheme='http://www.blogger.com/atom/ns#' term='Flas-Coffee'/><category scheme='http://www.blogger.com/atom/ns#' term='Flask'/><title type='text'>Flask-Coffee - Fill your flask with coffee</title><content type='html'>Flask-Coffee is a &lt;a href="http://flask.pocoo.org/"&gt;Flask&lt;/a&gt; extension that compiles .coffee &lt;a href="http://jashkenas.github.com/coffee-script/"&gt;CoffeeScript&lt;/a&gt; files into .js JavaScript files for you if they have changed before your app renders.&lt;br /&gt;&lt;br /&gt;This is a nice idea in development and not so nice an idea in production, so please keep that in mind.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Prerequisites&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;You will need to have to have Node.js installed with NPM and coffee-script.&lt;br /&gt;&lt;br /&gt;You can follow &lt;a href="http://terse-words.blogspot.com/2011/06/installing-nodejs-on-ubuntu-1104-and.html"&gt;the instructions in my previous article&lt;/a&gt; to install Node.js and then it's just&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint sh"&gt;npm -g install coffee-script&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Installation&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Install Flask-Coffee with &lt;a href="http://pip.openplans.org/"&gt;pip&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint sh"&gt;pip install flask-coffee&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Usage&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint sh"&gt;from flaskext.coffee import coffee&lt;br /&gt;&lt;br /&gt;coffee(app) &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This will watch your app’s static media directory and automatically render .coffee files into .js files in the same (sub)directory.&lt;br /&gt;&lt;br /&gt;The best way to incorporate Flask-Coffee into your development is as described for &lt;a href="http://sjl.bitbucket.org/flask-lesscss/"&gt;flask-lesscss&lt;/a&gt; in &lt;a href="http://terse-words.blogspot.com/2011/06/simple-flask-script-example.html"&gt;my earlier flask-script tutorial&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Contribute&lt;/span&gt;&lt;a href="http://sjl.bitbucket.org/flask-lesscss/#contribute"&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;If you want to contribute email me at the email at&amp;nbsp;&lt;a href="http://pypi.python.org/pypi/Flask-Coffee"&gt;http://pypi.python.org/pypi/Flask-Coffee&lt;/a&gt;&amp;nbsp;after checking out the code at&amp;nbsp;&lt;a href="http://bettercodes.org/projects/flask-coffee"&gt;http://bettercodes.org/projects/flask-coffee&lt;/a&gt;.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2368086490179632165-736615424246384862?l=terse-words.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://terse-words.blogspot.com/feeds/736615424246384862/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://terse-words.blogspot.com/2011/06/flask-coffee-fill-your-flask-with.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/736615424246384862'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/736615424246384862'/><link rel='alternate' type='text/html' href='http://terse-words.blogspot.com/2011/06/flask-coffee-fill-your-flask-with.html' title='Flask-Coffee - Fill your flask with coffee'/><author><name>Terse Col</name><uri>http://www.blogger.com/profile/07607140110549407614</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2368086490179632165.post-7311288759885086540</id><published>2011-06-20T04:58:00.000-07:00</published><updated>2011-06-20T05:16:51.960-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Development'/><category scheme='http://www.blogger.com/atom/ns#' term='CoffeeScript'/><title type='text'>CoffeeScript Development in 3 mintutes</title><content type='html'>&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-cAlTdbBRDic/Tf851oVttVI/AAAAAAAAAFk/gUI7uAhEIeI/s1600/coffee.jpg" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="240" src="http://3.bp.blogspot.com/-cAlTdbBRDic/Tf851oVttVI/AAAAAAAAAFk/gUI7uAhEIeI/s320/coffee.jpg" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Any obvious reference to coffee needs a picture&lt;/td&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;The idea of CoffeeScript just sounds great me. I like the idea of compiling decent JavaScript from code you can actually read. But what do you do if you have no Node.js available to compile it?&lt;br /&gt;&lt;br /&gt;Well the answer is to compile to JS at runtime. However, I had an awful time getting the right setup to get going. If you are interested in playing with CoffeeScript where Node.js is not available (I'm using it in work to show what it's capable of) then just follow these instructions.&lt;br /&gt;&lt;br /&gt;Create a directory to work in and inside that create an index.html file thus:&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint html"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;&amp;lt;html&amp;gt;&lt;br /&gt;&amp;lt;head&amp;gt;&lt;br /&gt;    &amp;lt;title&amp;gt;CoffeeScript Demo&amp;lt;/title&amp;gt;&lt;br /&gt;    &amp;lt;script data-main="scripts/requirements" &lt;br /&gt;               src="scripts/require.js"&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;/head&amp;gt;&lt;br /&gt;&amp;lt;body&amp;gt;&lt;br /&gt;    &amp;lt;h1&amp;gt;CoffeeScript Demo&amp;lt;/h1&amp;gt;&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;and a directory called 'scripts' into which you put the following.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://code.jquery.com/jquery-1.6.1.min.js"&gt;JQuery&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://requirejs.org/docs/release/0.24.0/minified/require.js"&gt;&lt;span id="goog_1220356373"&gt;&lt;/span&gt;&lt;span id="goog_1220356374"&gt;&lt;/span&gt;Require&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://github.com/jrburke/require-cs/raw/0.1.0/cs.js"&gt;CoffeeScript Plugin For Require&lt;/a&gt;&lt;/li&gt;&lt;li&gt;A file called requirements.js containing:&lt;/li&gt;&lt;/ul&gt;&lt;pre class="prettyprint js"&gt;require([&lt;br /&gt;    'scripts/jquery-1.6.1.min.js',&lt;br /&gt;    'cs', &lt;br /&gt;    'cs!app',&lt;br /&gt;]);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;And a file called app.coffee containing:&lt;/li&gt;&lt;/ul&gt;&lt;pre class="prettyprint txt"&gt;square = (x) -&amp;gt; x * x&lt;br /&gt;alert square 42&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;That's it!&lt;br /&gt;&lt;br /&gt;Now load the index.html page into your browser and the CoffeeScript code app.coffee should execute.&lt;br /&gt;&lt;br /&gt;Of course you will now have to go away and read the docs so that you know why that worked, but then so will I.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2368086490179632165-7311288759885086540?l=terse-words.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://terse-words.blogspot.com/feeds/7311288759885086540/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://terse-words.blogspot.com/2011/06/coffeescript-development-in-3-mintutes.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/7311288759885086540'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/7311288759885086540'/><link rel='alternate' type='text/html' href='http://terse-words.blogspot.com/2011/06/coffeescript-development-in-3-mintutes.html' title='CoffeeScript Development in 3 mintutes'/><author><name>Terse Col</name><uri>http://www.blogger.com/profile/07607140110549407614</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-cAlTdbBRDic/Tf851oVttVI/AAAAAAAAAFk/gUI7uAhEIeI/s72-c/coffee.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2368086490179632165.post-1269327130084857521</id><published>2011-06-15T06:30:00.000-07:00</published><updated>2011-06-15T06:30:10.162-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Authentication'/><category scheme='http://www.blogger.com/atom/ns#' term='Flask-Login'/><category scheme='http://www.blogger.com/atom/ns#' term='Security'/><category scheme='http://www.blogger.com/atom/ns#' term='Flask-Principal'/><category scheme='http://www.blogger.com/atom/ns#' term='Flask'/><category scheme='http://www.blogger.com/atom/ns#' term='Authorization'/><title type='text'>Flask Extensions For Authorization with Examples</title><content type='html'>In my opinion, there is one serious omission to Flask at the moment and that is that there is no authoritative method for authorizing users.&amp;nbsp;&lt;iframe align="right" frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="http://rcm.amazon.com/e/cm?t=coold0a-20&amp;amp;o=1&amp;amp;p=8&amp;amp;l=bpl&amp;amp;asins=1118026470&amp;amp;fc1=000000&amp;amp;IS2=1&amp;amp;lt1=_blank&amp;amp;m=amazon&amp;amp;lc1=0000FF&amp;amp;bc1=000000&amp;amp;bg1=FFFFFF&amp;amp;f=ifr" style="height: 245px; padding-right: 10px; padding-top: 5px; width: 131px;"&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;br /&gt;In a way this goes with the general ethos of micro frameworks - it isn't being forced down your throat unless you want it.&lt;br /&gt;&lt;br /&gt;However in this case I think that at least some structured 'recipes' are required to provide peer guidance, best practice or whatever you want to call it. Too often the advice is "roll your own", but I'm not sure I'd be comfortable recommending that to the inexperienced.&lt;br /&gt;&lt;br /&gt;So where are we?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Flask-Principal and Flask-Login&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;At the moment there is only one approved auth extension called Flask-Principal which takes care of authorizing different roles of user. It does not dictate what those&amp;nbsp;roles&amp;nbsp;should be and it does not force you to use any particular method to authenticate those users.&lt;br /&gt;&lt;br /&gt;A second extension called Flask-Login is currently awaiting approval, which I suspect it will soon get. This extension also takes care of authorizing users, but only understands one type of user&amp;nbsp;role, so in other words you are either a user or not. Like Flask-Principal it does not force you to use any particular method to authenticate those users.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Example Code&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The code below is sort of a basic outline that we will fill in using proper code in a moment.&lt;br /&gt;&lt;br /&gt;The User model is very silly. If you create a User by passing an id of '1' you get a User with a username of 'user1' and a password of 'user1_secret'. To help with the examples we then create users one to twenty (user1 to user20). Obviously you would normally have them stored in a database or something, but we're keeping it simple.&lt;br /&gt;&lt;br /&gt;At this stage there is nothing protecting access to the 'home' resource&amp;nbsp;and 'login' and 'logout' don't work yet either.&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint py"&gt;from flask import Flask, Response, redirect, \&lt;br /&gt;    url_for, request, session, abort&lt;br /&gt;&lt;br /&gt;app = Flask(__name__)&lt;br /&gt;&lt;br /&gt;# config&lt;br /&gt;app.config.update(&lt;br /&gt;    DEBUG = True,&lt;br /&gt;    SECRET_KEY = 'secret_xxx'&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;# middlewares etc go here&lt;br /&gt;      &lt;br /&gt;# silly user model&lt;br /&gt;class User(object):&lt;br /&gt;&lt;br /&gt;    def __init__(self, id):&lt;br /&gt;        self.id = id&lt;br /&gt;        self.name = "user" + str(id)&lt;br /&gt;        self.password = self.name + "_secret"        &lt;br /&gt;    def __repr__(self):&lt;br /&gt;        return "%d/%s/%s" % (self.id, self.name, self.password)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;# create some users with ids 1 to 20       &lt;br /&gt;users = [User(id) for id in range(1, 21)]&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;# we'd like to protect this resource&lt;br /&gt;@app.route('/')&lt;br /&gt;def home():&lt;br /&gt;    return Response("Hello World!")&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;# somewhere to login    &lt;br /&gt;@app.route('/login', methods=['GET', 'POST'])&lt;br /&gt;def login():&lt;br /&gt;    pass # this does not work yet&lt;br /&gt;&lt;br /&gt;# somewhere to logout&lt;br /&gt;@app.route("/logout")&lt;br /&gt;def logout():&lt;br /&gt;    pass # this does not work yet&lt;br /&gt;    &lt;br /&gt;        &lt;br /&gt;# handle login failed&lt;br /&gt;@app.errorhandler(401)&lt;br /&gt;def page_not_found(e):&lt;br /&gt;    return Response('Login failed')&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;@app.errorhandler(403)&lt;br /&gt;def page_not_found(e):&lt;br /&gt;    return Response('Unauthorized')&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;if __name__ == "__main__":&lt;br /&gt;    app.run()&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;a href="https://sites.google.com/site/tersewordsdownloads/downloads/flask-insecure-example.py?attredirects=0&amp;amp;d=1"&gt;Download the code!&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Flask-Principal Example&lt;iframe align="right" frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="http://rcm.amazon.com/e/cm?t=coold0a-20&amp;amp;o=1&amp;amp;p=8&amp;amp;l=bpl&amp;amp;asins=0596158106&amp;amp;fc1=000000&amp;amp;IS2=1&amp;amp;lt1=_blank&amp;amp;m=amazon&amp;amp;lc1=0000FF&amp;amp;bc1=000000&amp;amp;bg1=FFFFFF&amp;amp;f=ifr" style="align: right; height: 245px; padding-right: 10px; padding-top: 5px; width: 131px;"&gt;&lt;/iframe&gt;&lt;/span&gt;&lt;br /&gt;Now that we know how that works, or doesn't, let's look first at how flask principal might set about protecting the home resource.&lt;br /&gt;&lt;br /&gt;As I said earlier, Flask-Principal doesn't tell you what roles you need for your app. In this example I'm only using one called 'normal' which we need to tell the extension about before we tell Flask to initialize the extension:&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint py"&gt;# flask-principal&lt;br /&gt;principals = Principal()&lt;br /&gt;normal_role = RoleNeed('normal')&lt;br /&gt;normal_permission = Permission(normal_role)&lt;br /&gt;principals._init_app(app)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;After that we can protect the 'home' resource thus:&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint py"&gt;@normal_permission.require(http_exception=403)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;If your request's session doesn't have all the stuff it's asked for (ie. has not logged in) then Flask-Principal gives it a HTTP 403 (Forbidden) response which redirects it to:&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint py"&gt;@app.errorhandler(403)&lt;br /&gt;def page_not_found(e):&lt;br /&gt;    session['redirected_from'] = request.url&lt;br /&gt;    return redirect(url_for('login'))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Which, as you can see stores the URL that you wanted in the first place ('home' in this case) and then redirects you to the login page. Since by default this request is a GET, you are shown the login form and not the login process which is used for POSTs.&lt;br /&gt;&lt;br /&gt;Enter a valid&amp;nbsp;username/password combination, e.g. 'user7' and 'user7_secret' and you get logged in and sent back to the 'home' page. The login sends a signal to the extension to tell it who has logged in and congratulations you get to see the 'Hello World' message!&lt;br /&gt;&lt;br /&gt;If you enter an invalid&amp;nbsp;username/password combination&amp;nbsp;you get&amp;nbsp;served&amp;nbsp;an HTTP 401 (Unauthorized) and thus you end up in the 401 errorhandler seeing 'Login Failed'&lt;br /&gt;&lt;br /&gt;If you go to 'logout' you the code will destroy any of the relevent session information and tell you you are 'Logged Out':&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint py"&gt;@app.route("/logout")&lt;br /&gt;def logout():&lt;br /&gt;    for key in ['identity.name', 'identity.auth_type', 'redirected_from']:&lt;br /&gt;        try:&lt;br /&gt;            del session[key]&lt;br /&gt;        except:&lt;br /&gt;            pass&lt;br /&gt;    return Response('Logged out&lt;br /&gt;')&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;a href="https://sites.google.com/site/tersewordsdownloads/downloads/flask-principal-example.py?attredirects=0&amp;amp;d=1"&gt;Try out the code!&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Flask-Login Example&lt;/span&gt;&lt;br /&gt;With Flask-Login you need to tell Flask to use the extension and this time tell the extension where the login page is (in this case "login"):&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint py"&gt;# flask-login&lt;br /&gt;login_manager = LoginManager()&lt;br /&gt;login_manager.setup_app(app)&lt;br /&gt;login_manager.login_view = "login"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Secondly you have to use a mixin to create your User class. The mixin just makes some standard functions available for the User.&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint py"&gt;class User(UserMixin):&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Thirdly, you need to set up a user_loader that will load your user based on the user id:&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint py"&gt;# callback to relaad the user object        &lt;br /&gt;@login_manager.user_loader&lt;br /&gt;def load_user(userid):&lt;br /&gt;    return User(userid)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This time when you go to 'home' and you haven't yet logged in, you don't get a HTTP 403 (Forbidden), but instead get sent to the resource you defined earlier; 'login'.&lt;br /&gt;&lt;br /&gt;Login successfully and this time the login retrieves the actual User object and tells the extension using the login_user function. Again, congratulations!&lt;br /&gt;&lt;br /&gt;&lt;a href="https://sites.google.com/site/tersewordsdownloads/downloads/flask-login-example.py?attredirects=0&amp;amp;d=1"&gt;Try out the code!&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;You can work out for yourself how to store the User object in a database or datastore and how to check the passwords. There are a good ways to do both, but this is not an article about that. Should we have one in a future article?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2368086490179632165-1269327130084857521?l=terse-words.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://terse-words.blogspot.com/feeds/1269327130084857521/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://terse-words.blogspot.com/2011/06/flask-extensions-for-authorization-with.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/1269327130084857521'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/1269327130084857521'/><link rel='alternate' type='text/html' href='http://terse-words.blogspot.com/2011/06/flask-extensions-for-authorization-with.html' title='Flask Extensions For Authorization with Examples'/><author><name>Terse Col</name><uri>http://www.blogger.com/profile/07607140110549407614</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total><georss:featurename>Dunkeswell, Honiton, Devon, UK</georss:featurename><georss:point>50.8622895 -3.221804700000007</georss:point><georss:box>50.8274375 -3.259057200000007 50.897141500000004 -3.184552200000007</georss:box></entry><entry><id>tag:blogger.com,1999:blog-2368086490179632165.post-4722816564039020507</id><published>2011-06-14T04:04:00.000-07:00</published><updated>2011-06-16T07:39:50.553-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Weblayer'/><category scheme='http://www.blogger.com/atom/ns#' term='Web2py'/><category scheme='http://www.blogger.com/atom/ns#' term='Frameworks'/><category scheme='http://www.blogger.com/atom/ns#' term='Micro frameworks'/><category scheme='http://www.blogger.com/atom/ns#' term='Pyramid'/><category scheme='http://www.blogger.com/atom/ns#' term='CubicWeb'/><category scheme='http://www.blogger.com/atom/ns#' term='GAE'/><category scheme='http://www.blogger.com/atom/ns#' term='Bottle'/><category scheme='http://www.blogger.com/atom/ns#' term='Django'/><category scheme='http://www.blogger.com/atom/ns#' term='Nagare'/><category scheme='http://www.blogger.com/atom/ns#' term='GAE Framework'/><category scheme='http://www.blogger.com/atom/ns#' term='Flask'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><category scheme='http://www.blogger.com/atom/ns#' term='Tipfy'/><title type='text'>My Top Ten Python Web Frameworks</title><content type='html'>I have recently revisited all of the &lt;b&gt;Python Web Frameworks&lt;/b&gt; that I know of and re-evaluated them for use in a new project.&lt;br /&gt;&lt;br /&gt;I did this first two or three years years ago and so I imagine I will be biased by the decisions that I made then, so I think it's only fair to say that I started using &lt;b&gt;Django &lt;/b&gt;because of it's fantastic documentation and I suppose the helper scripts which help the beginner along. However, all that&amp;nbsp;&lt;a href="http://en.wikipedia.org/wiki/Convention_over_configuration"&gt;Convention over configuration&lt;/a&gt; stuff can be too much for me sometimes.&lt;br /&gt;&lt;br /&gt;I then moved onto &lt;b&gt;Tipfy &lt;/b&gt;because it slotted in so easily to &lt;b&gt;Google App Engine&lt;/b&gt; which I was using a lot at the time&amp;nbsp; and the Django framework itself was starting to be more of a hindrance than a help. &lt;br /&gt;&lt;br /&gt;One day however I stumbled upon &lt;b&gt;Bottle &lt;/b&gt;which was a revelation. Being a &lt;b&gt;&lt;i&gt;micro framework &lt;/i&gt;&lt;/b&gt;it's explicit. That is if you want to use something, you make up your mind to do so; it's not some cleverness built into the framework over which you have no obvious control. If you want to know how it works, then read the code!&lt;br /&gt;&lt;br /&gt;Finally I came to &lt;b&gt;Flask,&amp;nbsp;&lt;/b&gt;another micro framework, because I like the way it is based on &lt;b&gt;Werkzeug &lt;/b&gt;and other well trusted libraries which gives me a some peace of mind that it is supportable, and secondly because it is also explicit like Bottle. &lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.amazon.com/dp/0470138092?tag=coold0a-20&amp;amp;camp=213761&amp;amp;creative=393545&amp;amp;linkCode=bpl&amp;amp;creativeASIN=0470138092&amp;amp;adid=1QDMF2TRV60JB27Q9TWD&amp;amp;" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;" target="_blank"&gt;&lt;/a&gt;All that being said, here's my top ten:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;a href="http://wiki.python.org/moin/Flask"&gt;Flask &lt;/a&gt;- small, fast, easy to learn and built on reassuringly supported libraries. &lt;/li&gt;&lt;li&gt;&lt;a href="http://wiki.github.com/defnull/bottle"&gt;Bottle &lt;/a&gt;-  small, fast and a great tool for learning.&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.tipfy.org/"&gt;Tipfy &lt;/a&gt;- built for GAE, easy to pick up and well supported.&lt;/li&gt;&lt;li&gt;&lt;a href="http://wiki.python.org/moin/Django"&gt;Django &lt;/a&gt;- contains most of what you will ever need to build a website, well documented, but starting to bulge at the wasteline.&lt;/li&gt;&lt;li&gt; &lt;a href="http://pylonsproject.org/"&gt;Pyramid &lt;/a&gt;- the successor to Pylons, this one has great docs and great ideas. It is a framework, but you can unpick the bits you don't like.&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.cubicweb.org/"&gt;CubicWeb &lt;/a&gt;- like Django, Convention over configuration, but nice in some ways.&amp;nbsp;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.gaeframework.com/"&gt;GAE framework&lt;/a&gt; - Simple, built for GAE, and well documented.&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.web2py.com/"&gt;Web2py &lt;/a&gt;- I hate it, but love it. All that framework kinda helps, kinda hinders. Give it a little time and you can definitely pull a website together, it depends on your personality whether or not you go mad first though.&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.nagare.org/"&gt;Nagare &lt;/a&gt;- I admit I haven't built a full system with this one, but I have a feeling I will be soon. I'd rather it was a wee bit more mature though, but the libraries/concepts it's built on is all good stuff.&lt;/li&gt;&lt;li&gt;&lt;a href="http://packages.python.org/weblayer/"&gt;Weblayer &lt;/a&gt;- Another micro framework. Some good ideas here, but could do with a little love, If you are a developer looking for a worthwhile project, you should consider lending a hand.&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;For more information, please read:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://wiki.python.org/moin/WebFrameworks"&gt;http://wiki.python.org/moin/WebFrameworks&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Comparison_of_Web_application_frameworks"&gt;http://en.wikipedia.org/wiki/Comparison_of_Web_application_frameworks&lt;/a&gt; &lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2368086490179632165-4722816564039020507?l=terse-words.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://terse-words.blogspot.com/feeds/4722816564039020507/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://terse-words.blogspot.com/2011/06/top-ten-python-web-frameworks.html#comment-form' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/4722816564039020507'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/4722816564039020507'/><link rel='alternate' type='text/html' href='http://terse-words.blogspot.com/2011/06/top-ten-python-web-frameworks.html' title='My Top Ten Python Web Frameworks'/><author><name>Terse Col</name><uri>http://www.blogger.com/profile/07607140110549407614</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total><georss:featurename>Exeter, Devon, UK</georss:featurename><georss:point>50.72179999999999 -3.5336170000000493</georss:point><georss:box>50.67765649999999 -3.5931745000000492 50.765943499999985 -3.4740595000000494</georss:box></entry><entry><id>tag:blogger.com,1999:blog-2368086490179632165.post-2928725786862525833</id><published>2011-06-09T06:30:00.000-07:00</published><updated>2011-06-09T06:30:27.554-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='flask-script'/><category scheme='http://www.blogger.com/atom/ns#' term='email'/><category scheme='http://www.blogger.com/atom/ns#' term='model'/><category scheme='http://www.blogger.com/atom/ns#' term='cache'/><category scheme='http://www.blogger.com/atom/ns#' term='Flask'/><category scheme='http://www.blogger.com/atom/ns#' term='database'/><title type='text'>Let Your Imagination Run Riot On Our Flask-Script Example</title><content type='html'>In my last article in this series, "&lt;a href="http://terse-words.blogspot.com/2011/06/adding-shell-access-to-our-flask-script.html"&gt;Adding Shell Access to Our Flask-Script Example&lt;/a&gt;" I showed you how you could indeed get shell access from our script.&lt;br /&gt;&lt;br /&gt;You see the whole point of Flask-Script is that it gives you scripted access not to the application, but to the &lt;i&gt;environment&lt;/i&gt; in which the app runs. You don't actually need to be running the app, or importantly, to interfere with the app to do some task or other.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-YzS_XxRRMkU/TeSOR2XxCbI/AAAAAAAAAFI/C04i7aKohII/s1600/995000_46458615.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://3.bp.blogspot.com/-YzS_XxRRMkU/TeSOR2XxCbI/AAAAAAAAAFI/C04i7aKohII/s320/995000_46458615.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;An Example&lt;/span&gt;&lt;br /&gt;For example, lets say you want to load some data into the database model.&lt;br /&gt;&lt;br /&gt;There are three ways you could do this:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Write a script that understands your app's data model and get it to insert the data. You may be able to import the model module straight from your app, but you may not, due to dependencies etc.&lt;/li&gt;&lt;li&gt;Run the code straight from your app, possibly using an admin screen somewhere. This means designing and implementing the screens - including the obvious security requirements.&lt;/li&gt;&lt;li&gt;Use Flask-Script like this:&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;pre class="prettyprint py"&gt;from application.model import Articles&lt;br /&gt;import csv&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;@manager.command&lt;br /&gt;def ingest_csv():&lt;br /&gt;    '''read data from a csv file and ingest it into the database'''&lt;br /&gt;    reader = csv.reader(open('articles.csv'))&lt;br /&gt;    for row in reader:&lt;br /&gt;        a = Article()&lt;br /&gt;        a.init_from_csv_row(row)&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;and then;&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint sh"&gt;python manager.py ingest_csv&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Simpler I think you'll agree?&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-FPXlOM8NZg0/TfDKnxF9CHI/AAAAAAAAAFY/MfXS8tdS86g/s1600/1173624_old_time.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/-FPXlOM8NZg0/TfDKnxF9CHI/AAAAAAAAAFY/MfXS8tdS86g/s1600/1173624_old_time.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Scheduling Task&lt;/span&gt;&lt;br /&gt;There is one other huge advantage to using Flask-Script; you can run them from crontabs.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint sh"&gt;*/10 * * * * /some/path/bin/python /some/path/manager.py ingest_csv &amp;gt;&amp;gt;/tmp/ingest.log 2&amp;gt;&amp;amp;1&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Other Ideas&lt;/span&gt;&lt;br /&gt;Here are some other examples of things you might want to dovia script:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Purge old data from your database.&lt;/li&gt;&lt;li&gt;Backup data from your database.&lt;/li&gt;&lt;li&gt;Export data from your database.&lt;/li&gt;&lt;li&gt;Do anything else you want from your database!&lt;/li&gt;&lt;li&gt;Flush your caches.&lt;/li&gt;&lt;li&gt;Mail out reports.&lt;/li&gt;&lt;li&gt;Other stuff I haven't thought of. Let me know!&lt;/li&gt;&lt;/ul&gt;Okay, enough of all this, go and enjoy!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2368086490179632165-2928725786862525833?l=terse-words.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://terse-words.blogspot.com/feeds/2928725786862525833/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://terse-words.blogspot.com/2011/06/let-your-imagination-run-riot-on-our.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/2928725786862525833'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/2928725786862525833'/><link rel='alternate' type='text/html' href='http://terse-words.blogspot.com/2011/06/let-your-imagination-run-riot-on-our.html' title='Let Your Imagination Run Riot On Our Flask-Script Example'/><author><name>Terse Col</name><uri>http://www.blogger.com/profile/07607140110549407614</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-YzS_XxRRMkU/TeSOR2XxCbI/AAAAAAAAAFI/C04i7aKohII/s72-c/995000_46458615.jpg' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2368086490179632165.post-8622951482538597799</id><published>2011-06-08T12:37:00.000-07:00</published><updated>2011-06-14T04:07:08.381-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PostGIS'/><category scheme='http://www.blogger.com/atom/ns#' term='Postgres'/><title type='text'>Install Postgres/PostGIS on Ubuntu 11.04 (Natty) or Mint 11</title><content type='html'>One of my most visited entries on my old blog was "&lt;a href="http://www.cols-code-snippets.co.uk/2010/11/install-postgrespostgis-on-ubuntu.html"&gt;Install Postgres/PostGIS on Ubuntu Maverick/10.10&lt;/a&gt;". So I was keen to update what had obviously been quite a useful article. &lt;br /&gt;&lt;br /&gt;After all it was only a couple of dozen lines of code.&lt;br /&gt;&lt;br /&gt;Turns out that it's one of those things I know that will never be used again; like how to hotwire a 1972 Ford Cortina, or how to get into the Tullyglass Hotel Disco for free. &lt;br /&gt;&lt;br /&gt;Ah, for a misspent youth!&lt;br /&gt;&lt;br /&gt;What's&amp;nbsp;that? You want to know?&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint sh"&gt;sudo apt-get install postgresql-8.4-postgis&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2368086490179632165-8622951482538597799?l=terse-words.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://terse-words.blogspot.com/feeds/8622951482538597799/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://terse-words.blogspot.com/2011/06/install-postgrespostgis-on-ubuntu.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/8622951482538597799'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/8622951482538597799'/><link rel='alternate' type='text/html' href='http://terse-words.blogspot.com/2011/06/install-postgrespostgis-on-ubuntu.html' title='Install Postgres/PostGIS on Ubuntu 11.04 (Natty) or Mint 11'/><author><name>Terse Col</name><uri>http://www.blogger.com/profile/07607140110549407614</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2368086490179632165.post-6450047671366409078</id><published>2011-06-07T15:09:00.000-07:00</published><updated>2011-06-09T07:26:34.028-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='flask-script'/><category scheme='http://www.blogger.com/atom/ns#' term='Flask'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>Adding Shell Access to Our Flask-Script Example</title><content type='html'>The starting example of how you can use flask-script was given in my earlier article;&lt;br /&gt;&lt;a href="http://terse-words.blogspot.com/2011/06/simple-flask-script-example.html"&gt;A Simple Flask-Script Example&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;div&gt;Next thing we are going to add is the ability to run a shell which that shares your applications environment. You need to decide what you ant to import and put it in the &lt;i&gt;shell_context&lt;/i&gt; function. Call it whatever you want, but it has to return a dict with your context items inside. To keep it simple I just import the app itself. The lines you need to change are:&lt;/div&gt;&lt;br /&gt;&lt;pre class="prettyprint py"&gt;from flaskext.script import Manager, Server, Shell&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;and &lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint py"&gt;def shell_context():&lt;br /&gt;    return dict(app=app)            &lt;br /&gt;            &lt;br /&gt;if __name__ == "__main__":&lt;br /&gt;    manager.add_command('dev', DevServer())&lt;br /&gt;    manager.add_command('test', Test())&lt;br /&gt;    manager.add_command('zen', ZenTest())&lt;br /&gt;    manager.add_command('shell', Shell(make_context=shell_context))&lt;br /&gt;    manager.run()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;now test it:&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint sh"&gt;python manager.py shell&lt;br /&gt;&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; app.debug&lt;br /&gt;True&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; app.logger&lt;br /&gt;&lt;flask.logging.debuglogger 0x2ee3518="" at="" instance=""&gt;&amp;lt;flask.logging.DebugLogger instance at 0x2ee3518&amp;gt;&lt;br /&gt;&lt;/flask.logging.debuglogger&gt;&lt;/pre&gt;&lt;br /&gt;and so on.&lt;br /&gt;&lt;br /&gt;There's one final installment to follow - &lt;a href="http://terse-words.blogspot.com/2011/06/let-your-imagination-run-riot-on-our.html"&gt;Let Your Imagination Run Riot On Our Flask-Script Example &lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The full listing for what we did here is below:&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint py"&gt;from flaskext.script import Manager, Server, Shell&lt;br /&gt;from flaskext.zen import Test, ZenTest&lt;br /&gt;import application&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;app = application.create_app()&lt;br /&gt;&lt;br /&gt;manager = Manager(app)&lt;br /&gt;&lt;br /&gt;class DevServer(Server):&lt;br /&gt;    &lt;br /&gt;    def handle(self, app, host, port, use_debugger, use_reloader):&lt;br /&gt;        try:&lt;br /&gt;            from flaskext.lesscss import lesscss&lt;br /&gt;            lesscss(app)&lt;br /&gt;        except: pass&lt;br /&gt;&lt;br /&gt;        app.run(host=host,&lt;br /&gt;            port=port,&lt;br /&gt;            debug=use_debugger,&lt;br /&gt;            use_debugger=use_debugger,&lt;br /&gt;            use_reloader=use_reloader,&lt;br /&gt;            **self.server_options)&lt;br /&gt;    &lt;br /&gt;def shell_context():&lt;br /&gt;    return dict(app=app)            &lt;br /&gt;            &lt;br /&gt;if __name__ == "__main__":&lt;br /&gt;    manager.add_command('dev', DevServer())&lt;br /&gt;    manager.add_command('test', Test())&lt;br /&gt;    manager.add_command('zen', ZenTest())&lt;br /&gt;    manager.add_command('shell', Shell(make_context=shell_context))&lt;br /&gt;    manager.run()&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2368086490179632165-6450047671366409078?l=terse-words.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://terse-words.blogspot.com/feeds/6450047671366409078/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://terse-words.blogspot.com/2011/06/adding-shell-access-to-our-flask-script.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/6450047671366409078'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/6450047671366409078'/><link rel='alternate' type='text/html' href='http://terse-words.blogspot.com/2011/06/adding-shell-access-to-our-flask-script.html' title='Adding Shell Access to Our Flask-Script Example'/><author><name>Terse Col</name><uri>http://www.blogger.com/profile/07607140110549407614</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2368086490179632165.post-3087188059998255139</id><published>2011-06-07T09:25:00.000-07:00</published><updated>2011-07-11T12:53:28.624-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='flask-lesscss'/><category scheme='http://www.blogger.com/atom/ns#' term='Flask'/><category scheme='http://www.blogger.com/atom/ns#' term='NPM'/><category scheme='http://www.blogger.com/atom/ns#' term='Node.js'/><title type='text'>Installing Node.js on Ubuntu 11.04 and Mint 11</title><content type='html'>Installing Node.js is simple and let's you get play with all the Javascript goodness that it offers.&lt;br /&gt;&lt;br /&gt;Another reason to install it is to use &lt;a href="http://sjl.bitbucket.org/flask-lesscss/"&gt;Flask-CSS&lt;/a&gt; (and hence lesscss) which &lt;a href="http://terse-words.blogspot.com/2011/06/install-git-pip-and-virtualenv-and.html"&gt;I mentioned in my last article&lt;/a&gt;, so I thought I'd better cover that now.&lt;br /&gt;&lt;br /&gt;Let's install it in our home directory:&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint sh"&gt;cd ~&lt;br /&gt;rm -fr node # in case this is a fresh install&lt;br /&gt;&lt;br /&gt;sudo apt-get install -y g++ curl libssl-dev apache2-utils git-core&lt;br /&gt;wget http://nodejs.org/dist/node-v0.4.9.tar.gz&lt;br /&gt;tar xfz http://nodejs.org/dist/node-v0.4.9.tar.gz&lt;br /&gt;cd node-v0.4.9 &amp;amp;&amp;amp; ./configure &lt;br /&gt;# or the bleeding edge version&lt;br /&gt;# git clone git://github.com/joyent/node.git &lt;br /&gt;# cd node &amp;amp;&amp;amp; ./configure &lt;br /&gt;make &lt;br /&gt;sudo make install&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;and finally you need to add the following to your ~/.bashrc file:&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint sh"&gt;export PATH="$HOME/node/bin:$PATH"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Finally install NPM (Node Package Manager):&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint sh"&gt;source ~/.bashrc&lt;br /&gt;curl http://npmjs.org/install.sh | sudo sh&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Simples!&lt;br /&gt;&lt;br /&gt;Thanks to:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;div style="margin: 0px;"&gt;&lt;a href="http://thinkdevcode.wordpress.com/2011/05/14/installing-node-js-on-ubuntu-11-04-natty-narwhal"&gt;http://thinkdevcode.wordpress.com/2011/05/14/installing-node-js-on-ubuntu-11-04-natty-narwhal&lt;/a&gt;&amp;nbsp;&lt;/div&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2368086490179632165-3087188059998255139?l=terse-words.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://terse-words.blogspot.com/feeds/3087188059998255139/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://terse-words.blogspot.com/2011/06/installing-nodejs-on-ubuntu-1104-and.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/3087188059998255139'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/3087188059998255139'/><link rel='alternate' type='text/html' href='http://terse-words.blogspot.com/2011/06/installing-nodejs-on-ubuntu-1104-and.html' title='Installing Node.js on Ubuntu 11.04 and Mint 11'/><author><name>Terse Col</name><uri>http://www.blogger.com/profile/07607140110549407614</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2368086490179632165.post-5405447492573966500</id><published>2011-06-07T06:01:00.000-07:00</published><updated>2011-06-08T23:38:31.721-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='flask-script'/><category scheme='http://www.blogger.com/atom/ns#' term='flask-lesscss'/><category scheme='http://www.blogger.com/atom/ns#' term='flask-zen'/><category scheme='http://www.blogger.com/atom/ns#' term='Flask'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>A Simple Flask-Script Example</title><content type='html'>Here is a simple flask-script example that you can use to start your application in development mode, or test modes.&lt;br /&gt;&lt;br /&gt;I know that you can&lt;a href="http://flask.pocoo.org/docs/quickstart/"&gt; do that without flask-script&lt;/a&gt;, but the point of this script is that you can do so much more from this starting point. Notice for example that I'm trying to load &lt;a href="http://sjl.bitbucket.org/flask-lesscss/"&gt;flask-lesscss&lt;/a&gt; and execute it (which won't work, but won't fail if you don't have lesscss installed.)&lt;br /&gt;&lt;br /&gt;To get the application (in the 'application' module) running you just need to do one of the following:&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint sh"&gt;python manager.py dev&lt;br /&gt;python manager.py test&lt;br /&gt;python manager.py zen&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I show how to add shell access in &lt;a href="http://terse-words.blogspot.com/2011/06/adding-shell-access-to-our-flask-script.html"&gt;the second article in this series&lt;/a&gt;. Meanwhile why not let us see what you have in your manager script?&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint py"&gt;from flaskext.script import Manager, Server&lt;br /&gt;from flaskext.zen import Test, ZenTest&lt;br /&gt;import application&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;app = application.create_app()&lt;br /&gt;&lt;br /&gt;manager = Manager(app)&lt;br /&gt;&lt;br /&gt;class DevServer(Server):&lt;br /&gt;    &lt;br /&gt;    def handle(self, app, host, port, use_debugger, use_reloader):&lt;br /&gt;        try:&lt;br /&gt;            from flaskext.lesscss import lesscss&lt;br /&gt;            lesscss(app)&lt;br /&gt;        except: pass&lt;br /&gt;&lt;br /&gt;        app.run(host=host,&lt;br /&gt;            port=port,&lt;br /&gt;            debug=use_debugger,&lt;br /&gt;            use_debugger=use_debugger,&lt;br /&gt;            use_reloader=use_reloader,&lt;br /&gt;            **self.server_options)&lt;br /&gt;            &lt;br /&gt;            &lt;br /&gt;if __name__ == "__main__":&lt;br /&gt;    manager.add_command("dev", DevServer())&lt;br /&gt;    manager.add_command('test', Test())&lt;br /&gt;    manager.add_command('zen', ZenTest())&lt;br /&gt;    manager.run()&lt;br /&gt;    &lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2368086490179632165-5405447492573966500?l=terse-words.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://terse-words.blogspot.com/feeds/5405447492573966500/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://terse-words.blogspot.com/2011/06/simple-flask-script-example.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/5405447492573966500'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/5405447492573966500'/><link rel='alternate' type='text/html' href='http://terse-words.blogspot.com/2011/06/simple-flask-script-example.html' title='A Simple Flask-Script Example'/><author><name>Terse Col</name><uri>http://www.blogger.com/profile/07607140110549407614</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2368086490179632165.post-112613719252885554</id><published>2011-06-06T22:46:00.000-07:00</published><updated>2011-06-21T14:56:07.800-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Git'/><category scheme='http://www.blogger.com/atom/ns#' term='Pip and VirtualEnv'/><category scheme='http://www.blogger.com/atom/ns#' term='VirtualEnvWrapper'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>Install Git, Pip and VirtualEnv and VirtualEnvWrapper on Ubuntu in a Minute</title><content type='html'>From a terminal, type:&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint sh"&gt;sudo apt-get install git python-setuptools&lt;br /&gt;sudo easy_install pip&lt;br /&gt;sudo pip install virtualenv virtualenvwrapper&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now, you may want to set some defaults in your ~/.bashrc. My relevant entries look like this:&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint sh"&gt;export WORKON_HOME=$HOME/Projects&lt;br /&gt;export VIRTUALENVWRAPPER_HOOK_DIR=$HOME/.virtualenvs&lt;br /&gt;export VIRTUALENVWRAPPER_LOG_DIR=$HOME/.virtualenvs&lt;br /&gt;export VIRTUALENVWRAPPER_VIRTUALENV_ARGS='--no-site-packages --distribute'&lt;br /&gt;source /usr/local/bin/virtualenvwrapper.sh&lt;br /&gt;&lt;br /&gt;git config --global user.name "Terse Col"&lt;br /&gt;git config --global user.email myemail@gmail.com&lt;br /&gt;git config --global http.sslVerify false&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now away you go:&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint sh"&gt;mkdir $HOME/.virtualenvs&lt;br /&gt;source $HOME/.bashrc&lt;br /&gt;mkvirtualenv mynewproject &lt;br /&gt;cdvirtualenv&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2368086490179632165-112613719252885554?l=terse-words.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://terse-words.blogspot.com/feeds/112613719252885554/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://terse-words.blogspot.com/2011/06/install-git-pip-and-virtualenv-and.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/112613719252885554'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/112613719252885554'/><link rel='alternate' type='text/html' href='http://terse-words.blogspot.com/2011/06/install-git-pip-and-virtualenv-and.html' title='Install Git, Pip and VirtualEnv and VirtualEnvWrapper on Ubuntu in a Minute'/><author><name>Terse Col</name><uri>http://www.blogger.com/profile/07607140110549407614</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2368086490179632165.post-7765746724849522677</id><published>2011-06-06T15:58:00.000-07:00</published><updated>2011-06-06T15:58:06.520-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Pidgin'/><category scheme='http://www.blogger.com/atom/ns#' term='Facebook'/><category scheme='http://www.blogger.com/atom/ns#' term='Twitter'/><category scheme='http://www.blogger.com/atom/ns#' term='IM'/><title type='text'>Use Twitter and Facebook with Ubuntu 11.04 (Natty) or Mint 11</title><content type='html'>Ubuntu's&amp;nbsp;preferred&amp;nbsp;Internet&amp;nbsp;Messenger is not Pidgin which with a little love can happily act as your Twitter and Facebook&amp;nbsp;&amp;nbsp;messenger/client.&lt;br /&gt;&lt;br /&gt;You want to install the pidgin-microblog package which I think used to be called purple-pidgin:&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint sh"&gt;sudo apt-get install pidgin-microblog&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Strictly, Facebook doesn't need this, but it makes the experience nicer.&lt;br /&gt;&lt;br /&gt;Now you want to start up Pidgin and do "Accounts/Manage Accounts" (or CTRL+a).&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Add Twitter&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;"Add" (or ALT+a) then the protocol should be "TwitterIM"&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-GRNQ-lwcNvM/Te1YRpbciJI/AAAAAAAAAFM/auRxfwKQphM/s1600/addtwitter.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="242" src="http://2.bp.blogspot.com/-GRNQ-lwcNvM/Te1YRpbciJI/AAAAAAAAAFM/auRxfwKQphM/s320/addtwitter.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;and then "add and that's it"&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Add Facebook&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Facebook is almost the same, EXCEPT that you may or not actually know your Facebook username if you, like me have always used your email address and password.&lt;br /&gt;&lt;br /&gt;You can find it at Facebook, in the top right hand corner there's drop down called "Account" then "Account Settings/Settings/Username" which will show you what it is.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-j-TvQrM830k/Te1Z-sYH1wI/AAAAAAAAAFQ/XxqELg02ntg/s1600/fbacct.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="57" src="http://1.bp.blogspot.com/-j-TvQrM830k/Te1Z-sYH1wI/AAAAAAAAAFQ/XxqELg02ntg/s320/fbacct.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;Then back in Pidgin&amp;nbsp;do "Accounts/Manage Accounts" (or CTRL+a)&amp;nbsp;"Add" (or ALT+a) then the protocol should be "Facebook (XMPP)" and enter your details:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-Y9BQhvd_O_0/Te1bEFdASqI/AAAAAAAAAFU/37kJ3XEjteE/s1600/fba.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="http://1.bp.blogspot.com/-Y9BQhvd_O_0/Te1bEFdASqI/AAAAAAAAAFU/37kJ3XEjteE/s320/fba.png" width="219" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Note the Resource = Pidgin entry.&lt;br /&gt;&lt;br /&gt;Have fun and please comment on any problems you come&amp;nbsp;across.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2368086490179632165-7765746724849522677?l=terse-words.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://terse-words.blogspot.com/feeds/7765746724849522677/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://terse-words.blogspot.com/2011/06/use-twitter-and-facebook-with-ubuntu.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/7765746724849522677'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/7765746724849522677'/><link rel='alternate' type='text/html' href='http://terse-words.blogspot.com/2011/06/use-twitter-and-facebook-with-ubuntu.html' title='Use Twitter and Facebook with Ubuntu 11.04 (Natty) or Mint 11'/><author><name>Terse Col</name><uri>http://www.blogger.com/profile/07607140110549407614</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-GRNQ-lwcNvM/Te1YRpbciJI/AAAAAAAAAFM/auRxfwKQphM/s72-c/addtwitter.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2368086490179632165.post-3933844656768313409</id><published>2011-06-01T03:56:00.000-07:00</published><updated>2011-06-06T15:59:58.128-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Git'/><category scheme='http://www.blogger.com/atom/ns#' term='Repositories'/><title type='text'>A Review of Free Code Repositories</title><content type='html'>In this article, I’m going to assume you are part of a *One Sized Team*, because there are loads of alternatives and I’m trying to keep the word count at a reasonable level. If you don’t fit that outline then you can still read on because most of the available offerings also have options that might well be right for you, but at a small monthly cost. I cover these in my article on *Code Repositories for Fun Sized Teams*.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-HuRpWHpQNp0/TeSKfgvALNI/AAAAAAAAAFA/gyDBf3fb6wg/s1600/324180_2445.jpg" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="240" src="http://3.bp.blogspot.com/-HuRpWHpQNp0/TeSKfgvALNI/AAAAAAAAAFA/gyDBf3fb6wg/s320/324180_2445.jpg" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Where to store your code?&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;So you've got some code and you need somewhere to put it so that it won't get lost when someone steals your laptop.&lt;br /&gt;&lt;br /&gt;Well there are options:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Copy it to a USB drive&lt;/li&gt;&lt;li&gt;Upload the folder to &lt;a href="http://docs.google.com/"&gt;Google Docs&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Email it to yourself&lt;/li&gt;&lt;li&gt;Paste it into &lt;a href="http://pastebin.com/"&gt;Pastebin&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Well I know that I have done of all of these things at times and that’s just fine for snippets of code. With bigger bits of code you’ll need something a bit cleverer. Something that let’s you keep track of changes. A Code Repository.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Assembla&lt;/span&gt;&lt;br /&gt;&lt;a href="http://www.google.co.uk/url?sa=t&amp;amp;source=web&amp;amp;cd=1&amp;amp;ved=0CB0QFjAA&amp;amp;url=http%3A%2F%2Fwww.assembla.com%2F&amp;amp;rct=j&amp;amp;q=Assembla&amp;amp;ei=VtTkTfOMDsyXhQetgozzBw&amp;amp;usg=AFQjCNEEJZiAFnf7lkvoJFj5ylwa8lyxXg&amp;amp;sig2=GFkMKDi7Jts0mJsAjJh2XA&amp;amp;cad=rja"&gt;Assembla&lt;/a&gt; offers one free private Git or Subversion repository (which they call a space) although you have to find it because they'd rather you took a paid for option. You can find the free offerings at &lt;a href="https://www.assembla.com/free"&gt;https://www.assembla.com/free&lt;/a&gt;. You are allowed as many public spaces as you want. The Git&amp;nbsp; implementation uses &lt;a href="http://terse-words.blogspot.com/2011/05/what-smart-git.html"&gt;Git over ssh&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Also be aware that they automatically throw in the free trial additions which is fair enough, but you can drop these extras immediately if want and just get used to the free set of tools which include you're storage space and a ticketing system.&lt;br /&gt;&lt;br /&gt;They also provide nice clear instructions on how to get going with setting up your repository, although putting your stuff under 'start' in their menu system confused me because I expected it to be under 'Home' or 'Your spaces' or something similar.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Berlios&lt;/span&gt;&lt;br /&gt;&lt;a href="http://www.berlios.de/"&gt;Berlios &lt;/a&gt;offer Git and Subversion hosting (and other tools) for proper grown up Open Source projects. Too much hassle for me, which is probably their plan. Looks much like SourceForge. Have a read at the &lt;a href="http://en.wikipedia.org/wiki/BerliOS"&gt;Wikipedia entry&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Bettercodes&lt;/span&gt;&lt;br /&gt;&lt;a href="http://bettercodes.org/"&gt;Bettercodes&lt;/a&gt; is rather cool for a number of reasons. Firstly, they allow you multiple projects each with it's own Subversion or Git (&lt;a href="http://terse-words.blogspot.com/2011/05/what-smart-git.html"&gt;Smart HTTP&lt;/a&gt;) repository. You can either make your code public, private of hidden and also invite others to work on your projects. You also get milestones and tasks and flat file storage. One word of caution; this site is in beta and although the repository stuff worked fine, there are definitely some teething problems. There's no word yet of a pricing plan, so get on there and give them some feedback.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Bitbucket&lt;/span&gt;&lt;br /&gt;&lt;a href="https://bitbucket.org/"&gt;Bitbucket&lt;/a&gt; offers multiple, free, private project repositories with wikis and issue tracking. It's easy to use and reassuringly swish. &lt;br /&gt;&lt;br /&gt;My only issue is that it only offers Mercurial repositories and I much prefer Git. That being said, let me just repeat. Bitbcket offers multiple, free, private project repositories with wikis and issue tracking."&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Codeplex&lt;/span&gt;&lt;br /&gt;&lt;a href="http://www.codeplex.com/"&gt;Codeplex &lt;/a&gt;is Microsoft's version of proper grown up Open Source projects. Free for Open Source stuff and uses Mercurial or Subversion. Again, like Berlios,too much hassle for me. &lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Fedora Hosted&lt;/span&gt;&lt;br /&gt;"&lt;a href="https://fedorahosted.org/"&gt;Fedora Hosted&lt;/a&gt; is a project sponsored by the Fedora Project to allow upstream developers to host their code and collaborate online." See Berlios, Codeplex and grown ups. Not for me at this stage.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;GitHub&lt;/span&gt;&lt;br /&gt;&lt;a href="https://github.com/"&gt;GitHub&lt;/a&gt; is the most famous Git repository out there. Free plans are all public so other people will be able to see your code, but the interface, instructions etc are lovely and there's a nice repository explorer. Only Git (&lt;a href="http://terse-words.blogspot.com/2011/05/what-smart-git.html"&gt;over ssh&lt;/a&gt;) is available.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Gitorious&lt;/span&gt;&lt;br /&gt;Again, like GitHub, &lt;a href="http://gitorious.org/"&gt;Gitorious&lt;/a&gt; is&amp;nbsp;an attractive and easy to use site. Repositories are required to be under an open source licence (not just public) which may or may not suit your purposes. Only Git (&lt;a href="http://terse-words.blogspot.com/2011/05/what-smart-git.html"&gt;over ssh&lt;/a&gt;) is available.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;GNU Savannah&lt;/span&gt;&lt;br /&gt;&lt;a href="http://savannah.gnu.org/"&gt;Savannah&lt;/a&gt; is another site for grown ups. This time focusing on free software projects (hence GNU). The rules here are particularly strictly enforced and you aren't even allowed to utilize non-free formats in your code. They provide repositories in CVS, GNU arch, Subversion, Git, Mercurial, Bazaar which is quite astonishing and there are loads of extra tools such as mailing lists and bug tracking etc. Looks like SourceForge. Don't get me wrong, this is a mighty site, but it doesn't suit everybody's requirements.&lt;br /&gt;&lt;br /&gt;&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-YzS_XxRRMkU/TeSOR2XxCbI/AAAAAAAAAFI/C04i7aKohII/s1600/995000_46458615.jpg" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="240" src="http://3.bp.blogspot.com/-YzS_XxRRMkU/TeSOR2XxCbI/AAAAAAAAAFI/C04i7aKohII/s320/995000_46458615.jpg" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Is your's an Open Source Project?&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;span style="font-size: large;"&gt;Google Code&lt;/span&gt;&lt;br /&gt;The sheer number of Google tools that integrate into &lt;a href="http://http%3B//code.google.com"&gt;this site&lt;/a&gt; must make it tempting for anyone. It's really useful, but as obvious as the advantages are, I'm going to mention a couple negative points here, but please take them in the context of an excellent site. &lt;br /&gt;&lt;br /&gt;Firstly it only offers Mercurial and Subversion code repositories. These are perfectly good, but I still prefer Git.&lt;br /&gt;&lt;br /&gt;Secondly projects have to be Open Source. This is not so different from lots of other sites mentioned here, but since Google offers almost all it's tools freely, including Gigs of space for email, sites, docs etc, I don't really understand why they don't offer a few megabytes for private code repositories. Any Google guys out there?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;JavaForge&lt;/span&gt;&lt;br /&gt;&lt;a href="http://javaforge.com/"&gt;JavaForge&lt;/a&gt; looks excellent and the number of tools is impressive (" Web hosting, Document Management, Wiki, Forum, Online chat, Issue tracking integrated with optional Git, Mercurial or Subversion revision control"), but in short I don't do Java as a hobby and this is definitely a Java site. The Open Source rule applies. Java for grown ups.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;LaunchPad&lt;/span&gt;&lt;br /&gt;I haven't used &lt;a href="http://launchpad.net/"&gt;LaunchPad&lt;/a&gt;, but it looks really rather useful. Firstly it's only for Open Source projects (for which it is free), and secondly it uses Bazaar as it's version control system. If you can work with those then I think you should have a good hard look at this offering as it offers stuff like Bug Tracking, Mailing Lists, Teams, FAQs, Code Review and more. &lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;ProjectKenai&lt;/span&gt;&lt;br /&gt;&lt;a href="http://projectkenai.com/"&gt;ProjectKenai&lt;/a&gt; is now owned by Oracle and is being closed/shifted/shut down.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;SourceForge&lt;/span&gt;&lt;br /&gt;The daddy of them all, &lt;a href="http://sourceforge.net/"&gt;SourceForge&lt;/a&gt; has some great statistics. I looked just now and it claims to be hosting 294,229 projects and had 3.8 million downloads today. If you don't mind people downloading your code for free or with an Open Source license, you can host it here. It offers all the version control systems already mentioned (and good old CVS) and gives you room for WIKI, files and other niceties.&lt;br /&gt;&lt;br /&gt;Surely there's some kudos in just having a SourceForge Project. You could print your own t-shirts!&lt;br /&gt;&lt;br /&gt;Anyway, don't forget about SourceForge, there's a reason the other grown up sites tend to emulate it.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Finally&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Have I missed anything? Please ley me know.&lt;br /&gt;&lt;br /&gt;There's some other information on wikipedia:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Comparison_of_free_software_hosting_facilities"&gt;http://en.wikipedia.org/wiki/Comparison_of_free_software_hosting_facilities&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2368086490179632165-3933844656768313409?l=terse-words.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://terse-words.blogspot.com/feeds/3933844656768313409/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://terse-words.blogspot.com/2011/06/review-of-free-code-repositories.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/3933844656768313409'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/3933844656768313409'/><link rel='alternate' type='text/html' href='http://terse-words.blogspot.com/2011/06/review-of-free-code-repositories.html' title='A Review of Free Code Repositories'/><author><name>Terse Col</name><uri>http://www.blogger.com/profile/07607140110549407614</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-HuRpWHpQNp0/TeSKfgvALNI/AAAAAAAAAFA/gyDBf3fb6wg/s72-c/324180_2445.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2368086490179632165.post-6770207728514587236</id><published>2011-05-31T05:29:00.000-07:00</published><updated>2011-06-06T15:59:32.260-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Git'/><category scheme='http://www.blogger.com/atom/ns#' term='Smart HTTP'/><title type='text'>What a Smart Git</title><content type='html'>This article is a primer on Git protocols so that you get to grips with what specific Git repository providers are offering. I'll cover Code Repositories in &lt;a href="http://terse-words.blogspot.com/2011/06/review-of-free-code-repositories.html"&gt;a follow up article&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Traditionally Git lets you communicate with the Git Server (Repository) via four protocols:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Local (file system)&lt;/li&gt;&lt;li&gt;Secure Shell (SSH)&lt;/li&gt;&lt;li&gt;Git&lt;/li&gt;&lt;li&gt;Dumb HTTP&lt;/li&gt;&lt;/ul&gt;Local is probably little used because after all what's the point of having a repository for your code&amp;nbsp; on your hard disk if you're hard disk crashes, or your laptop gets stolen.&lt;br /&gt;&lt;br /&gt;SSH and Git protocols worked just fine because they could talk to the server and get things done efficiently.&lt;br /&gt;&lt;br /&gt;Dumb HTTP was a bit of a bodge because it could not be used to talk to the server and things were very inefficient (see the references below).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;So, What's The Problem?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Firewalls, especially in the workplace, just hate it when people try to use anything except the standard ports. You know, HTTP, HTTPS, SMTP and after that they get sulky. Maybe, you'll be allowed to use FTP, but certainly not port 9418 (Git) or 22 (SSH).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Smart HTTP&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The Smart HTTP protocol is really still just HTTP, but it's the server side that got smarter. Since Git version 1.6.6, Git servers can communicate with the client in a much smarter way using HTTP which makes it just as efficient as SSH or Git protocols AND allowing us to use Git anywhere we can browse the Internet; so long as the repository provider has things set up to use Smart HTTP.&lt;br /&gt;&lt;br /&gt;If they aren't now, they soon will be.&lt;br /&gt;&lt;br /&gt;References:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://progit.org/2010/03/04/smart-http.html%20"&gt;http://progit.org/2010/03/04/smart-http.html &lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://progit.org/book/ch4-1.html"&gt;http://progit.org/book/ch4-1.html&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2368086490179632165-6770207728514587236?l=terse-words.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://terse-words.blogspot.com/feeds/6770207728514587236/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://terse-words.blogspot.com/2011/05/what-smart-git.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/6770207728514587236'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2368086490179632165/posts/default/6770207728514587236'/><link rel='alternate' type='text/html' href='http://terse-words.blogspot.com/2011/05/what-smart-git.html' title='What a Smart Git'/><author><name>Terse Col</name><uri>http://www.blogger.com/profile/07607140110549407614</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
