<?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:blogger='http://schemas.google.com/blogger/2008' 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-8383226675188308439</id><updated>2024-03-13T01:48:38.223+00:00</updated><category term="ruby"/><category term="esper"/><category term="git"/><category term="rails"/><category term="rvm"/><category term="android"/><category term="backups"/><category term="ceph"/><category term="erlang"/><category term="gems"/><category term="heroku"/><category term="jruby"/><category term="kvm"/><category term="mac"/><category term="newbie"/><category term="open source"/><category term="operating systems"/><category term="programming"/><category term="qemu"/><category term="torquebox"/><category term="travis-ci"/><category term="yaml"/><category term="zsh"/><title type='text'>Ken&#39;s Blog</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://blog.bob.sh/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8383226675188308439/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://blog.bob.sh/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Ken Barber</name><uri>http://www.blogger.com/profile/15151872789024373679</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>22</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-8383226675188308439.post-8433523797128391026</id><published>2012-12-22T01:38:00.002+00:00</published><updated>2013-01-05T20:25:30.580+00:00</updated><title type='text'>Double buffering with HTML 5 Canvas</title><content type='html'>A neat trick with the HTML 5 canvas element in JavaScript is to use a second canvas to draw your canvas of screen, and flip it to a main canvas (examples include JQuery):&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;background-color: white; font-family: Courier New, Courier, monospace;&quot;&gt;/* Prepare your canvas */&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: white; font-family: Courier New, Courier, monospace;&quot;&gt;mainCanvas = $(&#39;#myCanvas&#39;);&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: white; font-family: Courier New, Courier, monospace;&quot;&gt;offscreenCanvas = document.createElement(&#39;canvas&#39;);&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: white;&quot;&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;/* Make sure your offscreen size matches your on screen&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: white;&quot;&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp;* size&lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp;*/&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: white; font-family: Courier New, Courier, monospace;&quot;&gt;offscreenCanvas.width = mainCanvas.width;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: white; font-family: Courier New, Courier, monospace;&quot;&gt;offscreenCanvas.height = mainCanvas.height;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: white;&quot;&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;/* Do some drawing on the offscreen canvas */&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: white; font-family: Courier New, Courier, monospace;&quot;&gt;ctxOffscreen = offscreenCanvas.getContext(&#39;2d&#39;);&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: white; font-family: Courier New, Courier, monospace;&quot;&gt;ctxOffscreen.strokeRect(0, 0, 10, 10);&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: white;&quot;&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;/* Now flip the offscreen canvas to the onscreen&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: white; font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp;* one */&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: white; font-family: Courier New, Courier, monospace;&quot;&gt;ctxMain = mainCanvas.getContext(&#39;2d&#39;);&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: white; font-family: Courier New, Courier, monospace;&quot;&gt;ctxMain.drawImage(offscreenCanvas, 0, 0);&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
And then your done. Whats nice about this, is its a good technique for creating flicker-reduced animations so you can prepare your next screen and &#39;flip&#39; it when ready. The actually copy is done in hardware in most browsers so its quite performant.&lt;br /&gt;
&lt;br /&gt;
Whats really nice about this concept, is that one can use &#39;drawImage&#39; to overlay multiple offscreen canvases onto a single canvas. Combined with the use of alphas (transparency) you can create layers to a scene at separate stages and combine them at &#39;paint&#39; time to be displayed on the onscreen canvas. Quite cool really.&lt;br /&gt;
&lt;br /&gt;
Another technique I&#39;ve heard about but never really used is to prepare 2 canvases and change the visibility:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;background-color: white; font-family: Courier New, Courier, monospace;&quot;&gt;/* Lets presume you already have two canvases with&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: white;&quot;&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp;* absolute layouts in the same place&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: white; font-family: Courier New, Courier, monospace;&quot;&gt;firstCanvas = $(&#39;#firstCanvas&#39;);&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: white; font-family: Courier New, Courier, monospace;&quot;&gt;firstCanvas.css(&#39;display&#39;, &#39;block&#39;);&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: white; font-family: Courier New, Courier, monospace;&quot;&gt;secondCanvas = $(&#39;#secondCanvas&#39;);&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: white; font-family: Courier New, Courier, monospace;&quot;&gt;secondCanvas.css(&#39;display&#39;, &#39;none&#39;); // hidden like a ninja&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: white;&quot;&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;/* Do some drawing on the &#39;hidden&#39; canvas */&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: white; font-family: Courier New, Courier, monospace;&quot;&gt;ctxSecond = firstCanvas.getContext(&#39;2d&#39;);&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: white; font-family: Courier New, Courier, monospace;&quot;&gt;ctxSecond.strokeRect(0, 0, 10, 10);&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: white;&quot;&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;/* Now flip the two canvases, display one and hide the&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: white;&quot;&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp;* other&lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp;*/&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: white; font-family: Courier New, Courier, monospace;&quot;&gt;firstCanvas.css(&#39;display&#39;, &#39;none&#39;);&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: white; font-family: Courier New, Courier, monospace;&quot;&gt;secondCanvas.css(&#39;display&#39;, &#39;block&#39;);&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: #cccccc; font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
I can&#39;t speak for the performance gain of this second methodology, but I can see it might have its advantages. Most conversations around double buffering suggest a technique like this, so its probably worth investigating.</content><link rel='replies' type='application/atom+xml' href='http://blog.bob.sh/feeds/8433523797128391026/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.bob.sh/2012/12/double-buffering-with-html-5-canvas.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8383226675188308439/posts/default/8433523797128391026'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8383226675188308439/posts/default/8433523797128391026'/><link rel='alternate' type='text/html' href='http://blog.bob.sh/2012/12/double-buffering-with-html-5-canvas.html' title='Double buffering with HTML 5 Canvas'/><author><name>Ken Barber</name><uri>http://www.blogger.com/profile/15151872789024373679</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8383226675188308439.post-8766169392485245325</id><published>2012-06-29T16:40:00.002+01:00</published><updated>2012-07-03T15:59:32.655+01:00</updated><title type='text'>How I got involved with Configuration Management</title><content type='html'>I sometimes speak to people publicly for my company, and I tell them I&#39;ve been involved in Configuration Management for 13 years. Obviously Puppet has not been around for that long, and a lot of people ask me if it was cfEngine or something else I used, well - it was bespoke - and I want to talk a little bit about that.&lt;br /&gt;
&lt;br /&gt;
In fact if someone was to look at my Linked in account, they would realise that the length of my administration experience is roughly that - 13 years. This is because there was never a time where I wasn&#39;t using configuration management of some kind.&lt;br /&gt;
&lt;br /&gt;
When I was younger and much more foolish I started work at a company called Microplex. Microplex was a Sydney based ISP and I had managed to work my way into Engineering thanks to the kind promotion of an old friend and mentor Michael O&#39;Reilly. At round that time Microplex was bought by Optus - one of the larger Telco&#39;s in Australia.&lt;br /&gt;
&lt;br /&gt;
Michael O&#39;Reilly used to partly own iiNet, one of the bigger ISP&#39;s in Australia today. When he started working in engineering at Microplex, he introduced a system for configuration management from the start - it was called &#39;conform&#39; and it consisted of about 100 lines of Perl code.&lt;br /&gt;
&lt;br /&gt;
My first experiences as an Engineer were what I would later consider to be some of the best in my life. The team was way ahead of their time, and in many cases way ahead of most technical teams even today (and this was 1999).&lt;br /&gt;
&lt;br /&gt;
At the time I had no idea about how to administrate systems, but my senior colleagues were automation mad. In fact we were all called &#39;Perl Programmers&#39; not administrators. This was DevOps long before the term was invented.&lt;br /&gt;
&lt;br /&gt;
We had &#39;conform&#39; doing our configuration management, which was awesome. In fact I think I was one of the earlier people to create a fully automated build, at the time it was the &#39;usrweb&#39; system - you know - the place where you use to upload your personal 5 mb website for Optus/Microplex? That was rebuilt by me using conform - 100% automatically. In 1999 no less.&lt;br /&gt;
&lt;br /&gt;
When I left that group to work in other teams I tried to follow their ways of working but always hit up against the manual error problem, being young and naive I couldn&#39;t understand how these people worked at all. Having grown up with pure CM deployment I was shocked to learn that the outside world had no idea nor concept of this. My attempts at introducing other tools always hit up against dusty engineers spouting &#39;we aren&#39;t developer&#39; mantras which drove me mad.&lt;br /&gt;
&lt;br /&gt;
In fact, there was a time where building systems was documented fully in large 200 page engineering manuals. Every configuration file, every Cisco router configuration. I was totally shocked by this way of working and only lasted a very short amount of time in these types of roles as my frustration with my colleagues drove me mad.&lt;br /&gt;
&lt;br /&gt;
Later I tried reimplementing the things I had at my first job at other places. I tried coercing JASS and Jumpstart to do things, but the single build concept was useless in a world of changes. I tried early versions of cfEngine only to find myself doing more work then necessary and living in a sea of badly documented tooling.&lt;br /&gt;
&lt;br /&gt;
I tried writing tools myself and tried forcing them on teams, only to find myself being the only one who maintained them as no one saw the benefit. Yep, my career was depressing on that level - as it seemed everyone was quite happy and job satisfied with making manual changes. Sad really knowing what I knew.&lt;br /&gt;
&lt;br /&gt;
Later I came back to work nearby the team I originally worked with at Optus/Microplex (I moved a bit within Optus) and found they were still using the old tooling, 8 years later. And still succeeding with it. In fact the tooling was so ingrained into their deployment process it was mandatory to use it, and manual changes were not allowed unless under incident. Brilliant :-).&lt;br /&gt;
&lt;br /&gt;
Later when I left Optus to come to England for fame and opportunity I found myself working for Alfresco. Alfresco at the time I had very little systems administration, as there infrastructure was small at that time. I immediately wanted to implement a tool, and learning the lesson from having written my own tools in the past I went looking for an Open Source tool.&lt;br /&gt;
&lt;br /&gt;
And this is how I got into Puppet, I tried all the popular tools - and Puppet started working for me quickly and I understood it the best. The resource model and granular ordering was something I had petitioned for at Optus for conform, but the change was too big and hard to make. So seeing that a tool was already a generation or two ahead of our old thinking and got right into it, and couldn&#39;t stop.&lt;br /&gt;
&lt;br /&gt;
I went on to automate almost 80% of what we did at Alfresco, and I believe they still use the tool.&lt;br /&gt;
&lt;br /&gt;
I had a stint at another company, and did the same thing - automated the hell out of it.&lt;br /&gt;
&lt;br /&gt;
Then James Turnbull from Puppetlabs reached out to me to work for them - I couldn&#39;t say no. Now I&#39;m a developer I&#39;m as happy as larry, as this is my favourite problem domain to work on. I&#39;m also surrounded by extremely smart people who are passionate about this problem domain as well. What more could I want?&lt;br /&gt;
&lt;br /&gt;
So that&#39;s it, I&#39;ve always been into configuration management. There hasn&#39;t been a time really when I wasn&#39;t or wasn&#39;t trying to get it into a company (and being ignored mostly). So if I struggle to answer your questions when you ask me why Configuration Management - its because I don&#39;t really understand the world without it. Its like a world without a modern Linux operating system, or a world without Open Source ... I just can&#39;t comprehend the world without it.&lt;br /&gt;
&lt;br /&gt;
And - when people say to me &#39;automation is too hard, it will take us years to automate&#39; remember this: Microplex was doing it in 1999, without any tools on the market to help them besides Perl. If your not doing it yet, change your attitude fast, and step into it - ignorance or fear shouldn&#39;t be an excuse any more.</content><link rel='replies' type='application/atom+xml' href='http://blog.bob.sh/feeds/8766169392485245325/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.bob.sh/2012/06/how-i-got-involved-with-configuration.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8383226675188308439/posts/default/8766169392485245325'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8383226675188308439/posts/default/8766169392485245325'/><link rel='alternate' type='text/html' href='http://blog.bob.sh/2012/06/how-i-got-involved-with-configuration.html' title='How I got involved with Configuration Management'/><author><name>Ken Barber</name><uri>http://www.blogger.com/profile/15151872789024373679</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8383226675188308439.post-185229788460329309</id><published>2012-06-29T15:28:00.002+01:00</published><updated>2012-06-29T15:35:51.272+01:00</updated><title type='text'>A Review of the book &#39;OpenNebula 3 Cloud Computing&#39;</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQNaP4aAciW2Z6m_MbzdOzL9Q946-_ik2yCbTFFJ53LOW2-ulQRHPAoOTeK3CxwZKkICcqEU3LSWHrLUqqMZb1vQRklDuJSAb4A2X2vUD-LFjyXi1C38IxsxUUWklj3e22FBeef1KVUGk/s1600/7461OS_OpenNebula+3cov.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQNaP4aAciW2Z6m_MbzdOzL9Q946-_ik2yCbTFFJ53LOW2-ulQRHPAoOTeK3CxwZKkICcqEU3LSWHrLUqqMZb1vQRklDuJSAb4A2X2vUD-LFjyXi1C38IxsxUUWklj3e22FBeef1KVUGk/s320/7461OS_OpenNebula+3cov.jpg&quot; width=&quot;259&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Some time ago I was at a conference and listened to an introduction to &lt;a href=&quot;http://opennebula.org/&quot;&gt;OpenNebula&lt;/a&gt;&amp;nbsp;2 by Tino Vasquez from the OpenNebula team. I was fascinated by the simplicity of the product and went on to write a &lt;a href=&quot;http://puppetlabs.com/blog/puppetizing-opennebula/&quot;&gt;Puppet module&lt;/a&gt; for it.&lt;br /&gt;
&lt;br /&gt;
Today PacktPub have asked me to write a review of an early beta of the most recent book on the platform &#39;&lt;a href=&quot;http://link.packtpub.com/NUSJO7&quot;&gt;OpenNebula 3 Cloud Computing&lt;/a&gt;&#39; by &lt;a href=&quot;http://gionn.net/&quot;&gt;Giovanni Toraldo&lt;/a&gt; and lacking anything better to do I thought I would give it a shot (just to be clear I&#39;m doing this for the fun of it, no money has changed hands - I just like to write about things).&lt;br /&gt;
&lt;br /&gt;
For those who aren&#39;t savvy with the technology OpenNebula is an Open Source cloud framework aimed at enterprises who wish to run private clouds, but it also provides hooks into public clouds as well so you get this &#39;single management&#39; effect no matter which direction you wish to go.&lt;br /&gt;
&lt;br /&gt;
The book begins with the normal introduction to the PaaS, SaaS &amp;amp; IaaS terminology for those who aren&#39;t in the know. Starting small is a good idea I believe, it really is a brave new world for some people.&lt;br /&gt;
&lt;br /&gt;
It also provides a lot of terminology that applies to most clouds.&amp;nbsp;&lt;span style=&quot;background-color: white;&quot;&gt;When the cloud industry started people barely knew where to start. Its funny now we can effectively model how most clouds should look, and the intro does a good job at describing that model.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: white;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;h3&gt;


Building&lt;/h3&gt;
3 hypervisors are covered in detail:&amp;nbsp;&lt;span style=&quot;background-color: white;&quot;&gt;KVM,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: white;&quot;&gt;Xen and&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: white;&quot;&gt;VMWare ESXi.&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: white;&quot;&gt;Which are the three bigger players in the market. Its important that all three are covered in a book such as this, as different companies have invested in different paths.&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
It talks about how Libvirt plays in with these technologies, Libvirt being integral to the integration within OpenNebula as it takes away some of the heavy lifting.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
The book states at the beginning that its focused on using Ubuntu 10.04. While I think this is fine I can hear the audible whine of the corporates who have rested their laurels on Redhat. I guess most people need to be mindful that this is just the hypervisor not the OS that applications will sit on, however haters will hate and divisions are clear.&amp;nbsp;&lt;span style=&quot;background-color: white;&quot;&gt;In my opinion over the years I&#39;ve started to see that a hybrid approach is probably better, but still this doesn&#39;t help with licensing this kind of environment when your guests are going to be Redhat for example.&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;background-color: white;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;background-color: white;&quot;&gt;Still, Debian and Ubuntu have put a lot of effort in making this platform work for them which is a testament to their great efforts lately in the server space.&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;background-color: white;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;background-color: white;&quot;&gt;The book does however talk about installation from source and pre-built packages, and with enough knowledge Redhat users can probably happily find packages or build them using FPM if need be.&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;background-color: white;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;h3&gt;


