<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title type="text">Jordi Romero</title>
  <updated>2013-07-17T10:00:00+00:00</updated>
  <generator uri="http://jrom.net">jrom.net</generator>
  <id>tag:jrom.net,2010:/</id>
  <link href="http://jrom.net/articles.xml" rel="self"/>
  <link href="http://jrom.net" rel="alternate"/>
  <author>
    <name>Jordi Romero</name>
    <uri>http://jrom.net</uri>
  </author>
  <entry>
    <title>Radical startup</title>
    <link type="text/html" href="http://jrom.net/radical-startup" rel="alternate"/>
    <id>tag:jrom.net,2013-07-17:/radical-startup</id>
    <content type="html">&lt;script async=&quot;true&quot; class=&quot;speakerdeck-embed&quot; data-id=&quot;0b2244c011b801319b243ee73b53aa89&quot; src=&quot;//speakerdeck.com/assets/embed.js&quot;&gt; &lt;/script&gt;

&lt;p&gt;This talk was presented in the context of &lt;a href=&quot;http://benasque.org/2013radical/&quot;&gt;Radical Benasque&lt;/a&gt;, a conference to explore the limits of your mind and body, where we discussed subjects such as Radical Brain (neurobiology), Radical Food (innovation in cuisine, evolution of food), Radical Science (quantum physics), etc.&lt;/p&gt;
</content>
    <published>2013-07-17T10:00:00+00:00</published>
    <updated>2013-07-17T10:00:00+00:00</updated>
    <category term="talks"/>
  </entry>
  <entry>
    <title>Control your life</title>
    <link type="text/html" href="http://jrom.net/control-your-life" rel="alternate"/>
    <id>tag:jrom.net,2013-05-06:/control-your-life</id>
    <content type="html">&lt;div class=&quot;responsive-container&quot;&gt;&lt;iframe src=&quot;//player.vimeo.com/video/65731113?byline=0&quot; width=&quot;700&quot; height=&quot;393&quot; frameborder=&quot;0&quot; webkitallowfullscreen=&quot;true&quot; mozallowfullscreen=&quot;true&quot; allowfullscreen=&quot;true&quot;&gt;&amp;nbsp;&lt;/iframe&gt;&lt;/div&gt;

&lt;p&gt;This video was recorded during the presentation at itnig’s fridays in May 2013.&lt;/p&gt;

&lt;script async=&quot;true&quot; class=&quot;speakerdeck-embed&quot; data-id=&quot;03ecbd2098930130d5ce2e588ebf9c37&quot; src=&quot;//speakerdeck.com/assets/embed.js&quot;&gt; &lt;/script&gt;

</content>
    <published>2013-05-06T10:00:00+00:00</published>
    <updated>2013-05-06T10:00:00+00:00</updated>
    <category term="talks"/>
  </entry>
  <entry>
    <title>Metrics for Pirates!</title>
    <link type="text/html" href="http://jrom.net/metrics-for-pirates" rel="alternate"/>
    <id>tag:jrom.net,2013-02-15:/metrics-for-pirates</id>
    <content type="html">&lt;h3 id=&quot;lean-startup--science&quot;&gt;Lean Startup &amp;amp; Science&lt;/h3&gt;

&lt;p&gt;&lt;img width=&quot;300px&quot; alt=&quot;Metrics for Pirates, AARRR, by Jordi Romero&quot; src=&quot;/files/metrics-for-pirates/Title.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Defining a strategy for a product startup is both exciting and hard to do
objectively. Most of the times the founders are guided by instinct and passion,
and that’s great, but can lead to follow false hypothesis.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Lean Startup&lt;/strong&gt; is this whole movement and set of best
practices that can reduce uncertainty by making the founders validate their
hypothesis one after the other. It’s all about validated learning, which means
applying &lt;em&gt;science&lt;/em&gt; to decide if the company is going in the right
direction.&lt;/p&gt;

&lt;p&gt;And by &lt;em&gt;science&lt;/em&gt; I mean &lt;strong&gt;metrics&lt;/strong&gt;.&lt;/p&gt;

&lt;h3 id=&quot;the-video&quot;&gt;The video&lt;/h3&gt;

&lt;p&gt;This week I gave a presentation in the &lt;a href=&quot;http://barcelona.leanstartupcircle.com/events/100202632/&quot;&gt;Barcelona Lean Startup
Circle&lt;/a&gt; titled
&lt;strong&gt;Metrics for Pirates&lt;/strong&gt;. &lt;a href=&quot;http://itnig.net/en&quot;&gt;Itnig&lt;/a&gt; was kind enough to record
and upload a video, so if you don’t feel like reading you can watch it here. Not
even half an hour.&lt;/p&gt;

&lt;div class=&quot;responsive-container&quot;&gt;&lt;iframe src=&quot;http://player.vimeo.com/video/59693529?byline=0&quot; width=&quot;710&quot; height=&quot;399&quot; frameborder=&quot;0&quot; webkitallowfullscreen=&quot;true&quot; mozallowfullscreen=&quot;true&quot; allowfullscreen=&quot;true&quot;&gt;&amp;nbsp;&lt;/iframe&gt;&lt;/div&gt;

&lt;p&gt;But moving on our subject, we were talking metrics…&lt;/p&gt;

&lt;h3 id=&quot;actionable-metrics&quot;&gt;Actionable metrics&lt;/h3&gt;
&lt;p&gt;&lt;img width=&quot;300px&quot; alt=&quot;Drawing by Jordi Romero, showing an acquisition funnel generating revenue&quot; src=&quot;/files/metrics-for-pirates/Art.png&quot; /&gt;
The secret to make smart and fast decisions in a startup is having metrics for
everything. Actionable metrics. An &lt;strong&gt;actionable metric&lt;/strong&gt; is one
that tells you that some relevant business indicator (revenue, I’m looking at
you) will increase by a known factor if some strengh is applied. This means that
if you have a 2.0% conversion rate and you can increase that by 20%, your
revenue will be affected proportionally. Of course there are variables that
affect this formula because the whole process is not rigid, but you get the
point.&lt;/p&gt;

&lt;h3 id=&quot;customer-acquisition-funnel&quot;&gt;Customer Acquisition Funnel&lt;/h3&gt;
&lt;p&gt;Another concept to talk about before going to the actual metrics is the Customer
Acquisition Funnel. We’re talking business here. And specifically we want people
to pay money for stuff. Let’s call these people &lt;strong&gt;customers&lt;/strong&gt;. I
wish there was a tree that grew customers, but as far as I know, there’s no such
thing. So we have to go get them. Out in the wild.&lt;/p&gt;

&lt;p&gt;There are many kinds of customers and many ways of finding them and converting
them into paying customers or any kind of revenue-generating users. We’ll not
get dirty discussing them, though I’d love to &lt;a href=&quot;/contact&quot;&gt;hear from you&lt;/a&gt; if you
want to discuss any specific case.&lt;/p&gt;

&lt;p&gt;&lt;img width=&quot;300px&quot; alt=&quot;Customer acquisition funnel drawing&quot; src=&quot;/files/metrics-for-pirates/Funnel++.png&quot; /&gt;
Here’s where I say: &lt;strong&gt;AARRR!&lt;/strong&gt; Acquisition, Activation, Retention,
Referral and Revenue. That’s what you do to your customers in order to make your
business work.&lt;/p&gt;

