Mastodon

My Git cheatsheet

“Good judgement comes from experience, and often experience comes from bad judgement.”

~Rita Mae Brown

I am pretty sure Rita Mae was talking about Git when she said that. Git is complicated and I don’t think you can really feel comfortable with it until you have created a few disasters with it and hopefully recovered from them using it. I’m no git guru, but I am starting to know a thing or two and I thought I would write down a few of the things that have come up a few times for me. I’ll be adding to this as new ones come up for me. Corrections or suggestions are welcome.

Seeing uncommitted modifications.

Quite a few times I have seen a file listed in git status as modified and thought “What changed in there?”. Essentialy what you are asking is whats the difference between the file pointed to by HEAD and the file.

mike@sleepycat:~/projects/myapp$ git diff — HEAD app/controllers/ceo_controller.rb

diff –git a/app/controllers/ceo_controller.rb b/app/controllers/ceo_controller.rb

index 927112d..3efc1fa 100755

— a/app/controllers/ceo_controller.rb

+++ b/app/controllers/ceo_controller.rb

@@ -26,6 +26,11 @@ class CeoController < ApplicationController

+

+ def claimed_reward

+ @claimed_reward = @member.claimed_rewards.find(params[:id])

+ show_image @claimed_reward.coupon.id

+ end

def gm_preferences

if request.post?

git diff will show all changes in all files.

Adding something to your last commit.

Inevitably after triumphantly committing a piece of code there will end up being some other thing you need to do. Perhaps its suddenly realizing the debugger statement is still in there, or realising that some comments would be a good idea.

…make changes…

git add -u

git commit

Oops! Forgot something

…make changes…

git add -u

git commit –amend

Undoing a commit –amend

Sometimes my last commit doesn’t end up being what I thought it was. Accidentally tacking a minor bug fix onto a merge commit with –amend is kind of goofy, so to undo it:

git reset –soft HEAD@{1}

For more info on the HEAD@{1} or related syntax like HEAD^, you want to look up treeishes.

Step back one commit.

git reset –hard HEAD^

The command above moves the head pointer back one commit and gets rid of the changes.

git reset –soft HEAD^

This would also move the head pointer back one commit but the files you changed would be visible as “modified” when you run git status.

If you are using Heroku to host your project there is an additional consideration. Stepping back one commit means that your remote master on the server at Heroku is further ahead than your local repo. When you try to push you are going to get this:

! [rejected] master -> master (non-fast forward)

The answer is; force it.

git push heroku master –force

Deleting merged branches.

Working with branches is great but it won’t take long before you end up with a pretty long list of branches. Prune your branches with

git branch -d name_of_branch

This will only delete the branch if it has been merged into the current branch. So:

git checkout master

git branch -d facebook_stuff

would only delete the facebook_stuff branch if it had been merged into the master branch already.

Adding a remote.

Out of a general sense of paranoia I periodically have a need to clone the main repository. I’ll try some experiment, fix something… whatever. and then ocaisionally I will want to send the results to staging which I have set up as a remote. The problem is that my staging remote is set up on the original project not the clone so I have to create it again. Since I have had to look this up a few times. This command will show the details for the repo I have titled “staging”:

git remote show staging

Doing that on my original project shows me the address of the repo which I copy to the clipboard and, switching to the newly cloned copy repo, can recreate my link to staging there. This will create a new remote titled staging pointing to an app on heroku.com:

git remote add staging git@heroku.com:<my_app_name>.git

Ignoring files and directories with .gitignore

Create a file in the root of your project called .gitignore. Add whatever rules you need. What you see below will ignore everything in the log directory and the tmp/sass-cache/ directory as well as any file with a .orig extension.

log/
tmp/sass-cache/
*.orig

Somewhat counter-intuitively you need to add the .gitignore file to your repo. For some reason my instinct is that is should somehow be ignored as well but my understanding is that you want it under revision control as well so add it and away you go.

Firefox 4 Beta on Ubuntu

I am playing with the 64 bit version on Ubuntu Karmic and so far is seems pretty great. You can grab a copy here and, once unzipped into a directory you can run it by doing

chmod +x firefox

./firefox