&lt;span style=&quot;background-color: white;&quot;&gt;Storage&lt;/span&gt;&lt;/h3&gt;
&lt;div&gt;
&lt;span style=&quot;background-color: white;&quot;&gt;The storage section is detailed, it goes through the basic variants using SCP transfers and of course NFS backed storage.&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: white;&quot;&gt;Which alone are enough to get most people up and running.&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;background-color: white;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;background-color: white;&quot;&gt;It also spends time talking about some distributed storage systems: MooseFS and GlusterFS. Its a shame Ceph isn&#39;t ready for prime-time yet, as I would love to see this covered at some point as well (perhaps next edition). Conversely though it does step into how a transfer driver is written, which gives you the grounding for adapting to any storage mechanism if you chose.&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3&gt;


Instances&lt;/h3&gt;
&lt;div&gt;
The book walks you though how to launch the example ttylinux demo instance. This instance itself is more of a light example for users, not really a production instance&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
The real meat that I wanted to see however was how to setup your own instance, as this is what most people have trouble with. However the chapter was very light on this, just mentioning it needs to be done on a another PC and imported into the OpenNebula environment. I would have liked to have seen a discussion on this in greater detail and some points on how to do it in a few hypervisors with Linux and Windows. Oh well, you can&#39;t have everything.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
The chapter however does talk about &lt;a href=&quot;http://en.wikipedia.org/wiki/Contextualization_(computer_science)&quot;&gt;contexualisation&lt;/a&gt;&amp;nbsp;of your VM quite a bit. This is where you individualise a machine from a stored image by passing scripts and data to the VM as it boots in the form of a mini ISO image. Philosophically this is the place where your own individual solutions come out, as this is more about how to modelling your environment - and everyones needs are different.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3&gt;


Web Interfaces&lt;/h3&gt;
&lt;div&gt;
The section on setting up Sunstone wasn&#39;t my favourite, but should be good enough to get people up and running. The tool itself is a pinch to setup, being a simple Ruby Sinatra application. However I would have preferred documentation on how to make this scale with a proper Ruby application server such as Unicorn or Passenger, which are the more preferred technologies for production Ruby web applications.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
They do have some information on how to configure Nginx however as a reverse-proxy, which is at least a start.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
The instructions on how to use the interface was very detailed however and included a lot of screenshots which was nice.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3&gt;


Monitoring&lt;/h3&gt;
&lt;div&gt;
The monitoring sections were very detailed and went into how to setup custom monitors for VM state which was interesting, especially for those who have custom requirements. It also describes how to setup scripted hooks for scenarios like VM failure, which is a real treat for those who are control freaks.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
There was an entire section for setting up Ganglia for uptime monitoring and OpenNebula integration. Its nice to see this covered, as monitoring is pretty critical to a real solution. Even users using other monitoring tools can take something away from this section as it helps one understand the entry points for monitoring regardless of tool.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3&gt;


Public Cloud Integration&lt;/h3&gt;
&lt;div&gt;
I must say the entire section on AWS integration was very detailed. I&#39;m not an expert on this part of OpenNebula, and the integration with AWS is often glossed over. The author however has spent quite a bit of time explaining how to make this work with Linux and Windows instances.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
In the next section of the book the author also covers the EC2 interface that OpenNebula emulates so you can use EC2 compatible API&#39;s which is a very nice feature.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3&gt;


Other Interfaces&lt;/h3&gt;
&lt;div&gt;
The final chapter gets into the nuts and bolts of how to configure OpenNebula to expose an EC2 and OCCI interface to the world, so that it can be called by third party tools designed around these protocols. The EC2 feature is of course interesting, as this means you can expose your private and public clouds using the same EC2 interface.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
It also talks about one of my more favourite topics: Zones and Virtual Data Centres. The concept of Zones here is to allow a single OpenNebula cloud serve multiple &#39;customers&#39; if you like: be it separate IT groups or even separate commercial customer entities. I believe this to be an integral part of the &#39;server provider&#39; aspect of cloud computing weither you are going to zone your various development groups or customers A, B and Z.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
In this section we get some setup instructions on how to configure the oZones service using Apache (not Nginx this time) as a reverse-proxy and some nice detailed instructions on how to use the management GUI.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3&gt;