&lt;p&gt;I hope the image next to this paragraph is clear enough, but in case it’s not:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Acquisition&lt;/strong&gt; is where you get the attention from somebody in your &lt;em&gt;customer
segment&lt;/em&gt;. Let’s say you get him to visit your landing page.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Activation&lt;/strong&gt; is when you make this user not regret his visit. She likes what she
sees. She’s happy. She clicks through your links (if you know what I mean).
She signs up for a newsletter, free trial, WHATEVER.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Retention&lt;/strong&gt; is when this user shows repeated interested in your product.
Either by coming back to your website a couple of times a month or by keep
using your free trial, opening the newsletter, reading the RSS feed, …&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Referral&lt;/strong&gt; is a little bit out of the loop, because that’s when you get your
best users (the promoters) to recommend your product to other users. This one
is a sexy one.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Revenue&lt;/strong&gt; is when you generate money out of a
user/lead/visitor or however you call the people in your funnel. If referral
is sexy, this is getting laid.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So there’s your funnel, pirate. Go make money with it. I’ll warn you: this
funnel is leaky. And your job (as a CEO, founder, or whatever kids call
themselves this days) is to patch the leaks and oil the machine. You want &lt;strong&gt;big
volume&lt;/strong&gt; at the beginning of the funnel and &lt;strong&gt;high conversion&lt;/strong&gt; through it.&lt;/p&gt;

&lt;h3 id=&quot;acquisition&quot;&gt;Acquisition&lt;/h3&gt;
&lt;p&gt;Acquisition is the first step in this process. It means feeding the funnel so
you can afterwards convert these people into revenue (paying customers,
revenue-generating users, …).&lt;/p&gt;

&lt;p&gt;How to get people into the funnel? Ask your marketing guy. A few concepts that
should ring a bell: SEO, SEM, PR, E-mail marketing, Social Media, Affiliation
platforms…&lt;/p&gt;

&lt;p&gt;How to &lt;strong&gt;measure&lt;/strong&gt; each of these channels? Try to segment well and go deep in
the funnel, then measure the revenue each of them is generating. That’s the best
way to set the dollars per user for each channel. Also, keep in mind that good
channel is one that can give &lt;em&gt;high volume&lt;/em&gt;, &lt;em&gt;high conversion&lt;/em&gt; and &lt;em&gt;low cost&lt;/em&gt;.
&lt;img width=&quot;710px&quot; alt=&quot;Acquisition, metrics for pirates&quot; src=&quot;/files/metrics-for-pirates/Acquisition.png&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;activation&quot;&gt;Activation&lt;/h3&gt;
&lt;p&gt;Once you get someone’s attention, you better keep it. So create killer landing pages for a product with killer features. You
need to &lt;strong&gt;make the user happy about finding you&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;How do you measure this happiness? Depends on the business, but bounce rate (or
the lack of it), visit duration, usage feature, newsletter subscription, free
trial signup, etc. are a few examples of activated users behavior. Tools like
A/B test are really valuable in this step. Don’t abuse them, remember to look at
statistical significance, use it in conjunction with your common sense and do
short cycles. My favorite tool here is &lt;a href=&quot;http://visualwebsiteoptimizer.com/?partner=jrom&quot;&gt;Visual Website
Optimizer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Also, remember tagging your users (via
&lt;a href=&quot;http://support.google.com/analytics/bin/answer.py?hl=en&amp;amp;answer=1033867&quot;&gt;URL&lt;/a&gt;,
via your own custom system, whatever) so you can then look &lt;em&gt;deep down in the
funnel&lt;/em&gt; and see what version of the split test is working better, etc. Most of
the analytics systems that we’re going to use understand Google’s way of tagging
links.
&lt;img width=&quot;710px&quot; alt=&quot;Activation, metrics for pirates&quot; src=&quot;/files/metrics-for-pirates/Activation.png&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;retention&quot;&gt;Retention&lt;/h3&gt;
&lt;p&gt;They say it’s cheaper to keep a customer than to get a new one, and they both
generate the same amount of revenue. And, true story, most people often forget
to take care of their own user/customer base. How do you measure people using
your product or staying as a lead for a long period of time? Repeated visits (%
of users that come 3 times a month to your website), active usage of your
software-as-a-service, open-rate in the weekly newsletter, RSS feed view-rate,
…&lt;/p&gt;

&lt;p&gt;If you can get your user’s e-mail, &lt;strong&gt;do it&lt;/strong&gt;! Then use some e-mail marketing
software such as &lt;a href=&quot;http://eepurl.com/vsFlT&quot;&gt;Mailchimp&lt;/a&gt;. With Mailchimp you can
nourish a user database that you can use for your weekly/monthly newsletter but
most importantly you can setup Autoresponders that will let you automate e-mails
given user behavior patterns such as: days of inactivity (one after 3d, 7d, 1m,
…), key feature usage (or the lack of), and many other creative ways of
ensuring your users are doing what you want them to do.&lt;/p&gt;

&lt;p&gt;If you don’t get our user’s e-mail, then you can try with Google AdWords
remarketing/retargeting campaigns. You should of course track all this activity
through &lt;a href=&quot;http://www.google.com/analytics/&quot;&gt;Google Analytics&lt;/a&gt; or
&lt;a href=&quot;http://kissmetrics.com/&quot;&gt;KissMetrics&lt;/a&gt;.
&lt;img width=&quot;710px&quot; alt=&quot;Retention, metrics for pirates&quot; src=&quot;/files/metrics-for-pirates/Retention.png&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;referral&quot;&gt;Referral&lt;/h3&gt;
&lt;p&gt;Who doesn’t want their product to go viral? This is in itself a science or an
art, I’m not sure, but we’re not going deep in this subject here. Maybe it
deserves its own article. Quick tips: don’t try to go viral unnaturally. If your
product rocks, it will go viral organically. If your product has some kind of
virality in its nature, then try to enhance it by offering your &lt;strong&gt;promoter
users&lt;/strong&gt; (people who would vote your product with a 9 out of 10) the right tools
to spread the word. Don’t push virality tools or reward programs to just
everybody, that could go against you.
&lt;img width=&quot;710px&quot; alt=&quot;Referral, metrics for pirates&quot; src=&quot;/files/metrics-for-pirates/Referral.png&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;revenue&quot;&gt;Revenue&lt;/h3&gt;
&lt;p&gt;You made it! Someone’s willing to pay you money, or do actions that will lead to
revenue indirectly (such as: active readers in a publication that makes money
via Google AdSense or other usual suspects).&lt;/p&gt;

&lt;p&gt;There’s nothing for me to tell you about your revenue strategies or how to
measure it, because I don’t know your business, but, remember, measure
everything, segment your revenue reports by user acquisition channels, user
behavior, etc. Then try to put more efforts in the best performing channels or
try to fix what’s wrong with the others.&lt;/p&gt;

&lt;p&gt;Enjoy!&lt;/p&gt;

&lt;p&gt;&lt;img width=&quot;710px&quot; alt=&quot;Revenue, metrics for pirates&quot; src=&quot;/files/metrics-for-pirates/Revenue.png&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;the-big-ass-flag&quot;&gt;The big-ass flag&lt;/h3&gt;
&lt;p&gt;&lt;img width=&quot;300px&quot; alt=&quot;CEO holding a flag with metrics&quot; src=&quot;/files/metrics-for-pirates/Flag.png&quot; /&gt;
You see the little guy holding a big flag? She’s the CEO. She has a great team of
1 to tens of people working real hard to deliver great product to a huge
customer segment with a growing market. Who doesn’t.&lt;/p&gt;

&lt;p&gt;Good news is that now she knows what business indicators (our old friends, the
&lt;strong&gt;metrics&lt;/strong&gt;) should be following and basing her decisions on. Bad news is that
this alone is a full-time job. And as the company grows CEOs have to delegate
work and responsibility to new executives. Delegating the ownership of these
metrics is crucial. In this example I wrote possible departments that could own
each metric. Read Marketing, Product, Growth Hacker™ (f*ck yeah buzzword),
Biz Dev, …&lt;/p&gt;

