<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" version="2.0">

<channel>
	<title>Guilherme Garnier</title>
	
	<link>http://blog.guilhermegarnier.com</link>
	<description>Desenvolvimento de Software e Open Source</description>
	<lastBuildDate>Thu, 04 Apr 2013 12:04:02 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/guilhermegarnier" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="guilhermegarnier" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>Design patterns em Ruby – Decorators, Presenters e Exhibits</title>
		<link>http://blog.guilhermegarnier.com/2013/04/design-patterns-em-ruby-decorators-presenters-e-exhibits/</link>
		<comments>http://blog.guilhermegarnier.com/2013/04/design-patterns-em-ruby-decorators-presenters-e-exhibits/#comments</comments>
		<pubDate>Tue, 02 Apr 2013 15:57:34 +0000</pubDate>
		<dc:creator>guilhermegarnier</dc:creator>
				<category><![CDATA[Programação]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[design patterns]]></category>
		<category><![CDATA[rails]]></category>

		<guid isPermaLink="false">http://blog.guilhermegarnier.com/?p=542</guid>
		<description><![CDATA[Ao criar um novo projeto Rails, o generator cria uma estrutura padrão de diretórios. Dentro de app, ele cria os diretórios models, controllers, views e helpers. Os três primeiros tem papéis bem definidos, mas mesmo assim há uma certa confusão quando surge algum arquivo &#8220;fora do padrão&#8221;. Numa aplicação típica, um model geralmente estende a [...]]]></description>
				<content:encoded><![CDATA[<p>Ao criar um novo projeto Rails, o generator cria uma estrutura padrão de diretórios. Dentro de <em>app</em>, ele cria os diretórios <em>models</em>, <em>controllers</em>, <em>views</em> e <em>helpers</em>. Os três primeiros tem papéis bem definidos, mas mesmo assim há uma certa confusão quando surge algum arquivo &#8220;fora do padrão&#8221;.</p>
<p>Numa aplicação típica, um model geralmente estende a classe <em>ActiveRecord::Base</em> ou inclui um módulo, como <em>Mongoid::Document</em>, no caso do <a href="http://mongoid.org">Mongoid</a>, por exemplo, para mapear a estrutura do banco de dados. Além disso, o model contém as regras de negócio associadas a ele. O controller tem a responsabilidade de mapear a ação atual numa view &#8211; por exemplo, ao submeter um formulário para criação de um novo objeto, um controller típico renderiza uma view exibindo uma mensagem de sucesso, ou renderiza a mesma view do formulário com as mensagens de erro, caso haja algum. Já a view é responsável por exibir os dados correspondentes à página atual.</p>
<p>Essa estrutura básica funciona bem numa aplicação simples. O problema é quando a view começa a conter muita lógica. Por exemplo, uma view para exibir dados de um usuário poderia ser simples assim:</p>
<pre class="brush: ruby; title: ; notranslate">
@usuario.nome
</pre>
<p>Porém, se o conteúdo muda dependendo do tipo de usuário (ex: usuário comum e admin), precisamos de um if dentro da view:</p>
<pre class="brush: ruby; title: ; notranslate">
&lt;% if @usuario.admin? %&gt;
  admin
&lt;% else %&gt;
  @usuario.nome
&lt;% end %&gt;
</pre>
<p>Quando mais diferenças houver, mais complexa fica a view. Consequentemente, fica mais difícil de gerenciar. Além disso, normalmente fazemos testes unitários para o model e o controller, e testamos a view somente com testes de aceitação, que são muito mais lentos (é preciso carregar todo o ambiente, Rails, banco de dados, e dependendo do teste, abrir um browser). Fica impraticável testar todos os fluxos de uma view cheia de if&#8217;s usando testes de aceitação.</p>
<p>Uma solução comum no mundo Rails é usar os helpers. No exemplo acima, eu poderia ter o seguinte helper:</p>
<pre class="brush: ruby; title: ; notranslate">
class UsuarioHelper
  def titulo_usuario(usuario)
    usuario.admin? ? &quot;admin&quot; : usuario.nome
  end
end
</pre>
<p>Isso deixa o código da view mais simples:</p>
<pre class="brush: ruby; title: ; notranslate">
titulo_usuario(@usuario)
</pre>
<p>E, além disso, posso testar a lógica num teste unitário do helper. Mas essa solução também tem problemas: o helper não está associado diretamente ao objeto em questão. Isso ficou claro no exemplo acima, onde precisei passar o usuário como parâmetro para o método do helper. Isso se repetiria para cada método.</p>
<p>Uma boa solução para este caso é utilizar o <a href="http://en.wikipedia.org/wiki/Software_design_pattern">design pattern</a> <a href="http://en.wikipedia.org/wiki/Decorator_pattern">Decorator</a>. Para isso, criamos uma classe que recebe o model como parâmetro no construtor e implementa todos os métodos necessários para lógicas de visualização (ou seja, que não estão associados ao negócio e não devem ficar no model). Quando é chamado um método que não existe, o Decorator delega (daí o nome do padrão) a chamada para o model. Existem várias implementações para o Decorator, essa é uma das mais simples:</p>
<pre class="brush: ruby; title: ; notranslate">
module Decorator
  attr_reader :model

  def initialize(model)
    @model = model
  end

  def method_missing(meth, *args)
    if @model.respond_to?(meth)
      @model.send(meth, *args)
    else
      super
    end
  end

  def respond_to?(meth)
    @model.respond_to?(meth)
  end

  def self.included(base)
    base.extend(ClassMethods)
  end

  module ClassMethods
    def decorate(object)
      if object.is_a? Enumerable
        object.map {|obj| self.new(obj)}
      else
        self.new(object)
      end
    end
  end
end


class UsuarioDecorator
  include Decorator

  def titulo
    @model.admin? ? &quot;admin&quot; : @admin.nome
  end
end
</pre>
<p>Desta forma, temos uma classe que recebe o model no construtor ou no método de classe <em>decorate</em>. A implementação do método titulo_usuario no Decorator ficou muito mais simples. Para utilizá-la, basta decorar o model no controller:</p>
<pre class="brush: ruby; title: ; notranslate">
class UsuariosController
  def show
    @usuario = UsuarioDecorator.decorate(Usuario.find(params[:id]))
  end
end
</pre>
<p>A implementação da view fica assim:</p>
<pre class="brush: ruby; title: ; notranslate">
@usuario.titulo
</pre>
<p>Em casos mais simples, o Decorator atende bem. Mas e quando temos uma página mais complexa, envolvendo diversos objetos? Precisaríamos criar um Decorator para cada model, e lembrar de decorar cada objeto na criação, assim como fizemos com o usuário no exemplo anterior. Outro problema é que podemos ter visualizações diferentes de um objeto em cada tela da aplicação. Como tratar este caso? Poderíamos criar métodos diferentes no Decorator, mas com o tempo o Decorator poderia virar um monstro. Outra opção é criar vários Decorators para aquele model, onde cada um se aplica a uma página. Ou podemos usar um outro padrão, o Presenter.</p>
<p>O Presenter é um padrão também conhecido por outros nomes, como <a href="http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/">View Object</a>, mas na comunidade Ruby o nome Presenter se popularizou com <a href="http://blog.jayfields.com/2007/03/rails-presenter-pattern.html">um post de Jay Fields</a>. O Presenter é muito parecido com o Decorator, mas envolve vários objetos. O contexto do Presenter é uma página específica da aplicação, e recebe como parâmetro todos os objetos necessários à exibição daquela página. Desta forma, toda a lógica de apresentação fica numa única classe. Segue um exemplo de uso do Presenter:</p>
<pre class="brush: ruby; title: ; notranslate">
class PedidoPresenter
  def initialize(usuario, pedidos)
    @usuario = usuario
    @pedidos = pedidos
  end

  def titulo
    &quot;Usuário #{@usuario.nome} - #{@pedidos.size} pedidos&quot;
  end

  def links
    @pedidos.map { |pedido| link_to pedido.nome, pedido_url(pedido) }
  end
end
</pre>
<p>Ainda há uma outra opção além do Presenter, que foi apresentada no livro <a href="http://objectsonrails.com">Objects on Rails</a>. É o padrão Exhibit. A diferença em relação ao Presenter é que, enquanto o Presenter disponibiliza métodos para serem chamados pela view (como no exemplo acima), o Exhibit é responsável pela renderização. Para isso, ele precisa receber um contexto:</p>
<pre class="brush: ruby; title: ; notranslate">
class Exhibit
  def initialize(obj, context)
    @obj = obj
    @context = context
  end

  def render_header
    @context.render :partial =&gt; &quot;header&quot;, :locals =&gt; {:obj =&gt; @obj}
  end
end
</pre>
<p>Este contexto pode ser o <em>view_context</em> do controller:</p>
<pre class="brush: ruby; title: ; notranslate">
class Controller
  def show
    @usuario = Exhibit.new(Usuario.find(params[:id]), view_context)
  end
end
</pre>
<p>Outra maneira de instanciar o Exhibit é através de um helper, como mostrado no livro <a href="http://pragprog.com/book/warv/the-rails-view">The Rails View</a>:</p>
<pre class="brush: ruby; title: ; notranslate">
class Helper
  def exhibit
    Exhibit.new(Usuario.find(params[:id]), self)
  end
end
</pre>
<p>São muitos padrões que tem a mesma função: encapsular a lógica de visualização num único local, que seja facilmente testável. E qual é a melhor opção entre os três? A resposta depende da situação. Não adianta querer encontrar um padrão perfeito para todos os casos. Na minha opinião, o Decorator funciona bem em páginas mais simples, que envolvem apenas um model. Quando a página é mais complexa e envolve vários models, o Presenter e o Exhibit são mais adequados. E a diferença entre os dois é uma questão de gosto.</p>
<p>Links relacionados:</p>
<ul>
<li><a href="http://robots.thoughtbot.com/post/20964851591/decorators-compared-to-strategies-composites-and">Decorators compared to Strategies, Composites, and Presenters</a></li>
<li><a href="http://robots.thoughtbot.com/post/14825364877/evaluating-alternative-decorator-implementations-in">Evaluating alternative Decorator implementations in Ruby</a></li>
<li><a href="http://blog.steveklabnik.com/posts/2011-09-09-better-ruby-presenters">Better Ruby Presenters</a></li>
<li><a href="https://speakerdeck.com/rodrigoospinto/explorando-as-views-rails">Explorando as views Rails</a></li>
</ul>
<h3 class='related_post_title'>Posts relacionados:</h3>
<ul class='related_post'>
<li><a href='http://blog.guilhermegarnier.com/2011/11/rails-e-mass-assignment-como-aumentar-a-seguranca-dos-atributos/' title='Rails e mass assignment: como aumentar a segurança dos atributos'>Rails e mass assignment: como aumentar a segurança dos atributos</a></li>
<li><a href='http://blog.guilhermegarnier.com/2009/06/instant-rails-o-ambiente-rails-de-bolso/' title='Instant Rails, o ambiente Rails de bolso'>Instant Rails, o ambiente Rails de bolso</a></li>
<li><a href='http://blog.guilhermegarnier.com/2008/10/ferramenta-em-rails-para-criacao-de-blogs/' title='Ferramenta em Rails para criação de blogs'>Ferramenta em Rails para criação de blogs</a></li>
<li><a href='http://blog.guilhermegarnier.com/2008/06/rails-sem-banco-de-dados/' title='Rails sem banco de dados'>Rails sem banco de dados</a></li>
<li><a href='http://blog.guilhermegarnier.com/2008/05/ides-para-ruby-on-rails/' title='IDEs para Ruby on Rails'>IDEs para Ruby on Rails</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.guilhermegarnier.com/2013/04/design-patterns-em-ruby-decorators-presenters-e-exhibits/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Sprites automáticos com Compass</title>
		<link>http://blog.guilhermegarnier.com/2012/07/sprites-automaticos-com-compass/</link>
		<comments>http://blog.guilhermegarnier.com/2012/07/sprites-automaticos-com-compass/#comments</comments>
		<pubDate>Thu, 26 Jul 2012 22:44:39 +0000</pubDate>
		<dc:creator>guilhermegarnier</dc:creator>
				<category><![CDATA[Programação]]></category>
		<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[compass]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[sass]]></category>
		<category><![CDATA[sprites]]></category>

		<guid isPermaLink="false">http://blog.guilhermegarnier.com/?p=514</guid>
		<description><![CDATA[Um dos temas mais atuais no desenvolvimento web é a otimização de sites. A motivação para reduzir o tempo de carregamento das páginas vem não só de estudos que mostram que quando maior o tempo de carregamento, maior o número de usuários que abandonam o site, mas também do fato de que o Google considera [...]]]></description>
				<content:encoded><![CDATA[<p>Um dos temas mais atuais no desenvolvimento web é a <a href="http://blog.caelum.com.br/por-uma-web-mais-rapida-26-tecnicas-de-otimizacao-de-sites/">otimização de sites</a>. A motivação para reduzir o tempo de carregamento das páginas vem não só de estudos que mostram que <a href="http://www.webperformancetoday.com/2010/06/15/everything-you-wanted-to-know-about-web-performance/">quando maior o tempo de carregamento, maior o número de usuários que abandonam o site</a>, mas também do fato de que <a href="http://googlewebmastercentral.blogspot.com.br/2010/04/using-site-speed-in-web-search-ranking.html">o Google considera o tempo de resposta na criação do PageRank</a>.</p>
<p>Um dos itens mais importantes ao otimizar um site, <a href="http://developer.yahoo.com/blogs/ydn/posts/2007/04/rule_1_make_few/">de acordo com Steve Souders</a>, é diminuir o número de requests. Um recurso muito útil para isso é a criação de sprites, ou seja, um único arquivo contendo várias imagens que são utilizadas no site. Nos locais que fazem referência a estas imagens, são definidos a largura, altura e offset do sprite. Desta forma, é feito um único request para obter todas as imagens. O uso de sprites é muito comum em <a href="http://en.webmolot.com/sprite-2/">grandes sites como Twitter, Facebook, Google e Yahoo</a>.</p>
<p>A criação de um sprite manualmente é uma tarefa bem trabalhosa. É necessário criar uma imagem utilizando uma ferramenta como o Photoshop, por exemplo, e colar cada imagem uma abaixo (ou ao lado) da outra, deixando alguns pixels entre imagens. Sempre que se quiser adicionar uma nova imagem, será necessário abrir o sprite novamente no Photoshop e repetir o processo para inserir a nova imagem.</p>
<p>Para simplificar esta tarefa, é possível utilizar uma ferramenta para geração automática de sprites. Uma das melhores ferramentas para isso é o <a href="http://compass-style.org/">Compass</a>. Após instalar e configurar, basta colocar as imagens num diretório e o sprite será gerado automaticamente. A instalação num projeto Rails é extremamente simples, e está bem explicada no <a href="http://compass-style.org/help/">help do Compass</a>.</p>
<p>A configuração básica do Compass para geração de sprites segue o padrão abaixo:</p>
<pre class="brush: ruby; title: ; notranslate">
$imagens-spacing: 2px
$imagens-sprite-dimensions: true
@import &quot;imagens/*.png&quot;
</pre>
<p>No exemplo acima, todas as propriedades são configuradas com o prefixo <em>imagens</em>. O sprite é configurado com espaçamento de 2 pixels entre cada imagem, para evitar sobreposição no limite entre as imagens. A segunda linha habilita a inclusão das dimensões das imagens no CSS gerado, o que é útil para manter fixo o tamanho ocupado pela imagem enquanto ela é carregada. A terceira linha informa quais imagens serão adicionadas. Neste caso, são todas as imagens com extensão png que estão no diretório <em>imagens</em>. É importante lembrar que o nome deste diretório deve ser igual ao prefixo utilizado nas propriedades.</p>
<p>Além de gerar o sprite, o Compass cria classes CSS para referenciar cada imagem. Os nomes das classes começam com o prefixo utilizado acima, seguido por hífen e o nome da imagem sem extensão. Por exemplo, para uma imagem chamada <em>excluir.png</em>, a classe teria o nome <em>imagens-excluir</em>.</p>
<p>O uso as imagens do sprite no seu CSS pode ser feito de duas formas: usando diretamente as classes criadas pelo Compass (como <em>imagens-excluir</em>, no exemplo anterior) ou utilizando um mixin do Compass no seu arquivo <a href="http://sass-lang.com/">Sass</a>:</p>
<pre class="brush: css; title: ; notranslate">
.minha-classe { @include imagens-sprite(excluir); }
</pre>
<p>Ao utilizar uma destas configurações, a imagem será configurada como background do elemento.</p>
<p>Para criar um segundo sprite, para a parte administrativa da aplicação, por exemplo, é necessário utilizar um prefixo diferente, como no exemplo abaixo:</p>
<pre class="brush: ruby; title: ; notranslate">
$imagens-admin-spacing: 2px
$imagens-admin-sprite-dimensions: true
@import &quot;admin/imagens-admin/*.png&quot;
</pre>
<p>Neste exemplo, as imagens do sprite estão no diretório <em>admin/imagens-admin</em>, e o prefixo segue o nome do último diretório (<em>imagens-admin</em>). Isso significa que, no exemplo acima, não seria possível manter o sprite do admin em <em>admin/imagens</em>, pois haveria conflito de nomes com o outro sprite.</p>
<p>Os sprites gerados pelo Compass são arquivos png que tem como nome o prefixo utilizado na configuração seguido por um hash (ex: <em>imagens-b03bdb7a79370e7ff107e7b37fe7df6e.png</em>). Quando o sprite é modificado (em ambiente de desenvolvimento o Compass verifica automaticamente a cada request se alguma imagem foi adicionada ou removida, e em produção é necessário executar um <em>rake task</em> para isso), o Compass gera um novo hash para o nome do arquivo. Isto é feito para evitar que o sprite seja cacheado pelo browser. Se isso acontecesse, o browser não buscaria o sprite atualizado, mantendo o arquivo anterior.</p>
<p>Os exemplos descritos acima descrevem apenas as configurações básicas para geração de sprites. A <a href="http://compass-style.org/help/tutorials/spriting/">documentação de sprites</a> traz mais detalhes sobre as opções de configuração. Além disso, o Compass tem muitas outras funcionalidades. Vale a pena pesquisar a <a href="http://compass-style.org/reference/compass/">referência no site do Compass</a> para mais detalhes.</p>
<p><strong>UPDATE:</strong> outra configuração útil para os sprites é o <a href="http://compass-style.org/help/tutorials/spriting/sprite-layouts/">layout das imagens</a>. Por padrão, o layout dos sprites é vertical, ou seja, cada imagem é colocada abaixo da anterior. Porém, o Compass também permite definir layout horizontal, diagonal ou smart. Neste último, a disposição das imagens é feita de acordo com o tamanho de cada uma, e o resultado é uma imagem menor do que com o layout padrão. No meu projeto, ao trocar o layout vertical pelo smart, o sprite ficou cerca de 10% menor. No primeiro exemplo deste post, a configuração do layout ficaria assim:</p>
<pre class="brush: ruby; title: ; notranslate">
$imagens-layout: smart
</pre>
<h3 class='related_post_title'>Posts relacionados:</h3>
<ul class='related_post'>
<li><a href='http://blog.guilhermegarnier.com/2013/04/design-patterns-em-ruby-decorators-presenters-e-exhibits/' title='Design patterns em Ruby &#8211; Decorators, Presenters e Exhibits'>Design patterns em Ruby &#8211; Decorators, Presenters e Exhibits</a></li>
<li><a href='http://blog.guilhermegarnier.com/2011/11/rails-e-mass-assignment-como-aumentar-a-seguranca-dos-atributos/' title='Rails e mass assignment: como aumentar a segurança dos atributos'>Rails e mass assignment: como aumentar a segurança dos atributos</a></li>
<li><a href='http://blog.guilhermegarnier.com/2009/06/instant-rails-o-ambiente-rails-de-bolso/' title='Instant Rails, o ambiente Rails de bolso'>Instant Rails, o ambiente Rails de bolso</a></li>
<li><a href='http://blog.guilhermegarnier.com/2008/10/ferramenta-em-rails-para-criacao-de-blogs/' title='Ferramenta em Rails para criação de blogs'>Ferramenta em Rails para criação de blogs</a></li>
<li><a href='http://blog.guilhermegarnier.com/2008/06/rails-sem-banco-de-dados/' title='Rails sem banco de dados'>Rails sem banco de dados</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.guilhermegarnier.com/2012/07/sprites-automaticos-com-compass/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Rails e mass assignment: como aumentar a segurança dos atributos</title>
		<link>http://blog.guilhermegarnier.com/2011/11/rails-e-mass-assignment-como-aumentar-a-seguranca-dos-atributos/</link>
		<comments>http://blog.guilhermegarnier.com/2011/11/rails-e-mass-assignment-como-aumentar-a-seguranca-dos-atributos/#comments</comments>
		<pubDate>Tue, 22 Nov 2011 13:24:47 +0000</pubDate>
		<dc:creator>guilhermegarnier</dc:creator>
				<category><![CDATA[Programação]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[activemodel]]></category>
		<category><![CDATA[activerecord]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[Segurança]]></category>

		<guid isPermaLink="false">http://blog.guilhermegarnier.com/?p=487</guid>
		<description><![CDATA[Ao utilizar o scaffold do Rails, ele criará todos os métodos necessários no controller. Depois que o usuário preenche os dados do formulário e envia, é executado o método create do controller. Este método faz algo semelhante ao código abaixo (no exemplo é um CRUD de usuário): Na forma em que o Rails cria o [...]]]></description>
				<content:encoded><![CDATA[<p>Ao utilizar o scaffold do Rails, ele criará todos os métodos necessários no controller. Depois que o usuário preenche os dados do formulário e envia, é executado o método create do controller. Este método faz algo semelhante ao código abaixo (no exemplo é um CRUD de usuário):</p>
<pre class="brush: ruby; title: ; notranslate">
@usuario = Usuario.new(params[:usuario])
</pre>
<p>Na forma em que o Rails cria o formulário, os atributos do usuário são passados ao controller como um hash. O valor do params acima é algo parecido com isso:</p>
<pre class="brush: jscript; title: ; notranslate">
{&quot;authenticity_token&quot;=&gt;&quot;xI1Cy+LvUZzg6FR/1Y/JHcaHVPRyWsHmRII8BhMOr0E=&quot;,
 &quot;utf8&quot;=&gt;&quot;?&quot;,
 &quot;action&quot;=&gt;&quot;create&quot;,
 &quot;controller&quot;=&gt;&quot;usuarios&quot;,
 &quot;usuario&quot;=&gt;{&quot;nome&quot;=&gt;&quot;Novo usuario&quot;, &quot;email&quot;=&gt;&quot;novo@usuario.com&quot;}}
</pre>
<p>Além da definição do token de segurança, codificação em utf-8, nome do controller e da action que será executada, o parâmetro usuario contém todos os atributos que foram preenchidos no formulário. Desta forma, é muito simples atribuir os parâmetros preenchidos a um objeto Usuario, seja criando um novo (<em>@usuario = Usuario.new(params[:usuario])</em>) ou editando (<em>@usuario.update_params(params[:usuario])</em>). O Rails chama isso de <a href="http://guides.rubyonrails.org/security.html#mass-assignment"><em>mass assignment</em></a>.</p>
<p>O problema desta abordagem é que o usuário poderia facilmente inserir novos parâmetros neste hash, simplesmente adicionando tags input hidden no formulário (usando o <a href="http://getfirebug.com/">Firebug</a>, por exemplo):</p>
<pre class="brush: xml; title: ; notranslate">
&lt;input type=&quot;hidden&quot; name=&quot;usuario[admin]&quot; id=&quot;usuario_admin&quot; value=&quot;true&quot; /&gt;
</pre>
<p>Adicionando o código acima, o novo usuário criado receberia o valor <em>true</em> no atributo <em>admin</em>, o que representa uma falha grave na segurança da aplicação.</p>
<p>O Rails oferece um mecanismo para garantir a segurança nestes casos, usando os métodos <a href="http://apidock.com/rails/ActiveModel/MassAssignmentSecurity/ClassMethods/attr_protected"><em>attr_protected</em></a> e <a href="http://apidock.com/rails/ActiveModel/MassAssignmentSecurity/ClassMethods/attr_accessible"><em>attr_accessible</em></a> do <a href="http://apidock.com/rails/ActiveModel">ActiveModel</a>. O primeiro permite definir atributos que não podem ser alterados através de <em>mass assignment</em>:</p>
<pre class="brush: ruby; title: ; notranslate">
class Usuario
  attr_protected :admin
end
</pre>
<p>E o <em>attr_accessible</em> é uma forma mais segura: somente os atributos passados para este método poderão ser alterados com <em>mass assignment</em>. Os demais ficam protegidos:</p>
<pre class="brush: ruby; title: ; notranslate">
class Usuario
  attr_accessible :nome, :email
end
</pre>
<p>Obviamente estes dois métodos não podem ser usados simultaneamente, pois um exclui o outro.</p>
<p>Se você quiser atualizar um objeto com <em>mass assignment</em> ignorando a segurança fornecida pelo <em>attr_accessible</em> e pelo <em>attr_protected</em>, basta utilizar o parâmetro <em>without_protection</em> (somente no Rails 3.1):</p>
<pre class="brush: ruby; title: ; notranslate">
Usuario.create(
  {:nome =&gt; &quot;Novo usuario&quot;, :email =&gt;&quot;novo@usuario.com&quot;, :admin =&gt; true},
  :without_protection =&gt; true)
</pre>
<p>No exemplo acima, o usuário criado terá o atributo <em>admin</em> igual a <em>true</em>, mesmo que tenha sido usado o método <em>attr_protected</em> ou o <em>attr_accessible</em> para evitar a alteração deste atributo.</p>
<p>Outra opção interessante para evitar a alteração de atributos indesejados é o método <a href="http://apidock.com/rails/ActiveRecord/Base/attr_readonly/class"><em>attr_readonly</em></a>. Os atributos passados para este método só poderão ser definidos na criação do objeto, e não poderão ser alterados depois. Porém, este método faz parte do <a href="http://apidock.com/rails/ActiveRecord/Base">ActiveRecord::Base</a>, e não do ActiveModel, ou seja, ele não estará disponível se você usar outro ORM. <a href="https://github.com/rails/rails/issues/3376">Há uma issue aberta no Github</a> solicitando que este método seja movido para o ActiveModel.</p>
<p>Link relacionado:</p>
<ul>
<li><a href="http://simplesideias.com.br/recebendo-dados-do-usuario-attr_accessible-e-attr_protected/">Recebendo dados do usuário: attr_accessible e attr_protected</a></li>
</ul>
<h3 class='related_post_title'>Posts relacionados:</h3>
<ul class='related_post'>
<li><a href='http://blog.guilhermegarnier.com/2008/06/rails-sem-banco-de-dados/' title='Rails sem banco de dados'>Rails sem banco de dados</a></li>
<li><a href='http://blog.guilhermegarnier.com/2008/04/configuracoes-fora-do-padrao-em-rails-parte-2-relacionamentos-habtm/' title='Configurações fora do padrão em Rails, parte 2 &#8211; Relacionamentos HABTM'>Configurações fora do padrão em Rails, parte 2 &#8211; Relacionamentos HABTM</a></li>
<li><a href='http://blog.guilhermegarnier.com/2008/03/configuracoes-fora-do-padrao-em-rails/' title='Configurações fora do padrão em Rails'>Configurações fora do padrão em Rails</a></li>
<li><a href='http://blog.guilhermegarnier.com/2008/03/acessando-multiplos-bancos-de-dados-em-rails/' title='Acessando múltiplos bancos de dados em Rails'>Acessando múltiplos bancos de dados em Rails</a></li>
<li><a href='http://blog.guilhermegarnier.com/2013/04/design-patterns-em-ruby-decorators-presenters-e-exhibits/' title='Design patterns em Ruby &#8211; Decorators, Presenters e Exhibits'>Design patterns em Ruby &#8211; Decorators, Presenters e Exhibits</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.guilhermegarnier.com/2011/11/rails-e-mass-assignment-como-aumentar-a-seguranca-dos-atributos/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Integrando o Remember the Milk ao Google Calendar e Gmail</title>
		<link>http://blog.guilhermegarnier.com/2011/09/integrando-o-remember-the-milk-ao-google-calendar-e-gmail/</link>
		<comments>http://blog.guilhermegarnier.com/2011/09/integrando-o-remember-the-milk-ao-google-calendar-e-gmail/#comments</comments>
		<pubDate>Wed, 21 Sep 2011 13:20:08 +0000</pubDate>
		<dc:creator>guilhermegarnier</dc:creator>
				<category><![CDATA[Google]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[gmail]]></category>
		<category><![CDATA[google calendar]]></category>
		<category><![CDATA[remember the milk]]></category>

		<guid isPermaLink="false">http://blog.guilhermegarnier.com/?p=473</guid>
		<description><![CDATA[O Google Calendar é uma excelente ferramenta para manter o controle de compromissos pendentes. Porém, tem dois problemas: é limitado a tarefas que tenham uma data específica e não dependem do usuário concluir, ou seja, uma tarefa que foi programada para ontem mas não foi realizada não aparecerá mais no meu calendário (ou melhor, aparecerá [...]]]></description>
				<content:encoded><![CDATA[<p>O <a href="http://calendar.google.com">Google Calendar</a> é uma excelente ferramenta para manter o controle de compromissos pendentes. Porém, tem dois problemas: é limitado a tarefas que tenham uma data específica e não dependem do usuário concluir, ou seja, uma tarefa que foi programada para ontem mas não foi realizada não aparecerá mais no meu calendário (ou melhor, aparecerá no dia em que estava prevista, e provavelmente será esquecida com o tempo). Isso acontece porque o Google Calendar não é uma ferramenta voltada para tarefas, e sim para eventos. Para realizar o controle de tarefas, o melhor é utilizar uma ferramenta específica para tal. Idealmente uma que seja integrável ao Google Calendar, pois este continua sendo uma excelente ferramenta para controle de eventos (visualizar eventos futuros, compartilhar com outras pessoas, etc).</p>
<p>A opção mais óbvia para controle de tarefas seria o <a href="http://mail.google.com/tasks">Google Tasks</a>, pois é do próprio Google, e como tal, é totalmente integrado não só ao Google Calendar, mas também ao Gmail. Apesar de ser uma boa opção, o Google Tasks é bastante limitado, e não possui (ainda) uma funcionalidade que considero básica para uma ferramenta de controle de tarefas: o cadastro de tarefas recorrentes (ex: toda segunda-feira, todo mês no dia 10).</p>
<p>Em função destas limitações, eu prefiro utilizar o <a href="http://www.rememberthemilk.com">Remember the Milk</a>, que é uma ferramenta muito mais completa que o Google Tasks. Ele também pode ser integrado tanto ao Gmail quanto ao Google Calendar.</p>
<h3>Integração com Google Calendar</h3>
<p>A integração é bem simples, através da interface iCalendar do Remember the Milk: vá até a opção settings, aba Info. Copie o link &#8220;iCalendar Events Service (All Lists)&#8221;. Em seguida, vá ao Google Calendar, em &#8220;other calendars&#8221;, à esquerda, há uma opção &#8220;Add by URL&#8221;. Cole a URL que foi copiada do Remember the Milk, e será criado um novo calendário com as suas tarefas &#8211; obviamente só aparecerão as que tem data.</p>
<p>Apesar de funcionar bem, a integração é limitada: a hora da tarefa não aparece, não há link direto para ver a tarefa no RTM, e é somente uma visualização, ou seja, não é possível editar, excluir ou concluir a tarefa a partir do Google Calendar. Além disso, quando uma tarefa é concluída, ela demora um tempo para sumir do calendário. Mas é possível configurar reminders para este calendário específico, o que torna a integração mais útil.</p>
<p>O calendário criado exibe todas as tarefas do seu RTM que não estão concluídas e tem data. Outra possibilidade é criar calendários com listas específicas. Para isso, vá ao RTM, faça uma busca ou selecione uma lista ou smart list específica. No lado direito aparecerá uma opção &#8220;iCalendar (Events)&#8221;. Copie esse link e repita o procedimento anterior no Google Calendar.</p>
<p>O RTM também disponibiliza dois <a href="http://www.rememberthemilk.com/services/googlecalendar/">gadgets para Google Calendar</a>:</p>
<ul>
<li><a href="http://www.rememberthemilk.com/services/googlecalendar/sidebar/">Sidebar Gadget</a></li>
<p>Permite visualizar, editar e adicionar tarefas diretamente no Google Calendar. Só não é possível visualizar e editar notas, mas há um link para exibir no RTM.</p>
<li><a href="http://www.rememberthemilk.com/services/googlecalendar/">Daily Gadget</a></li>
<p>Adiciona um botão a cada dia do calendário; ao ser clicado, exibe a lista de tarefas do dia.
</ul>
<h3>Integração com Gmail</h3>
<p>O RTM disponibiliza duas maneiras de exibir as tarefas no Gmail:</p>
<ul>
<li>Gadget do Google Calendar</li>
<p>Se você configurou a integração do RTM com o Google Calendar, descrita acima, o gadget do Google Calendar exibirá as tarefas do RTM.</p>
<li><a href="http://www.rememberthemilk.com/services/gmail/gadget/">Gmail Gadget</a></li>
<p>Este gadget possui as mesmas funcionalidades do Sidebar Gadget para Google Calendar.</p>
<li><a href="http://www.rememberthemilk.com/services/gmail/addon/">Add-on</a> (Firefox e Chrome)</li>
<p>Esta extensão é bem semelhante ao Gmail Gadget, mas possui algumas funcionalidades a mais: ela pode ser configurada para criar tarefas automaticamente quando um email for marcado com estrela ou com um label específico. Também é possível criar uma tarefa associada a um email específico, que será automaticamente concluída quando o email for respondido.
</ul>
<h3 class='related_post_title'>Posts relacionados:</h3>
<ul class='related_post'>
<li><a href='http://blog.guilhermegarnier.com/2010/01/problema-com-a-extensao-do-remember-the-milk-no-gmail/' title='Problema com a extensão do Remember The Milk no Gmail'>Problema com a extensão do Remember The Milk no Gmail</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.guilhermegarnier.com/2011/09/integrando-o-remember-the-milk-ao-google-calendar-e-gmail/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Gerenciando múltiplas versões de Ruby no Windows</title>
		<link>http://blog.guilhermegarnier.com/2011/05/gerenciando-multiplas-versoes-de-ruby-no-windows/</link>
		<comments>http://blog.guilhermegarnier.com/2011/05/gerenciando-multiplas-versoes-de-ruby-no-windows/#comments</comments>
		<pubDate>Thu, 19 May 2011 17:55:24 +0000</pubDate>
		<dc:creator>guilhermegarnier</dc:creator>
				<category><![CDATA[Programação]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[jruby]]></category>
		<category><![CDATA[pik]]></category>
		<category><![CDATA[rvm]]></category>
		<category><![CDATA[windows]]></category>

		<guid isPermaLink="false">http://blog.guilhermegarnier.com/?p=451</guid>
		<description><![CDATA[O RVM já se tornou a opção padrão para gerenciar múltiplas versões de Ruby. Ele permite instalar várias versões, alternar entre elas, instalar gems em cada versão independentemente&#8230; mas não funciona em ambiente Windows. Eu sei que este não é um ambiente muito popular para desenvolvimento Ruby, mas existem usuários de Windows (seja por opção [...]]]></description>
				<content:encoded><![CDATA[<p>O <a href="https://rvm.beginrescueend.com/">RVM</a> já se tornou a opção padrão para gerenciar múltiplas versões de Ruby. Ele permite instalar várias versões, alternar entre elas, instalar gems em cada versão independentemente&#8230; mas não funciona em ambiente Windows. Eu sei que este não é um ambiente muito popular para desenvolvimento Ruby, mas existem usuários de Windows (seja por opção ou por obrigação) programando em Ruby. Para estes, uma alternativa ao RVM é o <a href="https://github.com/vertiginous/pik">Pik</a>.</p>
<p>O Pik funciona de forma bastante semelhante ao RVM. Para instalá-lo, primeiro é necessário instalar o <a href="http://rubyinstaller.org/">Ruby Installer</a>, um pacote pré-configurado especialmente para instalar o Ruby no Windows. A documentação do Pik recomenda a versão 1.8.7. Em seguida, instale as gems rake, isolate e o próprio pik:</p>
<pre class="brush: bash; title: ; notranslate">
gem install rake isolate pik
</pre>
<p>Antes de instalar o isolate, talvez seja necessário atualizar o <a href="http://rubygems.org/">Rubygems</a> com o comando abaixo:</p>
<pre class="brush: bash; title: ; notranslate">
gem update --system
</pre>
<p>O próximo passo é instalar o Pik no diretório de sua preferência. Um detalhe importante que já me custou um bom tempo é que o path completo não deve conter espaços. Execute o seguinte comando para instalar em <em>C:\Ruby\pik</em>, por exemplo:</p>
<pre class="brush: bash; title: ; notranslate">
pik_install C:\Ruby\pik
</pre>
<p>Concluída a instalação, o comando <em>pik help commands</em> exibe uma lista com os comandos disponíveis. Quem já usou o RVM não terá dificuldades, pois os comandos são bem semelhantes. Os comandos mais comuns são:</p>
<ul>
<li><em>pik install ruby/jruby/ironruby [versão]</em> -> instala a versão desejada do Ruby, JRuby ou IronRuby. A versão é opcional; se for omitida, será instalada a versão mais recente. Importante: antes de executar este comando, instale o <a href="http://www.7-zip.org/">7zip</a> e adicione-o ao path</li>
<li><em>pik list</em> -> exibe as versões de Ruby atualmente instaladas</li>
<li><em>pik use [versão]</em> -> seleciona uma versão instalada</li>
<li><em>pik gem [comando]</em> -> executa um comando do Rubygems em todas as versões instaladas</li>
<li><em>pik ruby [parâmetros]</em> -> executa Ruby em todas as versões instaladas</li>
</ul>
<p>Inicialmente, o comando <em>pik list</em> exibe apenas a versão 1.8.7:</p>
<pre class="brush: bash; title: ; notranslate">
C:\Ruby\pik&gt;pik list
* 187: ruby 1.8.7 (2011-02-18 patchlevel 334) [i386-mingw32]
</pre>
<p>Decidi instalar a última versão do Ruby e do JRuby. Após instalar estas duas versões, a saída do comando <em>pik list</em> ficou assim (o asterisco mostra a versão atualmente em uso):</p>
<pre class="brush: bash; title: ; notranslate">
C:\Ruby\pik&gt;pik install ruby
...
C:\Ruby\pik&gt;pik install jruby
...
C:\Ruby\pik&gt;pik list
  161: jruby 1.6.1 (ruby-1.8.7-p330) (2011-04-12 85838f6) (Java HotSpot(TM) Client VM 1.6.0_24) [Windows XP-x86-java]
* 187: ruby 1.8.7 (2011-02-18 patchlevel 334) [i386-mingw32]
  192: ruby 1.9.2dev (2010-05-31) [i386-mingw32]
</pre>
<p>Para selecionar o JRuby, por exemplo, use o comando <em>pik use 161</em> (é importante lembrar que neste caso os comandos mudam de nome: <em>irb</em> vira <em>jirb</em>, <em>ruby</em> vira <em>jruby</em>):</p>
<pre class="brush: bash; title: ; notranslate">
C:\Ruby\pik&gt;pik use 161

C:\Ruby\pik&gt;ruby -v
'ruby' não é reconhecido como um comando interno
ou externo, um programa operável ou um arquivo em lotes.

C:\Ruby\pik&gt;jruby -v
jruby 1.6.1 (ruby-1.8.7-p330) (2011-04-12 85838f6) (Java HotSpot(TM) Client VM 1.6.0_24) [Windows XP-x86-java]
</pre>
<p>Para instalar gems, basta usar o comando <em>gem install</em> normalmente. A gem será instalada na versão atual do Ruby (ou seja, a que você selecionou com o comando <em>pik use</em>). O comando <em>pik gem</em> permite instalar uma gem em todas as versões:</p>
<pre class="brush: bash; title: ; notranslate">
C:\Ruby\pik&gt;pik gem install mongo
jruby 1.6.1 (ruby-1.8.7-p330) (2011-04-12 85838f6) (Java HotSpot(TM) Client VM 1.6.0_24) [Windows XP-x86-java]

Fetching: bson-1.3.1-jruby.gem (100%)
Fetching: mongo-1.3.1.gem (100%)
Successfully installed bson-1.3.1-java
Successfully installed mongo-1.3.1
2 gems installed

ruby 1.8.7 (2011-02-18 patchlevel 334) [i386-mingw32]

Fetching: bson-1.3.1.gem (100%)
Fetching: mongo-1.3.1.gem (100%)
Successfully installed bson-1.3.1
Successfully installed mongo-1.3.1
2 gems installed
Installing ri documentation for bson-1.3.1...
Installing ri documentation for mongo-1.3.1...
Installing RDoc documentation for bson-1.3.1...
Installing RDoc documentation for mongo-1.3.1...

ruby 1.9.2dev (2010-05-31) [i386-mingw32]

Successfully installed bson-1.3.1
Successfully installed mongo-1.3.1
2 gems installed
Installing ri documentation for bson-1.3.1...
Installing ri documentation for mongo-1.3.1...
Installing RDoc documentation for bson-1.3.1...
Installing RDoc documentation for mongo-1.3.1...

</pre>
<p>O comando <em>pik ruby</em> permite executar um código em todas as versões instaladas, útil para verificar incompatibilidades entre as versões, como por exemplo <a href="http://blog.guilhermegarnier.com/2011/03/representacao-de-data-e-hora-em-ruby-1-8-7-e-1-9/">o construtor com parâmetros da classe Time</a>:</p>
<pre class="brush: bash; title: ; notranslate">
C:\Ruby\pik&gt;pik ruby -e &quot;puts Time.new('2011-01-01')&quot;
jruby 1.6.1 (ruby-1.8.7-p330) (2011-04-12 85838f6) (Java HotSpot(TM) Client VM 1.6.0_24) [Windows XP-x86-java]

ArgumentError: wrong number of arguments (1 for 0)
  (root) at -e:1

ruby 1.8.7 (2011-02-18 patchlevel 334) [i386-mingw32]

-e:1:in `initialize': wrong number of arguments (1 for 0) (ArgumentError)
        from -e:1:in `new'
        from -e:1

ruby 1.9.2dev (2010-05-31) [i386-mingw32]

2011-01-01 00:00:00 -0200

</pre>
<p>Mais detalhes sobre o funcionamento do Pik podem ser encontrados no <a href="https://github.com/vertiginous/pik">Github do projeto</a>.<br />
<h3 class='related_post_title'>Posts relacionados:</h3>
<ul class='related_post'>
<li><a href='http://blog.guilhermegarnier.com/2011/03/representacao-de-data-e-hora-em-ruby-1-8-7-e-1-9/' title='Representação de data e hora em Ruby 1.8.7 e 1.9'>Representação de data e hora em Ruby 1.8.7 e 1.9</a></li>
<li><a href='http://blog.guilhermegarnier.com/2009/06/instant-rails-o-ambiente-rails-de-bolso/' title='Instant Rails, o ambiente Rails de bolso'>Instant Rails, o ambiente Rails de bolso</a></li>
<li><a href='http://blog.guilhermegarnier.com/2013/04/design-patterns-em-ruby-decorators-presenters-e-exhibits/' title='Design patterns em Ruby &#8211; Decorators, Presenters e Exhibits'>Design patterns em Ruby &#8211; Decorators, Presenters e Exhibits</a></li>
<li><a href='http://blog.guilhermegarnier.com/2011/02/ruby-no-ubuntu-erro-na-instalacao-de-rubygems/' title='Ruby no Ubuntu &#8211; erro na instalação de Rubygems'>Ruby no Ubuntu &#8211; erro na instalação de Rubygems</a></li>
<li><a href='http://blog.guilhermegarnier.com/2009/12/classes-abstratas-em-ruby/' title='Classes abstratas em Ruby?'>Classes abstratas em Ruby?</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.guilhermegarnier.com/2011/05/gerenciando-multiplas-versoes-de-ruby-no-windows/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ajude o Firefox a crescer com o Test Pilot</title>
		<link>http://blog.guilhermegarnier.com/2011/05/ajude-o-firefox-a-crescer-com-o-test-pilot/</link>
		<comments>http://blog.guilhermegarnier.com/2011/05/ajude-o-firefox-a-crescer-com-o-test-pilot/#comments</comments>
		<pubDate>Thu, 05 May 2011 11:13:35 +0000</pubDate>
		<dc:creator>guilhermegarnier</dc:creator>
				<category><![CDATA[Firefox]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[open source]]></category>

		<guid isPermaLink="false">http://blog.guilhermegarnier.com/?p=437</guid>
		<description><![CDATA[A principal característica de projetos open source é que qualquer pessoa pode contribuir com eles. Geralmente quando falamos em contribuir com este tipo de projeto, logo pensamos em código fonte &#8211; corrigir um bug ou implementar uma melhoria. Mas na verdade podemos contribuir de várias formas (para mais informações sobre o modelo open source, recomendo [...]]]></description>
				<content:encoded><![CDATA[<p>A principal característica de projetos open source é que qualquer pessoa pode contribuir com eles. Geralmente quando falamos em contribuir com este tipo de projeto, logo pensamos em código fonte &#8211; corrigir um bug ou implementar uma melhoria. Mas na verdade podemos contribuir de várias formas (para mais informações sobre o modelo open source, recomendo a leitura do famoso artigo <a href="http://www.catb.org/~esr/writings/homesteading/cathedral-bazaar/">The Cathedral and the Bazaar</a>, de Eric Raymond), mesmo sem conhecimento técnico. Outra possibilidade é através de ajuda na documentação &#8211; melhorar uma documentação incompleta ou traduzir para outras línguas. Porém, apesar de não exigir conhecimentos específicos, exige tempo, o que nem sempre as pessoas têm disponível.</p>
<p>No caso do Firefox, há uma outra forma de contribuir para o projeto, que não exige qualquer conhecimento específico. É através do <a href="https://testpilot.mozillalabs.com/">Test Pilot</a>, uma extensão que, ao ser instalada, exibe uma lista de estudos sendo conduzidos pela Mozilla. Sempre que surgir um novo estudo, você poderá ver os detalhes dele e optar por participar ou não. O estudo que acontece com mais frequencia é o <a href="https://testpilot.mozillalabs.com/testcases/aweeklife">&#8220;A Week in the Life of a Browser&#8221;</a>, onde, caso você aceite participar, durante uma semana o Test Pilot monitorará informações sobre o seu uso do browser, como memória utilizada, número de abas abertas simultaneamente, número de downloads e de bookmarks &#8211; ou seja, <a href="https://testpilot.mozillalabs.com/privacy.php">nenhuma informação sensível do usuário é coletada</a>. No final do período do estudo, esses dados são enviados para a Mozilla, mas antes você pode ver exatamente que informações serão enviadas através de gráficos como esse:</p>
<p><a href="http://blog.guilhermegarnier.com/wp-content/uploads/2011/03/testpilot-e1304592358105.jpg"><img src="http://blog.guilhermegarnier.com/wp-content/uploads/2011/03/testpilot-e1304592358105-169x300.jpg" alt="" title="testpilot" width="169" height="300" class="aligncenter size-medium wp-image-435" /></a></p>
<p>Alguns estudos são pesquisas sobre usabilidade e funcionalidades específicas, como mecanismos de busca e uso de bookmarks e dos botões na toolbar. Para ver os estudos já realizados, acesse a <a href="https://testpilot.mozillalabs.com/testcases/">página de test cases</a>. Para participar, basta <a href="https://addons.mozilla.org/pt-BR/firefox/addon/test-pilot/">instalar a extensão</a>.<br />
<h3 class='related_post_title'>Posts relacionados:</h3>
<ul class='related_post'>
<li><a href='http://blog.guilhermegarnier.com/2011/01/migrando-do-delicious-para-o-google-bookmarks/' title='Migrando do Delicious para o Google Bookmarks'>Migrando do Delicious para o Google Bookmarks</a></li>
<li><a href='http://blog.guilhermegarnier.com/2010/08/solucao-de-problema-com-o-flash-player-no-ubuntu-com-firefox-3-6-4/' title='Solução de problema com o Flash Player no Ubuntu com Firefox &gt;= 3.6.4'>Solução de problema com o Flash Player no Ubuntu com Firefox >= 3.6.4</a></li>
<li><a href='http://blog.guilhermegarnier.com/2010/06/exclusao-de-itens-individuais-do-historico-do-firefox/' title='Exclusão de itens individuais do histórico do Firefox'>Exclusão de itens individuais do histórico do Firefox</a></li>
<li><a href='http://blog.guilhermegarnier.com/2010/04/compartilhando-perfis-do-firefox-com-dual-boot/' title='Compartilhando perfis do Firefox com dual boot'>Compartilhando perfis do Firefox com dual boot</a></li>
<li><a href='http://blog.guilhermegarnier.com/2010/02/videos-com-html-5-e-a-nova-guerra-dos-browsers/' title='Vídeos com HTML 5 e a nova guerra dos browsers'>Vídeos com HTML 5 e a nova guerra dos browsers</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.guilhermegarnier.com/2011/05/ajude-o-firefox-a-crescer-com-o-test-pilot/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Representação de data e hora em Ruby 1.8.7 e 1.9</title>
		<link>http://blog.guilhermegarnier.com/2011/03/representacao-de-data-e-hora-em-ruby-1-8-7-e-1-9/</link>
		<comments>http://blog.guilhermegarnier.com/2011/03/representacao-de-data-e-hora-em-ruby-1-8-7-e-1-9/#comments</comments>
		<pubDate>Tue, 01 Mar 2011 10:57:10 +0000</pubDate>
		<dc:creator>guilhermegarnier</dc:creator>
				<category><![CDATA[Programação]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[jruby]]></category>

		<guid isPermaLink="false">http://blog.guilhermegarnier.com/?p=407</guid>
		<description><![CDATA[A classe Time do Ruby é usada, como esperado, para representar uma data e hora. Existem várias formas de criar uma nova instância, a mais óbvia é usando Time.new (ou Time.now), que cria uma nova instância com a data e hora atuais: Também é possível criar uma instância usando métodos como Time.at(time), que recebe um [...]]]></description>
				<content:encoded><![CDATA[<p>A classe <a href="http://www.ruby-doc.org/core/classes/Time.html">Time</a> do Ruby é usada, como esperado, para representar uma data e hora. Existem várias formas de criar uma nova instância, a mais óbvia é usando Time.new (ou Time.now), que cria uma nova instância com a data e hora atuais:</p>
<pre class="brush: ruby; title: ; notranslate">
irb(main):007:0&gt; Time.new
=&gt; Wed Feb 09 13:23:52 -0200 2011
irb(main):008:0&gt; Time.now
=&gt; Wed Feb 09 13:23:53 -0200 2011
</pre>
<p>Também é possível criar uma instância usando métodos como <a href="http://www.ruby-doc.org/core/classes/Time.html#M000334">Time.at(time)</a>, que recebe um timestamp como parâmetro, <a href="http://www.ruby-doc.org/core/classes/Time.html#M000337">Time.local(year, month, day, hour, min, sec_with_frac)</a> e outros. Também há um construtor que recebe como parâmetro uma string representando a data:</p>
<pre class="brush: ruby; title: ; notranslate">
irb(main):001:0&gt; Time.new('2011-01-01')
=&gt; Sat Jan 01 00:00:00 -0200 2011
</pre>
<p>Eu havia escrito um código que usava esse construtor no <a href="https://github.com/ggarnier/pidgin-logs-compressor">pidgin-logs-compressor</a>, mas quando testei no <a href="http://jruby.org">JRuby</a> 1.5.5, recebi uma exceção &#8220;ArgumentError: wrong number of arguments (1 for 0)&#8221;. Achei que fosse algum bug do JRuby, e realmente <a href="http://jira.codehaus.org/browse/JRUBY-5008">havia esse bug</a> na versão que eu usava, mas já estava corrigido no JRuby 1.6RC1. Atualizei para esta versão, mas o erro continuou. Descobri que o erro que eu estava cometendo era relacionado com a versão do Ruby, e não do JRuby. Esse construtor com parâmetros é aceito no Ruby 1.9, mas não no 1.8.7, que é a versão usada por padrão pelo JRuby. Para fazer com que ele utilize a versão 1.9, basta acrescentar o parâmetro <em>&#8211;1.9</em> na linha de comando:</p>
<pre class="brush: ruby; title: ; notranslate">
jruby --1.9 -e 'puts Time.new(&quot;2011-02-16&quot;)'
</pre>
<p>Para manter compatibilidade com versões anteriores, é necessário usar algum dos outros métodos, como eu optei por fazer no <a href="https://github.com/ggarnier/pidgin-logs-compressor">pidgin-logs-compressor</a>.</p>
<p>Para um overview de algumas novidades do Ruby 1.9: <a href="http://www.igvita.com/2011/02/03/new-ruby-19-features-tips-tricks/">New Ruby 1.9 Features, Tips &#038; Tricks</a>.<br />
<h3 class='related_post_title'>Posts relacionados:</h3>
<ul class='related_post'>
<li><a href='http://blog.guilhermegarnier.com/2013/04/design-patterns-em-ruby-decorators-presenters-e-exhibits/' title='Design patterns em Ruby &#8211; Decorators, Presenters e Exhibits'>Design patterns em Ruby &#8211; Decorators, Presenters e Exhibits</a></li>
<li><a href='http://blog.guilhermegarnier.com/2011/02/ruby-no-ubuntu-erro-na-instalacao-de-rubygems/' title='Ruby no Ubuntu &#8211; erro na instalação de Rubygems'>Ruby no Ubuntu &#8211; erro na instalação de Rubygems</a></li>
<li><a href='http://blog.guilhermegarnier.com/2009/12/classes-abstratas-em-ruby/' title='Classes abstratas em Ruby?'>Classes abstratas em Ruby?</a></li>
<li><a href='http://blog.guilhermegarnier.com/2009/06/instant-rails-o-ambiente-rails-de-bolso/' title='Instant Rails, o ambiente Rails de bolso'>Instant Rails, o ambiente Rails de bolso</a></li>
<li><a href='http://blog.guilhermegarnier.com/2008/10/ferramenta-em-rails-para-criacao-de-blogs/' title='Ferramenta em Rails para criação de blogs'>Ferramenta em Rails para criação de blogs</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.guilhermegarnier.com/2011/03/representacao-de-data-e-hora-em-ruby-1-8-7-e-1-9/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Ruby no Ubuntu – erro na instalação de Rubygems</title>
		<link>http://blog.guilhermegarnier.com/2011/02/ruby-no-ubuntu-erro-na-instalacao-de-rubygems/</link>
		<comments>http://blog.guilhermegarnier.com/2011/02/ruby-no-ubuntu-erro-na-instalacao-de-rubygems/#comments</comments>
		<pubDate>Mon, 21 Feb 2011 10:59:25 +0000</pubDate>
		<dc:creator>guilhermegarnier</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Programação]]></category>
		<category><![CDATA[rubygem]]></category>
		<category><![CDATA[Ubuntu]]></category>

		<guid isPermaLink="false">http://blog.guilhermegarnier.com/?p=404</guid>
		<description><![CDATA[Dica rápida de Ruby: se ao tentar instalar uma Rubygem no Ubuntu você receber uma mensagem como essa: A solução é simples: basta instalar o pacote ruby-dev: sudo apt-get install ruby-dev. Este pacote é necessário para a instalação de gems nativas, que precisam ser compiladas na instalação. Posts relacionados: Instant Rails, o ambiente Rails de [...]]]></description>
				<content:encoded><![CDATA[<p>Dica rápida de Ruby: se ao tentar instalar uma <a href="http://rubygems.org">Rubygem</a> no Ubuntu você receber uma mensagem como essa:</p>
<pre class="brush: bash; title: ; notranslate">
guilherme@guilherme-desktop:~$ sudo gem install mechanize
Building native extensions.  This could take a while...
ERROR:  Error installing mechanize:
    ERROR: Failed to build gem native extension.

/usr/bin/ruby1.8 extconf.rb
extconf.rb:5:in `require': no such file to load -- mkmf (LoadError)
    from extconf.rb:5
</pre>
<p>A solução é simples: basta instalar o pacote ruby-dev: <em>sudo apt-get install ruby-dev</em>. Este pacote é necessário para a instalação de gems nativas, que precisam ser compiladas na instalação.<br />
<h3 class='related_post_title'>Posts relacionados:</h3>
<ul class='related_post'>
<li><a href='http://blog.guilhermegarnier.com/2009/06/instant-rails-o-ambiente-rails-de-bolso/' title='Instant Rails, o ambiente Rails de bolso'>Instant Rails, o ambiente Rails de bolso</a></li>
<li><a href='http://blog.guilhermegarnier.com/2013/04/design-patterns-em-ruby-decorators-presenters-e-exhibits/' title='Design patterns em Ruby &#8211; Decorators, Presenters e Exhibits'>Design patterns em Ruby &#8211; Decorators, Presenters e Exhibits</a></li>
<li><a href='http://blog.guilhermegarnier.com/2011/03/representacao-de-data-e-hora-em-ruby-1-8-7-e-1-9/' title='Representação de data e hora em Ruby 1.8.7 e 1.9'>Representação de data e hora em Ruby 1.8.7 e 1.9</a></li>
<li><a href='http://blog.guilhermegarnier.com/2010/12/ubuntu-netbook-remix-no-hp-mini/' title='Ubuntu Netbook Remix no HP Mini'>Ubuntu Netbook Remix no HP Mini</a></li>
<li><a href='http://blog.guilhermegarnier.com/2010/08/solucao-de-problema-com-o-flash-player-no-ubuntu-com-firefox-3-6-4/' title='Solução de problema com o Flash Player no Ubuntu com Firefox &gt;= 3.6.4'>Solução de problema com o Flash Player no Ubuntu com Firefox >= 3.6.4</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.guilhermegarnier.com/2011/02/ruby-no-ubuntu-erro-na-instalacao-de-rubygems/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Migrando do Delicious para o Google Bookmarks</title>
		<link>http://blog.guilhermegarnier.com/2011/01/migrando-do-delicious-para-o-google-bookmarks/</link>
		<comments>http://blog.guilhermegarnier.com/2011/01/migrando-do-delicious-para-o-google-bookmarks/#comments</comments>
		<pubDate>Wed, 12 Jan 2011 10:21:16 +0000</pubDate>
		<dc:creator>guilhermegarnier</dc:creator>
				<category><![CDATA[Firefox]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[Bookmarks]]></category>
		<category><![CDATA[Chrome]]></category>
		<category><![CDATA[Delicious]]></category>

		<guid isPermaLink="false">http://blog.guilhermegarnier.com/?p=387</guid>
		<description><![CDATA[Alguns anos atrás, comecei a sentir necessidade de manter meus bookmarks sincronizados entre os diversos computadores que eu utilizava. Até que conheci o Delicious. Isso foi em 2007, e desde então eu comecei a usá-lo constantemente. Cada vez que eu usava o Firefox em algum computador pela primeira vez, a primeira extensão que eu instalava [...]]]></description>
				<content:encoded><![CDATA[<p>Alguns anos atrás, comecei a sentir necessidade de manter meus bookmarks sincronizados entre os diversos computadores que eu utilizava. Até que conheci o <a href="http://www.delicious.com">Delicious</a>. Isso foi em 2007, e desde então eu comecei a usá-lo constantemente. Cada vez que eu usava o Firefox em algum computador pela primeira vez, a primeira extensão que eu instalava era <a href="https://addons.mozilla.org/en-US/firefox/addon/3615/">a do Delicious</a>. Através desta extensão, um simples Control+D abre a janela para adicionar a página atual ao seus bookmarks do Delicious, e Control+B abre a barra lateral com seus bookmarks, organizados por tags.</p>
<p>Há alguns meses, eu havia pensado em migrar meus bookmarks para o <a href="http://www.google.com/bookmarks">Google Bookmarks</a>, mas desisti, pois eu já estava bastante acostumado com o Delicious. Até que no início de dezembro veio a bomba: o Yahoo, que havia comprado o Delicious em 2005, <a href="http://techcrunch.com/2010/12/16/is-yahoo-shutting-down-del-icio-us/">anunciou que encerraria o serviço</a>! Imediatamente comecei a pensar em alternativas, e o Google Bookmarks foi minha primeira opção. Alguns dias depois, o <a href="http://techcrunch.com/2010/12/17/yahoo-trying-to-sell-del-icio-us-not-to-shut-it-down/">Yahoo voltou à cena informando que iria vender, e não fechar o serviço</a>, e o próprio <a href="http://blog.delicious.com/blog/2010/12/whats-next-for-delicious.html">Delicious publicou uma nota sobre o assunto</a>. Mas, mesmo assim, para mim foi a deixa para fazer a migração para outro serviço. Apesar de existirem <a href="http://bookshop.livejournal.com/1080038.html">várias alternativas ao Delicious</a>, escolhi o Google Bookmarks pela simplicidade, e por já estar integrado à minha conta no Google.</p>
<p>A primeira parte da migração foi fácil: exportar os bookmarks do Delicious, através da opção Settings -> <a href="https://secure.delicious.com/settings/bookmarks/export">Export/Backup Bookmarks</a>. Para <a href="http://www.google.com/support/bookmarks/bin/answer.py?answer=178166">importá-los no Google Bookmarks</a>, uma das maneiras mais simples é importar os bookmarks do Delicious no Firefox e sincronizá-los com o <a href="http://www.toolbar.google.com/">Google Toolbar</a>. Também é possível fazer a importação usando o <a href="http://www.google.com/chrome">Google Chrome</a>, ou usar algum script (como <a href="http://blog.darkhax.com/2010/12/16/import-delicious-to-google-bookmarks">este</a>) ou serviço, como o <a href="http://delicious-export.appspot.com/">del.icio.us to Google Bookmarks</a>.</p>
<p>Em seguida, procurei as opções para integração com o browser (adicionar e pesquisar nos bookmarks). No Firefox existem diversas extensões para Google Bookmarks. Testei algumas, e a que achei melhor foi o <a href="https://addons.mozilla.org/pt-BR/firefox/addon/2888/">GMarks</a>. Com ela, é possível adicionar bookmarks com Control+D, de forma bem semelhante à extensão do Delicious, e também há uma barra lateral, acionada com Alt+M. Porém, não há integração com a barra de endereços, ou seja, não é possível pesquisar nos bookmarks digitando diretamente o endereço (como permitem as versões mais recentes da extensão do Delicious). Porém, há duas maneiras de pesquisar (além de acessar diretamente a página do Google Bookmarks para fazer a pesquisa):</p>
<ol>
<li>Ao digitar a tecla Home duas vezes, aparecerá uma caixa de texto para pesquisa. É só digitar qualquer coisa e depois escolher um resultado e apertar Enter (ou Alt+Enter para abrir em outra aba)</li>
<li>Criando um atalho para a busca: acesse o <a href="https://www.google.com/bookmarks">Google Bookmarks</a>, clique com o botão direito sobre o campo de busca e selecione a opção &#8220;Add a keyword for this search&#8221;. O Firefox adicionará a pesquisa nos bookmarks locais, e você poderá adicionar um keyword a este bookmark. Digite &#8220;gb&#8221;, por exemplo, e clique em OK. Agora, ao digitar qualquer texto precedido desta keyword na barra de endereços (por exemplo: &#8220;gb teste&#8221;), o Firefox pesquisará este texto no Google Bookmarks. Mas os resultados não aparecem diretamente, você precisa escolher a opção &#8220;Search Google Bookmarks&#8221; entre as sugestões que aparecem</li>
</ol>
<p>Para <a href="http://metaed.blogspot.com/2008/12/using-google-bookmarks-in-google-chrome.html">integrar o Google Bookmarks ao Chrome</a> é ainda mais simples, pois não é necessário instalar qualquer extensão (afinal, ambos são do Google). Para adicionar bookmarks, acesse a <a href="http://www.google.com/support/chrome/bin/answer.py?hl=en&#038;answer=100215">página de ajuda</a>. Ela disponibiliza um botão que pode ser arrastado para a barra de bookmarks, e ao clicar nele, a página atual será adicionada. Para adicionar a pesquisa no Google Bookmarks à barra de endereços, clique na barra com o botão direito, selecione &#8220;Edit search engines&#8221; e adicione um novo, com as seguintes configurações:<br />
<strong>Nome:</strong> Google Bookmarks<br />
<strong>Keyword:</strong> gb<br />
<strong>URL:</strong> http://google.com/bookmarks/find?&#038;q=%s</p>
<p>Agora, a pesquisa integrada à barra de endereços funcionará da mesma forma que no Firefox (&#8220;gb texto para pesquisa&#8221;).<br />
<h3 class='related_post_title'>Posts relacionados:</h3>
<ul class='related_post'>
<li><a href='http://blog.guilhermegarnier.com/2011/05/ajude-o-firefox-a-crescer-com-o-test-pilot/' title='Ajude o Firefox a crescer com o Test Pilot'>Ajude o Firefox a crescer com o Test Pilot</a></li>
<li><a href='http://blog.guilhermegarnier.com/2010/08/solucao-de-problema-com-o-flash-player-no-ubuntu-com-firefox-3-6-4/' title='Solução de problema com o Flash Player no Ubuntu com Firefox &gt;= 3.6.4'>Solução de problema com o Flash Player no Ubuntu com Firefox >= 3.6.4</a></li>
<li><a href='http://blog.guilhermegarnier.com/2010/06/exclusao-de-itens-individuais-do-historico-do-firefox/' title='Exclusão de itens individuais do histórico do Firefox'>Exclusão de itens individuais do histórico do Firefox</a></li>
<li><a href='http://blog.guilhermegarnier.com/2010/04/compartilhando-perfis-do-firefox-com-dual-boot/' title='Compartilhando perfis do Firefox com dual boot'>Compartilhando perfis do Firefox com dual boot</a></li>
<li><a href='http://blog.guilhermegarnier.com/2010/02/videos-com-html-5-e-a-nova-guerra-dos-browsers/' title='Vídeos com HTML 5 e a nova guerra dos browsers'>Vídeos com HTML 5 e a nova guerra dos browsers</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.guilhermegarnier.com/2011/01/migrando-do-delicious-para-o-google-bookmarks/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Ubuntu Netbook Remix no HP Mini</title>
		<link>http://blog.guilhermegarnier.com/2010/12/ubuntu-netbook-remix-no-hp-mini/</link>
		<comments>http://blog.guilhermegarnier.com/2010/12/ubuntu-netbook-remix-no-hp-mini/#comments</comments>
		<pubDate>Mon, 20 Dec 2010 10:21:35 +0000</pubDate>
		<dc:creator>guilhermegarnier</dc:creator>
				<category><![CDATA[Ubuntu]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[netbook]]></category>

		<guid isPermaLink="false">http://blog.guilhermegarnier.com/?p=378</guid>
		<description><![CDATA[Outro dia um amigo me pediu para instalar o Ubuntu no netbook dele, um HP Mini (não lembro exatamente qual modelo). Baixei o Ubuntu Netbook Remix 10.10 e instalei no pen drive, seguindo as instruções que aparecem na página de download. Em seguida, fiz o boot pelo pen drive e iniciei a instalação. Tudo ia [...]]]></description>
				<content:encoded><![CDATA[<p>Outro dia um amigo me pediu para instalar o Ubuntu no netbook dele, um HP Mini (não lembro exatamente qual modelo). Baixei o <a href="http://www.ubuntu.com/netbook">Ubuntu Netbook Remix 10.10</a> e instalei no pen drive, seguindo as instruções que aparecem na <a href="http://www.ubuntu.com/netbook/get-ubuntu/download">página de download</a>. Em seguida, fiz o boot pelo pen drive e iniciei a instalação. Tudo ia bem até que em determinado momento recebi uma mensagem de erro. Não lembro qual era a mensagem, mas parecia ser algo relacionado a disco. Tentei novamente e o erro se repetiu.</p>
<p>Em seguida, lembrei que quando eu havia instalado este mesmo sistema operacional num outro netbook HP Mini, mas a versão do Ubuntu era 10.04. Como a página principal do Ubuntu só disponibiliza links para download da última versão, encontrei as versões anteriores na página <a href="http://releases.ubuntu.com/">Ubuntu Releases</a>. Na página específica da <a href="http://releases.ubuntu.com/lucid/">versão 10.04 (Lucid Lynx)</a> o link aparece como <a href="http://releases.ubuntu.com/lucid/ubuntu-10.04-netbook-i386.iso">PC (Intel x86) netbook live CD</a>.</p>
<p>Após baixar esta versão e instalá-la no pen drive, tudo funcionou. Aparentemente é algum problema relacionado com a versão 10.10 mesmo. Tudo funciona de primeira, sem necessitar qualquer configuração (bluetooth, som, webcam, etc.), exceto o wifi. A página <a href="https://wiki.ubuntu.com/HardwareSupport/Machines/Netbooks">Hardware support</a> do wiki do Ubuntu traz a solução: basta conectar o netbook à Internet via porta Ethernet e reinstalar o driver <em>bcmwl</em>, digitando no terminal: <em>sudo apt-get install bcmwl-kernel-source</em>. Após a instalação, reinicie o netbook e tudo funcionará.<br />
<h3 class='related_post_title'>Posts relacionados:</h3>
<ul class='related_post'>
<li><a href='http://blog.guilhermegarnier.com/2011/02/ruby-no-ubuntu-erro-na-instalacao-de-rubygems/' title='Ruby no Ubuntu &#8211; erro na instalação de Rubygems'>Ruby no Ubuntu &#8211; erro na instalação de Rubygems</a></li>
<li><a href='http://blog.guilhermegarnier.com/2010/08/solucao-de-problema-com-o-flash-player-no-ubuntu-com-firefox-3-6-4/' title='Solução de problema com o Flash Player no Ubuntu com Firefox &gt;= 3.6.4'>Solução de problema com o Flash Player no Ubuntu com Firefox >= 3.6.4</a></li>
<li><a href='http://blog.guilhermegarnier.com/2008/11/matrix-rodando-no-windows/' title='Matrix rodando no Windows'>Matrix rodando no Windows</a></li>
<li><a href='http://blog.guilhermegarnier.com/2008/11/script-para-verificar-o-status-da-conexao-pppoe/' title='Script para verificar o status da conexão PPPoE'>Script para verificar o status da conexão PPPoE</a></li>
<li><a href='http://blog.guilhermegarnier.com/2008/06/instalacao-do-firefox-30-no-ubuntu/' title='Instalação do Firefox 3.0 no Ubuntu'>Instalação do Firefox 3.0 no Ubuntu</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.guilhermegarnier.com/2010/12/ubuntu-netbook-remix-no-hp-mini/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