Its generally feels snappy; opens quickly and loads the pages quickly. No crashes yet either. One serious downer is the lack of a 64 bit flash plugin which Adobe has recently withdrawn. Vendors have been selling 64 bit systems for years now, but for some reason Adobe hasn’t been able to release an official 64 bit flash plugin yet. So Mozilla finally launches a 64 bit browser and great swathes of the internet are unusable to anyone who uses it. Nice. No wonder Steve Jobs doesn’t like these guys. The speed the 64 bit gives is needed when dealing with Javascript intensive sites. The javascript driven Visual editor on WordPress, while sluggish at the best of times, is painfully slow with the Beta of 4. Even switching back to the tab running the WordPress editor is sluggish. On the other hand Google maps is noticeably faster and smoother at nearly everything.

I am also excited by the new Add-ons manager. Mozilla is taking things that typically open a new window and making them run in a new tab instead. This is excellent since the Add-ons definitely require more space than the dialog they were appearing in allowed for. Its interesting that for all the seeming obviousness of the tabbed window design and how long its been around, browser makers are still working on fully integrating the concept into the browser.

My only disappointment so far is likely not an issue with Firefox at all. When I first saw the mockups I was excited to see that Mozilla was following Chrome’s lead in moving the tabs into the otherwise underused title bar. While I love the screen real estate that Chrome gives, it hasn’t been enough to tempt me away from all the amazing plugins that Firefox has.

Version 4 was supposed to mean that I got to have my cake and eat it too, adding the look of Chrome to the browser I already use.However while Windows users get the Chrome like interface, on Linux they have merely simulated the effect by hiding the bookmarks toolbar. Irritatingly, the Windows 32bit version gets the full treatment, tabs on top, File, Edit and Bookmarks all hidden away until you hit the ALT key. Its pretty sexy.

Disappointing but my suspicion is that it likely has something to do with the way windows are handled by Gnome, rather than anything to do with Firefox. Hopefully that will be sorted out with Gnome 3. For the moment, fast is good enough.

Rubygems: Finding all available versions of a gem

Yesterday I was asked if I knew what the highest available version in the Rails 1.x line was. I knew it was going to be a variation of “gem list” but it took a little fiddling to get it right. This is just a little thing but its not something you end up doing often and it was useful so I thought I would write it down here.

Strangely “gem list” accepts a string argument (in this case “rails”) that it uses to search for any gem starting with that string. It would be nice to be able to be more specific than “rails*” but it does the job. So here we go.

Gem list –remote seems to return the curent version only:

mike@sleepycat:~$ gem list –remote rails
rails (2.3.8 ruby)
rails-action-args (0.1.1 ruby)

Including –all gets all the released versions:

mike@sleepycat:~$ gem list –remote rails –all

*** REMOTE GEMS ***

rails (2.3.8 ruby, 2.3.7 ruby, 2.3.6 ruby, 2.3.5 ruby, 2.3.4 ruby, 2.3.3 ruby, 2.3.2 ruby, 2.2.3 ruby, 2.2.2 ruby, 2.1.2 ruby, 2.1.1 ruby, 2.1.0 ruby, 2.0.5 ruby, 2.0.4 ruby, 2.0.2 ruby, 2.0.1 ruby, 2.0.0 ruby, 1.2.6 ruby, 1.2.5 ruby, 1.2.4 ruby, 1.2.3 ruby, 1.2.2 ruby, 1.2.1 ruby, 1.2.0 ruby, 1.1.6 ruby, 1.1.5 ruby, 1.1.4 ruby, 1.1.3 ruby, 1.1.2 ruby, 1.1.1 ruby, 1.1.0 ruby, 1.0.0 ruby, 0.14.4 ruby, 0.14.3 ruby, 0.14.2 ruby, 0.14.1 ruby, 0.13.1 ruby, 0.13.0 ruby, 0.12.1 ruby, 0.12.0 ruby, 0.11.1 ruby, 0.11.0 ruby, 0.10.1 ruby, 0.10.0 ruby, 0.9.5 ruby, 0.9.4.1 ruby, 0.9.4 ruby, 0.9.3 ruby, 0.9.2 ruby, 0.9.1 ruby, 0.9.0 ruby, 0.8.5 ruby, 0.8.0 ruby)