&lt;p&gt;So go build a dashboard with all these metrics and try to make all your
decisions as data-driven as you can. And if you’d like to discuss your
particular company or how does all this thing apply to it, don’t hesitate and
&lt;a href=&quot;/about&quot;&gt;contact me&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Credits&lt;/strong&gt;: This whole pirates thing is nothing new, &lt;a href=&quot;http://500hats.typepad.com/500blogs/2007/09/startup-metrics.html&quot;&gt;Dave
McClure&lt;/a&gt; has a
great presentation about it from back in 2007. If you’re interested in the
subject, you should definitely go check him out. All the drawings from this post
are carefully done by the author, Jordi Romero, using a Montblanc pen with a
black fineliner refill, then scanned and vectorized to give it a more digital
look.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://news.ycombinator.com/item?id=5226877&quot;&gt;&lt;strong&gt;Discussion&lt;/strong&gt; in Hackernews&lt;/a&gt;&lt;/p&gt;
</content>
    <published>2013-02-15T10:00:00+00:00</published>
    <updated>2013-02-15T10:00:00+00:00</updated>
    <category term="talks"/>
  </entry>
  <entry>
    <title>Create an e-commerce business</title>
    <link type="text/html" href="http://jrom.net/create-an-ecommerce-business" rel="alternate"/>
    <id>tag:jrom.net,2012-11-15:/create-an-ecommerce-business</id>
    <content type="html">&lt;script async=&quot;true&quot; class=&quot;speakerdeck-embed&quot; data-id=&quot;4fa3cfc011b70131e2504a1c325d810d&quot; src=&quot;//speakerdeck.com/assets/embed.js&quot;&gt; &lt;/script&gt;

&lt;p&gt;This talk was presented in &lt;a href=&quot;http://www.congresodeinternet.com/&quot;&gt;Congreso de internet&lt;/a&gt; and &lt;a href=&quot;http://itnig.net/en/fridays&quot;&gt;itnig friday’s&lt;/a&gt; events in November 2012.&lt;/p&gt;
</content>
    <published>2012-11-15T10:00:00+00:00</published>
    <updated>2012-11-15T10:00:00+00:00</updated>
    <category term="talks"/>
  </entry>
  <entry>
    <title>Google Images in Google Analytics</title>
    <link type="text/html" href="http://jrom.net/google-images-in-google-analytics" rel="alternate"/>
    <id>tag:jrom.net,2012-08-27:/google-images-in-google-analytics</id>
    <content type="html">&lt;style&gt;
  .article p img { float: none; margin: 0; }
&lt;/style&gt;

&lt;p&gt;A friend of mine has a &lt;a href=&quot;http://eumd.es/&quot; title=&quot;blog de fútbol&quot;&gt;soccer blog&lt;/a&gt; and I
happen to help him with the nuts and bolts behind it.  I’m not tracking it 24/7
but some times I like to see how it’s going, and I open Google Analytics to
check on its performance, see where the traffic’s coming from and if some post
went viral.&lt;/p&gt;

&lt;p&gt;One day, organic traffic went up noticeably, and after messing around with
&lt;strong&gt;Google Analytics&lt;/strong&gt; I saw that referral traffic went down significantly
exactly at the same time! Bummer, I didn’t just nail some SEO trick.
Something changed at Google’s end and now that’s messing with my data.
That was on July 23rd 2011.
After 5 more minutes of investigation, I realized all the traffic coming from
&lt;strong&gt;Google Images&lt;/strong&gt; was now being treated as &lt;strong&gt;organic search traffic&lt;/strong&gt;, as
before it was always considered &lt;strong&gt;referral traffic&lt;/strong&gt;.  I didn’t care much back
then, so I left it like that. Mystery solved. I moved on to the websites I was
actually working for.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/files/google-images-in-google-analytics/google-images-analytics-change.jpg&quot; alt=&quot;Google Analytics change for Google Images traffic&quot; /&gt;&lt;/p&gt;

&lt;p&gt;But…&lt;/p&gt;

&lt;p&gt;It turns out, one year later, I was again checking on my friend’s blog
analytics. And looking at what keywords were bringing the most traffic, I
realized there was no way I could segment &lt;strong&gt;real SEO effects&lt;/strong&gt; from this
combination of &lt;strong&gt;Web Search&lt;/strong&gt; and &lt;strong&gt;Image Search&lt;/strong&gt;. You can’t create a profile
with just the real &lt;strong&gt;organic traffic&lt;/strong&gt;, ignoring what comes from &lt;strong&gt;Google
Images&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Or at least I didn’t know how to. So I search The Googlez® for half an
hour, discussed the issue with a couple of colleagues, and then tweeted asking
for help. It turned out the last option gave me an answer.&lt;/p&gt;

&lt;p&gt;My friend &lt;strong&gt;&lt;a href=&quot;https://twitter.com/ferrangavin&quot; title=&quot;Ferran Gavin's
Twitter&quot;&gt;Ferran Gavin&lt;/a&gt;&lt;/strong&gt; recommended me to use this snippet to track Google Images traffic as
its own source.&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;script type=&quot;text/javascript&quot;&amp;gt;
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-XXXXXXX-X']);

var ref = document.referrer;
if (ref.search(/google\.([^\/]+)\/(ima?g|.*[?&amp;amp;]tbm=isch|.*[?&amp;amp;]site=images)/i) != -1) {
  var regex = /google\.([^\/]+)\/.*/i;
  var match = regex.exec(ref);

  if (ref.search(/[?&amp;amp;]prev=/i) != -1) {
    regex = /[?&amp;amp;]prev=([^&amp;amp;]*)/i;
    var match2 = regex.exec(ref);
    _gaq.push(['_addOrganic','images.googleSerps','q',true]);
    _gaq.push(['_setReferrerOverride', 'http://images.googleSerps.'+match[1]+unescape(match2[1])]);

  } else {
    _gaq.push(['_addOrganic','images.google','q',true]);
    _gaq.push(['_setReferrerOverride', 'http://images.'+match[0]]);
  }
}

_gaq.push(['_trackPageview']);

(function() {
  var ga = document.createElement('script'); ga.type = 'text/javascript';
  ga.async = true;
  ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www')
         + '.google-analytics.com/ga.js';
  var s = document.getElementsByTagName('script')[0];
  s.parentNode.insertBefore(ga, s);
})();
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Source: &lt;a href=&quot;http://productforums.google.com/d/topic/analytics/fnfq6A4FG5Q/discussion&quot;&gt;Google Products / Analytics
Forums&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After reading the code, it’s obvious that it doesn’t only track Google Image’s
traffic as its own organic source, but it also adds a different source for
Google Image SERPS (the little boxes of images embedded in a normal Google
Search Results Page). Useful trick.&lt;/p&gt;

&lt;p&gt;I trust that guy’s SEO knowledge, so I just added the code to my friend’s blog
after making sure the Javascript made sense, and then waited a few days to see
how it worked.&lt;/p&gt;

&lt;p&gt;After those changes, nothing actually changed, except that I started seeing
the &lt;strong&gt;Source&lt;/strong&gt; field in the &lt;strong&gt;Search / Organic&lt;/strong&gt; report as &lt;code class=&quot;highlighter-rouge&quot;&gt;google&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;images.google&lt;/code&gt;
or &lt;code class=&quot;highlighter-rouge&quot;&gt;images.googleSerps&lt;/code&gt; depending on where the traffic was coming from.&lt;/p&gt;

&lt;p&gt;Finally, I can now create separate profiles for &lt;strong&gt;normal organic search traffic&lt;/strong&gt;
and for &lt;strong&gt;Google Images traffic&lt;/strong&gt;. This is how I created a filter to show only
traffic from Google Images (both normal and SERPs):&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/files/google-images-in-google-analytics/google-analytics-filter-for-google-images-source.jpg&quot; alt=&quot;Google Analytics filter to segment traffic from Google
Images&quot; /&gt;&lt;/p&gt;

&lt;p&gt;You can just use one filter and because the &lt;em&gt;Filter Pattern&lt;/em&gt; field is a regular
expression, it will match both.&lt;/p&gt;

&lt;p&gt;I hope this article is useful for people with the same problem I had.
Surprisingly, this solution is not easy to find on Google. It took just a
minute thanks to Twitter and Ferran.&lt;/p&gt;

