<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title><![CDATA[4Trabes]]></title>
  <link href="http://4trabes.com/atom.xml" rel="self"/>
  <link href="http://4trabes.com/"/>
  <updated>2012-05-09T16:36:12+02:00</updated>
  <id>http://4trabes.com/</id>
  <author>
    <name><![CDATA[Trabe Soluciones S.L.]]></name>
    <email><![CDATA[contact@trabesoluciones.com]]></email>
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <entry>
    <title type="html"><![CDATA[PrettyKit, make your iOS app look pretty]]></title>
    <author><name>Victor</name></author>
    <link href="http://4trabes.com/2012/05/09/prettykit-make-your-ios-app-look-pretty/"/>
    <updated>2012-05-09T16:21:00+02:00</updated>
    <id>http://4trabes.com/2012/05/09/prettykit-make-your-ios-app-look-pretty</id>
    <content type="html"><![CDATA[<p>Since I started to work on my Computer Science Thesis here at <a href="http://www.trabesoluciones.com">Trabe Soluciones</a>, I&#8217;ve written some iOS <a href="https://github.com/vicpenap/">open source libraries</a>. Probably the biggest one is PrettyKit. You can find it at <a href="https://github.com/vicpenap/PrettyKit">Github</a>.</p>

<h2>What is PrettyKit?</h2>

<p>We&#8217;ve lately been seeing an interesting change on the interfaces of many iOS apps. The glossy effects and gray striped backgrounds nowadays look boring and démodé, and the tendency points to the use of gradients and patterns.</p>

<p><img class="center" src="http://4trabes.com/assets/PrettyKit/PK_tweetie_twitter.png" title="&#34;Tweetie vs Twitter&#34;" alt="&#34;Tweetie vs Twitter&#34;"></p>

<p>The latest apps introduced by Apple, such as Reminders, Game Center or Find My Friends use patterned backgrounds or leather-like navigation bars, for example. What&#8217;s more, <a href="http://developer.apple.com/library/ios/releasenotes/General/WhatsNewIniPhoneOS/Articles/iOS5.html#//apple_ref/doc/uid/TP30915195-SW15">a new API</a> to allow more appearance customization has been introduced in the iOS SDK. Although it is an interesting step, it is not big enough, as this API is only compatible with iOS 5 or higher and, in some cases, the new appearance&#8217;s properties might be not enough.</p>

<p>And here&#8217;s where PrettyKit comes.</p>

<p>PrettyKit is a library composed by a set of new widgets and UIKit subclasses that gives you more control to customize your interfaces. You will be able to easily change backgrounds, draw gradients, drop shadows and more. This library will help you to beautify your iOS apps and give them a modern look. Besides, it is fully compatible with iOS 4.0.</p>

<p>Besides, if you need even more control, you can subclass any Pretty class, which will give you even more possibilities. Or, if you&#8217;re feeling brave, fork the code, it&#8217;s open source ;)</p>

<p>Check this video to see what you can do with PrettyKit:</p>

<iframe width="320" height="480" src="http://www.youtube.com/embed/e4L6ZthZB8s" frameborder="0" allowfullscreen></iframe>


<h2>PrettyKit possibilities</h2>

<p>You might say:</p>

<blockquote><p>Until now you&#8217;ve only said that PrettyKit is cool and blah blah, but I want to see if it&#8217;s actually that cool.</p></blockquote>


<p>Challenge accepted!</p>

<p>Let&#8217;s say the interface of your application has been built with Interface Builder and it looks like this:</p>

<p><img class="center" src="http://4trabes.com/assets/PrettyKit/PK_before.png" title="&#34;Your application before PrettyKit&#34;" alt="&#34;Your application before PrettyKit&#34;"></p>

<p>We&#8217;ll now apply some PrettyKit customization, take a look:</p>

<ol>
<li><p>Go to the Interface Builder file, and change the classes of the navigation bar and tab bar to PrettyNavigationBar and PrettyTabBar.</p></li>
<li><p>Let&#8217;s change now the cells&#8217; appearance. First, <code>#import "PrettyKit.h"</code>. In your <code>tableView:cellForRowAtIndexPath:</code>, change all references to <code>UITableViewCell</code> to <code>PrettyTableViewCell</code>. And for each cell you work with, add this line <code>[cell prepareForTableView:tableView indexPath:indexPath];</code>. And in your <code>tableView:heightForRowAtIndexPath:</code> add <code>[PrettyTableViewCell tableView:tableView neededHeightForIndexPath:indexPath]</code> to your desired height. Nice, huh?</p></li>
<li><p>The final touches. First of all, the background is still stripped, so we&#8217;ll create a new one and we&#8217;ll set it. Then, let&#8217;s make the cells even nicer, less rounded. To change the cell&#8217;s corner radius, just do this when initializing them: <code>cell.cornerRadius = 5;</code>.</p></li>
</ol>


<p><img class="center" src="http://4trabes.com/assets/PrettyKit/PK_process.png" title="&#34;Your app being beautified&#34;" alt="&#34;Your app being beautified&#34;"></p>

<p>This is the final code to generate the cells. Lines 5 and 7 have changed the <code>UITableViewCell</code> reference to <code>PrettyTableViewCell</code>. Lines 8 and 11 are new. And <code>heightForRow</code> now has a sum. That&#8217;s all. That simple.</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
</pre></td><td class='code'><pre><code class='objc'><span class='line'><span class="o">-</span> <span class="p">(</span><span class="n">UITableViewCell</span> <span class="o">*</span><span class="p">)</span><span class="nl">tableView:</span><span class="p">(</span><span class="n">UITableView</span> <span class="o">*</span><span class="p">)</span><span class="n">tableView</span> <span class="nl">cellForRowAtIndexPath:</span><span class="p">(</span><span class="n">NSIndexPath</span> <span class="o">*</span><span class="p">)</span><span class="n">indexPath</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>    <span class="k">static</span> <span class="n">NSString</span> <span class="o">*</span><span class="n">CellIdentifier</span> <span class="o">=</span> <span class="s">@&quot;Cell&quot;</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">PrettyTableViewCell</span> <span class="o">*</span><span class="n">cell</span> <span class="o">=</span> <span class="p">[</span><span class="n">tableView</span> <span class="nl">dequeueReusableCellWithIdentifier:</span><span class="n">CellIdentifier</span><span class="p">];</span>
</span><span class='line'>    <span class="k">if</span> <span class="p">(</span><span class="n">cell</span> <span class="o">==</span> <span class="nb">nil</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>        <span class="n">cell</span> <span class="o">=</span> <span class="p">[[[</span><span class="n">PrettyTableViewCell</span> <span class="n">alloc</span><span class="p">]</span> <span class="nl">initWithStyle:</span><span class="n">UITableViewCellStyleDefault</span> <span class="nl">reuseIdentifier:</span><span class="n">CellIdentifier</span><span class="p">]</span> <span class="n">autorelease</span><span class="p">];</span>
</span><span class='line'>        <span class="n">cell</span><span class="p">.</span><span class="n">cornerRadius</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="p">[</span><span class="n">cell</span> <span class="nl">prepareForTableView:</span><span class="n">tableView</span> <span class="nl">indexPath:</span><span class="n">indexPath</span><span class="p">];</span>
</span><span class='line'>    <span class="n">cell</span><span class="p">.</span><span class="n">textLabel</span><span class="p">.</span><span class="n">text</span> <span class="o">=</span> <span class="p">[</span><span class="n">NSString</span> <span class="nl">stringWithFormat:</span><span class="s">@&quot;Text %d&quot;</span><span class="p">,</span><span class="n">indexPath</span><span class="p">.</span><span class="n">row</span><span class="p">];</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">return</span> <span class="n">cell</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>




<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='objc'><span class='line'><span class="o">-</span><span class="p">(</span><span class="n">CGFloat</span><span class="p">)</span> <span class="nl">tableView:</span><span class="p">(</span><span class="n">UITableView</span> <span class="o">*</span><span class="p">)</span><span class="n">tableView</span> <span class="nl">heightForRowAtIndexPath:</span><span class="p">(</span><span class="n">NSIndexPath</span> <span class="o">*</span><span class="p">)</span><span class="n">indexPath</span> <span class="p">{</span>
</span><span class='line'>    <span class="k">return</span> <span class="n">tableView</span><span class="p">.</span><span class="n">rowHeight</span> <span class="o">+</span> <span class="p">[</span><span class="n">PrettyTableViewCell</span> <span class="nl">tableView:</span><span class="n">tableView</span> <span class="nl">neededHeightForIndexPath:</span><span class="n">indexPath</span><span class="p">];</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>Not convinced yet?</p>

<p>OK. Have you seen those several-button cells in the video?</p>

<p><img class="center" src="http://4trabes.com/assets/PrettyKit/PK_grid.png" title="&#34;Grid cell&#34;" alt="&#34;Grid cell&#34;">
<img class="center" src="http://4trabes.com/assets/PrettyKit/PK_segmented_control.png" title="&#34;Grid cell&#34;" alt="&#34;Grid cell&#34;"></p>

<p>They are part of PrettyKit. And using them is really easy, look at this code:</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class='objc'><span class='line'><span class="n">gridCell</span><span class="p">.</span><span class="n">numberOfElements</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
</span><span class='line'><span class="p">[</span><span class="n">gridCell</span> <span class="nl">setText:</span><span class="s">@&quot;One&quot;</span> <span class="nl">atIndex:</span><span class="mi">0</span><span class="p">];</span>
</span><span class='line'><span class="p">[</span><span class="n">gridCell</span> <span class="nl">setDetailText:</span><span class="s">@&quot;Detail Text&quot;</span> <span class="nl">atIndex:</span><span class="mi">0</span><span class="p">];</span>
</span><span class='line'><span class="p">[</span><span class="n">gridCell</span> <span class="nl">setText:</span><span class="s">@&quot;Two&quot;</span> <span class="nl">atIndex:</span><span class="mi">1</span><span class="p">];</span>
</span><span class='line'><span class="p">[</span><span class="n">gridCell</span> <span class="nl">setDetailText:</span><span class="s">@&quot;Detail Text&quot;</span> <span class="nl">atIndex:</span><span class="mi">1</span><span class="p">];</span>
</span><span class='line'><span class="p">[</span><span class="n">gridCell</span> <span class="nl">setText:</span><span class="s">@&quot;Three&quot;</span> <span class="nl">atIndex:</span><span class="mi">2</span><span class="p">];</span>
</span><span class='line'><span class="p">[</span><span class="n">gridCell</span> <span class="nl">setDetailText:</span><span class="s">@&quot;Detail Text&quot;</span> <span class="nl">atIndex:</span><span class="mi">2</span><span class="p">];</span>
</span></code></pre></td></tr></table></div></figure>


<p>Or this line, if you&#8217;re using the segmented control row:</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='objc'><span class='line'><span class="n">segmentedCell</span><span class="p">.</span><span class="n">titles</span> <span class="o">=</span> <span class="p">[</span><span class="n">NSArray</span> <span class="nl">arrayWithObjects:</span><span class="s">@&quot;1&quot;</span><span class="p">,</span> <span class="s">@&quot;2&quot;</span><span class="p">,</span> <span class="s">@&quot;3&quot;</span><span class="p">,</span> <span class="s">@&quot;4&quot;</span><span class="p">,</span> <span class="nb">nil</span><span class="p">];</span>
</span></code></pre></td></tr></table></div></figure>


<p>And they use blocks, so it&#8217;s easy to add a callback when any button is pressed:</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class='objc'><span class='line'>
</span><span class='line'><span class="n">gridCell</span><span class="p">.</span><span class="n">actionBlock</span> <span class="o">=</span> <span class="o">^</span><span class="p">(</span><span class="n">NSIndexPath</span> <span class="o">*</span><span class="n">indexPath</span><span class="p">,</span> <span class="kt">int</span> <span class="n">selectedIndex</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>  <span class="c1">// whatever you want to do</span>
</span><span class='line'><span class="p">};</span>
</span></code></pre></td></tr></table></div></figure>


<h2>Performance</h2>

<p>Take a look at this <a href="http://engineering.twitter.com/2012/02/simple-strategies-for-smooth-animation.html">Twitter article</a> about smooth animation. As they state, jerky scrolling ruins the user experience. PrettyKit is entirely drawn with CoreGraphics. That means it&#8217;s really fast, and the scrolling, which usually causes headaches when customizing cells, is very smooth.</p>

<h2>Documentation</h2>

<p>PrettyKit has <a href="http://vicpenap.github.com/PrettyKit/">a very nice documentation</a>, that might help you more than once. It is written with appledoc syntax, so it will integrate very well with the rest of your project when generating the docs.</p>

<p>That&#8217;s all folks. If you&#8217;ve got any doubt or opinion to share, comment here, tweet me at <a href="https://www.twitter.com/vicpenap">@vicpenap</a> or visit the <a href="https://github.com/vicpenap/PrettyKit">project&#8217;s page at github</a>.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Desarrollando con Guard y LiveReload]]></title>
    <author><name>Asís</name></author>
    <link href="http://4trabes.com/2012/05/08/desarrollando-con-guard-y-livereload/"/>
    <updated>2012-05-08T10:07:00+02:00</updated>
    <id>http://4trabes.com/2012/05/08/desarrollando-con-guard-y-livereload</id>
    <content type="html"><![CDATA[<h2>TL;DR</h2>

<p>Para utilizar <a href="https://github.com/guard/guard">Guard</a> y
<a href="https://github.com/guard/guard-livereload">guard-livereload</a> para recargar
automáticamente la ventana de nuestro navegador cuando guardamos un fichero,
instala ambos, configura el plugin de LiveReload para tu navegador y listo.</p>

<p>Si quieres más detalles, sigue leyendo ;)</p>

<h2>Antes de nada</h2>

<p>Aunque todo lo que se comenta en este post es útil sea cual sea la tecnología
con la que trabajas, las herramientas que vamos a utilizar son todas del
<em>ecosistema</em> Ruby, así que va a ser necesario tener una versión de Ruby
instalada y funcionando. Si tu operativo es Linux o Mac OS X ya deberías
tenerlo de serie. De todos modos, puedes informarte en Google :)</p>

<h3>Bundler</h3>

<p><a href="http://gembundler.com/">Bundler</a> es una herramienta para gestionar las
dependencias de proyectos Ruby. Su instalación es muy sencilla:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>$ gem install bundler</span></code></pre></td></tr></table></div></figure>


<p>Para especificar las dependencias de nuestro proyecto crearemos un fichero
<code>Gemfile</code> en el que indicaremos las gemas a instalar:</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">source</span> <span class="s1">&#39;http://rubygems.org&#39;</span> <span class="c1"># gems source</span>
</span><span class='line'>
</span><span class='line'><span class="n">gem</span> <span class="s1">&#39;1st_gem_name&#39;</span> <span class="c1"># 1st dependency</span>
</span><span class='line'><span class="n">gem</span> <span class="s1">&#39;2nd_gem_name&#39;</span> <span class="c1"># 2nd dependency</span>
</span></code></pre></td></tr></table></div></figure>


<p>Para instalar las gemas listadas en el <code>Gemfile</code> (y todas sus
dependencias) bastará con ejecutar un comando:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>$ bundle</span></code></pre></td></tr></table></div></figure>


<p>Este mismo comando nos permitirá <em>actualizar</em> las gemas cada vez que cambiemos
el <code>Gemfile</code>.</p>

<p>Por último, si alguna gema proporciona ejecutables, para asegurarnos de que
todas las dependencias están cargadas, tendremos que ejecutarlos a través de
Bundler mediante el comando <code>bundle exec</code>:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>$ bundle exec some_gem_executable</span></code></pre></td></tr></table></div></figure>


<h2>Guard</h2>

<p>Ya sabemos cómo instalar gemas cómodamente usando Bundler. Ahora hablemos de Guard.</p>

<p><a href="https://github.com/guard/guard">Guard</a> es una herramienta Ruby que permite
automatizar tareas cuando se detecta algún cambio en el sistema de ficheros.
¿Para qué lo vamos a usar? En este caso para recargar automáticamente la
ventana del navegador cuando se detecte un cambio en las plantillas de la
vista, las CSS o el JS.</p>

<p>Este sería nuestro <code>Gemfile</code>:</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">source</span> <span class="s1">&#39;http://rubygems.org&#39;</span>
</span><span class='line'>
</span><span class='line'><span class="n">gem</span> <span class="s1">&#39;guard&#39;</span>
</span><span class='line'><span class="n">gem</span> <span class="s1">&#39;guard-livereload&#39;</span>
</span></code></pre></td></tr></table></div></figure>


<p>Es decir, vamos a instalar Guard y un <em>plugin</em> o <em>guard</em> llamado
<a href="https://github.com/guard/guard-livereload">guard-livereload</a> (como puedes ver en el wiki del proyecto,
<a href="https://github.com/guard/guard/wiki/List-of-available-Guards">la lista de guards disponibles</a> es
muy extensa). <code>guard-livereload</code> recarga la ventana del
navegador cuando detecta cambios en ficheros (más detalles cuando
hablemos de LiveReload).</p>

<p>Guard tiene <a href="https://github.com/guard/guard#guardfile-dsl">un DSL muy sencillo</a>
para describir qué hay que hacer cuando cambia un fichero y qué ficheros hay
que &#8220;viligar&#8221;. Por defecto, Guard leerá estas reglas de un fichero
<code>Guardfile</code>.  El nuestro tiene esta pinta:</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">guard</span> <span class="s1">&#39;livereload&#39;</span> <span class="k">do</span>
</span><span class='line'>  <span class="n">watch</span><span class="p">(</span><span class="sr">%r{public/.*}</span><span class="p">)</span> <span class="c1"># matches any file under the public directory</span>
</span><span class='line'>  <span class="n">watch</span><span class="p">(</span><span class="sr">%r{views/.*}</span><span class="p">)</span>  <span class="c1"># matches any file under the views directory</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Traducido: cada vez que un fichero dentro de los directorios <em>public</em> o <em>views</em>
cambie (en este caso el proyecto es una aplicación <a href="http://sinatrarb.com">Sinatra</a> y
ahí están los ficheros CSS, JS y HTML/Erb), LiveReload se encargará de
refrescar nuestro navegador. Si tienes dos monitores (o uno con el suficiente
espacio) puedes decir adiós a Alt+Tab-Ctrl+R o la secuencia de teclas que uses
habitualmente: podrás editar tu código y ver los cambios sin moverte del
editor. <em>Fuck yeah!</em></p>

<h2>LiveReload</h2>

<p>Te estarás preguntando dónde está la magia. Pues aquí:
<a href="http://livereload.com/">LiveReload</a>, una herramienta que hace precisamente
esto que estamos describiendo en este post: recargar la ventana del navegador cuando
detecta cambios en los ficheros del proyecto. ¿Y por qué no la usamos
directamente? Pues porque como dice en su propio sitio web:</p>

<blockquote><p>if GUI is not your thing, guard-livereload is the next best choice.</p></blockquote>


<p>Además, <code>guard-livereload</code> es la
única opción para Linux :)</p>

<p>Ya hemos instalado <code>guard-livereload</code> en el paso anterior, así que nos queda instalar la
extensión correspondiente en nuestro navegador (aquí <a href="https://addons.mozilla.org/en-US/firefox/addon/livereload/">LiveReload para Firefox</a> y aquí
<a href="https://chrome.google.com/webstore/detail/jnihajbhpnppcggbcgedagnkighmdlei">LiveReload para Chrome</a>).</p>

<h2>Poniéndolo todo a funcionar</h2>

<p>Suponiendo que estamos usando la configuración por defecto de LiveReload (si no
es así puedes configurar el plugin del navegador y configurar las opciones disponibles
de <code>guard-livereload</code> de manera acorde), solo nos resta:</p>

<ul>
<li>Activar LiveReload en el navegador, en la pestaña en la que estemos viendo
nuestra aplicación en desarrollo (es decir, hacer click en el iconillo de LiveReload, uno
que pone &#8220;LR&#8221;).</li>
<li>Lanzar <code>guard</code> mediante el siguiente comando:</li>
</ul>


<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>$ bundle exec guard</span></code></pre></td></tr></table></div></figure>


<ul>
<li>Trabajar mientras miramos cómo el navegador se actualiza solo cada vez que
guardamos un fichero :)</li>
</ul>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Sesiones Vim]]></title>
    <author><name>Asís</name></author>
    <link href="http://4trabes.com/2012/04/30/sesiones-vim/"/>
    <updated>2012-04-30T20:36:00+02:00</updated>
    <id>http://4trabes.com/2012/04/30/sesiones-vim</id>
    <content type="html"><![CDATA[<p>Cuando edito código con <a href="http://www.vim.org/">Vim</a>, normalmente utilizo <em>splits</em> para poder ver al mismo tiempo varios ficheros que me interesan. Por ejemplo, un poco de HTML, un poco de Javascript (o CoffeeScript) y un poco de CSS (o SASS, o LESS): todo lo que necesito para trabajar cómodo (más sobre trabajar cómodo en un próximo post). A veces tengo que parar antes de terminar el trabajo que estoy haciendo y no siempre puedo dejar el ordenador suspendido (es más, a veces aunque lo deje suspendido, Ubuntu se empeña en no volver a encenderlo como debe), así que para evitarme el coñazo de restaurar el estado de mi editor a mano, utilizo el comando <em>mksession</em> de Vim:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>:mksession my_session_file.vim</span></code></pre></td></tr></table></div></figure>


<p>Más tarde cuando quiero restaurar esa sesión, puedo hacerlo invocando Vim con la opción &#8216;-S&#8217;:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>vim -S my_session_file.vim</span></code></pre></td></tr></table></div></figure>


<p>Y listo, ya tengo el editor como lo había dejado :)</p>

<p>Por cierto, el fichero que describe la sesión no es más que un montón de <em>vimscript</em> en el que se restablece el valor de todas las variables, <em>mappings</em>, etc. tal y como estaban en el momento en el que guardamos la sesión (bueno, esto no exactamente así: lo que restablezca o no dependerá de nuestra configuración. Más detalles <a href="http://vimdoc.sourceforge.net/htmldoc/starting.html#:mksession">en la ayuda</a>).</p>

<h2>Plugins</h2>

<p>Hay plugins para gestionar las sesiones de una manera menos pedestre. No los he probado, pero supongo que funcionan :). Una <a href="https://www.google.com/search?q=vim+sessions+plugin">búsqueda en Google</a> y ya salen unos cuantos. Y si usas <a href="https://github.com/gmarik/vundle">Vundle</a> para gestionar tus plugins (recomendación de <a href="http://twitter.com/madtrick">@madtrick</a>) aparecen más de 10 plugins relacionados con la gestión de sesiones.</p>

<h2>Problemas</h2>

<p>Es posible que alguno de los plugins que tengas instalados den problemas a la hora de restaurar la sesión y aparezcan algunos errores. Supongo que no es lo más común, porque yo tengo instalada una buena cantidad de plugins y no tengo problemas, pero ya sabes, si es tu caso: Google.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[wsecli: a websocket client in Erlang]]></title>
    <author><name>Fuco</name></author>
    <link href="http://4trabes.com/2012/04/23/wsecli/"/>
    <updated>2012-04-23T16:21:00+02:00</updated>
    <id>http://4trabes.com/2012/04/23/wsecli</id>
    <content type="html"><![CDATA[<p>I&#8217;m combining my work at Trabe with doing my end of degree project - someday I&#8217;ll post about it. This end of degree project (EOP from now on) uses a nice amount of technologies being Erlang one of them.</p>

<p>A part of the EOP is a WebSocket endpoint built in Erlang (with <a href="https://github.com/extend/cowboy">cowboy</a>). To run some automated test on this endpoint I needed a WebSocket client in Erlang that was conformant to the last WebSocket version, wich now is the <a href="http://tools.ietf.org/html/rfc6455">RFC6455</a> for WebSocket version 13. To my dispair I could only find clients (not many) that were built for old versions of the protocol.</p>

<p>So&#8230;I had two choices:</p>

<ul>
<li>Skip all the tests wich involved using a client.</li>
<li>Build a client wich implements the RFC6455.</li>
</ul>


<p>So&#8230;being me I built it.</p>

<p>The result is <a href="https://github.com/madtrick/wsecli">wsecli</a>, a WebSocket client writen in Erlang wich implements the aforementioned WebSocket rfc6455. It was a nice toy-project to get a deeper understanding of:</p>

<ul>
<li>Erlang&#8217;s <a href="http://www.erlang.org/doc/reference_manual/expressions.html#id77874">bit sintax</a> which kicks asses when having to deal with data at a bit/byte level. Oh, fuck yeah!</li>
<li>WebSocket protocol itself.</li>
</ul>


<p>Using this project as a base I&#8217;m now working on <a href="https://github.com/madtrick/wsock">wsock</a>, a library to help you build WebSocket clients (like wsecli) and servers in Erlang. That&#8217;s for a future post (woo, too may posts piling up).</p>

<p>If you have any doubt or question  comment or tweet me at <a href="https://twitter.com/#!/madtrick">@madtrick</a>.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Net::IMAP y autenticación PLAIN con Ruby 1.8.7]]></title>
    <author><name>David</name></author>
    <link href="http://4trabes.com/2012/04/23/net-imap-y-autenticacion-plain-con-ruby-187/"/>
    <updated>2012-04-23T15:00:00+02:00</updated>
    <id>http://4trabes.com/2012/04/23/net-imap-y-autenticacion-plain-con-ruby-187</id>
    <content type="html"><![CDATA[<p>Hace poco tuvimos que recuperar correos de un servidor utilizando IMAP (con conexión segura) desde
una aplicación <em>legacy</em> que corre sobre Ruby 1.8.7. En principio, era
una tarea sencilla, sólo teníamos que usar <a href="http://ruby-doc.org/stdlib-1.8.7/libdoc/net/imap/rdoc/Net/IMAP.html">net/imap</a>:
conectarnos, autenticarnos, recuperar los correos y listo.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>$ irb -r
</span><span class='line'>>> require 'net/imap'
</span><span class='line'>=> true
</span><span class='line'>>> session = Net::IMAP.new("mail.server.com", 993, true)
</span><span class='line'>=> #&lt;Net::IMAP:0x19fb2c0 @tagno=0, @continuation_request=nil, ...
</span><span class='line'>
</span><span class='line'>>> session.capability
</span><span class='line'>=> ["ACL", "BINARY", "CATENATE", "CHILDREN", "CONDSTORE", "ENABLE", "ESEARCH", "ID", "IDLE", 
</span><span class='line'>    "IMAP4REV1", "LIST-EXTENDED", "LITERAL+", "MULTIAPPEND", "NAMESPACE", "QRESYNC", "QUOTA", 
</span><span class='line'>    "RIGHTS=EKTX", "SASL-IR", "SEARCHRES", "UIDPLUS", "UNSELECT", "WITHIN", "ESORT", "I18NLEVEL=1", 
</span><span class='line'>    "SORT", "THREAD=ORDEREDSUBJECT", "AUTH=PLAIN"]
</span><span class='line'>
</span><span class='line'>>> session.authenticate('PLAIN', "user", "plain_password")
</span><span class='line'>ArgumentError: unknown auth type - "PLAIN"
</span><span class='line'>  from /home/david/.rvm/rubies/ree-1.8.7-2010.02/lib/ruby/1.8/net/imap.rb:359:in `authenticate'
</span><span class='line'>  from (irb):4</span></code></pre></td></tr></table></div></figure>


<p>¡Ups!. Consultando la <a href="http://ruby-doc.org/stdlib-1.8.7/libdoc/net/imap/rdoc/Net/IMAP.html#method-i-authenticate">documentación</a>
observamos que la librería sólo soporta los métodos de autenticación,
<code>LOGIN</code> y <code>CRAM-MD5</code>. Ningún problema. net/imap permite registrar mecanismos de
autenticación adicionales.</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">ImapPlainAuthenticator</span>
</span><span class='line'>  <span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">user</span><span class="p">,</span> <span class="n">password</span><span class="p">)</span>
</span><span class='line'>    <span class="vi">@user</span> <span class="o">=</span> <span class="n">user</span>
</span><span class='line'>    <span class="vi">@password</span> <span class="o">=</span> <span class="n">password</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">process</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
</span><span class='line'>    <span class="k">return</span> <span class="s2">&quot;</span><span class="si">#{</span><span class="vi">@user</span><span class="si">}</span><span class="se">\0</span><span class="si">#{</span><span class="vi">@user</span><span class="si">}</span><span class="se">\0</span><span class="si">#{</span><span class="vi">@password</span><span class="si">}</span><span class="s2">&quot;</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="no">Net</span><span class="o">::</span><span class="no">IMAP</span><span class="o">::</span><span class="n">add_authenticator</span><span class="p">(</span><span class="s1">&#39;PLAIN&#39;</span><span class="p">,</span> <span class="no">ImapPlainAuthenticator</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>




<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>$ irb -r
</span><span class='line'>>> require 'net/imap'
</span><span class='line'>>> require 'imap_plain_authenticator.rb'
</span><span class='line'>>> session = Net::IMAP.new("mail.udc.es", 993, true
</span><span class='line'>=> #&lt;Net::IMAP:0x1b0edb0 @tagno=0, @continuation_request=nil, ...
</span><span class='line'>>> session.authenticate('PLAIN', "user", "plain_password")
</span><span class='line'>=> #&lt;struct Net::IMAP::TaggedResponse tag="RUBY0001", name="OK", ...</span></code></pre></td></tr></table></div></figure>


<p><em>Voilà, C&#8217;est fini.</em></p>

<h2>¿Qué pasa con Ruby 1.9.x?</h2>

<p>En la <a href="http://ruby-doc.org/stdlib-1.9.3/libdoc/net/imap/rdoc/Net/IMAP.html#method-i-authenticate">documentación</a>
no lo indica, pero si utilizáis Ruby 1.9.x veréis que sí incorpora soporte <code>AUTH=PLAIN</code> y
no es necesario que registréis esta extensión.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Bye bye Mephisto, Hello Octopress]]></title>
    <author><name>Asís y David</name></author>
    <link href="http://4trabes.com/2012/04/19/bye-bye-mephisto-hello-octopress/"/>
    <updated>2012-04-19T11:58:00+02:00</updated>
    <id>http://4trabes.com/2012/04/19/bye-bye-mephisto-hello-octopress</id>
    <content type="html"><![CDATA[<p>Un silencio en el blog de cuatro meses significa varias cosas: que
estamos trabajando como animales, que estamos demasiado vagos para
escribir o que también, como sucede en este caso, le hayamos dado un lavado de
cara.</p>

<p>La novedad más destacable no es el cambio de <em>look</em>, si no el cambio tecnológico.
Abandonamos <a href="http://www.mephistoblog.com/">Mephisto</a> (que llevaba con nosotros desde 2006) y adoptamos
<a href="http://octopress.org">Octopress</a>.</p>

<p>Octopress es un framework que utiliza
<a href="http://github.com/mojombo/jekyll">Jekyll</a> como base y que facilita la
creación y gestión de blogs. Incopora una plantilla HTML5 semántica, un
layout <em>&#8220;responsive&#8221;</em>, temificación con
<a href="http://compass-style.org/">Compass</a> y <a href="http://sass-lang.com">Sass</a>, integración con Disqus, una
pléyade de plugins y alguna cosilla más. Para nosotros, más que un cambio tecnológico
implica un cambio en la manera de trabajar: en lugar de pegarnos con la administración de
Mephisto nos dedicamos a abrir un editor, escribir, hacer commits y desplegar.</p>

<p>En cuanto al <em>look</em> (o al <em>no-look</em>), aun no estamos del todo satisfechos, pero no queríamos seguir con el blog
parado. Podéis considerar que es un <em>work in progress</em> y aun tenemos que ajustar cosillas. Consideramos que lo
más importante es tener buenos contenidos en el blog y últimamente no hemos estado muy productivos. Esperemos que
este <em>reset</em> venga acompañado de muchos e interesantes posts.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Disfrutad de las fiestas mordiendo]]></title>
    <author><name>David</name></author>
    <link href="http://4trabes.com/2011/12/23/disfrutad-de-las-fiestas-mordiendo/"/>
    <updated>2011-12-23T00:00:00+01:00</updated>
    <id>http://4trabes.com/2011/12/23/disfrutad-de-las-fiestas-mordiendo</id>
    <content type="html"><![CDATA[<p>No es una tradición, pero casi, porque ya es el segundo año. En este 2011 que ahora acaba hemos intentado hacer llegar a clientes y amigos un poco de grasa camuflada como magdalenas. Esperamos que os hayan gustado y que vuestras arterias nos disculpen. Ya veremos qué os trae el 2012. ¡Felices fiestas a todos!</p>
<p><img class="center" src="http://4trabes.com/assets/IMAG0993.jpg" title="Muffins navideños trábicos" ></p>
<p>P.D.- si nuestros amigos de Autoradio han perpetrado el mismo atentado con todos los paquetes, pegándoles una gran etiqueta sobre el lazo y la tarjeta, la mayoría no habréis visto esta última. Lo sentimos. Venía a felicitar las fiestas, nada más. Lo bueno estaba dentro :)<br />
<!--more--><br />
<p id="legacy_comments">Lo sentimos, pero los comentarios están cerrados</p></p>]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[RVM, bundler y binstubs]]></title>
    <author><name>David</name></author>
    <link href="http://4trabes.com/2011/12/01/rvm-bundler-y-binstubs/"/>
    <updated>2011-12-01T00:00:00+01:00</updated>
    <id>http://4trabes.com/2011/12/01/rvm-bundler-y-binstubs</id>
    <content type="html"><![CDATA[<p><a href="http://gembundler.com/">Bundler</a> tiene una opción maravillosa: <a href="http://gembundler.com/man/bundle-exec.1.html"><code>--binstubs</code></a>, que instala en el directorio de nuestra elección (por defecto <code>./bin</code>) scripts que invocan los ejecutables de las gemas contenidas en el <em>bundle</em>, permitiendo invocar directamente dichos ejecutables sin recurrir a <code>bundle exec</code>. Si hacemos esto, lo más cómodo es añadir <code>./bin</code> como primer elemento de nuestro <code>PATH</code>. Por desgracia, si usamos <a href="http://beginrescueend.com"><span class="caps">RVM</span></a> esto no funciona. Dado su funcionamiento, <span class="caps">RVM</span> necesita ajustar el <span class="caps">PATH</span> cada vez que invocamos un <code>rvm use</code>. Nuestro gozo en un pozo.</p>
<h2>.rvmrc al rescate</h2>
<p>Los ficheros <a href="http://beginrescueend.com/workflow/rvmrc/"><code>.rvmrc</code></a></code> valen para mucho más que fijar la versión de ruby o el <em>gemset</em> que queremos usar en un proyecto concreto; son scripts de shell en toda regla. Podemos, por lo tanto, utilizarlos para modificar el <code>PATH</code> y dar prioridad a nuestro <code>.bin</code>, arreglando el problema.</p>
<p><div class='bogus-wrapper'><notextile><figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>rvm use ruby-1.9.2-p290
</span><span class='line'><span class="nb">export </span><span class="nv">PATH</span><span class="o">=</span>./bin:<span class="nv">$PATH</span>
</span></code></pre></td></tr></table></div></figure></div></notextile></p>
<h2>La alternativa: rbenv</h2>
<p>Si esto os parece incómodo o sucio, siempre podéis utilizar <a href="https://github.com/sstephenson/rbenv">rbenv</a> en lugar de <span class="caps">RVM</span>. Yo he empezado a usarlo en casa y estoy bastante contento; en lo básico es muy parecido a <span class="caps">RVM</span> y es menos intrusivo con el shell.<br />
<!--more--><br />
<p id="legacy_comments">Lo sentimos, pero los comentarios están cerrados</p></p>]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Movember at Trabe]]></title>
    <author><name>Asís</name></author>
    <link href="http://4trabes.com/2011/11/17/movember-at-trabe/"/>
    <updated>2011-11-17T00:00:00+01:00</updated>
    <id>http://4trabes.com/2011/11/17/movember-at-trabe</id>
    <content type="html"><![CDATA[<p>Noviembre es el mes de <a href="http://es.movember.com">Movember</a>, un movimiento que &#8220;pide a hombres de todo el mundo que se dejen bigote con el objetivo de recaudar fondos y aumentar la sensibilización sobre la salud del hombre&#8221;.</p>
<p><a href="http://es.movember.com"><img src="http://4trabes.com/assets/moustacheseason_download.jpg" /></a></p>
<p>En Trabe hemos decidido hacer una interpretación particular de esta iniciativa, dándole la vuelta: en lugar de dejarnos crecer el bigote, hemos decidido sacrificar nuestras barbas por tan solidaria iniciativa.</p>
<p>Para que seáis conscientes de lo impactante del proceso, hemos preparado una miniweb que resume por lo que hemos pasado estos días: <a href="http://trabesoluciones.com/movember">http://trabesoluciones.com/movember</a>. Os animamos a todos a visitarla. Cuidado, es posible que no os podáis resistir a nuestro encanto bigotudo :)</p>
<p><a href="http://trabesoluciones.com/movember"><img src="http://4trabes.com/assets/movemtrabe_2.png" /></a></p>
<p>También podéis visitar nuestro espacio en la web de Movember en <a href="http://mobro.co/trabe">http://mobro.co/trabe</a> para ver más fotos y poder aportar vuestro donativo. Venga, no seáis agarrados, que es por una buena causa :)</p>
<p>¡Gracias a todos!</p>
<p><strong>Update</strong> Nos habíamos olvidado de hacer mención especial a <a href="http://twitter.com/bugyou">@bugyou</a> y agradecerle desde aquí que cediera su bigote de forma desinteresada :)<br />
<!--more--><br />
<p id="legacy_comments">Lo sentimos, pero los comentarios están cerrados</p></p>
<div class="legacy_post">
<blockquote><p>Nos hemos olvidado de comentarlo porque cae de cajón, pero ahí va: en Trabe todo el mundo ha hecho su donativo (además del afeitado) :D</p><footer><strong>17/Nov/2011</strong> <cite>Asís</cite></footer></blockquote>
<blockquote><p>Esos mo! La verdad es que os quedan de maravilla, espero aguanten para verlos en directo! ;)</p><footer><strong>18/Nov/2011</strong> <cite><a href='http://aquiyenlima.tumblr.com'>Lucas</a></cite></footer></blockquote>
</div>]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[SVN: branching y merging en 8 comandos]]></title>
    <author><name>David</name></author>
    <link href="http://4trabes.com/2011/10/24/svn-branching-y-merging-en-8-comandos/"/>
    <updated>2011-10-24T00:00:00+02:00</updated>
    <id>http://4trabes.com/2011/10/24/svn-branching-y-merging-en-8-comandos</id>
    <content type="html"><![CDATA[<p>Trabajar con ramas en <a href="subversion.tigris.org"><span class="caps">SVN</span></a> es un dolor de muelas (sobre todo si estás acostumbrado a <a href="http://git-scm.com"><span class="caps">GIT</span></a>), pero eso no es razón para no utilizarlas. Sólo hace falta conocer 8 sencillos comandos.</p>
<h2>1. Branching</h2>
<p><div class='bogus-wrapper'><notextile><figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>$ svn copy http://my.svn.com/myrepo/trunk \
</span><span class='line'>           http://my.svn.com/myrepo/branches/featurex \
</span><span class='line'>           -m "Created featurex branch from trunk"
</span><span class='line'>$ svn switch http://my.svn.com/myrepo/featurex</span></code></pre></td></tr></table></div></figure></div></notextile></p>
<h2>2. Algunos commits después: Merging</h2>
<p><div class='bogus-wrapper'><notextile><figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>$ svn switch http://my.svn.com/myrepo/trunk
</span><span class='line'>$ svn up</span></code></pre></td></tr></table></div></figure></div></notextile></p>
<p>Tomemos la revisión que nos indica el comando y llamémosla YY.</p>
<p><div class='bogus-wrapper'><notextile><figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>$ svn log --stop-on-copy http://my.svn.com/branches/featurex</span></code></pre></td></tr></table></div></figure></div></notextile></p>
<p>Cojamos ahora, la revisión del último mensaje de log y llamémosla XX.</p>
<p><div class='bogus-wrapper'><notextile><figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>$ svn merge -rXX:YY http://my.svn.com/branches/featurex
</span><span class='line'>$ svn ci -m "Merge branch featurex into trunk [XX:YY]"</span></code></pre></td></tr></table></div></figure></div></notextile></p>
<h2>3. Un poco de limpieza (opcional)</h2>
<p><div class='bogus-wrapper'><notextile><figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>$ svn delete http://my.svn.com/branches/featurex \
</span><span class='line'>             -m "Removed featurex branch"</span></code></pre></td></tr></table></div></figure></div></notextile></p>
<p><!--more--><br />
<p id="legacy_comments">Lo sentimos, pero los comentarios están cerrados</p></p>
<div class="legacy_post">
<blockquote><p>Mi consejo: usar git sobre svn (http://andy.delcambre.com/2008/03/04/git-svn-workflow.html). Si, por el motivo que sea, no se puede cambiar el repositorio remoto, al menos localmente se puede trabajar a gusto :)</p><footer><strong>24/Oct/2011</strong> <cite><a href='http://simonpena.com/blog'>Simón P.</a></cite></footer></blockquote>
<blockquote><p>Totalmente de acuerdo ;)</p><footer><strong>24/Oct/2011</strong> <cite><a href='http://trabesoluciones.com'>David</a></cite></footer></blockquote>
</div>]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[pry-buffers 1.0.0]]></title>
    <author><name>David</name></author>
    <link href="http://4trabes.com/2011/10/19/pry-buffers-1-0-0/"/>
    <updated>2011-10-19T00:00:00+02:00</updated>
    <id>http://4trabes.com/2011/10/19/pry-buffers-1-0-0</id>
    <content type="html"><![CDATA[<p>Ayer, mientras Fuco y yo depurabamos una aplicación utilizando esa pequeña maravilla que es <a href="http://pry.github.com">Pry</a>, sentimos la necesidad de evaluar varios fragmentos de código. Para esto, Pry proporciona el comando &#8220;edit&#8221; que ofrece dos posibilidades: 1) utilizar fichero temporal (la opción -t) , o 2) indicar una ruta donde leer/escribir un fichero. En el primer caso no podemos reutilizar el contenido del fichero por lo que más nos vale no equivocarnos al teclear, y en el segundo nos vemos obligados a indicar dónde guardar los ficheros, lo que es tedioso si sólo pretendemos hacer algo temporal. No pasa nada,  pry-buffers al rescate.</p>
<p>Con pry-buffers lo que queremos es juntar lo mejor de 1) y 2), permitiendo manejar buffers persistentes. Veamos cómo es una sesión pry con pry-buffers.</p>
<p><div class='bogus-wrapper'><notextile><figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>pry(main)> buf
</span><span class='line'>    ...  Aquí un rato con el vim (o con lo que uséis)...
</span><span class='line'>This is de default buffer
</span><span class='line'>pry(main)> buf -l
</span><span class='line'>Available buffers: default
</span><span class='line'>pry(main)> buf -s default
</span><span class='line'>puts "This is the default buffer"
</span><span class='line'>pry(main)> buf test
</span><span class='line'>    ...  Aquí otro rato más con el vim...
</span><span class='line'>This is a test 2
</span><span class='line'>pry(main)> buf -s test
</span><span class='line'>Buffer test contents:
</span><span class='line'>puts "This is a test #{1 + 1}"
</span><span class='line'>pry(main)> buf -l
</span><span class='line'>Available buffers: default, test
</span><span class='line'>pry(main)> buf -d test
</span><span class='line'>Buffer test cleaned</span></code></pre></td></tr></table></div></figure></div></notextile></p>
<p>En resumen, podéis usar y gestionar tantos buffers como queráis y estos serán persistentes entre comandos (y entre sesiones Pry).</p>
<p>Para lograrlo hemos uttilizado el mecanismo de extensión de Pry, que permite definir nuevos comandos a través del fichero de configuración de pry ($<span class="caps">HOME</span>/.pryrc) o mediante plugins (como pry-doc o pry-remote). Nosotros hemos optado por la segunda opción.  Si os apetece probarlo instalad la gema</p>
<p><div class='bogus-wrapper'><notextile><figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>gem install pry-buffers</span></code></pre></td></tr></table></div></figure></div></notextile></p>
<p>Y si tenéis curiosidad, el <a href="https://github.com/davidbarral/pry-buffers">código fuente está en github</a>.</p>
<p>Esta es una gema para uso interno (vamos, para que Fuco sea feliz) pero esperamos que os resulte útil a alguno.</p>
<p>Happy Prying!<br />
<!--more--><br />
<p id="legacy_comments">Lo sentimos, pero los comentarios están cerrados</p></p>]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Tunnelblick y múltiples push dhcp-option DOMAIN]]></title>
    <author><name>David</name></author>
    <link href="http://4trabes.com/2011/10/12/tunnelblick-y-multiples-push-dhcp-option-domain/"/>
    <updated>2011-10-12T00:00:00+02:00</updated>
    <id>http://4trabes.com/2011/10/12/tunnelblick-y-multiples-push-dhcp-option-domain</id>
    <content type="html"><![CDATA[<p>Para el que no lo conozca, <a href="http://code.google.com/p/tunnelblick">Tunnelblick</a> es un <span class="caps">GUI</span> gratuito y open-source que permite controlar OpenVPN en Mac OS X, y que viene siendo lo que usamos los maqueros de Trabe en nuestras casas para conectarnos a la feliz <span class="caps">VPN</span> de Trabe. Es un software muy interesante pero tiene un bug que impide tener múltiples dominios de búsqueda configurados.</p>
<p>Como no quiero resultar pesado, este post tiene dos versiones: la corta, que va al grano y da una solución, y la extendida que explica un poquillo las cosas para el que quiera entender el problema y la solución (TL;DR).</p>
<h2>La versión corta</h2>
<p>Si vuestra <span class="caps">VPN</span> publica varios dominios de búsqueda Tunnelblick sólo se va a quedar con él último dominio (un fallo conocido y documentado: issue 144). Para solucionarlo sólo es necesario explorar los contenidos de la aplicación Tunnelblick.app (versión 3.2beta32) y modificar el contenido del fichero client.3.up.tunnelblick.sh (en Contents/Resources/) con el script que os dejo en este <a href="https://gist.github.com/1282101">gist</a> (el diff por un lado y el script completo por otro). Configurais la <span class="caps">VPN</span> para usar el método de establecimiento de <span class="caps">DNS</span> &#8220;Asignar servidores de nombre (alternativa 1)&#8221; (en inglés &#8220;Set nameserver (alternate 1)&#8221;) y listo.</p>
<h2>La versión extendida (con explicaciones y todo eso)</h2>
<p>En Trabe tenemos un <span class="caps">DNS</span> interno y varios dominios de búsqueda y los resolv.conf de nuestras máquinas se parecen a esto:</p>
<p><div class='bogus-wrapper'><notextile><figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>search pizza.it moussaka.gr tortilla.es
</span><span class='line'>nameserver 192.168.1.10</span></code></pre></td></tr></table></div></figure></div></notextile></p>
<p>La <span class="caps">VPN</span> está configurada para que envíe esta información a los clientes, utilizando directivas push en la configuración del servidor OpenVPN:</p>
<p><div class='bogus-wrapper'><notextile><figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>push "dhcp-option DNS 192.168.1.10"
</span><span class='line'>push "dhcp-option DOMAIN pizza.it"
</span><span class='line'>push "dhcp-option DOMAIN moussaka.gr"
</span><span class='line'>push "dhcp-option DOMAIN tortilla.es"</span></code></pre></td></tr></table></div></figure></div></notextile></p>
<p>Tunnelblick tiene un modo de funcionamiento que teóricamente detecta esta información y modifica el resolv.conf de la máquina cliente de manera adecuada (&#8220;Asignar servidores de nombre (alternativa 1)&#8221;  en castellano y &#8220;Set nameserver (alternate 1)&#8221; en inglés). Por desgracia no funciona correctamente y sólo tiene en cuenta la última entrada, es decir, que nuestro resolv.conf una vez conectados queda así:</p>
<p><div class='bogus-wrapper'><notextile><figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>search tortilla.es
</span><span class='line'>nameserver 192.168.1.10</span></code></pre></td></tr></table></div></figure></div></notextile></p>
<p>El problema está en el script que detecta estas opciones y le indica al cliente que modifique su configuración. La cosa comienza a torcerse en la línea 105 del script client.3.up.tunnelblick.sh:</p>
<p><div class='bogus-wrapper'><notextile><figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
</pre></td><td class='code'><pre><code class='applescript'><span class='line'><span class="k">while</span> <span class="nv">vForOptions</span><span class="o">=</span><span class="nv">foreign_option_</span><span class="err">$</span><span class="nv">nOptionIndex</span><span class="err">;</span> <span class="err">[</span> <span class="o">-</span><span class="nv">n</span> <span class="s2">&quot;${!vForOptions}&quot;</span> <span class="err">];</span> <span class="nv">do</span>
</span><span class='line'>	<span class="p">{</span>
</span><span class='line'>	<span class="nv">vOptions</span><span class="err">[</span><span class="nv">nOptionIndex</span><span class="o">-</span><span class="mi">1</span><span class="err">]</span><span class="o">=</span><span class="err">$</span><span class="p">{!</span><span class="nv">vForOptions</span><span class="p">}</span>
</span><span class='line'>	<span class="nv">case</span> <span class="err">$</span><span class="p">{</span><span class="nv">vOptions</span><span class="err">[</span><span class="nv">nOptionIndex</span><span class="o">-</span><span class="mi">1</span><span class="err">]</span><span class="p">}</span> <span class="k">in</span>
</span><span class='line'>		<span class="o">*</span><span class="nv">DOMAIN</span><span class="o">*</span> <span class="p">)</span>
</span><span class='line'>			<span class="nv">domain</span><span class="o">=</span><span class="s2">&quot;$(trim &quot;</span><span class="err">$</span><span class="p">{</span><span class="nv">vOptions</span><span class="err">[</span><span class="nv">nOptionIndex</span><span class="o">-</span><span class="mi">1</span><span class="err">]</span><span class="o">//</span><span class="nv">dhcp</span><span class="o">-</span><span class="nv">option</span> <span class="nv">DOMAIN</span> <span class="o">/</span><span class="p">}</span><span class="s2">&quot;)&quot;</span>
</span><span class='line'>			<span class="err">;;</span>
</span><span class='line'>		<span class="o">*</span><span class="nv">DNS</span><span class="o">*</span>    <span class="p">)</span>
</span><span class='line'>			<span class="nv">vDNS</span><span class="err">[</span><span class="nv">nNameServerIndex</span><span class="o">-</span><span class="mi">1</span><span class="err">]</span><span class="o">=</span><span class="s2">&quot;$(trim &quot;</span><span class="err">$</span><span class="p">{</span><span class="nv">vOptions</span><span class="err">[</span><span class="nv">nOptionIndex</span><span class="o">-</span><span class="mi">1</span><span class="err">]</span><span class="o">//</span><span class="nv">dhcp</span><span class="o">-</span><span class="nv">option</span> <span class="nv">DNS</span> <span class="o">/</span><span class="p">}</span><span class="s2">&quot;)&quot;</span>
</span><span class='line'>			<span class="nv">let</span> <span class="nv">nNameServerIndex</span><span class="o">++</span>
</span><span class='line'>			<span class="err">;;</span>
</span><span class='line'>		<span class="o">*</span><span class="nv">WINS</span><span class="o">*</span>    <span class="p">)</span>
</span><span class='line'>			<span class="nv">vWINS</span><span class="err">[</span><span class="nv">nWINSServerIndex</span><span class="o">-</span><span class="mi">1</span><span class="err">]</span><span class="o">=</span><span class="s2">&quot;$(trim &quot;</span><span class="err">$</span><span class="p">{</span><span class="nv">vOptions</span><span class="err">[</span><span class="nv">nOptionIndex</span><span class="o">-</span><span class="mi">1</span><span class="err">]</span><span class="o">//</span><span class="nv">dhcp</span><span class="o">-</span><span class="nv">option</span> <span class="nv">WINS</span> <span class="o">/</span><span class="p">}</span><span class="s2">&quot;)&quot;</span>
</span><span class='line'>			<span class="nv">let</span> <span class="nv">nWINSServerIndex</span><span class="o">++</span>
</span><span class='line'>			<span class="err">;;</span>
</span><span class='line'>	<span class="nv">esac</span>
</span><span class='line'>	<span class="nv">let</span> <span class="nv">nOptionIndex</span><span class="o">++</span>
</span><span class='line'>	<span class="p">}</span>
</span><span class='line'><span class="nv">done</span>
</span></code></pre></td></tr></table></div></figure></div></notextile></p>
<p>La opción <span class="caps">DOMAIN</span> se trata como un campo univaluado y hay que modificar el script para tratarlo como multivaluado, al igual que se hace con el campo <span class="caps">DNS</span>.  En este <a href="https://gist.github.com/1282101">gist</a> podéis encontrar el script modificado. Para ponerlo a funcionar os remito a la versión corta del post ;).</p>
<p>Ya hemos notificado todo esto a la gente que hace Tunnelblick y esperamos que lo tengan en cuenta para próximas releases y evitar tener que andar parcheando la aplicación.</p>
<p>Happy VPNing!<br />
<!--more--><br />
<p id="legacy_comments">Lo sentimos, pero los comentarios están cerrados</p></p>]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[SugarfreeConfig 2.0.0]]></title>
    <author><name>David</name></author>
    <link href="http://4trabes.com/2011/10/12/sugarfreeconfig-2-0-0/"/>
    <updated>2011-10-12T00:00:00+02:00</updated>
    <id>http://4trabes.com/2011/10/12/sugarfreeconfig-2-0-0</id>
    <content type="html"><![CDATA[<p>La semana pasada publicamos la versión 2.0.0 de <a href="https://github.com/davidbarral/sugarfree-config">SugarfreeConfig</a>, nuestra pequeña gema para acceder de manera sexy a valores de configuración almacenados en un fichero <span class="caps">YAML</span>.</p>
<p>Coincidiendo con el arranque de un par de proyectos Rails 3.1 hemos aprovechado para actualizar la gema: hemos modificado levemente el <span class="caps">API</span> para hacer SugarfreeConfig un poco más configurable y que se pueda usar fuera de Rails (eliminado la dependencia con ActiveSupport) y hemos cubierto todo el código con tests (utilizando specs de <a href="https://github.com/seattlerb/minitest">MiniTest</a> para comparar su uso con <a href="https://www.relishapp.com/rspec">RSpec</a>, pero esa es otra historia).</p>
<p>Más detalles acerca de SugarfreeConfig en github: <a href="https://github.com/davidbarral/sugarfree-config">https://github.com/davidbarral/sugarfree-config</a>.<br />
<!--more--><br />
<p id="legacy_comments">Lo sentimos, pero los comentarios están cerrados</p></p>]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Rails 3.1: algunas impresiones y un temazo]]></title>
    <author><name>Asís</name></author>
    <link href="http://4trabes.com/2011/09/22/rails-3-1-algunas-impresiones-y-un-temazo/"/>
    <updated>2011-09-22T00:00:00+02:00</updated>
    <id>http://4trabes.com/2011/09/22/rails-3-1-algunas-impresiones-y-un-temazo</id>
    <content type="html"><![CDATA[<p>Durante este verano hemos estado desarrollando una aplicación con Rails 3.1 para uno de nuestros clientes.</p>
<p>La nueva versión de Rails (y aquí me refiero a Rails 3.x) es un <a href="http://www.youtube.com/watch?v=WosrUnjb2UQ&amp;feature=youtu.be&amp;t=1m">melocotonazo de miedo</a>.</p>
<div class="iframe">
<p><iframe width="420" height="315" src="http://www.youtube.com/embed/WosrUnjb2UQ" frameborder="0" allowfullscreen></iframe></p>
</div>
<p><br/></p>
<p>A nivel interno, las &#8220;tripas&#8221; de Rails han cambiado para mucho mejor y a nivel externo las mejoras se dejan notar en todas las partes del framework. En concreto, tras la experiencia de estos pasados meses, nosotros nos quedamos con esto:</p>
<h2>Lo bueno</h2>
<h3>Bundler</h3>
<p>Rails 3 y <a href="http://gembundler.com/">Bundler</a> se integran tan bien que pensar en cómo desarrollábamos antes, cuando no había <em>Gemfile</em>, me da escalofríos. Con Bundler, la gestión de dependencias <em>es chicle</em> para cualquiera :).</p>
<h3>Routing</h3>
<p>El nuevo <span class="caps">DSL</span> para la definición de las rutas de la aplicación es mucho más directo y sencillo de utilizar. En concreto, la sintaxis <em>controlador#acción</em>, que permite decir cosas como:</p>
<p><div class='bogus-wrapper'><notextile><figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'> <span class="n">match</span> <span class="s1">&#39;login&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;sessions#new&#39;</span>
</span></code></pre></td></tr></table></div></figure></div></notextile></p>
<h3>ActiveRecord Query Interface</h3>
<p>El <span class="caps">API</span> para consultas del &#8220;nuevo&#8221; ActiveRecord (básicamente, <a href="https://github.com/rails/arel">Arel</a>) simplifica muchísimo el trabajo a la hora de escribir y utilizar los modelos de la aplicación. Cambiamos los hashes con miles de parámetros por el encadenamiento de métodos (y esto nos permite refactorizar el código de acceso a datos de una manera mucho más natural, ¡claro!).</p>
<h3>ActiveModel</h3>
<p>Gracias al esfuerzo de modularización llevado a cabo en Rails 3, extender el framework con nuestro propio código (y hacerlo sin recurrir a trucos oscuros) es <a href="http://yehudakatz.com/2010/01/10/activemodel-make-any-ruby-object-feel-like-activerecord/">casi trivial</a>.  En el caso de ActiveModel, proporciona mecanismos para disponer de todas las ventajas de los modelos Rails en nuestras clases: validación, internacionalización, <em>callbacks</em>, integración con los <em>helpers</em> de generación de formularios, etc.</p>
<h3>Asset Pipeline</h3>
<p>La <a href="http://guides.rubyonrails.org/asset_pipeline.html">joya de la corona</a> de la versión 3.1.  Como en el caso de ActiveRecord y Arel, aquí los cambios se pueden resumir en la adopción de <a href="https://github.com/sstephenson/sprockets">Sprockets</a> para la gestión de los <em>assets</em> de la aplicación. Además, el <em>asset pipeline</em> ha llegado acompañado de una decisión polémica: apostar por <a href="http://jashkenas.github.com/coffee-script/">CoffeeScript</a> como solución &#8220;por defecto&#8221; para escribir Javascript (sin escribirlo, claro); y de otra no tan polémica: <a href="http://sass-lang.com/">Sass</a> para escribir <span class="caps">CSS</span>.</p>
<p>En general, la impresión es muy positiva: <strong>CoffeeScript</strong> es mucho más compacto que Javascript y es realmente sencillo de usar (aunque creo que es muy interesante tener un <em>background</em> más o menos amplio en cuanto a Javascript, principalmente cuando llega el momento de depurar el código generado :P). No es un cambio que me parezca fundamental y escribir Javascript no me parece &#8220;peor&#8221;&#8230;  pero el hecho es que hemos utilizado CoffeeScript :D</p>
<p><strong>Sass</strong> (o <a href="http://lesscss.org/"><span class="caps">LESS</span></a>), por contra, no ofrece discusión.  Escribir CSSs &#8220;a pelo&#8221; es tan desesperante que la mínima mejora es bienvenida.  Y en el caso de este tipo de &#8220;extensiones&#8221; a las <span class="caps">CSS</span>, las mejoras son tantas y de tanto calado (reglas anidadas, <em>mixin</em> de estilos, variables, operadores, funciones, bucles, etc.) que uno lo tiene claro: jamás volveré a escribir CSSs &#8220;a pelo&#8221; si puedo evitarlo.</p>
<h3>jQuery</h3>
<p>Adiós <a href="http://www.prototypejs.org/">Prototype</a>, hola <a href="http://jquery.com/">jQuery</a>. Arrastrados por las anteriores versiones de Rails, siempre habíamos sido más &#8220;prototyperos&#8221;. Y ahora, arrastrados de nuevo por Rails, estamos reconvirtiéndonos y adaptándonos a jQuery. Y la verdad es que la experiencia, dejando a un lado los primeros &mdash; y tambaleantes &mdash; pasos, ha sido muy positiva. Es posible que se deba a haber adquirido un mayor y más profundo conocimiento del lenguaje (Javascript, me refiero) y no sea solo cuestión del cambio de <em>framework</em>, pero la sensación que me queda es que el &#8220;estilo jQuery&#8221; está más directamente ligado al Javascript que el &#8220;estilo Prototype&#8221;. Lo dicho, impresiones mías.</p>
<h3>ActiveSupport</h3>
<p>Hay mucho más en <a href="http://guides.rubyonrails.org/active_support_core_extensions.html">ActiveSupport</a>, pero sólo voy a mencionar una cosa. Ahora se puede decir:</p>
<p><div class='bogus-wrapper'><notextile><figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="mi">1</span><span class="o">.</span><span class="n">in?</span> <span class="o">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="o">]</span> <span class="c1">#=&gt; true</span>
</span><span class='line'><span class="mi">4</span><span class="o">.</span><span class="n">in?</span> <span class="o">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="o">]</span> <span class="c1">#=&gt; false</span>
</span></code></pre></td></tr></table></div></figure></div></notextile></p>
<p>Y esto hacía falta :D</p>
<h2>Lo no tan bueno</h2>
<p>El <em>asset pipeline</em>, con todas sus ventajas, también trae de la mano algunos inconvenientes:</p>
<ul>
	<li>A la hora de desplegar en producción hay que ser especialmente cuidadoso con la configuración y con las referencias <em>interassets</em> (por ejemplo, las imágenes en las hojas de estilos). Hay nuevos <em>helpers</em> para ayudar con esto, así que no es para tanto.</li>
	<li>En desarrollo todo funciona un poco más lento por la necesidad de compilar los <em>coffeescripts</em> y los <em>scss</em>. No es una barbaridad, pero a veces se nota.</li>
</ul>
<p>Y poco más en este apartado :D</p>
<h2>En resumen</h2>
<p>Lo dicho: un <a href="http://www.youtube.com/watch?v=WosrUnjb2UQ&amp;feature=youtu.be&amp;t=1m">melocotonazo de miedo</a>.</p>
<div class="iframe">
<p><iframe width="420" height="315" src="http://www.youtube.com/embed/WosrUnjb2UQ" frameborder="0" allowfullscreen></iframe></p>
</div>
<p><!--more--><br />
<p id="legacy_comments">Lo sentimos, pero los comentarios están cerrados</p></p>
<div class="legacy_post">
<blockquote><p>Buen resumen, a ver si te animas a publicar más, la siguiente con el Morito Juan ;)</p><footer><strong>22/Sep/2011</strong> <cite><a href='http://andion.heroku.com'>Andion</a></cite></footer></blockquote>
<blockquote><p>bien explicado, especialmente para los que no hemos empezado con rails 3 todavia!</p><p>gracias por el articulo.</p><p>salu2,</p><footer><strong>20/Nov/2011</strong> <cite>Ruben</cite></footer></blockquote>
</div>]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[See you soon Victor]]></title>
    <author><name>David</name></author>
    <link href="http://4trabes.com/2011/08/30/see-you-soon-victor/"/>
    <updated>2011-08-30T00:00:00+02:00</updated>
    <id>http://4trabes.com/2011/08/30/see-you-soon-victor</id>
    <content type="html"><![CDATA[<p>El tiempo vuela y ya han pasado los dos meses que duraban <a href="http://4trabes.com/2011/7/4/welcome-victor">las prácticas de Victor en Trabe</a>. Hoy ha tocado despedirse, aunque no es un adiós, es un hasta luego. Nos ha encantado tenerlo en Trabe, aunque sólo fuesen dos meses escasos. Gran informático y gran persona, ya es uno más de nuestra pequeña familia.</p>
<p>Esperemos que en el futuro nuestros caminos vuelvan a juntarse. Hasta entonces: ¡Suerte con todo!. Nos vemos.<br />
<!--more--><br />
<p id="legacy_comments">Lo sentimos, pero los comentarios están cerrados</p></p>
<div class="legacy_post">
<blockquote><p>E tanto que voa o tempo, que mágoa! En realidade é culpa vosa, por terme acollido tan ben :D</p><p>Un placer ter compartido estes dous meses convosco, estou encantado de formar parte da familia de Trabe! :D</p><p>Gracias por todo, e ata a próxima :)</p><footer><strong>30/Aug/2011</strong> <cite><a href='http://www.victorpena.es'>Victor</a></cite></footer></blockquote>
</div>]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Farewell Lucas]]></title>
    <author><name>4Trabes</name></author>
    <link href="http://4trabes.com/2011/08/16/farewell-lucas/"/>
    <updated>2011-08-16T00:00:00+02:00</updated>
    <id>http://4trabes.com/2011/08/16/farewell-lucas</id>
    <content type="html"><![CDATA[<p>El viernes pasado nuestro querido Lucas se despidió de Trabe con el siguiente tweet:</p>
<blockquote><p>1 <span class="caps">PFC</span>, 3 años, 687 bollos, 5496 horas y 8mil risas después: hoy cierro el mejor período de mi vida en @trabe y comienza mi viaje. Ojalá se repita</p></blockquote>
<p>Nosotros teníamos que despedirnos de él con un post que he estado posponiendo porque no encontraba las palabras adecuadas para decirle &#8220;hasta luego&#8221; a este pedazo de ser humano. Después de una épica fiesta de despedida y una resaca descomunal sigo sin encontrarlas. No voy a intentarlo. Lucas, sólo te diré que te queremos un montón, que te echaremos mucho de menos y que esta es tu casa y siempre lo será. Graciñas por todo.</p>
<p>Disfruta de tu nueva aventura transoceánica y envíanos muchas postales :)<br />
<!--more--><br />
<p id="legacy_comments">Lo sentimos, pero los comentarios están cerrados</p></p>
<div class="legacy_post">
<blockquote><p>:´(</p><footer><strong>16/Aug/2011</strong> <cite>Silvia</cite></footer></blockquote>
</div>]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Thymeleaf 1.0.0]]></title>
    <author><name>David</name></author>
    <link href="http://4trabes.com/2011/07/18/thymeleaf-1-0-0/"/>
    <updated>2011-07-18T00:00:00+02:00</updated>
    <id>http://4trabes.com/2011/07/18/thymeleaf-1-0-0</id>
    <content type="html"><![CDATA[<p>Ayer nuestro amigo Dani publicó la primera versión estable de <a href="http://www.thymeleaf.org/">Thymeleaf</a> (la 1.0.0), un motor de plantillas <span class="caps">XML</span>, xHTML y HTML5 que pretende ser una alternativa a <span class="caps">JSP</span> + <span class="caps">JSTL</span> (o a otras cosas, como puede ser Velocity), y que, además, dispone de un módulo de integración con Spring <span class="caps">MVC</span> &#8220;out of the box&#8221;.</p>
<p>En Trabe estamos realizando algunos proyectos con Spring <span class="caps">MVC</span> y Thymeleaf como motor de plantilas y de momento las sensaciones son buenas. A ver si la gente que está directamente involucrada en estos proyectos se anima a hacer un post introductorio (venga, vamos, a qué estáis esperando).</p>
<p>Os invito a que le echéis un ojo al proyecto, a que lo probéis y que, si os interesa, colaboréis con Dani enviando parches, escribiendo tutoriales, etc. Y para terminar, y como curiosidad, deciros que Dani también es el padre de <a href="http://www.jasypt.org/">Jasypt</a> una librería de encriptación que lleva tiempo dando guerra y que seguramente muchos de vosotros ya habréis usado. <br />
<!--more--><br />
<p id="legacy_comments">Lo sentimos, pero los comentarios están cerrados</p></p>]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Usando un keystore con Play, versión 1.2.2]]></title>
    <author><name>David</name></author>
    <link href="http://4trabes.com/2011/07/07/usando-un-keystore-con-play-version-1-2-2/"/>
    <updated>2011-07-07T00:00:00+02:00</updated>
    <id>http://4trabes.com/2011/07/07/usando-un-keystore-con-play-version-1-2-2</id>
    <content type="html"><![CDATA[<p>Hace un tiempo, cuando empecé a trastear con <a href="http://www.playframework.org">Play</a>, tuve que <a href="http://4trabes.com/2010/7/27/usando-un-keystore-con-play">modificar el script de arranque de Play para poder utilizar un keystore de Java</a>. Dicha solución era valida para las versiones 1.0.x del framework. En versiones posteriores (de la 1.1 a la actual 1.2.2) los señores que hacen Play han dividido y ordenado el código del script de arranque. Para que todo vuelva a funcionar sólo tenemos que editar el fichero <code>${PLAY_HOME}/framework/pym/play/application.py</code> y en la línea 251 (por ejemplo) pegar el siguiente código (fijaos en la sutil diferencia con la versión anterior, un par de selfs).</p>
<p><div class='bogus-wrapper'><notextile><figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
</pre></td><td class='code'><pre><code class='python'><span class='line'><span class="n">trustStore</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">readConf</span><span class="p">(</span><span class="s">&#39;java.trustStore&#39;</span><span class="p">)</span>
</span><span class='line'><span class="k">if</span> <span class="ow">not</span> <span class="n">trustStore</span> <span class="o">==</span> <span class="s">&#39;&#39;</span><span class="p">:</span>
</span><span class='line'>  <span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">trustStore</span><span class="p">):</span>
</span><span class='line'>    <span class="k">print</span> <span class="s">&quot;~ using keystore </span><span class="se">\&quot;</span><span class="si">%s</span><span class="se">\&quot;</span><span class="s">&quot;</span> <span class="o">%</span> <span class="n">trustStore</span>
</span><span class='line'>    <span class="n">java_args</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s">&#39;-Djavax.net.ssl.trustStore=</span><span class="si">%s</span><span class="s">&#39;</span> <span class="o">%</span> <span class="n">trustStore</span><span class="p">)</span>
</span><span class='line'>    <span class="n">trustStorePassword</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">readConf</span><span class="p">(</span><span class="s">&#39;java.trustStore.password&#39;</span><span class="p">)</span>
</span><span class='line'>    <span class="k">if</span> <span class="n">trustStorePassword</span> <span class="o">==</span> <span class="s">&#39;&#39;</span><span class="p">:</span>
</span><span class='line'>      <span class="k">print</span> <span class="s">&quot;~ WARNING: No java.trustStore.password key found in config. You need a password to use a keystore&quot;</span>
</span><span class='line'>    <span class="k">else</span><span class="p">:</span>
</span><span class='line'>      <span class="n">java_args</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s">&#39;-Djavax.net.ssl.trustStorePassword=</span><span class="si">%s</span><span class="s">&#39;</span> <span class="o">%</span> <span class="n">trustStorePassword</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure></div></notextile></p>
<p><strong>Ojo a los espacios, que esto es Python ;)</strong><br />
<!--more--><br />
<p id="legacy_comments">Lo sentimos, pero los comentarios están cerrados</p></p>
<div class="legacy_post">
<blockquote><p>Sigue siendo válido para la versión 1.2.3.</p><footer><strong>24/Oct/2011</strong> <cite><a href='http://trabesoluciones.com'>David</a></cite></footer></blockquote>
</div>]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Welcome Víctor]]></title>
    <author><name>David</name></author>
    <link href="http://4trabes.com/2011/07/04/welcome-victor/"/>
    <updated>2011-07-04T00:00:00+02:00</updated>
    <id>http://4trabes.com/2011/07/04/welcome-victor</id>
    <content type="html"><![CDATA[<p>Si la semana pasada dabamos la <a href="http://4trabes.com/2011/7/1/welcome-fuco">bienvenida a Fuco</a>, hoy toca dársela a  <a href="http://twitter.com/vicpenap">Víctor</a>, que va a estar de prácticas con nosotros este verano. Víctor es uno de los papás de <a href="http://www.filloadev.com/otempo">O tempo</a>, una aplicación para iOS que un servidor viene usando desde hace una temporada. Como curiosidad os diré que Víctor es hermano de <a href="http://twitter.com/spenap">Simón</a>, al que Asís y yo dimos clase en el Master de Software Libre y al que, además, <a href="http://4trabes.com/2010/7/27/usando-un-keystore-con-play">dedicamos un post en este blog</a>. ¡Qué pequeño es el mundo!<br />
<!--more--><br />
<p id="legacy_comments">Lo sentimos, pero los comentarios están cerrados</p></p>
<div class="legacy_post">
<blockquote><p>Moitas gracias! Unha benvida estupenda, con tarta incluída! Así da gusto :-)</p><footer><strong>04/Jul/2011</strong> <cite>Víctor</cite></footer></blockquote>
</div>]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Welcome Fuco]]></title>
    <author><name>David</name></author>
    <link href="http://4trabes.com/2011/07/01/welcome-fuco/"/>
    <updated>2011-07-01T00:00:00+02:00</updated>
    <id>http://4trabes.com/2011/07/01/welcome-fuco</id>
    <content type="html"><![CDATA[<p>Hoy volvemos a ser siete en Trabe. <a href="http://blog.tenako.com/">Fuco</a>, que estuvo haciendo su proyecto de fin de carrera con nosotros hace algo más de un año, se convierte en nuestro fichaje estrella del verano. Llevábamos mucho tiempo fantaseando con su llegada y por fin lo hemos conseguido.</p>
<p>¡Welcome fiera!, esperamos que disfrutes de la Trabe aventura.<br />
<!--more--><br />
<p id="legacy_comments">Lo sentimos, pero los comentarios están cerrados</p></p>
<div class="legacy_post">
<blockquote><p>Ya tenéis a vuestro CR7, FS7. Espero que no lo volváis loco, a la cantera hay que cuidarla!</p><footer><strong>01/Jul/2011</strong> <cite>Adrián</cite></footer></blockquote>
<blockquote><p>Welcome! El bizcocho ese de bienvenida&#8230; era para todos, no? :P</p><footer><strong>04/Jul/2011</strong> <cite><a href='http://andion.heroku.com'>Andion</a></cite></footer></blockquote>
<blockquote><p>Ains, gracias gracias!! </p><p>@andion, no contaba con tu ausencia. Otro día más</p><footer><strong>04/Jul/2011</strong> <cite><a href='http://blog.tenako.com'>Fuco</a></cite></footer></blockquote>
</div>]]></content>
  </entry>
  
</feed>