And if you wondered, as I did, “Where is Rails 3 in that list?”. You need to include a flag for prereleases:

mike@sleepycat:~$ gem list –remote –prerelease rails –all

rails (3.0.0.beta4 ruby, 3.0.0.beta3 ruby, 3.0.0.beta2 ruby, 3.0.0.beta ruby, 2.3.8 ruby, 2.3.8.pre1 ruby, 2.3.7 ruby, 2.3.6 ruby, 2.3.5 ruby, 2.3.4 ruby, 2.3.3 ruby, 2.3.2 ruby, 2.2.3 ruby, 2.2.2 ruby, 2.1.2 ruby, 2.1.1 ruby, 2.1.0 ruby, 2.0.5 ruby, 2.0.4 ruby, 2.0.2 ruby, 2.0.1 ruby, 2.0.0 ruby, 1.2.6 ruby, 1.2.5 ruby, 1.2.4 ruby, 1.2.3 ruby, 1.2.2 ruby, 1.2.1 ruby, 1.2.0 ruby, 1.1.6 ruby, 1.1.5 ruby, 1.1.4 ruby, 1.1.3 ruby, 1.1.2 ruby, 1.1.1 ruby, 1.1.0 ruby, 1.0.0 ruby, 0.14.4 ruby, 0.14.3 ruby, 0.14.2 ruby, 0.14.1 ruby, 0.13.1 ruby, 0.13.0 ruby, 0.12.1 ruby, 0.12.0 ruby, 0.11.1 ruby, 0.11.0 ruby, 0.10.1 ruby, 0.10.0 ruby, 0.9.5 ruby, 0.9.4.1 ruby, 0.9.4 ruby, 0.9.3 ruby, 0.9.2 ruby, 0.9.1 ruby, 0.9.0 ruby, 0.8.5 ruby, 0.8.0 ruby)

Don’t forget that when the output gets to long (like when you ask for details) you can always redirect it into a file:

mike@sleepycat:~$ gem list –remote –details –prerelease rails –all > gemlist.txt

Like I said… a little thing, but useful to know about.

Dear Canonical: Need Data.

Dell’s partnered with Canonical in 2007 was pretty exciting news. In my professional life I have spent close to half a million on computer hardware with the majority of it going to Dell. All my personal computers have always come from them as well. When I decided to get myself a new laptop, I went to straight to Dell.ca/ubuntu to pick out my dream machine.

After a little poking around I realised that they only sell Ubuntu on the low end machines. At the time (almost a year and a half ago now) they sold Ubuntu preinstalled on at least one desktop machine and on maybe three different laptops. Their best one was the lowest end of the XPS line and had very few customisation options.

While I really wanted to buy a system with Ubuntu preinstalled so Dell would know that a market for this stuff actually exists, I also knew I would be doing myself a disservice by buying something less powerful than I needed. After agonising over it I bit the bullet and bought the top of the range XPS with most of the bells and whistles… and Windows Vista.

Looking again, Dell seems to have reduced even that meagre offering and is now only offering Ubuntu preinstalled on the Dell mini netbook and a low-end Inspiron laptop. Aside from the fact that Ubuntu is almost impossible find for anyone not typing in the URL directly, the worst part is the Inspiron 15 with Ubuntu is $579 while the Inspiron 15 with Windows 7 is $569. Perhaps I’m old fashioned, but a computer with a $110 copy of Windows 7 on it should be more expensive than one without. It would be nice if one of the most obvious benefits of Linux were a little more obvious in the pricing. For a partner, Dell seems to have some funny ideas about what will help Ubuntu sell well.

While I believe Dell was correct in sensing that there is a market out there, and gutsy enough to try it out, its Ubuntu offerings seem to be languishing. Partly its pricing silliness and poor marketing but mostly it seems like they are misreading the market. Its been my experience that Linux users don’t buy low end hardware. Low end hardware in the Linux community seems to be something that is either gifted or salvaged, not something you purchase. When purchasing, its mid range to high end systems they are after. With that in mind, I can’t help but feel that Dell has missed the mark with their offering.