&lt;span style=&quot;background-color: white;&quot;&gt;Summary&lt;/span&gt;&lt;/h3&gt;
&lt;div&gt;
I think all in all the book is a good reference guide, and would be perfect for those stepping out into building an OpenNebula driven cloud for themselves. It reads well, and the layout is front-to-back so you can step through it in a lab.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
In some parts the author could have extended into more detail on production setups (use of Passenger, Unicorn for example) and scaling the oned daemon, as I feel these are the questions people ultimately ask.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
It drills into some detail and explanations, and generally doesn&#39;t focus on one type of solution which is nice to see.&amp;nbsp;&lt;span style=&quot;background-color: white;&quot;&gt;A&lt;/span&gt;&lt;span style=&quot;background-color: white;&quot;&gt;ll in all a good read and I&#39;d recommend it to anyone stepping into the world of cloud building with OpenNebula. Well done Giovanni :-).&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;background-color: white;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;i&gt;&lt;span style=&quot;background-color: white;&quot;&gt;If you are interested in obtaining this book, it can be purchased from the PacktPub website at:&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: white;&quot;&gt;&lt;a href=&quot;http://link.packtpub.com/NUSJO7&quot;&gt;http://link.packtpub.com/NUSJO7&lt;/a&gt;&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bob.sh/feeds/185229788460329309/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.bob.sh/2012/06/a-review-of-book-opennebula-3-cloud.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8383226675188308439/posts/default/185229788460329309'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8383226675188308439/posts/default/185229788460329309'/><link rel='alternate' type='text/html' href='http://blog.bob.sh/2012/06/a-review-of-book-opennebula-3-cloud.html' title='A Review of the book &#39;OpenNebula 3 Cloud Computing&#39;'/><author><name>Ken Barber</name><uri>http://www.blogger.com/profile/15151872789024373679</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQNaP4aAciW2Z6m_MbzdOzL9Q946-_ik2yCbTFFJ53LOW2-ulQRHPAoOTeK3CxwZKkICcqEU3LSWHrLUqqMZb1vQRklDuJSAb4A2X2vUD-LFjyXi1C38IxsxUUWklj3e22FBeef1KVUGk/s72-c/7461OS_OpenNebula+3cov.jpg" height="72" width="72"/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8383226675188308439.post-3561390237235552259</id><published>2012-06-11T15:28:00.000+01:00</published><updated>2012-06-16T09:10:26.981+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="erlang"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><category scheme="http://www.blogger.com/atom/ns#" term="torquebox"/><title type='text'>Torquebox: Making Message Processors behave Synchronously</title><content type='html'>In Erlang using processes and in-built functions you are able to send message to processes anywhere in your cluster, and there is a pattern to extend this to wait on a returned message as well. This allows you to call out to a separate utility process to do some work and wait for its response.&lt;br /&gt;
&lt;br /&gt;
This can be quite useful for example where you might want to move common processing off to a remote machine, (like image processing or something that takes time &amp;amp; cpu) where you don&#39;t want to consume the CPU on the current machine.&lt;br /&gt;
&lt;br /&gt;
In erlang the code example is quite straight-forward for this (this is a simplified variation taken from: &lt;a href=&quot;http://www.erlang.org/doc/getting_started/conc_prog.html&quot;&gt;http://www.erlang.org/doc/getting_started/conc_prog.html&lt;/a&gt;):&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;font-family: Courier, monospace;&quot;&gt;-module(async).

-export([start/0, ping/1, pong/0]).

ping(Pong_PID) -&amp;gt;
    Pong_PID ! {ping, self()},
    receive
        pong -&amp;gt;
            io:format(&quot;Ping received pong~n&quot;, [])
    end.

pong() -&amp;gt;
    receive
        finished -&amp;gt;
            io:format(&quot;Pong finished~n&quot;, []);
        {ping, Ping_PID} -&amp;gt;
            io:format(&quot;Pong received ping~n&quot;, []),
            Ping_PID ! pong,
            pong()
    end.

start() -&amp;gt;
    Pong_PID = spawn(async, pong, []),
    spawn(async, ping, [Pong_PID]).&lt;/pre&gt;
&lt;br /&gt;
In this example in the &#39;start()&#39; function we begin by spawning the receiver process &#39;pong&#39;. This process is setup to receive messages and respond to them using the syntax:&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;font-family: Courier, monospace;&quot;&gt;Ping_PID ! pong&lt;/pre&gt;
&lt;br /&gt;
Thus we have our receiver/processor ready and prepared. The second step is that we spawn a second process that is responsible for sending the message, ie. the &#39;ping&#39;. Now here is where it gets interesting.&lt;br /&gt;
&lt;br /&gt;
The outbound message is sent with:&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;font-family: Courier, monospace;&quot;&gt;Pong_PID ! {ping, self()}
&lt;/pre&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
This means the outbound message is sending the symbol &#39;ping&#39;, and a reference to its own process. It then blocks indefinately, waiting for a response of &#39;pong&#39;:&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;font-family: Courier, monospace;&quot;&gt;receive
    pong -&amp;gt;
        io:format(&quot;Ping received pong~n&quot;, [])
end.
&lt;/pre&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
Quite simple really. The entire point here is that both of these processes can live on completely separate machines, the receiver or processor able to do work on its own, while the requester can simple wait for a response.&lt;br /&gt;
&lt;br /&gt;
I saw this pattern recently echoed when I was looking at the Torquebox platform:&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://torquebox.org/documentation/2.0.3/messaging.html#synchronous-messaging&quot;&gt;http://torquebox.org/documentation/2.0.3/messaging.html#synchronous-messaging&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Here we have a very basic copy of the same concept:&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;font-family: Courier, monospace;&quot;&gt;queue = TorqueBox::Messaging::Queue.new(&#39;/queues/foo&#39;)
Thread.new {
  queue.receive_and_publish(:timeout =&amp;gt; 5000) { |message| message.upcase }
}
message = queue.publish_and_receive &quot;ping&quot;, :timeout =&amp;gt; 5000
&lt;/pre&gt;
&lt;br /&gt;
Which is interesting on its own, but it does require you to write your own Torquebox Service to listen for these requests.&lt;br /&gt;
&lt;br /&gt;
I figured we could do better then that though. In Erlang it most certainly supports the concept of processor groups and supervisors and workers for scaling up a set of workers and I wanted to mimic this somehow.&lt;br /&gt;
&lt;br /&gt;
So ... Torquebox already has its own concept of workers that can receive messages on queues and scale up as your needs scale - these are called Message Processors:&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://torquebox.org/documentation/2.0.3/messaging.html#messaging-consumers&quot;&gt;http://torquebox.org/documentation/2.0.3/messaging.html#messaging-consumers&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Now the beauty of these Message Processors is that they are fairly much just Ruby objects that have little knowledge of the fact they are at the end of a queue. What I like about them is that they allow me to think using the Actor model, however they don&#39;t support the synchronous methodology out of the box as described above so I set out to mimic it myself.&lt;br /&gt;
&lt;br /&gt;
First of all, synchronous messages contain some extra data when sending messages to designate the request and response. In particular the call &#39;publish_and_receive&#39; includes the message parameter synchronous = &#39;true&#39;.&lt;br /&gt;
&lt;br /&gt;
So lets start out by making sure our message processor setup is correctly. In your torquebox.yml you add the following:&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;font-family: Courier, monospace;&quot;&gt;queues:
  /queues/ping_pong:
    durable: true

messaging:
  /queues/ping_pong:
    PingPong:
      selector: &quot;synchronous = &#39;true&#39;&quot;
      concurrency: 5
&lt;/pre&gt;
&lt;br /&gt;
Note the selector setting - this means it will only receive messages with this parameter setting in the JMS message. This is important and very relevant to ensure the receiver doesn&#39;t get all the response messages we&#39;re going to send back onto the queue later on. I&#39;ve also set the concurrency to 5 just to show how you can control the number of workers/receivers.
&lt;br /&gt;
&lt;br /&gt;
Now for the receiver code (ping_pong.rb):&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;font-family: Courier, monospace;&quot;&gt;require &#39;rubygems&#39;
require &#39;torquebox-messaging&#39;

class PingPong &amp;lt; TorqueBox::Messaging::MessageProcessor
  def initialize(hash = {})
    @logger = TorqueBox::Logger.new
  end

  def on_message(body)&lt;/pre&gt;
&lt;pre style=&quot;font-family: Courier, monospace;&quot;&gt;    # The synchronous methods always put the user message inside&lt;/pre&gt;
&lt;pre style=&quot;font-family: Courier, monospace;&quot;&gt;    # a :message parameter, hence the need to descend here.
    message = body[:message][:command]&lt;/pre&gt;
&lt;pre style=&quot;font-family: Courier, monospace;&quot;&gt;&lt;/pre&gt;
&lt;pre style=&quot;font-family: Courier, monospace;&quot;&gt;    # This should result in &#39;ping&#39; being displayed in your logs&lt;/pre&gt;
&lt;pre style=&quot;font-family: Courier, monospace;&quot;&gt;    @logger.info(message)

    sync_reply({&#39;command&#39; =&amp;gt; &#39;pong&#39;})
  end

  def sync_reply(reply)
    queue_name = message.jms_message.jms_destination.name
    jms_message_id = message.jms_message.jms_message_id

    queue = TorqueBox::Messaging::Queue.new(queue_name)
    queue.publish(reply, {&lt;/pre&gt;
&lt;pre style=&quot;font-family: Courier, monospace;&quot;&gt;      :correlation_id =&amp;gt; jms_message_id,&lt;/pre&gt;
&lt;pre style=&quot;font-family: Courier, monospace;&quot;&gt;      :encoding =&amp;gt; :json}&lt;/pre&gt;
&lt;pre style=&quot;font-family: Courier, monospace;&quot;&gt;    )
  end
end
&lt;/pre&gt;
&lt;br /&gt;
What&#39;s happening here, is that when the queue receives a message that matches the selector above - it will send the entire body of the message to the #on_message method. The body is already decoded using JSON.parse so we can just treat it like a hash. The main difference between this and normal Message Processor behaviour is that the method #publish_and_receive will always embed the users message inside the &#39;message&#39; parameter, so we need to retrieve things from there instead.&lt;br /&gt;
&lt;br /&gt;
At the end of processing (in this case we just log the received message) I&#39;ve provided an extra method called &#39;sync_reply&#39;. This method is responsible for creating the reply and adding the necessary &#39;correlation_id&#39; setting to make sure the response is only caught by the original sender.
&lt;br /&gt;
&lt;br /&gt;
The important part here is that we must make sure:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;We send the message back on the same queue as it was sent out on. We do this by unpacking the JMS message and pulling out the &#39;jms_destination&#39;.&lt;/li&gt;
&lt;li&gt;We make sure we add a :correlation_id field when sending the message back, this correlation_id must match the original sender&#39;s &#39;jms_message_id&#39;. This is because the original sender is now waiting using a receive call with a selector designated to only match that correlation_id.&lt;/li&gt;
&lt;/ul&gt;
So now that you have a receiver built, if you want to send a message it&#39;s simple, you can use the built-in publish_and_receive method from somewhere else in your application:&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;font-family: Courier, monospace;&quot;&gt;queue = TorqueBox::Messaging::Queue.new(&quot;/queues/ping_pong&quot;)
response = queue.publish_and_receive(
  {:command =&amp;gt; &quot;ping&quot;},
  {:encoding =&amp;gt; :json, :timeout =&amp;gt; 60000 }
)
puts response.inspect
&lt;/pre&gt;
&lt;br /&gt;
And thus we have achieved synchronous messaging using Torquebox Message Processors.</content><link rel='replies' type='application/atom+xml' href='http://blog.bob.sh/feeds/3561390237235552259/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.bob.sh/2012/06/torquebox-making-message-processors.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8383226675188308439/posts/default/3561390237235552259'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8383226675188308439/posts/default/3561390237235552259'/><link rel='alternate' type='text/html' href='http://blog.bob.sh/2012/06/torquebox-making-message-processors.html' title='Torquebox: Making Message Processors behave Synchronously'/><author><name>Ken Barber</name><uri>http://www.blogger.com/profile/15151872789024373679</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8383226675188308439.post-2807451402976944240</id><published>2012-06-09T02:53:00.001+01:00</published><updated>2012-06-11T15:30:14.236+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="newbie"/><category scheme="http://www.blogger.com/atom/ns#" term="programming"/><title type='text'>Newbie programmer: Focusing on getting the job done</title><content type='html'>So I&#39;ve started work for the first time as a full time developer at a popular software company recently, and I&#39;ve been jotting down some notes on my first impression on how to get stuff done and be as productive as possible. It might be totally wrong, its primarily from the perspective of a newbie - but might be an interesting read none-the-less.&lt;br /&gt;
&lt;br /&gt;
If you have your own ideas of getting things done, and you have more experience then this spring chicken, feel free to comment.&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;


Prototype first, optimize later&lt;/h4&gt;
Premature optimisation is actually an anti-pattern according to Wikipedia, and I&#39;m starting to realise why. With the amount of backwards and forwards one can do in code during a design phase - it makes sense to optimize later once the prototype and design has been agreed on.&lt;br /&gt;
&lt;br /&gt;
I find though doing this in chunks once you feel you have a feature working enough is a good idea. Leaving optimisation late can make it feel like a less interesting task, so wrap it up in chunks.&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;


Style&lt;/h4&gt;
Get style issues out of the way early. Write using good style all the time, it can avoid a lot of unnecessary chatter with your colleagues. Programmers I know have a special aversion to bad style and its not worth the hassle I assure you. Getting to know their style and sticking to it saves time.&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;


Task Tracking&lt;/h4&gt;
Use a micro task tracker to keep track of tasks that don&#39;t really belong in a major task tracker. I use OmniFocus but any GTD style tracker is probably adequate.&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;


Music&lt;/h4&gt;
Get yourself some playlists for music - something that runs for many hours so you don&#39;t have to break concentration to switch tunes. I use Youtube for my music on my spare Ubuntu desktop here, but if the ads nag you, get something on ITunes or whatever is your favourite poison.&lt;br /&gt;
&lt;br /&gt;
I also have different play-lists for different moods. I have slower music for concentration and thinking about problems, and faster music for just hammering things out.&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;


Distractions in the Workspace&lt;/h4&gt;
Sort out distractions early, don&#39;t let background noise linger - make it clear to people around you that you are in a sprint and you don&#39;t want to be disturbed.&lt;br /&gt;
&lt;br /&gt;
I work from home a lot. My kids know now that I need my peace and quiet during &#39;work hours&#39;, and I try to make it up to them when I&#39;m out of work mode.&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;


Socialising Specifications and Design&lt;/h4&gt;
Get your specifications out in the open earlier, if you are designing a website, protocol or otherwise - write the design early, and get the feedback loop happening earlier. This saves you having to rewrite a lot of code later on.&lt;br /&gt;
&lt;br /&gt;
You might presume that the design is &#39;obvious&#39; and follows standards. The truth is probably far from it. Once you put it on paper (well - google docs or whatever) you&#39;ll find your assumptions shattered. This is a good thing.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;


Fussing over old code&lt;/h4&gt;
When looking at new features you want to add to existing code, you may find you are not happy with the existing code. Mostly, this is due to your initial understanding of the objectives of this code as written at the time - that will pass. But regardless, its not worth fretting or pondering why code was written in such a way. If you find yourself wanting to adjust the code - just do it and move on, but make sure you understand the overall objective before destroying someones dream.&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;


You&#39;re probably wrong&lt;/h4&gt;
&lt;div&gt;
When socialising your work amongst your colleagues, you may get opinions that don&#39;t make sense to you. Welcome to the real world. I&#39;ve learnt that the best thing to do is to understand these needs and try to meet them if they are reasonable, chances are the person has a good perspective. I think as a programmer you will have to get used to outside influence - I think embracing with good debates and discussions is easier then rejecting it.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Also - be humble. Be prepared for being wrong. As a user you were always right ... as a programmer, you have to listen to your users.&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bob.sh/feeds/2807451402976944240/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.bob.sh/2012/06/newbie-programmer-focusing-on-getting.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8383226675188308439/posts/default/2807451402976944240'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8383226675188308439/posts/default/2807451402976944240'/><link rel='alternate' type='text/html' href='http://blog.bob.sh/2012/06/newbie-programmer-focusing-on-getting.html' title='Newbie programmer: Focusing on getting the job done'/><author><name>Ken Barber</name><uri>http://www.blogger.com/profile/15151872789024373679</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8383226675188308439.post-4171628367663581092</id><published>2012-02-28T22:37:00.000+00:00</published><updated>2012-02-28T22:37:11.623+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><title type='text'>Pretty Ruby Data</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
Here is the output of some code I wrote to output hashes and arrays in a more colourful way:&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhI9wApMcSk2smPKWwpxQw67d8ntp_GiVlO9JDUBU90r0TllApX9nShib-VBvtyGvBsVvL-62S8AAl-duhS5oo8aKD_shSQUxQbtvE6pLssia2gBceNg_48GlgHLEPq04wCadEEwuRgniU/s1600/Screen+Shot+2012-02-28+at+23.26.45.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhI9wApMcSk2smPKWwpxQw67d8ntp_GiVlO9JDUBU90r0TllApX9nShib-VBvtyGvBsVvL-62S8AAl-duhS5oo8aKD_shSQUxQbtvE6pLssia2gBceNg_48GlgHLEPq04wCadEEwuRgniU/s640/Screen+Shot+2012-02-28+at+23.26.45.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
The code is here if you&#39;re interested:&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://github.com/kbarber/pretty_data/blob/master/pretty_data.rb&quot;&gt;https://github.com/kbarber/pretty_data/blob/master/pretty_data.rb&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bob.sh/feeds/4171628367663581092/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.bob.sh/2012/02/pretty-ruby-data.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8383226675188308439/posts/default/4171628367663581092'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8383226675188308439/posts/default/4171628367663581092'/><link rel='alternate' type='text/html' href='http://blog.bob.sh/2012/02/pretty-ruby-data.html' title='Pretty Ruby Data'/><author><name>Ken Barber</name><uri>http://www.blogger.com/profile/15151872789024373679</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhI9wApMcSk2smPKWwpxQw67d8ntp_GiVlO9JDUBU90r0TllApX9nShib-VBvtyGvBsVvL-62S8AAl-duhS5oo8aKD_shSQUxQbtvE6pLssia2gBceNg_48GlgHLEPq04wCadEEwuRgniU/s72-c/Screen+Shot+2012-02-28+at+23.26.45.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8383226675188308439.post-5389615758695870766</id><published>2012-02-10T16:57:00.000+00:00</published><updated>2012-02-11T21:35:13.675+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><category scheme="http://www.blogger.com/atom/ns#" term="yaml"/><title type='text'>Ruby YAML and sorting top-level keys</title><content type='html'>I wanted to sort the top-level keys in a YAML hash in Ruby in a once-off way (that is, not sort all the time - just this once). I found two methods.&lt;br /&gt;
&lt;br /&gt;
The first one is based on something I found on StackOverflow. So given a hash:&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;white-space: pre-wrap; word-wrap: break-word;&quot;&gt;a = { 
  &quot;a&quot; =&amp;gt; &quot;b&quot;,
  &quot;e&quot; =&amp;gt; &quot;b&quot;,
  &quot;c&quot; =&amp;gt; &quot;b&quot;,
  &quot;p&quot; =&amp;gt; &quot;b&quot;,
  &quot;z&quot; =&amp;gt; &quot;b&quot;,
  &quot;x&quot; =&amp;gt; &quot;b&quot;,
  &quot;d&quot; =&amp;gt; &quot;b&quot;,
}
&lt;/pre&gt;
&lt;br /&gt;
The function looks something like:&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;white-space: pre-wrap; word-wrap: break-word;&quot;&gt;def sort_yaml1(obj)
  YAML::quick_emit(obj) do |out|
    out.map(obj.taguri, obj.to_yaml_style) do |map|
      obj.keys.sort.each do |k| 
        v = obj[k]
        map.add(k, v)
      end 
    end 
  end 
end

puts sort_yaml1(a)&lt;/pre&gt;
&lt;br /&gt;
The second methodology is very manual and not quite as elegant, but is probably less dependant on the YAML internals:&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;white-space: pre-wrap; word-wrap: break-word;&quot;&gt;def sort_yaml2(obj)
  arr = obj.sort
  out = &quot;---\n&quot;
  arr.each do |element|
    entry = {element[0] =&amp;gt; element[1]}
    out += entry.to_yaml.to_a[1..-1].join + &quot;\n&quot;
  end 
  out 
end

puts sort_yaml2(a)&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
Its a shame the SortedKeys option isn&#39;t supported out of the box in Ruby 1.8.7, but it seems the SortedKeys option isn&#39;t passed to the underlying syck driver at all.</content><link rel='replies' type='application/atom+xml' href='http://blog.bob.sh/feeds/5389615758695870766/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.bob.sh/2012/02/ruby-yaml-and-sorting-top-level-keys.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8383226675188308439/posts/default/5389615758695870766'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8383226675188308439/posts/default/5389615758695870766'/><link rel='alternate' type='text/html' href='http://blog.bob.sh/2012/02/ruby-yaml-and-sorting-top-level-keys.html' title='Ruby YAML and sorting top-level keys'/><author><name>Ken Barber</name><uri>http://www.blogger.com/profile/15151872789024373679</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8383226675188308439.post-3519373234348829268</id><published>2012-02-05T21:54:00.001+00:00</published><updated>2012-06-09T19:07:25.391+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ceph"/><category scheme="http://www.blogger.com/atom/ns#" term="kvm"/><category scheme="http://www.blogger.com/atom/ns#" term="qemu"/><title type='text'>A Basic Ceph Storage &amp; KVM Virtualisation Tutorial</title><content type='html'>So I had been meaning to give &lt;a href=&quot;http://ceph.newdream.net/&quot;&gt;CEPH&lt;/a&gt; &amp;amp; KVM Virtualisation a whirl in the lab for quite some time now. Here I have provided for you all a set of command-by-command instructions I used for setting it up on a single host. The goal here is really just to get it to the &#39;working&#39; stage for some basic functional experimentation.&lt;br /&gt;
&lt;br /&gt;
Ideally you would want to set this up on multiple hosts with proper network separation so you can see how it performs with real-world attenuation.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;
&lt;span style=&quot;font-size: large;&quot;&gt;Overview&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
For those who don&#39;t know it, CEPH is a distributed storage solution that allows you to scale horizontally with multiple machines/heads instead of the more traditional methodologies which use centralised heads with large amounts of storage attached to them.&lt;br /&gt;
&lt;br /&gt;
The principle here is that you should be able to buy lots of inexpensive computers with a bunch of direct attached storage and just cluster them to achieve scalability. Also, without a central point of failure or performance bottleneck you should be able to scale beyond the limitations of our past storage architectures.&lt;br /&gt;
&lt;br /&gt;
So CEPH like most distributed storage solutions, really has 3 main components:&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Object Storage Device (ODS):&lt;/b&gt; this is where the blocks get stored. You would usually have lots of these.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Meta-Data Server (MDS):&lt;/b&gt; This where the metadata gets stored. You would have less of these. They are used for looking up where the blocks are stored and storing meta-data about files and blocks.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Monitor (MON):&lt;/b&gt; Cluster management, configuration and state. This component keeps track of the state of the clustering really.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
Here is a basic diagram provided from the official site (so yes I stole it - I hope thats okay):&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://ceph.newdream.net/w/images/f/f6/Ceph_architecture.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;259&quot; src=&quot;http://ceph.newdream.net/w/images/f/f6/Ceph_architecture.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
As you can see, ideally these components are meant to be ran on different sets of systems, with the OSD component being the most frequent. I&#39;m just going to run them all on the same host for this demo, which is useful for a functional test, but not for a destructive or performance test.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
By the way the OSD part can used different types of backends and filesystems for storage, but in this example I&#39;ve chosen BTRFS.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
So CEPH itself supports multiple different ways of mounting its storage, which makes it quite a flexible solution.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
In this demo I&#39;m going to concentrate only on the RBD and Ceph DFS mechanisms.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
This installation was tested with:&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;ceph 0.4.0&lt;/li&gt;
&lt;li&gt;qemu-kvm 1.0&lt;/li&gt;
&lt;li&gt;libvirt 0.9.8&lt;/li&gt;
&lt;li&gt;debian 7.0 (wheezy)&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div&gt;
I&#39;m using the bleeding edge versions of these components because CEPH is really in heavy development its better to see how the main-line of development works to get a clearer picture.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-size: large;&quot;&gt;OS Preparation&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;
It was tested with real hardware hosted by Hetzner in Germany. The box specs were roughly something like:&lt;/div&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;Quad-Core processor&lt;/li&gt;
&lt;li&gt;16 GB of RAM&lt;/li&gt;
&lt;li&gt;2 x 750 GB disks (no hardware raid)&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;br /&gt;
To begin, I personally built a Debian 6.0 system (because thats all Hetzner offers you within its Robot tool) with a spare partition that I later use for the OSD/BTRFS volume. The layout was something like:&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;&lt;b&gt;/dev/md0:&lt;/b&gt; /boot, 512MB&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;&lt;b&gt;/dev/md1:&lt;/b&gt; LVM, 74 GB&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;&lt;b&gt;/dev/md2:&lt;/b&gt; the rest of the disk&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
And in the LVM partition I defined the following logical volumes:&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;&lt;b&gt;/:&lt;/b&gt; 50 GB (ext4)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;&lt;b&gt;swap:&lt;/b&gt; 20 GB&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
The device /dev/md2 I reserved for BTRFS. I believe a more optimal configuration is to not use an MD device but just use /dev/sda2 &amp;amp; /dev/sda3 and let BTRFS do the mirroring. I however have no data or performance statistics to prove this at the moment.&lt;br /&gt;
&lt;br /&gt;
To get the system upgraded from Debian 6 to 7 is fairly straight-forward. First update the APT sources list.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;/etc/apt/sources.list:&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;deb &amp;nbsp; &amp;nbsp; http://ftp.de.debian.org/debian/ wheezy main contrib non-free&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;deb &amp;nbsp; &amp;nbsp; http://ftp.de.debian.org/debian/ wheezy-proposed-updates main contrib non-free&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Then run the following to then get the latest updates:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;apt-get update&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;apt-get -y dist-upgrade&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
The kernel would have been upgraded so you should reboot at this point.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span style=&quot;font-size: large;&quot;&gt;CEPH Installation&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Install CEPH using the ceph package. This should pull in all the dependencies you need.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;apt-get install ceph&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Create some directories for the various CEPH components:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;mkdir -p /srv/ceph/{osd,mon,mds}&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
I used a configuration file like this below. Obviously you will need to change the various parts to suit your environment. I&#39;ve left out authentication in this demo for simplicity, although if you want to do real destructive and load-testing you should always include this.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;/etc/ceph/ceph.conf:&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;[global]&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; log file = /var/log/ceph/$name.log&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; pid file = /var/run/ceph/$name.pid&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;[mon]&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mon data = /srv/ceph/mon/$name&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;[mon.&amp;lt;your_short_hostname&amp;gt;]&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;host = &amp;lt;your_hostname&amp;gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;mon addr = &amp;lt;your_ip_address&amp;gt;:6789&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;[mds]&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;[mds.&amp;lt;your_short_hostname&amp;gt;]&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;host = &amp;lt;your_hostname&amp;gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;[osd]&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;osd data = /srv/ceph/osd/$name&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;osd journal = /srv/ceph/osd/$name/journal&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;osd journal size = 1000 ; journal size, in megabytes&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;[osd.0]&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;host = &amp;lt;your_hostname&amp;gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;btrfs devs = /dev/md2&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; btrfs options = rw,noatime&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Now for configuration, CEPH chooses to try and SSH into remote boxes and configure things. I believe this is nice for people who are just getting started, but I&#39;m not sure if this is correct going forward if you already have your own Configuration Management tool like Puppet, Chef or CFEngine.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
So to begin with, there is a command that will initialise your CEPH filesystems based on the configuration you have provided:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;/sbin/mkcephfs -a -c /etc/ceph/ceph.conf --mkbtrfs --no-copy-conf&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Starting the daemon was a little strange (see the -a switch?):&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;/etc/init.d/ceph -a start&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
So just to test its all working, lets mount the CEPH DFS volume onto the local system:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;mount -t ceph &amp;lt;your_hostname&amp;gt;:/ /mnt&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
What you are looking at here is the CEPH object store mounted in /mnt. This is a shared object store - and you should be able to have multiple hosts mount it just like NFS. As mentioned before-hand however, this is not the only way of getting access to the CEPH storage cluster.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-size: large;&quot;&gt;CEPH DFS &amp;amp; Directory Snapshots&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
So I just wanted to segway a little and talk about this neat feature. CEPH &amp;amp; the ceph based mount point above has the capability to do per-directory snapshots which could come in useful. The interface is quite simple as well.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;making a snapshot:&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;mkdir /mnt/test&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;cd /mnt/test&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;touch a b c&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;mkdir .snap/my_snapshot&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;deleting a snapshot:&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;rmdir .snap/my_snapshot&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;finding a snapshot:&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
The .snap directory won&#39;t show up when you do a ls -la in the dir.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Simply assume its there and do something like:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;ls -la .snap&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
... in the directory and the snapshots should show up under the names you created them with.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-size: large;&quot;&gt;RADOS Block Device&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
So an alternative way of using your CEPH storage is by using RBD. The RBD interface gives you the capability to expose an object onto a remote system as a block device. Obviously this has the same caveats as any block device, so multiple hosts that mount the same device must ensure they use some sort of clustered file system such as OCFS2.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
So first if its not already, load the rbd kernel module:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;modprobe rbd&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Using the &#39;rbd&#39; command line tool, create an image (size is in megs):&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;rbd create mydisk --size 10000&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
You can list the current images if you want:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;rbd list&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Now to mount the actually device, you just have to tell the kernel first:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;echo &quot;&amp;lt;your_ip_address&amp;gt; name=admin rbd mydisk&quot; &amp;gt; /sys/bus/rbd/add&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
It should create a device like /dev/rbd/rbd/mydisk. Lets now&amp;nbsp;format it with a real filesystem and mount it:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;mkfs -t ext4 /dev/rbd/rbd/mydisk&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;mkdir /srv/mydisk&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;mount -t ext4 /dev/rbd/rbd/mydisk /srv/mydisk&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-size: large;&quot;&gt;KVM/Qemu Support&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
QEMU (and libvirt for that matter) at some point merged in patched to allow you to specify an &#39;rbd&#39; store as a backend to a QEMU virtual instance. I&#39;m going to focus on using an Intel/KVM image for this tutorial.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
So lets start by installing KVM &amp;amp; Qemu and the various other pieces we&#39;ll need:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;apt-get install kvm libvirt-bin virtinst iptables-persistent&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
We want to probably create a pool for vm disks separate from the pre-existing ones. You can create as many of these as you need:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;rados mkpool vm_disks&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Now create a qemu image inside the pool. Notice we are just using &#39;qemu-image&#39; to do this?&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;qemu-img create -f rbd rbd:vm_disks/box1_disk1 10G&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Create yourself a bridge network by modifying the correct Debian configuration file.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;/etc/network/interfaces:&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;auto virbr0&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;iface virbr0 inet static&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; bridge_ports none&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; address 192.168.128.1&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; netmask 255.255.255.0&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; network 192.168.128.0&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; broadcast 192.168.128.255&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
And now bring up the interface:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;ifup --verbose virbr0&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
We&#39;ll need some firewall rules so that NAT works in this case. Obviously your network needs may vary here.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;/etc/iptables/rules.v4:&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;*filter&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;:INPUT ACCEPT [0:0]&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;:FORWARD ACCEPT [0:0]&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;:OUTPUT ACCEPT [0:0]&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;-A FORWARD -s 192.168.128.0/24 -m comment --comment &quot;100 allow forwarding from internal&quot; -j ACCEPT&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;-A FORWARD -d 192.168.128.0/24 -m comment --comment &quot;100 allow forwarding to internal&quot; -j ACCEPT&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;COMMIT&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;*nat&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;:PREROUTING ACCEPT [0:0]&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;:INPUT ACCEPT [0:0]&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;:OUTPUT ACCEPT [0:0]&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;:POSTROUTING ACCEPT [0:0]&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;-A POSTROUTING -s 192.168.128.0/24 -o eth0 -m comment --comment &quot;500 outbound nat for internal&quot; -j MASQUERADE&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;COMMIT&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
And restart iptables-persistent to load the rules:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;service iptables-persistent restart&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Turn on forwarding for IPv4:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;echo 1 &amp;gt; /proc/sys/net/ipv4/ip_forward&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Now that the network is done, we want to create a script to help us launch our VM instance.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
First of all create a device definition file called disk.xml with the following contents. This allows us to work-around limitations in virt-install, as it doesn&#39;t yet support these extra options as command-line arguments.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;/root/disk.xml:&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;disk type=&#39;network&#39; device=&#39;disk&#39;&amp;gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;lt;source protocol=&#39;rbd&#39; name=&#39;vm_disks/box1_disk1&#39;/&amp;gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;lt;target dev=&#39;vda&#39; bus=&#39;virtio&#39;/&amp;gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;/disk&amp;gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Now lets create our script.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;/root/virt.sh:&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;#!/bin/bash&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;set -x&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;virt-install \&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; --name=box1 \&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; --ram=512 \&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; --vcpus=1 \&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; --location=http://ftp.de.debian.org/debian/dists/wheezy/main/installer-amd64/ \&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; --extra-args=&quot;console=ttyS0&quot; \&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; --serial=pty \&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; --console=pty,target_type=serial \&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; --os-type=linux \&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; --os-variant=debiansqueeze \&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; --network=bridge=virbr0,model=virtio \&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; --graphics=none \&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; --virt-type=kvm \&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; --noautoconsole \&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; --nodisks&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;# This is because virt-install doesn&#39;t support passing rbd&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;# style disk settings yet.&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;# Attaching it quickly before system boot however seems to work&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;virsh attach-device box1 disk.xml --persistent&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
And finally we should be able to run it:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;./virt.sh&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Now attach to the console and go through the standard installation steps for the OS.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;virsh console box1&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQ-Ar8JkYZ2G4Rtlu8xO7xeOlq-T3eznSPWgsydcVb7OqJ2aG61f9_gAp120RFa0mwsLSFowyH01g8nNG094CcxedevVcy36Dd28xEXBpq7o_WGad8GtatMbIr5piJN1kpEp6uVk2O_f0/s1600/Screen+Shot+2012-02-05+at+21.46.25.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;388&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQ-Ar8JkYZ2G4Rtlu8xO7xeOlq-T3eznSPWgsydcVb7OqJ2aG61f9_gAp120RFa0mwsLSFowyH01g8nNG094CcxedevVcy36Dd28xEXBpq7o_WGad8GtatMbIr5piJN1kpEp6uVk2O_f0/s640/Screen+Shot+2012-02-05+at+21.46.25.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;Note:&lt;/b&gt;&amp;nbsp;There is no DHCP or DNS server setup - for this test I just provided a static IP and used my own DNS servers.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
As you go through the setup, the RBD disk we defined and created should be available like a normal disk as you would expect. After installation you shouldn&#39;t really notice any major functional difference.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Once installation is complete, you should be able to boot the system:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;virsh start box 1&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
And then access the console:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;# virsh console box1&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;Connected to domain box1&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;Escape character is ^]&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;Debian GNU/Linux 6.0 box1 ttyS0&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;box1 login:&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
And then your done.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-size: large;&quot;&gt;Summary&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-size: large;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
So this is quite an interesting exercise and one worth doing, but the software is still very much early-release. They even admit this themselves.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
I&#39;m wary of performance and stability more then anything, something I can&#39;t test with just a single host - so if I ever get the time I&#39;d really like to run this thing properly.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
I had a brief look at the operations guide, and it seems the instructions for adding and removing a host to the OSD cluster looks not as automatic as I would like it. Ideally, you really want the kind of behaviour that ElasticSearch offers on this level so that adding and removing nodes is almost a brain-dead task. Having said that, adding a node seems easier then some of the storage systems/solutions I&#39;ve seen about the place :-).&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
So regardless of my concerns - I think this kind of storage is definitely the future and I&#39;m certainly cheering the CEPH team on for this one. The functionality was fun (and yes kind of exciting) to play with and I can see that the real-world possibilities of such a solution in the open-source arena are quite probable now.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-size: large;&quot;&gt;Other things to try from here&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;Check out another alternative: &lt;a href=&quot;http://www.osrg.net/sheepdog/&quot;&gt;Sheepdog&lt;/a&gt;, which also seems to be gaining ground but only on the QEMU storage front. Its a very specific solution as apposed to CEPH&#39;s generic storage solution.&lt;/li&gt;
&lt;li&gt;Test CEPH integration with OpenNebula and OpenStack so you can see it within a full cloud provisioning case. This might require some custom scripts to support cloning RBD-stored base images etc. but should be interesting.&lt;/li&gt;
&lt;li&gt;Test the &lt;a href=&quot;http://ceph.newdream.net/wiki/S3-compatible_Gateway&quot;&gt;S3 emulation&lt;/a&gt; provided by the RadosGW component.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-size: large;&quot;&gt;References&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Formal (yet incomplete) Documentation:&lt;/div&gt;
&lt;div&gt;
&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://ceph.newdream.net/docs/latest/&quot;&gt;http://ceph.newdream.net/docs/latest/&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
Wiki:&lt;/div&gt;
&lt;div&gt;
&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://ceph.newdream.net/wiki/Main_Page&quot;&gt;http://ceph.newdream.net/wiki/Main_Page&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
Installation on Debian:&lt;/div&gt;
&lt;div&gt;
&amp;nbsp; &lt;a href=&quot;http://ceph.newdream.net/wiki/Installing_on_Debian&quot;&gt;http://ceph.newdream.net/wiki/Installing_on_Debian&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
RBD:&lt;/div&gt;
&lt;div&gt;
&amp;nbsp; &lt;a href=&quot;http://ceph.newdream.net/wiki/Rbd&quot;&gt;http://ceph.newdream.net/wiki/Rbd&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
QEMU-RBD:&lt;/div&gt;
&lt;div&gt;
&amp;nbsp;&amp;nbsp;&lt;a href=&quot;http://ceph.newdream.net/wiki/QEMU-RBD&quot;&gt;http://ceph.newdream.net/wiki/QEMU-RBD&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
Snapshots:&lt;/div&gt;
&lt;div&gt;
&amp;nbsp; &lt;a href=&quot;http://ceph.newdream.net/wiki/Snapshots&quot;&gt;http://ceph.newdream.net/wiki/Snapshots&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bob.sh/feeds/3519373234348829268/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.bob.sh/2012/02/basic-ceph-storage-kvm-virtualisation.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8383226675188308439/posts/default/3519373234348829268'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8383226675188308439/posts/default/3519373234348829268'/><link rel='alternate' type='text/html' href='http://blog.bob.sh/2012/02/basic-ceph-storage-kvm-virtualisation.html' title='A Basic Ceph Storage &amp; KVM Virtualisation Tutorial'/><author><name>Ken Barber</name><uri>http://www.blogger.com/profile/15151872789024373679</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQ-Ar8JkYZ2G4Rtlu8xO7xeOlq-T3eznSPWgsydcVb7OqJ2aG61f9_gAp120RFa0mwsLSFowyH01g8nNG094CcxedevVcy36Dd28xEXBpq7o_WGad8GtatMbIr5piJN1kpEp6uVk2O_f0/s72-c/Screen+Shot+2012-02-05+at+21.46.25.png" height="72" width="72"/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8383226675188308439.post-865406265078769350</id><published>2012-01-23T19:06:00.001+00:00</published><updated>2012-01-23T19:06:08.530+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="open source"/><title type='text'>Social Aspects of Open Source Contribution</title><content type='html'>Lately I&#39;ve been helping out on a piece of software that has a reasonably wide circulation, and I must say the experience has been interesting. My role in that project is to not only think about wider issues and write code for them, but also to help out with community contribution.&lt;br /&gt;
&lt;br /&gt;
While the technical side of this is interesting, a lot of time is spent on the social side - and I wanted to talk about my experiences, my deficiencies and various gripes from both contributors and &quot;merge-masters&quot; specifically around code contribution. I&#39;m an absolutely crap social person (all my ex-girlfriends think I&#39;m a bastard), and recent discussions with a friend/colleague made me think of writing this article and the struggles with being sociable in this arena in an effort to get myself and others thinking about it more.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Talking Terse&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTm9LCr4ACvWYah0bY4fjwHTQwct8bzriAc9EjaWkqNqTS14GrWByFPa8egEP9Zq20XLT6jGme6sUVqHRjGSe4-bEcz-tEKyoNw321z0xEGbq4bylu5aSbUOZDX4zq79DlVT40vdEX29Q/s1600/arguing_cartoon.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;178&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTm9LCr4ACvWYah0bY4fjwHTQwct8bzriAc9EjaWkqNqTS14GrWByFPa8egEP9Zq20XLT6jGme6sUVqHRjGSe4-bEcz-tEKyoNw321z0xEGbq4bylu5aSbUOZDX4zq79DlVT40vdEX29Q/s320/arguing_cartoon.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
Although its hard not to, its unavoidable in this game that emotion becomes involved. I get a lot of commits that come through, and sometimes I&#39;m not the best at appearing to be &quot;nice&quot;. If you&#39;ve seen me do this - its not even that I&#39;m trying to be nasty - but my choice of language is short because I&#39;m in a rush and I haven&#39;t taken the time to think about how people might interpret it.&lt;br /&gt;
&lt;br /&gt;
I think its easy for an external committer to take personal pride in his submission - and so he should. My terseness or brevity isn&#39;t a reflection on this, in fact I think every community commit is a piece of awesomeness. But like everyone we have limited time and can&#39;t always display that emotion all the time. Like my wife says: &quot;You are an insensitive guy after all&quot;.&lt;br /&gt;
&lt;br /&gt;
When you have a good relationship with a committer that kind of social thing isn&#39;t necessary, but even then I find I need to sit up and just be a person again - not a code testing machine. I think the trick here is that we have to be &quot;nice&quot; no matter what. But more importantly, if you are nasty - say sorry :-).&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Differences of Opinion&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://www.marktoon.co.uk/sayings.htm&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2IZr2PcFUwkSfyBfDBSiTSvvRVe5EqeZV8Q6dMhJr5JFx7GICm1lB_v4qg8hHYdDqXBrDmwnZPAStFoQta0Jx2A_2StKXfiPjD5ia21uKXOfeG2ZLhdUHC6To7ch1DAzPh94E7NUtyEI/s320/too-many-cooks-spoil-the-broth-clipart.gif&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Sometimes you get into arguments as well differences of opinion and sometimes all out slinging matches (although I&#39;ve had very little of these). I&#39;ve found stepping back and trying to put myself in the submitters shoes is the best thing. I have once or twice sparked off emotionally and said &#39;no we&#39;ll never do that&#39;. Only later to realise I was being an arse. The thing is, people are raising these issues because they feel its important to them - the fact that someone has submitted any amount of code shows it matters. So I try to always consider their perspective, but I&#39;m not always successful.&lt;br /&gt;
&lt;br /&gt;
Its easy to be myopic as well about an issue, and I&#39;ve tried recently to purposely give up on arguments when I new the consequences of letting a change through aren&#39;t really going to affect the overall product anyway. I&#39;m a terribly myopic individual at times, but dealing with other people in this case is starting to loosen that up.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Processes&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGnRfHKyD5zP_w7-lTCf5WOZGDW6bPutdIVI9BaXcPPBSiFrAyQOcBKPTe4bBzzcWhyphenhyphenRxIwa6qVLUPLDMdxD7dMpXSDHtn5HMNkjAtz7dNqpWufTz6O8_GWQEQOMogRqlze3Zjq08aBDw/s1600/Peer-Review-Cartoon2.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;205&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGnRfHKyD5zP_w7-lTCf5WOZGDW6bPutdIVI9BaXcPPBSiFrAyQOcBKPTe4bBzzcWhyphenhyphenRxIwa6qVLUPLDMdxD7dMpXSDHtn5HMNkjAtz7dNqpWufTz6O8_GWQEQOMogRqlze3Zjq08aBDw/s320/Peer-Review-Cartoon2.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
My company has a semi-strict processes for code (although not as bad as others I&#39;ve seen). Broken builds must be fixed quickly, and all commits if possible should have tests. All code must be peer reviewed, and must have a ticket. It can be painful - but in our defence we&#39;re asking these things because we have found over time this is the simplest path to quality. Yes - all processes can be argued and not every process fits every problem. But for us we find its the best path to success, and we (my org that is) generally all agree on this.&lt;br /&gt;
&lt;br /&gt;
Not everyone gets this though, sometimes its because they are new. Sometimes they have their own process and this is just an annoying distraction. Sometimes they can&#39;t see the benefit for them in following the process.&lt;br /&gt;
&lt;br /&gt;
So I try hard to help out. For example - writing tests for code is actually generally harder then writing the code itself, but it stops regression and increases the chances that the code was well thought through. Yes its a hassle, but we can&#39;t compromise since we want our product to be high quality and have as little technology debt going forward. I find showing people examples helps, so if I write tests I try to make them readable and&amp;nbsp;reproducible.&lt;br /&gt;
&lt;br /&gt;
For Git based workflow problems (which happen when committers are new) - I will actually spend more time helping them get through the process then if it took me to just write the code. A lot of people ask me why I bother. My attitude is that if I help people out, they contribute more. I want their contribution experience to be a nice one (despite sometimes me ruining it &amp;nbsp;:-).&lt;br /&gt;
&lt;br /&gt;
Some people bitch to me about the process. I hear them loud and clear, I hated the process myself when I first started. Now I need the process. I need to know when a ticket needs to be merged (so change the status). I need to have clear commit messages (so I can see what that change was all about after all). I need the ticket in the commit message (so I can go back and read the back-story behind the change). From my perspective all the various pending changes appear as a stream of tasks I must complete ... and without some semblance of order my brain explodes :-).&lt;br /&gt;
&lt;br /&gt;
Having said that, I want the process to be easier for everyones sake. Always questioning the process if there is a perception it is wrong is the key to this I believe. As a contributor you should also be questioning but more importantly suggesting alternatives. Most projects aren&#39;t doing something because they are trying to cause pain, finding the reasoning behind a process and suggesting an alternative I&#39;m sure for most project members would be more welcome then &#39;your process sucks&#39;.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;For the common good&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNMj4LL2CjnY_q_RmgJoFiiz5AaiBt9eP31PDDgvxxyaHACIsvCgd3KEJO6l-sitI1XYkxMfxyBC-Jk9vGFZcuiu6dzE3-nRD4nyzQ-MpAb_gsEvzuyKxYH8KnkxEaui2aSp9wM8T7NU0/s1600/Earth.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;160&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNMj4LL2CjnY_q_RmgJoFiiz5AaiBt9eP31PDDgvxxyaHACIsvCgd3KEJO6l-sitI1XYkxMfxyBC-Jk9vGFZcuiu6dzE3-nRD4nyzQ-MpAb_gsEvzuyKxYH8KnkxEaui2aSp9wM8T7NU0/s320/Earth.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
Sometimes people want their change to go through, but don&#39;t want to think about how this affects the product as a whole. I always have to think about the product as a whole. Its my curse and well - my job.&lt;br /&gt;
&lt;br /&gt;
I try as much as I can to get people to think about use-cases beyond their own. Sometimes this doesn&#39;t work and I probably come across as difficult. But while I&#39;m being difficult to that person, its in reality being nice to everyone else trying to use it. Does that make sense? Its a bit existential I know :-).&lt;br /&gt;
&lt;br /&gt;
I think the answer sometimes is to provide a plugin system where peoples ideas can be tested on an audience without making it into core. This is certainly a valuable test, as the numbers and the popularity of a solution then speak for themselves.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Anticipating problems&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtIJJsHwd-E_cLGOMNK5Lyv5mRfHiNBMtiZ586yMbfzrNSEcUW4g9CJSWBt2MCnAADWV13NcWiHtv0pAdj15lqbcBUPowbzHfd3Pq0N_gBYoSuQfvNoJEuamvVNL_M25HH6bxMwexqgYQ/s1600/crystalball.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;254&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtIJJsHwd-E_cLGOMNK5Lyv5mRfHiNBMtiZ586yMbfzrNSEcUW4g9CJSWBt2MCnAADWV13NcWiHtv0pAdj15lqbcBUPowbzHfd3Pq0N_gBYoSuQfvNoJEuamvVNL_M25HH6bxMwexqgYQ/s320/crystalball.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
I&#39;ve seen the effect of when a bad change comes through, then the follow up tickets where people bitch about it being broken. I hate that, so I&#39;m pedantic at times. Why? Because I don&#39;t want those follow up tickets - not a single one. I want it right every single bloody time.&lt;br /&gt;
&lt;br /&gt;
But this is not always realistic. Sometimes I have my doubts and let the fates decide, but when I know its a bad idea I dig my heals in. My biggest problem is I have trouble getting my point across as to why I think its a bad problem. Sometimes its just a feeling and hard to quantify. I think my biggest problem as a technical person is my ability to explain an issue via a text based format, and something I need to work on.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Great idea, bad timing&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
And finally there is the ticket that is awesome and cool, but we want to wait because it needs a big change somewhere else. I like these tickets, they confirm that our thinking is right. But as usual we need to consider the blocking change from all perspectives, not just from a 1-bug perspective. Its a pain, and its slow and excruciating and if I could I would love to work on big architecture changes all day long to make the minor functional changes as easy as pie.&lt;br /&gt;
&lt;br /&gt;
But I think these things turn people off. Ultimately there is a perception that these big changes need some staff member or senior to execute it. This in part is true, its much easier to get what you want done when you work near the top of a project (either as part of the company sponsoring it or you are in the upper ranks). This most certainly is something I feel is a big problem, and needs more thought as to its resolution.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;But the people are awesome&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
And this is so true. I&#39;ve met many awesome individuals while doing this kind of work. Sometimes they are short-term relationships, and others I consider to be friends.&lt;br /&gt;
&lt;br /&gt;
Whats awesome about this aspect of the community, is that your working with this people as if they were colleagues - but its all volunteer and without as much constraint. No bosses, no contracts, no business plan, no strict HR - just human beings getting along, writing code and working for the greater good. And this is what I think makes Open Source totally awesome :-).&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiElmGWp_uhbSfqgydHY2p0WWnqqU4UxdElKEcGlMW6LJpCb2VOKD-IukX9sU1MV78T5s8T5nyDW3U9yx8LBl7QU4sFSbDj80glj3jV9EuMYjHsoWrHWVZcYB0JUKaNtl86voxwgqr0DIc/s1600/political-pictures-high-five.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;236&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiElmGWp_uhbSfqgydHY2p0WWnqqU4UxdElKEcGlMW6LJpCb2VOKD-IukX9sU1MV78T5s8T5nyDW3U9yx8LBl7QU4sFSbDj80glj3jV9EuMYjHsoWrHWVZcYB0JUKaNtl86voxwgqr0DIc/s320/political-pictures-high-five.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&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;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bob.sh/feeds/865406265078769350/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.bob.sh/2012/01/social-aspects-of-open-source.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8383226675188308439/posts/default/865406265078769350'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8383226675188308439/posts/default/865406265078769350'/><link rel='alternate' type='text/html' href='http://blog.bob.sh/2012/01/social-aspects-of-open-source.html' title='Social Aspects of Open Source Contribution'/><author><name>Ken Barber</name><uri>http://www.blogger.com/profile/15151872789024373679</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTm9LCr4ACvWYah0bY4fjwHTQwct8bzriAc9EjaWkqNqTS14GrWByFPa8egEP9Zq20XLT6jGme6sUVqHRjGSe4-bEcz-tEKyoNw321z0xEGbq4bylu5aSbUOZDX4zq79DlVT40vdEX29Q/s72-c/arguing_cartoon.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8383226675188308439.post-2986640983113719194</id><published>2012-01-22T00:52:00.000+00:00</published><updated>2012-01-22T00:55:57.868+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="rails"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><category scheme="http://www.blogger.com/atom/ns#" term="travis-ci"/><title type='text'>Travis CI</title><content type='html'>So previously I wrote about &lt;a href=&quot;http://blog.bob.sh/2012/01/rails-31-and-heroku.html&quot;&gt;Heroku&lt;/a&gt; which is a cloud based PaaS service. On the same theme I want to try out another cloud service for development: &lt;a href=&quot;http://travis-ci.org/&quot;&gt;Travis CI&lt;/a&gt;. This tool was suggested to me today by a community committer at my work.&lt;br /&gt;
&lt;br /&gt;
Travis CI is a cloud based continuous integration tool that has deep integration with Github so fits perfectly with the recommended stack outlined in the Rails&amp;nbsp;&lt;a href=&quot;http://ruby.railstutorial.org/ruby-on-rails-tutorial-book&quot;&gt;tutorial&lt;/a&gt; I mentioned in my last post.&lt;br /&gt;
&lt;br /&gt;
So I wanted to try this tool out with some sample code, I decided to just try it on the tutorial code I had written last time: &lt;a href=&quot;https://github.com/kbarber/jakovo&quot;&gt;Jakovo&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
So I followed the &lt;a href=&quot;http://about.travis-ci.org/docs/user/getting-started/&quot;&gt;Getting Started&lt;/a&gt; instructions on the Travis website:&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Logged into the website using Github&lt;/li&gt;
&lt;li&gt;Authorised Travis-CI to access my public github projects&lt;/li&gt;
&lt;li&gt;Went to my &lt;a href=&quot;http://travis-ci.org/profile&quot;&gt;profile page&lt;/a&gt; and flicked the switch for Jakovo&lt;/li&gt;
&lt;li&gt;Added a &lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;.travis.yml&lt;/span&gt; file to my project&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/kbarber/jakovo/commit/3ca808495bf8e5322dcacb1e57bbe09af3896d54&quot;&gt;Commit&lt;/a&gt;ted the git changes to my project, and push it to Github&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
At first it broke. The &lt;a href=&quot;http://travis-ci.org/#!/kbarber/jakovo/builds/555521&quot;&gt;results are here&lt;/a&gt;&amp;nbsp;(but here is a screenshot):&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjO0n_Flbn09CjM7yzqViTBHMZDYC_CRZ0xhH47WmO2oopqtoJ_UkSmb-YMCWU2Y-U8EqjLIgVrnytrXV3NenrWNmGBhHqcMRk1NlvZPow3dWM4vatGUZf5af4GBlgjcC8Y-o-78K9mvOI/s1600/Screen+Shot+2012-01-22+at+00.55.26.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;198&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjO0n_Flbn09CjM7yzqViTBHMZDYC_CRZ0xhH47WmO2oopqtoJ_UkSmb-YMCWU2Y-U8EqjLIgVrnytrXV3NenrWNmGBhHqcMRk1NlvZPow3dWM4vatGUZf5af4GBlgjcC8Y-o-78K9mvOI/s400/Screen+Shot+2012-01-22+at+00.55.26.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
There needs to be a database created before the tests can succeed. So I jumped to the &lt;a href=&quot;http://about.travis-ci.org/docs/user/build-configuration/&quot;&gt;next part&lt;/a&gt; of the Travis CI documentation and read-on.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Turns out the solution is to just provide a setup step before you run the test, its recommended that if you have a lot of steps you write separate scripts for this - but I&#39;m going to take the easy option and just add:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;before_script: bundle exec rake db:migrate&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
To the definition file. Again, &lt;a href=&quot;https://github.com/kbarber/jakovo/commit/289a6b1c424a6143f0a557495ecc7bfe52a69e83&quot;&gt;committing&lt;/a&gt; and pushing this to Github, I get back positive results for the &lt;a href=&quot;http://travis-ci.org/#!/kbarber/jakovo/builds/555532&quot;&gt;next test&lt;/a&gt;. Fairly impressive really:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj72ujWub-BZrt93gXFHbpLN0bl8MuqtJCRRw6iKCtZY0O-k4PctWML8X2FCYT1vmXznQLOykrcy7up7CRII97rMKa_RLM3MIMApoBrBzm0nFVjXDPGaWaEJAicn6XLh_1TjVKZ-5BYLsA/s1600/Screen+Shot+2012-01-22+at+00.53.31.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;215&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj72ujWub-BZrt93gXFHbpLN0bl8MuqtJCRRw6iKCtZY0O-k4PctWML8X2FCYT1vmXznQLOykrcy7up7CRII97rMKa_RLM3MIMApoBrBzm0nFVjXDPGaWaEJAicn6XLh_1TjVKZ-5BYLsA/s400/Screen+Shot+2012-01-22+at+00.53.31.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
What impressed me about this, is just like Jenkins it displays the running results in real-time so you can see it do the build instead of waiting for a failure/success.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
The Github integration is sublime and suits my preferred workflow perfectly. The ability for users to have their clones be tested before they submit a pull request to a main clone will surely be helpful as well (although I haven&#39;t looked into how to do this on a topic branch yet).&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
I guess the only gap I see is the ability to have code tested on multiple platforms, which in my business is important. However, for a lot of projects this won&#39;t matter.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
The ability to choose different Ruby revisions, Gemfiles and Environments creates an interesting matrix capability which parallels the capability in Jenkins that I find quite useful.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
All in all - this looks like a fascinating and useful tool.&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bob.sh/feeds/2986640983113719194/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.bob.sh/2012/01/travis-ci.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8383226675188308439/posts/default/2986640983113719194'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8383226675188308439/posts/default/2986640983113719194'/><link rel='alternate' type='text/html' href='http://blog.bob.sh/2012/01/travis-ci.html' title='Travis CI'/><author><name>Ken Barber</name><uri>http://www.blogger.com/profile/15151872789024373679</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjO0n_Flbn09CjM7yzqViTBHMZDYC_CRZ0xhH47WmO2oopqtoJ_UkSmb-YMCWU2Y-U8EqjLIgVrnytrXV3NenrWNmGBhHqcMRk1NlvZPow3dWM4vatGUZf5af4GBlgjcC8Y-o-78K9mvOI/s72-c/Screen+Shot+2012-01-22+at+00.55.26.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8383226675188308439.post-6101295727567289667</id><published>2012-01-16T01:02:00.004+00:00</published><updated>2012-01-16T01:05:13.433+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="heroku"/><category scheme="http://www.blogger.com/atom/ns#" term="rails"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><title type='text'>Rails 3.1 and Heroku</title><content type='html'>So I finally found some quiet moments to try out the latest Rails 3.1 incarnation. I had tried Rails 2 many years ago and found it quite enjoyable but figured I&#39;d give Rails 3.x a try since I&#39;ve been doing more development along these lines &lt;a href=&quot;https://github.com/ohadlevy/foreman/commit/9b41cf08caf63c343ac3142fb912e914cc15f827&quot;&gt;lately&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
First of all I started with the &lt;a href=&quot;http://ruby.railstutorial.org/ruby-on-rails-tutorial-book&quot;&gt;Ruby on Rails Tutorial&lt;/a&gt; by Michael Hartl. This is a fine starting guide for most people and includes modern techniques including:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Using github to manage your code&lt;/li&gt;
&lt;li&gt;Using Heroku to upload your code to a cloud host&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
I really wanted to try out the Heroku capabilities to see how far the state of the PaaS for Ruby had evolved as I had tried Google App Engine many years ago with both Java and Python and found it very inflexible.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
So I created a little piece of code and called it &lt;a href=&quot;https://github.com/kbarber/jakovo&quot;&gt;Jakovo&lt;/a&gt;&amp;nbsp;loosely based on the tutorial code just to try the Rails + Heroku combination. Its meant to be a task list, as I find task lists are always great for tutorials of this kind.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
At the moment I&#39;ve only gotten as far as creating a basic model with relationship between a user and task, and spent no time on making it look pretty. If I find more time I&#39;ll continue the work.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;Extra Heroku Steps&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
When uploading to Heroku I found a couple of problems that I had to work-around that weren&#39;t clear &amp;nbsp;from the tutorial, so I&#39;ll outline these first.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
First of all, Heroku uses Postgresql as a database, so my code I added the following to Gemfile (for bundler) to handle this:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;group :production do&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; gem &quot;pg&quot;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;end&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
For asset support, I added &lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;therubyracer&lt;/span&gt; gem to my Gemfile. This uses the Chrome V8 javascript runtime.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;group :assets do&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; # A javascript runtime used during asset compilation in heroku&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; gem &#39;therubyracer&#39;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; gem &#39;sass-rails&#39;, &amp;nbsp; &#39;~&amp;gt; 3.1.5&#39;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; gem &#39;coffee-rails&#39;, &#39;~&amp;gt; 3.1.1&#39;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; gem &#39;uglifier&#39;, &#39;&amp;gt;= 1.0.3&#39;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;end&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Then I compiled the assets and checked them into git:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;# bundle exec rake assets:precompile&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;# git add public/assets&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;# git commit -a&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
This is because you can&#39;t modify the filesystem remotely using the heroku interface.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
To prepare the database I ran the following heroku command:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;# heroku run bundle exec rake db:migrate&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Which works the same as it does locally.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;Deploying Using Heroku&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
The Heroku gem was a pleasure to use. After creating a Heroku account on heroku.com I added my keys:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;# heroku keys:add&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Then created an application:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;# heroku create&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
This automatically added the necessary configuration to my local .git/config file that allowed me to deploy:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;# git push heroku master&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
The deployment then walks through on the console all the steps it is performing before telling you it is done. I then navigated to the website:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;# heroku open&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;Troubleshooting Heroku&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
To troubleshoot, Heroku includes some nice tools for this. Here are just a few I found handy during my attempts to dig into problems:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;# heroku logs&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
This displays the remote logs in a nice colourful format.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;# heroku pg:psql&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Gives you a console to the remote Postgresql database, great for analysing your data.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;# heroku apps:info&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Shows detailed information on applications.&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bob.sh/feeds/6101295727567289667/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.bob.sh/2012/01/rails-31-and-heroku.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8383226675188308439/posts/default/6101295727567289667'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8383226675188308439/posts/default/6101295727567289667'/><link rel='alternate' type='text/html' href='http://blog.bob.sh/2012/01/rails-31-and-heroku.html' title='Rails 3.1 and Heroku'/><author><name>Ken Barber</name><uri>http://www.blogger.com/profile/15151872789024373679</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8383226675188308439.post-3769127967021185359</id><published>2012-01-15T18:11:00.000+00:00</published><updated>2012-01-24T13:37:00.285+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="backups"/><category scheme="http://www.blogger.com/atom/ns#" term="mac"/><title type='text'>Time Capsule 4th Generation</title><content type='html'>So recently I obtained a Time Capsule (4th generation) for work for backing up my Mac laptop. Its not a bad little device. This one has 2 TB of internal storage, plus USB support for plugging in&amp;nbsp;additional&amp;nbsp;storage.&lt;br /&gt;
&lt;br /&gt;
While most of my work doesn&#39;t require backups as I use Git for all my development, I do have the odd file that I wouldn&#39;t want to lose - and in the case of a catastrophic failure or during a full restore case this becomes quite important.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Time Machine&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Time machine is a lovely backup solution I must admit, more because it mostly follows the &#39;just works&#39; principles I would expect from a Mac. Getting the Time Machine backups setup with my Time Capsule took very little effort and I&#39;ve only had a couple of problems with it.&lt;br /&gt;
&lt;br /&gt;
After setup for the initial backup, I did this over Ethernet so it would occur in reasonable time. Ongoing backups I do over wireless.&lt;br /&gt;
&lt;br /&gt;
The Time Machine interface is not so bad, the idea is that on the right of the interface you get a timeline that you can roll back to. You are presented primarily with a Finder GUI so you can analyse files on a particular time line easily and restore them if&amp;nbsp;necessary.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_bS5_yxe_xO9mt3MeA5A8a1w_94gSlSeAO0la0i3Sad6Zo2tSPsmORrOXsJ9ZEN5w4ImrJp-xaK7u3-lAyD0C-SCJ6A8qsNs7ZFTWA4oToYcq27etWRQGKMeK05EjkFi4OPu1GdFKrug/s1600/Screen+Shot+2012-01-24+at+13.35.04.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;250&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_bS5_yxe_xO9mt3MeA5A8a1w_94gSlSeAO0la0i3Sad6Zo2tSPsmORrOXsJ9ZEN5w4ImrJp-xaK7u3-lAyD0C-SCJ6A8qsNs7ZFTWA4oToYcq27etWRQGKMeK05EjkFi4OPu1GdFKrug/s400/Screen+Shot+2012-01-24+at+13.35.04.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
While I think this is nice I&#39;d like to explore any command line options that are available as well, but this is more my requirement as I live in the CLI quite a lot.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Wireless Support&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
The unit also acts as an Airport wireless access point. I thought this would be useful due to its 802.11n support, plus when I&#39;m travelling I can hook it into hotel room Ethernet connections and it would provide wireless when its not available - or even better wireless when the hotel wireless has a lot of contention.&lt;br /&gt;
&lt;br /&gt;
From a range perspective, the range for my phone is actually worse compared to when I use my Thompson Router V2 (the thing that O2 gives you in the UK) although this could be an Android problem as I haven&#39;t had another phone to compare it with. For my laptop the range is reasonably acceptable. It supports WPAv2 Personal which is enough for my requirements and can act as a wireless extender, but only with supported routers or other Airport compatible access points.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Problem 1 - Sitting in Preparing backup ...&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;
So I had an issue with the backups sitting in &quot;Preparing backup ...&quot; forever (well for a few days anyway). I cleared this issue first by switching off backups in Time Machine preferences:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhE4sb3zsIK0qV8MssDdAqM4xF6FklIs5nbAeOhaDIzvo_uW1rptaCvzLQTMBSJ6xihau9OvCNZNIsH9aUxxBK6m5tXyA4tcrIJClKcXwIMOrt1KfWIT-K6OOMVfNF9lYNnWYImaLQT5e4/s1600/Screen+Shot+2012-01-15+at+18.05.01.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;285&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhE4sb3zsIK0qV8MssDdAqM4xF6FklIs5nbAeOhaDIzvo_uW1rptaCvzLQTMBSJ6xihau9OvCNZNIsH9aUxxBK6m5tXyA4tcrIJClKcXwIMOrt1KfWIT-K6OOMVfNF9lYNnWYImaLQT5e4/s400/Screen+Shot+2012-01-15+at+18.05.01.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
Then clearing the time machine settings:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;rm /Library/Preferences/com.apple.TimeMachine.plist&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Opening up the Time Machine settings again I chose my disk and re-enabled backups again. This seemed to clear the issue without backup loss.&lt;br /&gt;
&lt;br /&gt;
I&#39;ve only had to do this once, but its fairly repeatable without a major problem (well at least none that I&#39;ve identified yet).&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Problem 2 - Ethernet Port not working&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
I plugged in another laptop to the Ethernet port of the Time Capsule and the port wouldn&#39;t work. I fixed this by rebooting the unit. Such a fundamental problem is pretty disappointing I must admit but it wasn&#39;t a complete blocker.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Things I&#39;d like to see improved&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
The unit is fairly mac-centric. A web interface for configuration would be awesome, but this doesn&#39;t affect me much as I have a Mac to manage the unit.&lt;br /&gt;
&lt;br /&gt;
There is no quota support for managing how much of the in-built disk you want to use for backups versus general storage. The work-around is to dedicate an external USB disk for your own storage requirements but this comes at an extra cost.&lt;br /&gt;
&lt;br /&gt;
Also - there is no in-built encryption for the internal disk for the purpose of backups. Two work-arounds I have seen for this:&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Use an external storage unit that is encrypted&lt;/li&gt;
&lt;li&gt;Find a different encryption solution that serves itself up as a file, and back that up. Store your important data using this solution.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
There are lots of discussions about this on the net, and people saying that this &#39;isn&#39;t an important feature&#39; but I think this is from people who haven&#39;t had to live with strict corporate policies and higher encryption requirements for storage.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;Summary&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
I think the solution isn&#39;t a bad one if you can afford it. It certainly was an easy solution without any major hiccups so totally recommend it for non-power users. I think an alternative would be to use just an Airport unit with external HDD via USB which would save some costs (and probably be more flexible) but as a complete solution its not that bad.&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bob.sh/feeds/3769127967021185359/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.bob.sh/2012/01/time-capsule-4th-generation.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8383226675188308439/posts/default/3769127967021185359'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8383226675188308439/posts/default/3769127967021185359'/><link rel='alternate' type='text/html' href='http://blog.bob.sh/2012/01/time-capsule-4th-generation.html' title='Time Capsule 4th Generation'/><author><name>Ken Barber</name><uri>http://www.blogger.com/profile/15151872789024373679</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_bS5_yxe_xO9mt3MeA5A8a1w_94gSlSeAO0la0i3Sad6Zo2tSPsmORrOXsJ9ZEN5w4ImrJp-xaK7u3-lAyD0C-SCJ6A8qsNs7ZFTWA4oToYcq27etWRQGKMeK05EjkFi4OPu1GdFKrug/s72-c/Screen+Shot+2012-01-24+at+13.35.04.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8383226675188308439.post-8708702018498192615</id><published>2012-01-01T21:45:00.001+00:00</published><updated>2012-01-01T22:30:41.545+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="gems"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><category scheme="http://www.blogger.com/atom/ns#" term="rvm"/><title type='text'>Using rvmrc files for project based gemsets</title><content type='html'>So my good friend Adrien Thebo recommended I check out rvmrc files as a technique for project specific RVM settings. I wanted to see if I could produce gemsets specific to each project without the hassle of switching it myself all the time I change between projects.&lt;br /&gt;
&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
So I started with a basic example. Lets start at the root of my dev area:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;cd ~/Development&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
And I create a project called monstermash:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;mkdir monstermash&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;cd monstermash&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Now I need to create a .rvmrc file for this, but I specify a brand new gemset:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;# rvm --rvmrc --create use ruby-1.8.7@monstermash&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Using /Users/ken/.rvm/gems/ruby-1.8.7-p357 with gemset monstermash&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Now there are two patterns already prepared for preserving what gem to use: bundler and gemset exports. Both reasonable choices but I&#39;m going to use gemset export/import files for now since it needs very little setup. Bundler is a better choice probably when not everyone uses RVM.&lt;br /&gt;
&lt;br /&gt;
So let me build up the monstermash gemset manually now by just installing particular gems:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;gem install rspec --version 2.6.0&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;gem install json --version 1.6.2&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;gem install mocha --version 0.9.12&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;gem install jgrep --version 1.3.1&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
And then finally lets export them:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;# rvm gemset export&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Exporting current environments gemset to .gems&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
This saves the gemset in the local .gems file. Now I modify the created project .rvmrc in ~/Development/monstermash/.rvmrc and comment out the gemset area:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;filename=&quot;.gems&quot;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;if [[ -s &quot;$filename&quot; ]]&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;then&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; rvm gemset import &quot;$filename&quot; | grep -v already | grep -v listed | grep -v complete | sed &#39;/^$/d&#39;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;fi&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Okay. To test, I cd back into my development area and specifically delete the gemset I just created:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;# cd ~/Development&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;# rvm gemset delete monstermash&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;WARN: Are you SURE you wish to remove the entire gemset directory &#39;monstermash&#39; (/Users/ken/.rvm/gems/ruby-1.8.7-p357@monstermash)?&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;(anything other than &#39;yes&#39; will cancel) &amp;gt; yes&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Now lets test if the rvmrc does the right thing by changing into the monstermash directory. As you can see I needed to &#39;trust&#39; the file first, but this is only needed the first time you try to use it and every time it changes.&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;# cd monstermash&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;lt;snip&amp;gt;Big notice about trusting the file&amp;lt;/snip&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Do you wish to trust this .rvmrc file? (/Users/ken/Development/monstermash/.rvmrc)&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;y[es], n[o], v[iew], c[ancel]&amp;gt; y&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;installing diff-lcs 1.1.3...&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;diff-lcs 1.1.3 installed.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;installing jgrep 1.3.1...&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;jgrep 1.3.1 installed.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;installing json 1.6.2...&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;json 1.6.2 installed.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;installing rspec 2.6.0...&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;rspec 2.6.0 installed.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Using: /Users/ken/.rvm/gems/ruby-1.8.7-p357@monstermash&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
And there we go. Not only did it create the monstermash gemset, but it populated it from my projects .gems file:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;# gem list&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;*** LOCAL GEMS ***&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;bundler (1.0.21)&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;diff-lcs (1.1.3)&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;jgrep (1.3.1)&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;json (1.6.4, 1.6.2)&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;rspec (2.6.0)&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;rspec-core (2.6.4)&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;rspec-expectations (2.6.0)&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;rspec-mocks (2.6.0)&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;Now whenever I cd into the directory, it does the right thing:&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;# cd ~/Development/monstermash&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Using: /Users/ken/.rvm/gems/ruby-1.8.7-p357@monstermash&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;So in theory you could check-in the .rvmrc and .gems files into your VCS system so everyone could benefit from this. Of course, you&#39;d want to make sure your project team was happy with this workflow as it only really benefits RVM uses.&lt;/span&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bob.sh/feeds/8708702018498192615/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.bob.sh/2012/01/using-rvmrc-files-for-project-based.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8383226675188308439/posts/default/8708702018498192615'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8383226675188308439/posts/default/8708702018498192615'/><link rel='alternate' type='text/html' href='http://blog.bob.sh/2012/01/using-rvmrc-files-for-project-based.html' title='Using rvmrc files for project based gemsets'/><author><name>Ken Barber</name><uri>http://www.blogger.com/profile/15151872789024373679</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8383226675188308439.post-839915045767346833</id><published>2011-12-31T17:56:00.003+00:00</published><updated>2012-01-01T16:01:23.665+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><category scheme="http://www.blogger.com/atom/ns#" term="rvm"/><category scheme="http://www.blogger.com/atom/ns#" term="zsh"/><title type='text'>Zsh prompt and rvm current</title><content type='html'>So I finally got around to doing something with my boring prompt in zsh. I added this to my .zshrc:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;autoload -U colors &amp;amp;&amp;amp; colors&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;export RPROMPT=&quot;%{$fg[green]%}$(rvm current)%{$reset_color%}&quot;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;And then I added the export to my precmd so it runs it each time:&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;precmd () {&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; export RPROMPT=&quot;%{$fg[green]%}$(rvm current)%{$reset_color%}&quot;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;}&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;Now I get a little green prompt in the far right telling me what version of Ruby (and rvm gemset) I&#39;m using.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;I guess having the prompt change when I switch rvm itself is probably more efficient, I&#39;ll look into that another day.&lt;/span&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bob.sh/feeds/839915045767346833/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.bob.sh/2011/12/zsh-prompt-and-rvm-current.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8383226675188308439/posts/default/839915045767346833'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8383226675188308439/posts/default/839915045767346833'/><link rel='alternate' type='text/html' href='http://blog.bob.sh/2011/12/zsh-prompt-and-rvm-current.html' title='Zsh prompt and rvm current'/><author><name>Ken Barber</name><uri>http://www.blogger.com/profile/15151872789024373679</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8383226675188308439.post-830290059453700109</id><published>2011-12-30T10:19:00.000+00:00</published><updated>2011-12-30T10:31:01.709+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><title type='text'>Backwards Compatible rbconfig</title><content type='html'>My friend James Turnbull came up with this little gem the other day:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;CONFIG = Object.const_get(defined?(RbConfig) ? :RbConfig : :Config)::CONFIG&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
The idea being that since Config is now deprecated in Ruby 1.9.3 and yet RbConfig is not available pre-1.8.5. This work-around covers both angels.&lt;br /&gt;
&lt;br /&gt;
Maybe its the old Perl hacker in me, but there is something about it I really like.</content><link rel='replies' type='application/atom+xml' href='http://blog.bob.sh/feeds/830290059453700109/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.bob.sh/2011/12/backwards-compatible-rbconfig.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8383226675188308439/posts/default/830290059453700109'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8383226675188308439/posts/default/830290059453700109'/><link rel='alternate' type='text/html' href='http://blog.bob.sh/2011/12/backwards-compatible-rbconfig.html' title='Backwards Compatible rbconfig'/><author><name>Ken Barber</name><uri>http://www.blogger.com/profile/15151872789024373679</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8383226675188308439.post-4446785853820061277</id><published>2011-12-28T18:04:00.002+00:00</published><updated>2011-12-28T18:07:54.172+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="esper"/><title type='text'>Esper and Structured Content Struggles</title><content type='html'>Working with structured data in Esper means you need to deal with a varying amount of issues including special character types and nesting. As Esper is Java all this data must be represented as a java.util.Map type before representation which adds some special cases.&lt;br /&gt;
&lt;br /&gt;
I&#39;ve compiled a number of problems and solutions that I have experience directly. The code and data examples will be using JRuby since this is what I develop with. For more details getting this working see my &lt;a href=&quot;http://blog.bob.sh/2011/12/esper-jruby.html&quot;&gt;article provided earlier&lt;/a&gt;.&lt;br /&gt;
&lt;b&gt;&lt;/b&gt;&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;b&gt;Doing a select on a stream that contains special characters&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Sometimes structured data can contain special characters that need escaping. This is especially a problem in the label or key part of the data. Lets take the character &#39;@&#39;. If you need to escape, you must use the &lt;a href=&quot;http://esper.codehaus.org/esper-4.4.0/doc/reference/en/html/event_representation.html#eventrep-properties-escaping&quot;&gt;back-tick character&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Input Data:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;{&quot;itemName&quot;=&amp;gt;&quot;test&quot;,&quot;price&quot;=&amp;gt;100, &quot;@foo&quot; =&amp;gt; { &quot;bar&quot; =&amp;gt; &quot;baz&quot; }}&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Select statement:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;select `@foo`.bar from OrderEvent&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
This would return:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;{&quot;@foo.bar&quot;=&amp;gt;&quot;baz&quot;}&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;Without the escape, you would get the error:&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;NativeException: com.espertech.esper.client.EPStatementSyntaxException: Incorrect syntax near &#39;@&#39; at line 1 column 7, please check the select clause [select @foo.bar from OrderEvent]&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;&lt;b&gt;Returning a column with special characters&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;The converse of the last section is the returning of special characters in column names. Lets say we want to return the above example but with a column name of &#39;@selected&#39;. You&#39;ll need to escape it:&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;select `@foo`.bar as `@selected` from OrderEvent&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;The problem with this, is that now your column will still contain the back-ticks. I&#39;m not sure if this is meant to be a bug or not, but I wrote a small function to clean this up:&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;def clean_escapes(old_hash)&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; new_hash = {}&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; old_hash.each do |k,v|&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; new = k.gsub(&#39;`&#39;,&#39;&#39;)&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; new_hash[new] = v&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; end&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; new_hash&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;end # def clean_escapes&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;This will strip out back-ticks aggressively, but you may find you want something more selective that only does this on the first and last characters.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;&lt;b&gt;Selecting a property that is dynamic&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;Dynamic properties are allowed in Esper, however they must be dealt with during a select properly or else you will receive an error if you hit a block of data that does not contain the property.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;Lets say we have 3 pieces of input data:&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;{&quot;itemName&quot;=&amp;gt;&quot;test&quot;,&quot;price&quot;=&amp;gt;100, &quot;@foo&quot; =&amp;gt; { &quot;bar&quot; =&amp;gt; &quot;baz&quot; }}&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;{&quot;itemName&quot;=&amp;gt;&quot;test&quot;,&quot;price&quot;=&amp;gt;200}&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;{&quot;itemName&quot;=&amp;gt;&quot;test&quot;,&quot;price&quot;=&amp;gt;300}&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;You can see that the property &#39;@foo&#39; only exists in one case. This is a dynamic property.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;So first of all declare the event type. For some reason, without defining @foo earlier, you will get an error (this only seems to happen at the top level with properties that require escaping):&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;order_event_type = {&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &quot;itemName&quot; =&amp;gt; &quot;string&quot;,&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &quot;price&quot; =&amp;gt; &quot;double&quot;,&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &quot;@foo&quot; =&amp;gt; {},&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;}&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;ep_config.addEventType(&quot;OrderEvent&quot;, order_event_type)&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;The select statement to grab @foo.bar whenever it exists would be:&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;select `@foo`.bar? from OrderEvent&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;This then returns:&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;{&quot;@foo.bar?&quot;=&amp;gt;&quot;baz&quot;}&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;{&quot;@foo.bar?&quot;=&amp;gt;nil}&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;{&quot;@foo.bar?&quot;=&amp;gt;nil}&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;
As you can see, it returns only a match once.&lt;/div&gt;
&lt;div style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;
&lt;b&gt;Returning original and new data&lt;/b&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;
Sometimes you want to preserve the original data as well as add new properties. Lets say you have the following set of data:&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;{&quot;id&quot; =&amp;gt; 4, &quot;itemName&quot;=&amp;gt;&quot;test&quot;, &quot;price&quot;=&amp;gt;100}&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: Times;&quot;&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;{&quot;id&quot; =&amp;gt; 5, &quot;itemName&quot;=&amp;gt;&quot;test&quot;, &quot;price&quot;=&amp;gt;100}&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: Times;&quot;&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;{&quot;id&quot; =&amp;gt; 6, &quot;itemName&quot;=&amp;gt;&quot;test&quot;, &quot;price&quot;=&amp;gt;300}&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: Times;&quot;&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;{&quot;id&quot; =&amp;gt; 7, &quot;itemName&quot;=&amp;gt;&quot;test&quot;, &quot;price&quot;=&amp;gt;300}&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: Times;&quot;&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;{&quot;id&quot; =&amp;gt; 8, &quot;itemName&quot;=&amp;gt;&quot;foo&quot;, &quot;price&quot;=&amp;gt;300}&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: Times;&quot;&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;{&quot;id&quot; =&amp;gt; 9, &quot;itemName&quot;=&amp;gt;&quot;test&quot;, &quot;price&quot;=&amp;gt;500}&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: Times;&quot;&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;And you want to provide a brand new property called &#39;doublePrice&#39;. You normally would select the information this way:&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;font-family: Times;&quot;&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;select price * 2 as doublePrice from OrderEvent&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;Which produces the following output:&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;{&quot;doublePrice&quot;=&amp;gt;200}&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;{&quot;doublePrice&quot;=&amp;gt;200}&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;{&quot;doublePrice&quot;=&amp;gt;600}&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;{&quot;doublePrice&quot;=&amp;gt;600}&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;{&quot;doublePrice&quot;=&amp;gt;600}&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;{&quot;doublePrice&quot;=&amp;gt;1000}&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;
Now if instead you want to return the original and new properties, the SQL query can be modified as such:&lt;/div&gt;
&lt;div style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: Times;&quot;&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;select *, price * 2 as doublePrice from OrderEvent&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;The problem however, is that your UpdateListener class now receives a new class type:&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;com.espertech.esper.event.WrapperEventBean&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;This wrapper contains separate underlying returned events for the origin and new properties. So using a small change to my handler code, I merge this whenever it occurs:&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;
if event.class == com.espertech.esper.event.WrapperEventBean then&lt;/div&gt;
&lt;div style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;
&amp;nbsp; c = event.getUnderlying.first.merge(event.getUnderlying.second)&amp;nbsp;&lt;/div&gt;
&lt;div style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;
&amp;nbsp; puts c.inspect&lt;/div&gt;
&lt;div style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;
else&lt;/div&gt;
&lt;div style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;
&amp;nbsp; puts event.getUnderlying.inspect&lt;/div&gt;
&lt;div style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;
end&lt;/div&gt;
&lt;div style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;Now I get combined output:&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;{&quot;id&quot;=&amp;gt;4, &quot;itemName&quot;=&amp;gt;&quot;test&quot;, &quot;price&quot;=&amp;gt;100, &quot;doublePrice&quot;=&amp;gt;200}&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;{&quot;id&quot;=&amp;gt;5, &quot;itemName&quot;=&amp;gt;&quot;test&quot;, &quot;price&quot;=&amp;gt;100, &quot;doublePrice&quot;=&amp;gt;200}&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;{&quot;id&quot;=&amp;gt;6, &quot;itemName&quot;=&amp;gt;&quot;test&quot;, &quot;price&quot;=&amp;gt;300, &quot;doublePrice&quot;=&amp;gt;600}&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;{&quot;id&quot;=&amp;gt;7, &quot;itemName&quot;=&amp;gt;&quot;test&quot;, &quot;price&quot;=&amp;gt;300, &quot;doublePrice&quot;=&amp;gt;600}&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;{&quot;id&quot;=&amp;gt;8, &quot;itemName&quot;=&amp;gt;&quot;foo&quot;, &quot;price&quot;=&amp;gt;300, &quot;doublePrice&quot;=&amp;gt;600}&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;{&quot;id&quot;=&amp;gt;9, &quot;itemName&quot;=&amp;gt;&quot;test&quot;, &quot;price&quot;=&amp;gt;500, &quot;doublePrice&quot;=&amp;gt;1000}&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;div style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;
Now this won&#39;t work for nested data as Ruby&#39;s Hash merge will only work on the shallow level and override keys on the left hand side of the merge operator. If you want to merge structured data, you will need a far more intelligent way of merging data in that case.&lt;/div&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bob.sh/feeds/4446785853820061277/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.bob.sh/2011/12/esper-and-structured-content-struggles.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8383226675188308439/posts/default/4446785853820061277'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8383226675188308439/posts/default/4446785853820061277'/><link rel='alternate' type='text/html' href='http://blog.bob.sh/2011/12/esper-and-structured-content-struggles.html' title='Esper and Structured Content Struggles'/><author><name>Ken Barber</name><uri>http://www.blogger.com/profile/15151872789024373679</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8383226675188308439.post-1556392695237525273</id><published>2011-12-28T17:03:00.001+00:00</published><updated>2011-12-30T10:25:22.691+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="esper"/><title type='text'>Esper Aggregation Examples</title><content type='html'>&lt;br /&gt;
&lt;br /&gt;
I&#39;ve been playing with more Esper stuff. Here is some quick useful aggregation examples I&#39;ve found. Again - if your looking for the context of these posts check my &lt;a href=&quot;http://blog.bob.sh/search/label/esper&quot;&gt;&#39;esper&#39; label&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;
&lt;b&gt;Aggregating Events into a Single Event&lt;/b&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;
If you have multiple events, and wish to aggregate them into a single event,&amp;nbsp;&lt;a href=&quot;http://esper.codehaus.org/esper-4.4.0/doc/reference/en/html/processingmodel.html#processingmodel_aggregation_batch_full_agg&quot;&gt;you can use aggregation functions with a window&lt;/a&gt;. The window provides a time frame in which to evaluate, as aggregation is only really that useful within a span of time, or span of events (there are however exceptions).&lt;/div&gt;
&lt;div style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;
Given the following data:&lt;/div&gt;
&lt;div style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: Times;&quot;&gt;
&lt;/div&gt;
&lt;div style=&quot;font-family: Times;&quot;&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;{&quot;itemName&quot;=&amp;gt;&quot;test&quot;,&quot;price&quot;=&amp;gt;100}&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: Times;&quot;&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;{&quot;itemName&quot;=&amp;gt;&quot;test&quot;,&quot;price&quot;=&amp;gt;200}&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: Times;&quot;&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;{&quot;itemName&quot;=&amp;gt;&quot;test&quot;,&quot;price&quot;=&amp;gt;300}&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: Times;&quot;&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;We want to return every 5 seconds the sum of all these pieces. This can be done with a query using a time_batch window, and using the aggregate &#39;sum&#39; function:&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;select sum(price) from OrderEvent.win:time_batch(5 sec)&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;Which will return the following if the input data is pushed into the stream in the first 5 seconds:&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;{&quot;sum(price)&quot;=&amp;gt;600}&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;You may notice however, that it will emit events every 5 seconds like this afterwards:&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;{&quot;sum(price)&quot;=&amp;gt;nil}&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;You can correct this by changing the select clause to match on the aggregate function. This isn&#39;t done with a &#39;where&#39; clause but instead with aggregates you can use the &#39;having&#39; clause:&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;select sum(price) from OrderEvent.win:time_batch(5 sec) having sum(price) &amp;gt;= 0&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;Now it will only emit an event if the sum of the price is equal to or over 0 and nil events will no longer be returned.&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;
Other examples of aggregate functions are provided &lt;a href=&quot;http://esper.codehaus.org/esper-4.4.0/doc/reference/en/html/functionreference.html#epl-function-aggregation&quot;&gt;in the documentation&lt;/a&gt;.&lt;/div&gt;
&lt;div style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;div style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;
&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;
&lt;b&gt;Selecting Distinct Events from a Stream&lt;/b&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;
&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;
Often you want to be able to pick out distinct events from a series of events defined within a window (either a time window or number of events usually).&lt;/div&gt;
&lt;div style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;
Lets say you have a series of events:&lt;/div&gt;
&lt;div style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;{&quot;id&quot; =&amp;gt; 4, &quot;itemName&quot;=&amp;gt;&quot;test&quot;, &quot;price&quot;=&amp;gt;100}&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;{&quot;id&quot; =&amp;gt; 5, &quot;itemName&quot;=&amp;gt;&quot;test&quot;, &quot;price&quot;=&amp;gt;100}&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;{&quot;id&quot; =&amp;gt; 6, &quot;itemName&quot;=&amp;gt;&quot;test&quot;, &quot;price&quot;=&amp;gt;300}&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;{&quot;id&quot; =&amp;gt; 7, &quot;itemName&quot;=&amp;gt;&quot;test&quot;, &quot;price&quot;=&amp;gt;300}&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;{&quot;id&quot; =&amp;gt; 8, &quot;itemName&quot;=&amp;gt;&quot;foo&quot;, &quot;price&quot;=&amp;gt;300}&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;{&quot;id&quot; =&amp;gt; 9, &quot;itemName&quot;=&amp;gt;&quot;test&quot;, &quot;price&quot;=&amp;gt;500}&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;You can use the distinct keyword during the select to pluck out only the distinct events:&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;select distinct itemName, price from OrderEvent.win:time_batch(1 sec)&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;Which would return:&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;{&quot;itemName&quot;=&amp;gt;&quot;test&quot;, &quot;price&quot;=&amp;gt;100}&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;{&quot;itemName&quot;=&amp;gt;&quot;test&quot;, &quot;price&quot;=&amp;gt;300}&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;{&quot;itemName&quot;=&amp;gt;&quot;foo&quot;, &quot;price&quot;=&amp;gt;300}&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;{&quot;itemName&quot;=&amp;gt;&quot;test&quot;, &quot;price&quot;=&amp;gt;500}&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bob.sh/feeds/1556392695237525273/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.bob.sh/2011/12/esper-aggregation-examples.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8383226675188308439/posts/default/1556392695237525273'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8383226675188308439/posts/default/1556392695237525273'/><link rel='alternate' type='text/html' href='http://blog.bob.sh/2011/12/esper-aggregation-examples.html' title='Esper Aggregation Examples'/><author><name>Ken Barber</name><uri>http://www.blogger.com/profile/15151872789024373679</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8383226675188308439.post-4714184319698293843</id><published>2011-12-24T16:11:00.000+00:00</published><updated>2011-12-25T03:03:44.678+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="operating systems"/><title type='text'>OS package search facilities</title><content type='html'>So I have compiled here a list here of searchable facilities for different OS and distributions. I often need to look this information up myself, thought it might be handy for others.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Meta Search Engines&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Linux Packages Search:&amp;nbsp;&lt;a href=&quot;http://pkgs.org/&quot;&gt;http://pkgs.org/&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Debian Family&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Debian:&amp;nbsp;&lt;a href=&quot;http://www.debian.org/distrib/packages&quot;&gt;http://www.debian.org/distrib/packages&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Ubuntu:&amp;nbsp;&lt;a href=&quot;http://packages.ubuntu.com/&quot;&gt;http://packages.ubuntu.com/&lt;/a&gt;&lt;br /&gt;
&lt;div&gt;
Nexenta:&amp;nbsp;&lt;a href=&quot;http://archive.nexenta.org/&quot;&gt;http://archive.nexenta.org/&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;Redhat Family&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;br /&gt;
Fedora/EPEL:&amp;nbsp;&lt;a href=&quot;https://admin.fedoraproject.org/updates/&quot;&gt;https://admin.fedoraproject.org/updates/&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;SuSE&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
SLES:&amp;nbsp;&lt;a href=&quot;http://support.novell.com/products/server/supported_packages/&quot;&gt;http://support.novell.com/products/server/supported_packages/&lt;/a&gt;&lt;br /&gt;
openSUSE Build Service:&amp;nbsp;&lt;a href=&quot;http://software.opensuse.org/search&quot;&gt;http://software.opensuse.org/search&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;BSD Family&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
OpenBSD Ports:&amp;nbsp;&lt;a href=&quot;http://openports.se/&quot;&gt;http://openports.se/&lt;/a&gt;&lt;br /&gt;
Mac Ports:&amp;nbsp;&lt;a href=&quot;http://www.macports.org/ports.php&quot;&gt;http://www.macports.org/ports.php&lt;/a&gt;&lt;br /&gt;
FreeBSD Ports:&amp;nbsp;&lt;a href=&quot;http://www.freebsd.org/ports/searching.html&quot;&gt;http://www.freebsd.org/ports/searching.html&lt;/a&gt;&lt;br /&gt;
NetBSD Ports:&amp;nbsp;&lt;a href=&quot;http://www.uk.netbsd.org/ports/&quot;&gt;http://www.uk.netbsd.org/ports/&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Solaris Family&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Solaris - OpenCSW:&amp;nbsp;&lt;a href=&quot;http://www.opencsw.org/search/&quot;&gt;http://www.opencsw.org/search/&lt;/a&gt;&lt;br /&gt;
Solaris - Blastwave:&amp;nbsp;&lt;a href=&quot;http://www.blastwave.org/jir/packages.fam&quot;&gt;http://www.blastwave.org/jir/packages.fam&lt;/a&gt;&lt;br /&gt;
OpenIndiana:&amp;nbsp;&lt;a href=&quot;http://wiki.openindiana.org/oi/Package+Repositories&quot;&gt;http://wiki.openindiana.org/oi/Package+Repositories&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Others&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Gentoo:&amp;nbsp;&lt;a href=&quot;http://packages.gentoo.org/&quot;&gt;http://packages.gentoo.org/&lt;/a&gt;&lt;br /&gt;
Arch Linux:&amp;nbsp;&lt;a href=&quot;http://www.archlinux.org/packages/&quot;&gt;http://www.archlinux.org/packages/&lt;/a&gt;&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bob.sh/feeds/4714184319698293843/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.bob.sh/2011/12/os-package-search-facilities.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8383226675188308439/posts/default/4714184319698293843'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8383226675188308439/posts/default/4714184319698293843'/><link rel='alternate' type='text/html' href='http://blog.bob.sh/2011/12/os-package-search-facilities.html' title='OS package search facilities'/><author><name>Ken Barber</name><uri>http://www.blogger.com/profile/15151872789024373679</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8383226675188308439.post-2461923475182801427</id><published>2011-12-24T14:30:00.002+00:00</published><updated>2011-12-24T23:54:34.560+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="git"/><title type='text'>Finding the tag that contains a commit in git</title><content type='html'>I was trying to figure out the exact version when RbConfig was introduced to Ruby 1.8.&lt;br /&gt;
&lt;br /&gt;
So I checked out Ruby from &lt;a href=&quot;http://github.com/ruby/ruby&quot;&gt;http://github.com/ruby/ruby&lt;/a&gt; and then changed to the Ruby 1.8 branch:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;% git checkout ruby_1_8&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
I found the commit in question with a combination of git log and git blame:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;% git show&amp;nbsp;c24a0d897e97c3bb8cc32effd6ca5e9bd9de58c1&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Then I used git describe to found the containing tag:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;% git describe --contains&amp;nbsp;c24a0d897e97c3bb8cc32effd6ca5e9bd9de58c1&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;v1_8_5_preview1~259&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Version 1.8.5. Too easy.</content><link rel='replies' type='application/atom+xml' href='http://blog.bob.sh/feeds/2461923475182801427/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.bob.sh/2011/12/finding-tag-that-contains-commit-in-git.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8383226675188308439/posts/default/2461923475182801427'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8383226675188308439/posts/default/2461923475182801427'/><link rel='alternate' type='text/html' href='http://blog.bob.sh/2011/12/finding-tag-that-contains-commit-in-git.html' title='Finding the tag that contains a commit in git'/><author><name>Ken Barber</name><uri>http://www.blogger.com/profile/15151872789024373679</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8383226675188308439.post-5148772688176468547</id><published>2011-12-23T11:36:00.000+00:00</published><updated>2011-12-24T23:54:55.932+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="android"/><title type='text'>My Initial Assessment of Android 4.0</title><content type='html'>&lt;br /&gt;
&lt;div&gt;
I&#39;m basing a lot of the&amp;nbsp;comparative&amp;nbsp;judgements from my memory of 2.3 since I don&#39;t have it around to compare with. Also most of these items are based on my usage of my phone - other people use their phone in different ways so I won&#39;t be surprised if opinions differ.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Here is what I like:&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;It feels faster. It doesn&#39;t get pauses when I scroll around. The initial splash screen for example doesn&#39;t differ and refreshes itself without my brain noticing any fault.&lt;/li&gt;
&lt;li&gt;The calendar widget is resizable, scrollable and covers multiple days.&lt;/li&gt;
&lt;li&gt;Widget resizing in general is great.&lt;/li&gt;
&lt;li&gt;The alarm now has an adjustable snooze time.&lt;/li&gt;
&lt;li&gt;Favourites bar at the bottom is quite nice. When I first saw this I was apprehensive but now I actually find it quite handy.&lt;/li&gt;
&lt;li&gt;Talk seems to finally have support for switching between my 2 google apps accounts.&lt;/li&gt;
&lt;li&gt;Adding a new app adds a shortcut, which is actually turning out to be a nice convenience for me.&lt;/li&gt;
&lt;li&gt;Viewing all the apps is now much nicer as the screens a flippable, not a huge mess of scrolling.&lt;/li&gt;
&lt;li&gt;GMail App is much nicer and feels easier to navigate. Switching between accounts is more accessible.&lt;/li&gt;
&lt;li&gt;The data usage component in settings is quite handy. I had a third part app for this but now its integrated with extra features. Seeing usage per application is quite handy.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
Things I haven&#39;t been so impressed with:&lt;/div&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;The voice integration doesn&#39;t work for me. The accuracy rate is far too low to be interesting, and its not obvious how to correct this. At least for now. This isn&#39;t a surprise really, no one has really gotten voice working that well - although I do remember Dragon Dictate getting it reasonably accurate at the cost of CPU and $$.&lt;/li&gt;
&lt;li&gt;The bookmark widget is not so nice to look at and use and I can&#39;t refresh it manually I think.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
Things I want to see:&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;Google Docs synchronisation native to the Google Docs app would be nice. Maybe there is a setting - I know there is a cache, but I want it to work offline.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
I&#39;m tempted to get a tab soon with Android, primarily because now I think they seemed to have solved the scheduling/performance issues I was seeing on the old Android software. I&#39;ll have to find one with Android 4.0 to give it a try again.&lt;/div&gt;
&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bob.sh/feeds/5148772688176468547/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.bob.sh/2011/12/my-initial-assessment-of-android-40.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8383226675188308439/posts/default/5148772688176468547'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8383226675188308439/posts/default/5148772688176468547'/><link rel='alternate' type='text/html' href='http://blog.bob.sh/2011/12/my-initial-assessment-of-android-40.html' title='My Initial Assessment of Android 4.0'/><author><name>Ken Barber</name><uri>http://www.blogger.com/profile/15151872789024373679</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8383226675188308439.post-9154789919244300999</id><published>2011-12-23T01:21:00.001+00:00</published><updated>2011-12-24T23:55:25.570+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="esper"/><category scheme="http://www.blogger.com/atom/ns#" term="jruby"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><title type='text'>Esper and JRuby</title><content type='html'>&lt;div&gt;
Based on some advice from RI Pienaar I started to experiment a little with using the &lt;a href=&quot;http://esper.codehaus.org/&quot;&gt;Esper&lt;/a&gt;&amp;nbsp;complex event processing (CEP) engine in JRuby.&lt;br /&gt;
&lt;br /&gt;
So I&#39;ve got some sample code which does a basic match if anyone is interested:&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://github.com/kbarber/esper_testing&quot;&gt;https://github.com/kbarber/esper_testing&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
It requires the Esper &lt;a href=&quot;http://esper.codehaus.org/esper/download/download.html&quot;&gt;jars&lt;/a&gt; to be placed in lib/ to work and has only been tested with Ruby 1.6.5 &amp;amp; Esper 4.4.0.&lt;br /&gt;
&lt;br /&gt;
In the basic example I have the script &#39;&lt;a href=&quot;https://github.com/kbarber/esper_testing/blob/master/basic_match.rb&quot;&gt;basic_match.rb&lt;/a&gt;&#39; I ran a series of data (3 sample orders with different prices in this case):&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;{&quot;itemName&quot;=&amp;gt;&quot;test&quot;,&quot;price&quot;=&amp;gt;100}&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;{&quot;itemName&quot;=&amp;gt;&quot;test&quot;,&quot;price&quot;=&amp;gt;200}&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;{&quot;itemName&quot;=&amp;gt;&quot;test&quot;,&quot;price&quot;=&amp;gt;300}&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
So the first query I ran against it was a basic averaging EPL query:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;select avg(price) from OrderEvent&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
This simply averages the price over time. The output is:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;% ./basic_match.rb&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Dec 23, 2011 10:49:21 AM com.espertech.esper.core.service.EPServiceProviderImpl doInitialize&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;INFO: Initializing engine URI &#39;default&#39; version 4.4.0&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;matched:&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;- {&quot;avg(price)&quot;=&amp;gt;100.0}&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;matched:&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;- {&quot;avg(price)&quot;=&amp;gt;150.0}&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;matched:&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;- {&quot;avg(price)&quot;=&amp;gt;200.0}&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
The second query of interest was using a clause:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;select * from OrderEvent where cast(price,double) &amp;gt; 150&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Where I&#39;m matching all data where the price is over 150. You&#39;ll notice I had to case the price to a double to make it work:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;% ./basic_match.rb &amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Dec 23, 2011 10:51:27 AM com.espertech.esper.core.service.EPServiceProviderImpl doInitialize&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;INFO: Initializing engine URI &#39;default&#39; version 4.4.0&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;unmatched:&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;- {&quot;itemName&quot;=&amp;gt;&quot;test&quot;, &quot;price&quot;=&amp;gt;100}&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;matched:&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;- {&quot;itemName&quot;=&amp;gt;&quot;test&quot;, &quot;price&quot;=&amp;gt;200}&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;matched:&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;- {&quot;itemName&quot;=&amp;gt;&quot;test&quot;, &quot;price&quot;=&amp;gt;300}&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
As you can see here, I have handling for matched and unmatched data.&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bob.sh/feeds/9154789919244300999/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.bob.sh/2011/12/esper-jruby.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8383226675188308439/posts/default/9154789919244300999'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8383226675188308439/posts/default/9154789919244300999'/><link rel='alternate' type='text/html' href='http://blog.bob.sh/2011/12/esper-jruby.html' title='Esper and JRuby'/><author><name>Ken Barber</name><uri>http://www.blogger.com/profile/15151872789024373679</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8383226675188308439.post-4269002994312575040</id><published>2011-12-22T11:30:00.004+00:00</published><updated>2011-12-24T23:55:37.921+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="git"/><title type='text'>Breaking up git-pull</title><content type='html'>Up until now, whenever I wanted to clean up mistakes in a branch on my local repo I had been executing the following:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;% git checkout master&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;% git pull origin +master&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Which has forced the update from my remote origin branch, wiping anything locally and reverting me back to where I wanted to be.&lt;br /&gt;
&lt;br /&gt;
So since git-pull is really just a convenience wrapper around git fetch &amp;amp; merge, I was always curious about the real commands were behind the git pull, and finally figured it out:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;% git fetch -u origin +master&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
The key pieces meaning:&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;+ - force a fetch regardless of whether the branch is a descendant of the current branch. This is required because your trying to rewrite history.&lt;/li&gt;
&lt;li&gt;-u - update the current HEAD. Without this git will refuse to do the operation.&lt;/li&gt;
&lt;/ul&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.bob.sh/feeds/4269002994312575040/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.bob.sh/2011/12/breaking-up-git-pull.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8383226675188308439/posts/default/4269002994312575040'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8383226675188308439/posts/default/4269002994312575040'/><link rel='alternate' type='text/html' href='http://blog.bob.sh/2011/12/breaking-up-git-pull.html' title='Breaking up git-pull'/><author><name>Ken Barber</name><uri>http://www.blogger.com/profile/15151872789024373679</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>