&lt;!-- **Update**: There's a discussion about this on [Hacker
News](http://news.ycombinator.com/). --&gt;
</content>
    <published>2012-08-27T10:00:00+00:00</published>
    <updated>2012-08-27T10:00:00+00:00</updated>
    <category term="SEO"/>
  </entry>
  <entry>
    <title>WAT Driven Development</title>
    <link type="text/html" href="http://jrom.net/wat-driven-development" rel="alternate"/>
    <id>tag:jrom.net,2012-03-14:/wat-driven-development</id>
    <content type="html">&lt;style&gt;
  .article li p { margin: 0 0 0.5em 0; }
  .article img { margin-top: 20px; }
&lt;/style&gt;

&lt;p&gt;Yesterday &lt;a href=&quot;https://twitter.com/#!/masylum&quot;&gt;@masylum&lt;/a&gt; showed me &lt;a href=&quot;http://watbutton.com/&quot;&gt;watbutton.com&lt;/a&gt; and after playing with it for 2 minutes we couldn’t help it:
We needed &lt;a href=&quot;https://www.destroyallsoftware.com/talks/wat&quot;&gt;WATs&lt;/a&gt; in our development tools ASAP. &lt;em&gt;Read: Replace the Terminal bell with a WAT&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Imagine hearing &lt;a href=&quot;https://twitter.com/#!/garybernhardt&quot;&gt;Gary Bernhardt&lt;/a&gt;’s &lt;em&gt;voice&lt;/em&gt; each time you hit an extra key by mistake. I no longer hit &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;Esc&amp;gt;&lt;/code&gt; more than once to exit insert mode in vim, because the second time I’d hear: WAT? &lt;em&gt;What the fuck are you doing hitting escape again if you’re already in normal mode?&lt;/em&gt; This is the path to perfect typing.&lt;/p&gt;

&lt;p&gt;Now, if you also want WATs in your Mac:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Grab your favorite WAT.
  Three of them are available at &lt;a href=&quot;http://watbutton.com/&quot;&gt;watbutton.com&lt;/a&gt; (look at the source). The one I like best is &lt;a href=&quot;http://watbutton.com/wat1.mp3&quot;&gt;this one&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Convert it to a compatible AIF file.
  Follow &lt;a href=&quot;http://www.mymacosx.com/snow-leopard/custom-alert-sounds-mac-os-leopard.html&quot;&gt;these steps&lt;/a&gt; or just &lt;strong&gt;save yourself some time and use &lt;a href=&quot;/files/wat-driven-development/wat.aif&quot;&gt;mine&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Copy the file to &lt;code class=&quot;highlighter-rouge&quot;&gt;~/Library/Sounds&lt;/code&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Select it in &lt;strong&gt;System Preferences » Sound&lt;/strong&gt;
  &lt;img src=&quot;/files/wat-driven-development/preferences.png&quot; alt=&quot;System Preferences&quot; /&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Make sure you have your bell enabled in your terminal app. Most people disable it because they don’t master the art of precise typing, but this was before they knew about WAT Driven Development.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;hr /&gt;

&lt;p&gt;PS: My only contribution to WAT Driven Development was putting things together. &lt;a href=&quot;https://twitter.com/#!/garybernhardt&quot;&gt;Gary Bernhardt&lt;/a&gt; is an awesome dude who makes a living with his &lt;a href=&quot;https://www.destroyallsoftware.com/&quot;&gt;advanced programming screencasts&lt;/a&gt; and his WATs traveled around the interwebs thanks to his &lt;a href=&quot;https://www.destroyallsoftware.com/talks/wat&quot;&gt;lightning talk&lt;/a&gt;.
&lt;a href=&quot;https://twitter.com/#!/kantrn&quot;&gt;Noah Kantrowitz&lt;/a&gt; did &lt;a href=&quot;http://watbutton.com/&quot;&gt;watbutton.com&lt;/a&gt;. &lt;a href=&quot;https://twitter.com/#!/masylum&quot;&gt;Pau Ramon&lt;/a&gt; showed it to me and got me excited to do the actual thing. He blogs &lt;a href=&quot;http://pau.calepin.co/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can comment on the &lt;a href=&quot;http://news.ycombinator.com/item?id=3703900&quot;&gt;Hacker News entry&lt;/a&gt;.&lt;/p&gt;
</content>
    <published>2012-03-14T11:00:00+00:00</published>
    <updated>2012-03-14T11:00:00+00:00</updated>
    
  </entry>
  <entry>
    <title>API design and more</title>
    <link type="text/html" href="http://jrom.net/api-design-and-more" rel="alternate"/>
    <id>tag:jrom.net,2011-12-01:/api-design-and-more</id>
    <content type="html">&lt;p&gt;This is the description (and slides) from the talk I gave at the
&lt;a href=&quot;http://toster.ru/&quot;&gt;toster.ru&lt;/a&gt; conference in Moscow.&lt;/p&gt;

&lt;p&gt;The main point of the talk is to go through every major design decision
around API design, so both API producers and consumers know what to
offer or expect from a well designed &lt;strong&gt;REST API&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;REST APIs are essential in any modern web application. It’s currently a
trend not to build &lt;em&gt;Web Apps&lt;/em&gt; but &lt;em&gt;Platforms&lt;/em&gt;. A good REST
API is the core of the platform, where web apps, mobile apps, 3rd party
integrations, etc. can just use as its brain.&lt;/p&gt;

&lt;p&gt;Some of the concepts the talk goes around are: HTTP, REST, URI,
metadata, representations, security, versioning, pagination. These are
all relevant aspects of a good REST API design. After that, some tips
about &lt;strong&gt;implementation&lt;/strong&gt; and &lt;strong&gt;deployment&lt;/strong&gt;
are thrown to the mix. Finally, &lt;strong&gt;scaling&lt;/strong&gt; is mentioned as
a key challenge a successful API will find. Horizontal scaling, HTTP
cache, application cache, database replication and asynchrony are
mentioned as possible methods to help the scaling of an API, although
the design will still carry most of the responsability to decide if an
API can scale easily or not.&lt;/p&gt;

&lt;p&gt;Watch the talk dubbed in Russian:&lt;/p&gt;

&lt;div class=&quot;responsive-container&quot;&gt;&lt;iframe width=&quot;709&quot; height=&quot;399&quot; src=&quot;http://www.youtube-nocookie.com/embed/7h0V3OlVkEI?rel=0&quot; frameborder=&quot;0&quot;&gt; &lt;/iframe&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href=&quot;https://speakerd.s3.amazonaws.com/presentations/4ed88ddb013097005000379b/api-for-the-mobile-era.pdf&quot;&gt;Download the PDF&lt;/a&gt;
or see it embedded here:&lt;/p&gt;

&lt;script src=&quot;http://speakerdeck.com/embed/4ed88ddb013097005000379b.js&quot;&gt; &lt;/script&gt;

</content>
    <published>2011-12-01T12:00:00+00:00</published>
    <updated>2011-12-01T12:00:00+00:00</updated>
    <category term="talks"/>
  </entry>
  <entry>
    <title>Teambox: Starting and learning</title>
    <link type="text/html" href="http://jrom.net/starting-and-learning" rel="alternate"/>
    <id>tag:jrom.net,2011-11-17:/starting-and-learning</id>
    <content type="html">&lt;p&gt;Slides from my talk at the &lt;a href=&quot;http://bcndevcon.org/&quot;&gt;Barcelona Developer Conference 2011&lt;/a&gt;.&lt;/p&gt;

&lt;script src=&quot;http://speakerdeck.com/embed/4ec50458e2f5020054007f5a.js&quot;&gt; &lt;/script&gt;

</content>
    <published>2011-11-17T14:00:00+00:00</published>
    <updated>2011-11-17T14:00:00+00:00</updated>
    <category term="talks"/>
  </entry>
  <entry>
    <title>Stop being Paranoid, be Immortal</title>
    <link type="text/html" href="http://jrom.net/stop-being-paranoid-be-immortal" rel="alternate"/>
    <id>tag:jrom.net,2011-01-16:/stop-being-paranoid-be-immortal</id>
    <content type="html">&lt;p&gt;A while ago, &lt;a href=&quot;https://github.com/saimonmoore&quot;&gt;Saimon&lt;/a&gt; and I started
upgrading &lt;a href=&quot;http://teambox.com&quot;&gt;Teambox&lt;/a&gt; to Rails 3.  Once we got a
bootable application (more on that in another post) the first big
problem we faced was &lt;code class=&quot;highlighter-rouge&quot;&gt;acts_as_paranoid&lt;/code&gt;. Its internals are a mess, so
there was no chance we could just &lt;em&gt;fix&lt;/em&gt; that for Rails 3. We decided we
would just write a brand new gem that shared the API as much as
possible.&lt;/p&gt;

&lt;p&gt;The main goals were: implement almost the whole API from
acts_as_paranoid (this way the impact of replacing it in Teambox would
be minimal) and make it as small and lightweight as possible. We are
true BDD believers, so we started writing a
&lt;a href=&quot;https://github.com/teambox/immortal/blob/29ffd7/spec/immortal_spec.rb&quot;&gt;spec&lt;/a&gt;
for what we needed. After that, writing the
&lt;a href=&quot;https://github.com/teambox/immortal/blob/29ffd7/lib/immortal.rb&quot;&gt;code&lt;/a&gt;
was quite easy.&lt;/p&gt;

&lt;p&gt;In our way, we changed some assumptions from acts_as_paranoid, such as
the need of storing &lt;strong&gt;when&lt;/strong&gt; a row was deleted. Because of that, we no
longer needed a &lt;code class=&quot;highlighter-rouge&quot;&gt;deleted_at&lt;/code&gt; field but a boolean &lt;code class=&quot;highlighter-rouge&quot;&gt;deleted&lt;/code&gt; field. This
change demands a migration:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;class MigrateParanoidFields &amp;lt; ActiveRecord::Migration
  def self.up
    add_column :users, :deleted, :boolean
    add_index :users, [:deleted]
    User.update_all [&quot;deleted = ?&quot;, true], &quot;deleted_at IS NOT NULL&quot;
    remove_column :users, :deleted_at
  end

  def self.down
    add_column :users, :deleted_at, :datetime
    add_index :users, [:deleted_at]
    User.update_all [&quot;deleted_at = ?&quot;, Time.now], [&quot;deleted = ?&quot;, true]
    remove_column :users, :deleted
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;While doing all this, at some point I regretted changing the &lt;code class=&quot;highlighter-rouge&quot;&gt;deleted&lt;/code&gt;
field to a boolean, because it looks like every relational database out
there decides to implement (or not) their own boolean data type. This is
where &lt;a href=&quot;https://github.com/rails/arel&quot;&gt;Arel&lt;/a&gt; comes handy, because you can
just do something like this:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;default_scope where(arel_table[:deleted].eq(nil).or(arel_table[:deleted].eq(false)))
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Although there has been
&lt;a href=&quot;http://blog.semanticart.com/2009/10/13/killing-is-paranoid.html&quot;&gt;discussions&lt;/a&gt;
about the convenience of using &lt;code class=&quot;highlighter-rouge&quot;&gt;default_scope&lt;/code&gt; for anything other than
&lt;code class=&quot;highlighter-rouge&quot;&gt;order&lt;/code&gt;, it just feels right to do it in this use case.&lt;/p&gt;

&lt;p&gt;To sum up: the code is available at
&lt;a href=&quot;https://github.com/teambox/immortal&quot;&gt;github&lt;/a&gt; or just as a &lt;a href=&quot;https://rubygems.org/gems/immortal&quot;&gt;Ruby
Gem&lt;/a&gt;.
Please feel free to contribute,
&lt;a href=&quot;https://github.com/unixcharles&quot;&gt;Charles&lt;/a&gt; already &lt;a href=&quot;https://github.com/teambox/immortal/commit/3bc92da646009425a45e205d0cc60e8eef205ea1&quot;&gt;did it&lt;/a&gt;!&lt;/p&gt;

</content>
    <published>2011-01-16T13:00:00+00:00</published>
    <updated>2011-01-16T13:00:00+00:00</updated>
    <category term="ruby"/>
  </entry>
  <entry>
    <title>I did it again!</title>
    <link type="text/html" href="http://jrom.net/i-did-it-again" rel="alternate"/>
    <id>tag:jrom.net,2011-01-10:/i-did-it-again</id>
    <content type="html">&lt;p&gt;I &lt;a href=&quot;/i-like-coding-blogs&quot;&gt;said it once&lt;/a&gt; already, but I’m going to talk
about the same thing today. I enjoy rewriting or reimplementing blog
engines. Most definitely more than writing blog posts.&lt;/p&gt;

&lt;p&gt;The last time I did that, I kept the design and went from a &lt;a href=&quot;https://github.com/jrom/jromrb&quot;&gt;sinatra app
with database backend&lt;/a&gt; to a &lt;a href=&quot;https://github.com/jrom/jrom.net&quot;&gt;git-backed
engine&lt;/a&gt; (a fork of
&lt;a href=&quot;http://effectif.com/nesta&quot;&gt;Nesta&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;This time, i kept absolutely everything (design, html, feed, sitemap,
about pages, etc.) but went to the static site generator
&lt;a href=&quot;https://github.com/mojombo/jekyll&quot;&gt;Jekyll&lt;/a&gt;. The goal was to make this
change transparent to the (possible) readers, search engines and feed
subscribers would never notice the change, except for this post. In the
last &lt;em&gt;migration&lt;/em&gt; I moved all the blog posts to Markdown files, this was
very nice, because I love formatting text using that markup language,
and I still use it with Jekyll. The worst part were the haml and sass
files. There’s no support for haml or sass on Github Pages (the
generator I’m using to host this blog now), so I had to go back to plain
CSS and HTML. This made me sad, but I definitely wanted everything in
the same place and without using weird deployment strategies. Just git
push for both posts and layout modifications. Github pages were the
answer, so the move back made sense to me.&lt;/p&gt;

&lt;p&gt;Other than that, I just had to replace some haml/erb/builder files with
plain html/xml using &lt;a href=&quot;http://www.liquidmarkup.org/&quot;&gt;Liquid&lt;/a&gt; and make
sure everything was smooth again.&lt;/p&gt;

&lt;p&gt;Thanks to the awesome &lt;a href=&quot;http://pages.github.com/&quot;&gt;&lt;strong&gt;Github pages&lt;/strong&gt;&lt;/a&gt;
service, all I had to do is push to
&lt;a href=&quot;https://github.com/jrom/jrom.github.com&quot;&gt;github.com/jrom/jrom.github.com&lt;/a&gt;
and wait a couple of minutes.&lt;/p&gt;

&lt;p&gt;Enjoy!&lt;/p&gt;
</content>
    <published>2011-01-10T01:00:00+00:00</published>
    <updated>2011-01-10T01:00:00+00:00</updated>
    
  </entry>
  <entry>
    <title>Super simple authentication in Rails</title>
    <link type="text/html" href="http://jrom.net/super-simple-authentication-in-rails" rel="alternate"/>
    <id>tag:jrom.net,2010-05-07:/super-simple-authentication-in-rails</id>
    <content type="html">&lt;p&gt;Here comes another short but (hopefully) useful Rails trick. In my client applications I often need to do some protected section to do backoffice stuff or similar. Sometimes I need a fully featured &lt;strong&gt;authentication system&lt;/strong&gt;, then usually use &lt;a href=&quot;http://github.com/binarylogic/authlogic&quot;&gt;Authlogic&lt;/a&gt; (although I’m willing to try &lt;a href=&quot;http://github.com/plataformatec/devise&quot;&gt;Devise&lt;/a&gt;). Some other times you just need to hide a page to the public, and one password just works. And like everything in Rails, there’s a quick way of doing that.&lt;/p&gt;

&lt;p&gt;All you need is some controller code to protect the private pages and some code to check the credentials. The easier way is not even creating any HTML code for that and take advantage of the HTTP Authentication. Here’s what I do in &lt;code&gt;app/controllers/application_controller.rb&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;helper_method :logged_in?

def logged_in?
  session[:login]
end

private
def authenticate
  login = authenticate_or_request_with_http_basic do |username, password|
    username == &quot;username&quot; &amp;amp;&amp;amp; password == &quot;password&quot;
  end
  session[:login] = login
end

def do_logout
  session[:login] = nil
end
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;And now all it takes to force the user to authenticate for viewing some action, you just need to add a &lt;code&gt;before_filter&lt;/code&gt; in that controller. It may look like this:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;class NewsController &amp;lt; ApplicationController
  before_filter :authenticate, :except =&amp;gt; [:index, :show]
  # ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Here we are allowing public access to list and show a &lt;em&gt;New&lt;/em&gt; but we are restricting all other actions (for example, creating, editing or destroying &lt;em&gt;News&lt;/em&gt;) unless authenticated, but that’s getting &lt;em&gt;offtopic&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;As a small extra, there’s a helper method useful to show or hide special menus or something in the views, just put any &lt;em&gt;private&lt;/em&gt; html inside an &lt;code&gt;if logged_in? ... end&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That solution was really &lt;em&gt;quick&lt;/em&gt;, but not very elegant. We don’t want our credentials hardcoded into a controller, and sure we don’t want our password in clear text! One better solution would be to use a &lt;a href=&quot;/config-file-in-rails-apps&quot;&gt;config file&lt;/a&gt; and hash the password, replacing the comparison line with this one:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;username == APP_CONFIG['username'] &amp;amp;&amp;amp; Digest::SHA1.hexdigest(password) == APP_CONFIG['password']
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;And of course storing this two variables in our config YAML file. To create the hashed version of the password for the config file the easiest way is by using the Rails console or just &lt;code&gt;irb&lt;/code&gt;, and use the &lt;code&gt;hexdigest&lt;/code&gt; method shown here. This will provide a quick but nice solution to our private sections.&lt;/p&gt;
</content>
    <published>2010-05-07T18:00:00+00:00</published>
    <updated>2010-05-07T18:00:00+00:00</updated>
    <category term="ruby"/>
  </entry>
  <entry>
    <title>Gmail in Mutt</title>
    <link type="text/html" href="http://jrom.net/gmail-in-mutt" rel="alternate"/>
    <id>tag:jrom.net,2010-04-30:/gmail-in-mutt</id>
    <content type="html">&lt;p&gt;&lt;img src=&quot;/files/gmail-in-mutt/mutts.png&quot; alt=&quot;Screenshot of the Mutt mail client&quot; /&gt;
&lt;strong&gt;Mutt&lt;/strong&gt; is an open-source (&lt;a href=&quot;http://www.gnu.org/licenses/gpl.html&quot;&gt;GPL&lt;/a&gt;) text-based mail client for Unix. It may not be the best client if you receive a lot of messages formatted with HTML (most newsletters or &lt;em&gt;good&lt;/em&gt; spam are), but it’s a nice program to know, because some day you may feel more hacker and want to use it.&lt;/p&gt;

&lt;p&gt;To use Mutt, you must first install it. But that’s too easy: it’s on every &lt;em&gt;&lt;acronym title=&quot;FreeBSD's ports, Debian's dpkg, OS X's macports, homebrew, etc.&quot;&gt;package management system&lt;/acronym&gt;&lt;/em&gt; after that weird name: &lt;strong&gt;mutt&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Before touching &lt;strong&gt;Mutt&lt;/strong&gt;, you must enable Gmail’s IMAP for your account, going to &lt;strong&gt;Settings&lt;/strong&gt; → &lt;strong&gt;Forwarding and POP/IMAP&lt;/strong&gt; → &lt;strong&gt;Enable IMAP&lt;/strong&gt;. &lt;a href=&quot;/files/gmail-in-mutt/gmail-imaps.png&quot;&gt;Like this&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After that comes the only tricky part: configuring Mutt to check your Gmail’s IMAP Inbox and send emails through Google’s SMTP server. And I already did the research on what’s needed to this. I’m using &lt;a href=&quot;http://www.google.com/apps/&quot;&gt;Google Apps&lt;/a&gt; for my personal domain, and it works exactly like a regular &lt;code&gt;@gmail.com&lt;/code&gt; account, with the only difference of the username format. (Google Apps is absolutely a &lt;em&gt;must-have&lt;/em&gt; for your domain unless you have some bigger solution).&lt;/p&gt;

&lt;p&gt;You need to populate your &lt;code&gt;~/.muttrc&lt;/code&gt; like this:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# Me
set from = &quot;you@gmail_or_your_domain.com&quot;
set realname = &quot;Jordi Romero&quot;

# My credentials
set smtp_url = &quot;smtp://you@gmail_or_your_domain.com@smtp.gmail.com:587/&quot;
set smtp_pass = &quot;password&quot;
set imap_user = &quot;you@gmail_or_your_domain.com&quot;
set imap_pass = &quot;password&quot;

# My mailboxes
set folder = &quot;imaps://imap.gmail.com:993&quot;
set spoolfile = &quot;+INBOX&quot;
set postponed = &quot;+[Gmail]/Drafts&quot;

# Where to put the stuff
set header_cache = &quot;~/.mutt/cache/headers&quot;
set message_cachedir = &quot;~/.mutt/cache/bodies&quot;
set certificate_file = &quot;~/.mutt/certificates&quot;

# Etc
set mail_check = 30
set move = no
set imap_keepalive = 900
set sort = threads
set editor = &quot;vim&quot;

# GnuPG bootstrap
# source ~/.mutt/gpg.rc
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Of course you’ll want to &lt;code&gt;chmod 700 ~/.muttrc&lt;/code&gt; if you put that kind of sensitive data, or just don’t specify your passwords and will be prompted every time (for example in a non private environment). And you will also need to &lt;code&gt;mkdir -p ~/.mutt/cache&lt;/code&gt; before firing mutt.&lt;/p&gt;

&lt;h3 id=&quot;using-mutt&quot;&gt;Using Mutt&lt;/h3&gt;

&lt;p&gt;Now you can start it by typing &lt;code&gt;mutt&lt;/code&gt; in a terminal. Read the &lt;a href=&quot;http://www.mutt.org/doc/manual/manual-2.html&quot;&gt;Documentation&lt;/a&gt; on how to move and use Mutt. The main concepts are similar to vim’s navigation shortcuts.&lt;/p&gt;

&lt;h3 id=&quot;encryption-with-gnupg&quot;&gt;Encryption with GnuPG&lt;/h3&gt;

&lt;p&gt;One of the nice things about Mutt is that it has &lt;strong&gt;encryption&lt;/strong&gt;/&lt;strong&gt;signing&lt;/strong&gt; support out of the box. You just need to setup your keys in your environment and it will do the rest. If you already have your key in the ~/.gnupg/ directory, skip to the next point.&lt;/p&gt;

&lt;p&gt;As before, you first need to install &lt;strong&gt;gnupg&lt;/strong&gt; with your package management system. After that, you will need to:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# Generate your key
# You can use the default answers
# Choose a strong passphrase
gpg --gen-key

# Generate your Public key
gpg --armor --output pubkey.txt --export 'name'

# Register your public key in a public server
gpg --send-keys --keyserver hkp://subkeys.pgp.net
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;And you are done. You can share your &lt;code&gt;pubkey.txt&lt;/code&gt; with everybody and everybody will be able to send you encrypted mails or check your signed messages.&lt;/p&gt;

&lt;p&gt;Besides that, to setup correctly the environment for Mutt, you will have to uncomment the last line of the &lt;code&gt;~/.muttrc&lt;/code&gt; and copy the &lt;a href=&quot;/files/gmail-in-mutt/gpg.rc&quot;&gt;gpg.rc&lt;/a&gt; file to &lt;code&gt;~/.mutt/gpg.rc&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now you can fire &lt;strong&gt;Mutt&lt;/strong&gt; again and encrypt or sign a message by pressing the &lt;strong&gt;p&lt;/strong&gt; key just before sending (&lt;strong&gt;y&lt;/strong&gt;). Decryption or signature verification is done behind the scenes.&lt;/p&gt;

&lt;h3 id=&quot;feedback-highly-appreciated&quot;&gt;Feedback highly appreciated&lt;/h3&gt;
&lt;p&gt;I hope some of you will actually use Mutt and give back to me some tips! Until the comments are on, please use the &lt;a href=&quot;/contact&quot;&gt;contact page&lt;/a&gt;.&lt;/p&gt;

</content>
    <published>2010-04-30T18:00:00+00:00</published>
    <updated>2010-04-30T18:00:00+00:00</updated>
    
  </entry>
  <entry>
    <title>Config file in Rails apps</title>
    <link type="text/html" href="http://jrom.net/config-file-in-rails-apps" rel="alternate"/>
    <id>tag:jrom.net,2010-04-28:/config-file-in-rails-apps</id>
    <content type="html">&lt;p&gt;How many times do you find yourself hardcoding something that you now you’ll have to refactor and extract into a config file? But you don’t, because you don’t have that config file, and you don’t want to loose 10 minutes thinking (or the XXI’s century equivalent, googling) a solution.  If you are nodding and feeling guilty, continue reading.&lt;/p&gt;

&lt;p&gt;In an existent Rails application, just type&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rake rails:template LOCATION=http://github.com/jrom/rails-app.yml/raw/master/rails-app.yml.rb
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;or if you are about to create the app, extend the rails command like this:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rails &amp;lt;app&amp;gt; -m http://github.com/jrom/rails-app.yml/raw/master/rails-app.yml.rb
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;That wasn’t hard, was it? The code that just ran is &lt;strong&gt;so&lt;/strong&gt; simple that you can go &lt;a href=&quot;http://github.com/jrom/rails-app.yml/blob/master/rails-app.yml.rb&quot;&gt;check it&lt;/a&gt;. After asking you the name of that config (or assuming the default: &lt;em&gt;app&lt;/em&gt;) it will create the &lt;strong&gt;YAML&lt;/strong&gt; file under the &lt;code&gt;config&lt;/code&gt; directory and create an initializer to load its content when the application starts. The config comes with a demo variable, defined in the three typical Rails environments: &lt;em&gt;production&lt;/em&gt;, &lt;em&gt;development&lt;/em&gt; and &lt;em&gt;test&lt;/em&gt;. You can use &lt;code&gt;APP_CONFIG['variable']&lt;/code&gt; (if the config name was app) anywhere and it will return the value for the current environment and that variable.&lt;/p&gt;

&lt;p&gt;Enjoy it and use the &lt;a href=&quot;http://github.com/jrom/rails-app.yml/issues&quot;&gt;issues&lt;/a&gt; section in Github for any comment about the code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bonus plus&lt;/strong&gt;: it’s Rails 3 compatible!&lt;/p&gt;
</content>
    <published>2010-04-28T23:00:00+00:00</published>
    <updated>2010-04-28T23:00:00+00:00</updated>
    <category term="ruby"/>
  </entry>
  <entry>
    <title>Page caching with Sinatra and nginx</title>
    <link type="text/html" href="http://jrom.net/page-caching-with-sinatra-and-nginx" rel="alternate"/>
    <id>tag:jrom.net,2010-04-28:/page-caching-with-sinatra-and-nginx</id>
    <content type="html">&lt;p&gt;&lt;img src=&quot;/files/page-caching-with-sinatra-and-nginx/sinatra.gif&quot; alt=&quot;Sinatra&quot; /&gt;
I’ve built some small websites with Sinatra lately (this blog itself). And in exactly all the cases I needed page caching, because the content would change once a month, a week, or a day. Page caching is &lt;strong&gt;easy&lt;/strong&gt;, but sometimes you just need some tip. Let’s fix that by giving some simple and direct instructions in order to enable page caching and serving it from nginx:&lt;/p&gt;

&lt;p&gt;First of all, we need &lt;a href=&quot;http://github.com/kematzy/sinatra-cache&quot; title=&quot;sinatra-cache on Github&quot;&gt;Sinatra::Cache&lt;/a&gt;, the Sinatra extension that will make our life much nicer. You can either &lt;code&gt;gem install sinatra-cache&lt;/code&gt; or add &lt;code&gt;gem &quot;sinatra-cache&quot;, &quot;0.3.2&quot;&lt;/code&gt; to your Gemfile.&lt;/p&gt;

&lt;p&gt;After that, you will have to require and activate the extension in a &lt;em&gt;configure&lt;/em&gt; block:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;require 'sinatra/cache'

module Jrom
  class Application &amp;lt; Sinatra::Base
    configure do
      register(Sinatra::Cache)
      set :root, File.dirname(__FILE__)
      set :cache_enabled, true
      set :cache_output_dir, Proc.new { File.join(root, 'public', 'cache') }
    end

    get '/' do
      &quot;Hi there&quot;
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;As you can see, first we &lt;em&gt;register&lt;/em&gt; it, and then set a couple of config options. Actually, I wasn’t able to get it to work in a &lt;em&gt;classic style&lt;/em&gt; app (when you just start coding &lt;em&gt;get&lt;/em&gt;’s and &lt;em&gt;post&lt;/em&gt;’s to the Ruby file, opposed to creating a subclass of &lt;em&gt;Sinatra::Base&lt;/em&gt;), and that’s why I’m using the &lt;em&gt;subclass style&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;If this is the first time you see a Sinatra application using the &lt;em&gt;Sinatra::Base&lt;/em&gt; thing, just remember to have a &lt;code&gt;config.ru&lt;/code&gt; like this:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;require 'app'
run Jrom::Application
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Let’s continue, now we have our Sinatra app performing caching (by default it only does in production environment, check the &lt;em&gt;cache_environment&lt;/em&gt; setting to change that if needed). A lot of people would stop here and go have some beers happy with an app that will be creating a cached page in &lt;strong&gt;every request&lt;/strong&gt;, doing actually &lt;strong&gt;more work&lt;/strong&gt; instead of less… That’s lame, but a lot of people does it.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/files/page-caching-with-sinatra-and-nginx/nginx.gif&quot; alt=&quot;nginx&quot; /&gt;
The next but very important step is telling the web server (aka &lt;strong&gt;nginx&lt;/strong&gt;) to serve the cached page if there is some. The following code must be added in the &lt;code&gt;server { ... }&lt;/code&gt; block of the nginx config:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;if (-f $request_filename)
{
  break;
}

if (-f $document_root/cache$request_filename)
{
  rewrite (.*) /cache$1 break;
  break;
}

if (-f $document_root/cache$request_uri.html)
{
  rewrite (.*) /cache$1.html break;
  break;
}

if (-f $document_root/cache$request_uri/index.html)
{
  rewrite (.*) /cache$1/index.html break;
  break;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;This code is derived from the one published by Josh Susser on this &lt;a href=&quot;http://blog.hasmanythrough.com/2008/1/30/segregated-page-cache-storage&quot;&gt;blog post&lt;/a&gt;. His code &lt;em&gt;as is&lt;/em&gt; didn’t work for me, if you know why, please tell me.&lt;/p&gt;

&lt;p&gt;Now our app is caching and enjoying the cached files nicely. But two small tweaks can still be done:&lt;/p&gt;

&lt;p&gt;Add &lt;code&gt;&amp;lt;%= cache_timestamp %&amp;gt;&lt;/code&gt; in your layout to print a comment with the timestamp when the page was cached, and add this &lt;strong&gt;Capistrano&lt;/strong&gt; tasks to create the cache directory, link it to shared and flush the cached files when deploying:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;after &quot;deploy:setup&quot;, &quot;create_page_cache&quot;
desc &quot;Creates the cache dir&quot;
task :create_page_cache, :roles =&amp;gt; :app do
  run &quot;umask 02 &amp;amp;&amp;amp; mkdir -p #{shared_path}/cache&quot;
end

after &quot;deploy:update_code&quot;,&quot;symlink_shared_dirs&quot;
desc &quot;Links the public/cache with the shared/cache&quot;
task :symlink_shared_dirs, :roles =&amp;gt; :app do
  run &quot;cd #{release_path} &amp;amp;&amp;amp; ln -nfs {shared_path}/cache #{release_path}/public/cache&quot;
end

set :flush_cache, true

task :keep_page_cache do
  set :flush_cache, false
end

after &quot;deploy:cleanup&quot;, &quot;flush_page_cache&quot;
desc &quot;Empties the page cache&quot;
task :flush_page_cache, :roles =&amp;gt; :app do
  if flush_cache
    run &quot;rm -rf #{shared_path}/cache/*&quot;
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;I think that’s enough to get a healthy Sinatra application performing page caching and flushing when deploying. You can also use the &lt;code&gt;cache_expire('/path')&lt;/code&gt; to expire pages on some actions (e.g.. when an article is saved), but that’s out of this post’s subject, just read the doc of the extension.&lt;/p&gt;

&lt;p&gt;I hope that was useful to somebody, and I encourage you to cache every possible page in your web applications. The performance boost will be incredible.&lt;/p&gt;
</content>
    <published>2010-04-28T01:00:00+00:00</published>
    <updated>2010-04-28T01:00:00+00:00</updated>
    <category term="ruby"/>
  </entry>
  <entry>
    <title>I like coding blogs</title>
    <link type="text/html" href="http://jrom.net/i-like-coding-blogs" rel="alternate"/>
    <id>tag:jrom.net,2010-04-27:/i-like-coding-blogs</id>
    <content type="html">&lt;p&gt;As I &lt;a href=&quot;/hi-again&quot;&gt;just mentioned&lt;/a&gt;, I’ve been in a passive-aggressive relationship with my blogger alter ego. There are many reasons to that, but one is more interesting to me:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I enjoy more writing blog engines than writing blog posts.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I’ve been using &lt;em&gt;Wordpress&lt;/em&gt; most of the time, for which I developed some themes (most of them lost, but I just keep the &lt;a href=&quot;http://github.com/jrom/jrom09&quot;&gt;last&lt;/a&gt; &lt;a href=&quot;http://github.com/jrom/jrom10&quot;&gt;two&lt;/a&gt;). Then, I’ve coded blog engines in PHP by myself (the source code is lost), using Rails (never finished) and Sinatra (first version using a database and coded from scratch &lt;a href=&quot;http://github.com/jrom/jromrb&quot;&gt;here&lt;/a&gt;). I’m sure I forgot some weekend projects done some years ago.&lt;/p&gt;

&lt;p&gt;And now, this one. What’s special about this blog? Well, it’s the latest. And the prettiest. And is build as a &lt;strong&gt;Sinatra&lt;/strong&gt; application using &lt;strong&gt;Git&lt;/strong&gt; to store the posts. I discovered &lt;strong&gt;&lt;a href=&quot;http://effectif.com/nesta&quot;&gt;Nesta&lt;/a&gt;&lt;/strong&gt; a couple of months ago thanks to the &lt;a href=&quot;http://blog.peepcode.com/tutorials/2010/about-this-blog&quot;&gt;Peepcode blog&lt;/a&gt;. I cloned it and built this blog on top of it. I took the look and feel I already designed in my latest Sinatra blog (the one with the database that never got to see the sunlight) and &lt;em&gt;voilà&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Besides from loading all the content from static files (pushed via Git), this blog features an awesome &lt;em&gt;non-existent&lt;/em&gt; admin section, some very nice page caching (using the neat &lt;a href=&quot;http://github.com/kematzy/sinatra-cache&quot;&gt;sinatra-cache&lt;/a&gt; extension by Kematzy) to prevent loading the Ruby stack, a &lt;a href=&quot;/articles.xml&quot;&gt;feed&lt;/a&gt; and a &lt;a href=&quot;/sitemap.xml&quot;&gt;sitemap&lt;/a&gt;. Oh, and the content is formatted using &lt;a href=&quot;http://daringfireball.net/projects/markdown/&quot;&gt;Markdown&lt;/a&gt; (almost everywhere) and &lt;a href=&quot;http://haml-lang.com/&quot;&gt;Haml&lt;/a&gt; (where the layout may be trickier). For the stylesheet generation, Haml’s sister is used: &lt;a href=&quot;http://sass-lang.com/&quot;&gt;Sass&lt;/a&gt;. There’s some code highlighting capabilities thanks to &lt;a href=&quot;http://softwaremaniacs.org/soft/highlight/en/&quot;&gt;highlight.js&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There is one feature I haven’t implemented yet, but will do soon: &lt;strong&gt;comments&lt;/strong&gt;. This blog now is using no database to work, and everything is page-cached when the first request arrives, so a traditional comments functionality would fuck everything up a little… unless I use some service like Disqus or Itense debate. I don’t like these services (if there’s a better alternative, please &lt;a href=&quot;/contact&quot;&gt;tell me&lt;/a&gt;), so I will have to code some mini-disqus-like web-service to feed my own blog’s comments. I’ll keep you posted.&lt;/p&gt;
</content>
    <published>2010-04-27T23:00:00+00:00</published>
    <updated>2010-04-27T23:00:00+00:00</updated>
    
  </entry>
  <entry>
    <title>Hi... again</title>
    <link type="text/html" href="http://jrom.net/hi-again" rel="alternate"/>
    <id>tag:jrom.net,2010-04-27:/hi-again</id>
    <content type="html">&lt;p&gt;Hi, I’m &lt;a href=&quot;/about&quot;&gt;Jordi Romero&lt;/a&gt;. This is a blog, or it’s supposed to be, where I can publish anything I may find useful. The subjects will vary, from programming to computer architecture, or maybe some &lt;em&gt;sysadmin&lt;/em&gt; trick that took me all night to find out and want to share to make the world a better place. Time will tell.&lt;/p&gt;

&lt;p&gt;I’m trying to have and maintain a blog since &lt;strong&gt;2004&lt;/strong&gt;! In 6 years I never published more than 20 posts, most of which never stayed online after some months. I started blogging in Catalan, my first language. Later on 2006 I deleted the blog and replaced it with a static &lt;acronym title=&quot;Curriculum Vitae&quot;&gt;CV&lt;/acronym&gt; in the front page (the first screenshot). One year later I started a &lt;em&gt;new&lt;/em&gt; version of the blog (the right image) in Spanish, my second language. I published some useful Ruby on Rails tutorials, and an article about my &lt;a href=&quot;http://en.wikipedia.org/wiki/File:Happy_Hacking_Keyboard_Professional_2.jpg&quot; title=&quot;Happy Hacking Keyboard Professional 2&quot;&gt;keyboard&lt;/a&gt; that got some attention. Sincerely, nothing worth saving or translating to this &lt;em&gt;newer&lt;/em&gt; version. Some good and interesting content is out there, and I will write it down.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/files/hi-again/jrom.jpg&quot; alt=&quot;jrom.net when it was a CV in catalan&quot; class=&quot;center no-margin&quot; /&gt;
&lt;img src=&quot;/files/hi-again/jrom-2.jpg&quot; alt=&quot;jrom.net when it was a blog in spanish&quot; class=&quot;center no-margin&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;If you just want to say something to me, make sure you check the &lt;a href=&quot;/contact&quot;&gt;contact&lt;/a&gt; page.&lt;/p&gt;

</content>
    <published>2010-04-27T22:00:00+00:00</published>
    <updated>2010-04-27T22:00:00+00:00</updated>
    
  </entry>
  
</feed>