I suspect they missed it for the same reason most other companies still think there is no money to be made in the Linux world; there’s very little data. While Canonical is starting to gather a little data for their servers, I think the desktop probably needs it more. Perhaps its time for an Ubuntu version of the Steam Hardware Survey. Maybe they should consider some demographic surveys as well.  I think its time we find out big the GNU dollar is.

I think this needs to happen before companies fall prey to a self fulfilling prophecy; Offer a product blindly, receive an underwhelming response, and conclude that there really is no money to be made from the 12 million+ Ubuntu machines and the unknown number of users of other distros. This kind of data would be invaluable not only to developers considering a Linux version of an existing program, but also to partners like Dell who just seem to need a bit of a nudge in the right direction.

What say you Canonical?

Rubygems: Installing downloaded gems

I set aside some time this evening to move one of my projects forward. Just as I was getting into it I realised I needed to install some gems. The normally quick “sudo gem install blah” took forever.  After several frustrating minutes, rubygems coughed up the following error:

WARNING:  RubyGems 1.2+ index not found for:
http://gemcutter.org
http://gems.rubyforge.org/

RubyGems will revert to legacy indexes degrading performance.

Degrading performance it certainly was. Both aggravated and curious, I embarked on a flurry of pings, nslookups and GET requests which seem to indicate that Rubygems.org is, in fact, down. Interestingly, Heroku, which hosts rubygems.org was up, reachable and blazing fast. Not wanting to totally waste an evening I figured now was a pretty good time to look into installing gems manually. Luckily it was really easy, but rubygems generally makes it so you don’t need to consider any other options.

The gem I was after offered two options: download as a tar file or a gem file.

Installing from the tar file seems to be a matter of extracting it into /usr/lib/ruby/gems/1.8/gems/ and a quick look at the README file indicated I needed to run setup.rb. That might not hold for all gems but it worked for that one.

Just out of interest I also tried installing from the downloaded gem file. It turns out that its even easier. After downloading the gem file all it took was:

mike@sleepycat:~$ cd Downloads/
mike@sleepycat:~/Downloads$ sudo gem install ruby-openid-2.1.8.gem
Successfully installed ruby-openid-2.1.8
1 gem installed
Installing ri documentation for ruby-openid-2.1.8…
Installing RDoc documentation for ruby-openid-2.1.8…

Not difficult, but not something I had had to do before. Hopefully Rubygems.org will be back up shortly and I won’t have to do again any time soon.I can understand the urge to centralise like Rubygems.org has done with the gem hosting community. The problem is that while you might save some bucks and/or some hassle by centralising, you are multiplying the impact of the inevitable. At least tonight, it doesn’t feel worth it.

Lean Startups and the Microsoft BizSpark fat bomb.

There is a lot of talk in tech circles about running a “lean” startup. Eric Ries, Paul Graham from the Ycombinator and many others investing in technology are all pushing this model of launching a company. There are quite a few definitions out there but they all centre on having a low burn rate. Eric Ries sums up the advice on achieving this:

“by taking advantage of open source, agile software, and iterative development, lean startups can operate with much less waste.

I suspect it is exactly that advice that prompted Microsoft to launch their BizSpark program. When the ad “Microsoft BizSpark – Programs for software start-ups. 3 years for just US$100!” showed up in my Gmail a while back I couldn’t resist reading the terms to find out what happens at the three year mark.

Having priced out some Microsoft Sharepoint based websites in my previous career, I had a pretty good idea what the punchline might be. On their site they explain:

“In addition to responsibility for the USD$100 program offering fee, Startups can continue to use the development tools they previously obtained through the program. If Startups wish to continue to receive updates to development tools, Startups can renew their MSDN subscription at usual rates and terms. To continue to use the production licenses, Startups may choose to take advantage of a licensing program like Microsoft’s Services Provider License Agreement program (or other Microsoft licensing programs that may be available at the time), but are in no way obligated to do so.”

http://www.microsoftstartupzone.com/BIZSPARK/Pages/FAQ.aspx#q9

While this sounds “lean”, to me, this is a fat bomb, waiting to go off. We all need to keep our software up to date for security reasons if nothing else, so its not as though its a real option to run without updates for very long. They know you are going to have to pony up sooner or later. After three years of writing Microsoft code and immersing yourself in their ecosystem, the likelihood you will have both the skill set and the motivation to start again on another platform is low.

While I thought that at the time, just today I read about the exception that proves the rule. The smart and obviously multi-talented duo behind Tekpub had some interesting thoughts on BizSpark they shared in an interview about their recent switch from .Net MVC to the open source Ruby on Rails framework:

RB: If the platform was holding up fine, what prompted the change of architecture?

RC: Money. We were enrolled in Microsoft BizSpark Program and it was great for getting off the ground, but projecting into the future we realized that everything – from our database down to our development environment would have to be paid for after 3 years. We also figured that we’d probably need a separate server to run videos properly (for streaming) to Silverlight (using Streaming Media) which would be another license cost – and, in addition, we’d need to buy Media Encoder in order to encode the video for Smooth Streaming.

This might not be an issue for a large company, but when we sat down to assess what the bills would be – well let’s just say that it was about 5 figures. We put our business hats on and tried to justify that cost – and we couldn’t.

JA: As Rob mentioned cost was one of the factors, BizSpark is great but it is basically a ticking time bomb.

The emphasis is mine, but the sentiments are theirs.The five figures number they mention, agrees with the numbers I came up with in my pricing exercise a few years ago. Working with a Microsoft Licensing specialist, I ended up somewhere a little shy of $150,000, for the server alone.

That gave me a pretty serious case of sticker shock at the time and still blows me away when I think of the implications of it for the organisation as a whole. While the market sets the highest price a company can sell its product/service for, it seems that for a lot of companies the lowest price is being set in Redmond. While I have to accept the former, the latter, fortunately, is optional.
Now I am not an economist, but the view from here is that the costs for a “lean” startup, look something like:

coffee + people + place

While for a Microsoft-based company or a BizSpark company on year 4 it is:

coffee + people + place + licence costs

If both those companies have to spring for developers and all the usual stuff, then when prices are high the lean company would have a higher profit margin and when things get competitive they can drop their prices lower. A BizSpark business will be able to behave like a lean startup for the first few years, but will moving up a few weight classes while others in the field stay lean. Effectively the lowest price you can sell your product for is suddenly being determined in Redmond rather than in your office. For those tackling tough markets, or dealing with big organisations where you can easily run out of money waiting for a sale to come through the pipeline, this should be a terrifying prospect. With recession talk and belt tightening all around, why would anyone think running lean is less important on year four than it is in year three?

Update – Feb 2014: It seems like even success can’t protect you. Having exited the Bizspark program somewhere around 2011, and seemingly having coasted as long as possible on their exising licences, Stackoverflow  co-founder and Bizspark alumnus Joel Splosky is now balking at the licencing costs for Microsoft’s SQLserver.

He took to Twitter asking about porting a large database to Postgres. When prodded for more detail he added:

If you read the full exchange you can see that the suggested remedy ends up being to use Stackoverflow’s “posterboy” status as a Microsoft success story to work a deal with Microsoft for some reduced rates, which brings in Microsoft’s Scott Hanselman:

The thread ends rather suddenly as the whole thing goes offline as the Bizspark posterboy is presumably offered whatever deal is required to keep their success story looking like a success. Illusion of financial viability maintained. +1 Microsoft.

Let’s also ignore the face that Stackoverflow’s other co-founder Jeff Atwood decided to use Ruby on Rails, Postgres and Javascript for his new project; discourse.

Image overlays with Rmagick and Rails

I knew it wouldn’t be long before I had another foray into Rmagick. This time is pretty similar to last time, except this time I needed to overlay one image on top of another image. There are a few people who have posted about how to do this but I found the information pretty sparse. As I was looking I noticed that some people were using the ImageList class and others the Image class. After ping-ponging between the various tutorials and finding the differences between them pretty confusing, I thought I would sort myself out by using both.

So here is the code that generated that stunning image overlay. I tend to figure this stuff out by sticking it in a controller and tinkering  with it. Once it works I will move it into a model. The code below is taken from my controller. First, the version using the Rmagick’s ImageList class:

def rubylist
ruby = ImageList.new(‘public/images/ruby.jpg’)
rails = ImageList.new(‘public/images/rails.png’)
ruby.gravity=EastGravity
ruby.geometry=’0x0+20+20′
rails_on_ruby = ruby.composite_layers(rails, Magick::OverCompositeOp)
rails_on_ruby.format = ‘jpeg’
send_data rails_on_ruby.to_blob, :stream => ‘false’, :filename => ‘test.jpg’, :type => ‘image/jpeg’, :disposition => ‘inline’
end

So what we have are two ImageList objects; ruby and rails. I am going to use ruby as my “destination” ImageList, meaning it will be the base image that  the other image is applied to. Setting the Gravity and Geometry attributes on the “destination” object means that Rmagick will position the “source” image according to those settings. Calling composite_layers on ruby and feeding it rails and a composite operator let Rmagick know what should be combine with the base image and how it should combine them. Since we already gave it the “where” part of the equation with the gravity and geometry, the rest is easy.

Doing the same thing with the Image class instead of ImageList is just different enough to trip you (read: Me) up:

def ruby
ruby = Image.read(‘public/images/ruby.jpg’)[0] #This returns an Array! Get the first element.
rails = Image.read(‘public/images/rails.png’)[0]
rails_on_ruby = ruby.composite(rails, Magick::EastGravity, 0, 0, Magick::OverCompositeOp) #the 0,0 is the x,y
rails_on_ruby.format = ‘jpeg’
send_data rails_on_ruby.to_blob, :stream => ‘false’, :filename => ‘test.jpg’, :type => ‘image/jpeg’, :disposition => ‘inline’
end

Rmagick pretty consistently works in a way that is the opposite of what I expect. Where I would expect Image.read to return, say, an image, instead it returns an Array. So after some head scratching and a little RTFM time I learned you could do what you see above. Alternately you could do “Image.read(‘public/images/rails.png’).first” if you think it’s prettier. The geometry stuff takes a little fooling around to get sorted out and to see how it works with the gravity. My understanding is that the x,y is just to offset the object from where the gravity setting alone would have placed it.

Like the image annotations before, its not difficult to do, but its a pain to figure out. While there are a bunch of other ways to write this code, this will at least give a running start.

Steam on Linux will be a very big deal.

Today Phoronix “officially” announced that Steam is coming to Linux. While their definition of “official” doesn’t seem to require any input from Valve (the company that makes Steam), it does seem likely that they are correct given the screenshots and whatnot circulating on their site.

Its been pointed out before (I can’t remember where) that gamers are a perfect target market for Linux. They are more technical than the average user, looking for performance and geeky. I also think Linux and gaming are a match made in heaven, and now that it seems like it may actually happen, it does make you wonder about the ripple effect this will have across the industry.

For Microsoft there are a few interesting implications. First, one of the top games companies has gone cross-platform. To do this you would have to ditch Microsoft’s DirectX and code using OpenGL. Losing a company like Valve is bad, but its made worse since Steam is now cross-platform (currently on Windows and Mac, Linux rumours aside) and as such incentivizes other developers using Steam as a sales platform to follow suit.

Judging from the recent success of Wolfire’s Humble indie bundle, Mac and Linux users are worth the trouble of reaching out to. Had Valve been a little faster at making Steam cross-platform,  some of the nearly $1.2 million they Wolfire raised could have gone to Valve. All the games in the bundle are available via Steam already, but only for Windows. Hopefully other developers were paying attention.

Also, pretty much every Linux user I know has a Windows machine they keep around for gaming. There is also a pretty sizeable number of Mac users out there that do the same. If you can get all (or even most) of your favourite games for your chosen OS, why keep Windows around?

Linux users may have some additional reasons to keep a Windows box around (Photoshop jumps to mind) but Mac users will likely just jettison Windows entirely the first chance they get. This effect will probably be noticeable only in some indirect ways: more pressure on OEM’s like Dell or HP to deliver machines without Windows, sluggish sales of the next version of Windows. While it won’t be huge, I think this effect would probably be big enough to be noticed by Microsoft. That said, I don’t think you could ever make a direct causal link.

The effect on the Linux community is also interesting to think about. Will we see stripped down gaming distros, tweaked to get the highest possible Frames Per Second, running Xfce (or even TWM), Steam and not much more? Imagine having both game and OS compiled from source specifically to squeeze every bit of performance out of your processor. Gentoo… I think we have found your calling. Of course, if gamers come to expect the ability to significantly optimize their operating systems, they may start demanding that of their video drivers as well…

Even though Steam is still vaporware at the moment, it’s awfully fun to speculate about. While it’s still possible that it won’t actually happen, one thing if for sure; Steam on Linux would be a very big deal.

The budding business case for linux

Wolfire games has teamed up with some of the other top indie game developers and put together a cross platform game bundle that is selling like hotcakes. It includes the games World of Goo, Aquaria, Gish, Lugaru and Penumbra. Their “pay what you want” game bundle has made them half a million dollars (and counting) to be split amongst the developers from the participating studios as well as selected charities (EFF and Child’s Play). While the sale of the bundle is generating some good money, it’s also generating some fascinating statistical data:

Windows ~90% of the market 65% of donations 52% of revenue
Mac ~6% of the market 21% of donations 25% of revenue
Linux: ~1% of the market 14% of donations 23% of revenue

There is plenty of conjecture about why they numbers shake out that way but, pretty much any way you look at them there it is looks like a pretty solid business case for supporting Mac and Linux. Until recently there was precious data about what it might be like selling into the Linux community. Most simply wrote it off assuming that the ~1% market share was all there was to the story. While not every company will have the same experience as Wolfire, I think that they have proved there is more going on there than the 1% suggests.

This bodes particularly well for Valve and their imminent release of their Steam platform for the Mac (curently in Beta), and their upcoming version for Linux. It will be really interesting to see what kind of numbers they come up with after running Steam across all three platforms. If they are anything like the numbers from Wolfire, the next couple of years are going to be pretty interesting for Linux.

I also wonder if the bundle method could also be harnessed as a broader method of funding Free Software development. Imagine a web of cross promotion where developers with easily monitized software (like a game) include a donation to a less easily monitized project (like a bittorrent client) exactly as was done with the EFF in the Humble bundle. Wolfire has done something inspirational, and shown there are lots of possibilities to explore. Go and support them!

Adding text to pictures with Rmagick and Rails.

Recently I needed to add some dynamically generated text to an image with Ruby on Rails. For some reason there do not seem to be many tutorials on how to work with RMagick so I thought I would share what little I now about it. Originally I looked at Image Science but it turns out that its very focused on simply resizing images. So for this I turned to RMagick. I was a little worried that the installation would be nightmarish but it turned out to be quite painless (at least on Ubuntu. I can’t imagine what it would be like on Windows. Probably bad.):

mike@sleepycat:~$ sudo aptitude install imagemagick librmagick-ruby libmagickwand-dev

Then install the gem:

mike@sleepycat:~$ sudo gem install rmagick

RMagick is a complex library that has tonnes of graphics functions and can transform images in many different ways.
It seems that RMagick works conceptually the same for both Vector graphics and bitmap images: create an image and add text objects to it or create a canvas and add vector objects to it (using Ruby Vector Graphics aka:RVG). So lets do that. So here is an image to start with:

To start playing with RMagick, you can stick this in one of your controllers:

require ‘RMagick’
include Magick

def lolcat

img = ImageList.new(‘public/computer-cat.jpg’)
txt = Draw.new

img.annotate(txt, 0,0,0,0, “In ur Railz, annotatin ur picz.”){
txt.gravity = Magick::SouthGravity
txt.pointsize = 25
txt.stroke = ‘#000000’
txt.fill = ‘#ffffff’
txt.font_weight = Magick::BoldWeight
}

img.format = ‘jpeg’
send_data img.to_blob, :stream => ‘false’, :filename => ‘test.jpg’, :type => ‘image/jpeg’, :disposition => ‘inline’

end

And here is the output of that script:

Although sticking that in a controller is a quick way to see the results of some tinkering and experimentation, this is the kind of stuff that should really be in a model. You would likely want to return img.to_blob from one of your model methods and then use send_data from there.

It’s pretty basic but it was all I needed to get my project working. RMagick does seem to be a little arcane. A lot of the things I tried along the way failed in pretty confusing ways and with pretty cryptic errors. While simple stuff like this is fine its going to take a lot more reading and fiddling to make me truly comfortable with RMagick. At least I have this written down for next time…