<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	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/"
	>

<channel>
	<title>DestaqueBlog &#187; Programação</title>
	<atom:link href="http://weblog.destaquenet.com/category/pt-br/programacao/feed/" rel="self" type="application/rss+xml" />
	<link>http://weblog.destaquenet.com</link>
	<description>Blog da equipe Destaquenet.</description>
	<lastBuildDate>Tue, 23 Nov 2010 17:06:50 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
		<item>
		<title>Entendendo Licenças Open Source com Clojure</title>
		<link>http://weblog.destaquenet.com/2010/10/05/entendendo-licencas-open-source-com-clojure/</link>
		<comments>http://weblog.destaquenet.com/2010/10/05/entendendo-licencas-open-source-com-clojure/#comments</comments>
		<pubDate>Tue, 05 Oct 2010 12:52:42 +0000</pubDate>
		<dc:creator>Daniel Martins</dc:creator>
				<category><![CDATA[Português]]></category>
		<category><![CDATA[Programação]]></category>
		<category><![CDATA[app]]></category>
		<category><![CDATA[appengine]]></category>
		<category><![CDATA[clojure]]></category>
		<category><![CDATA[compojure]]></category>
		<category><![CDATA[licenças]]></category>
		<category><![CDATA[licensator]]></category>
		<category><![CDATA[opensource]]></category>
		<category><![CDATA[programação funcional]]></category>
		<category><![CDATA[projeto]]></category>

		<guid isPermaLink="false">http://weblog.destaquenet.com/?p=1141</guid>
		<description><![CDATA[Só quem desenvolve ou contribui com projetos open source sabe como é legal. A pior parte é definir sob qual licença soltar o código, e essa tarefa é muitas vezes negligenciada por desenvolvedores de software. Para quem não viu, recentemente &#8230; <a href="http://weblog.destaquenet.com/2010/10/05/entendendo-licencas-open-source-com-clojure/">Continue lendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Só quem desenvolve ou contribui com projetos open source sabe como é legal. A pior parte é definir sob qual licença soltar o código, e essa tarefa é muitas vezes negligenciada por desenvolvedores de software.</p>
<p>Para quem não viu, recentemente colocamos no ar o <a href="http://www.destaquenet.com/portifolio/licensator/">Licensator</a>, uma aplicação web que, além de reunir informações sobre as licenças open source mais populares, é capaz de indicar as licenças apropriadas para cada caso.</p>
<p>A linguagem escolhida para implementar o projeto foi <a href="http://clojure.org">Clojure</a>, que se mostrou excelente para resolver esse tipo de problema. Veremos hoje como o principal algoritmo da aplicação funciona.</p>
<p><span id="more-1141"></span></p>
<h3>REPL: onde tudo começa</h3>
<p>Um dos pontos fortes das linguagens dinâmicas é a facilidade em transformar idéias em código funcional, e com Clojure não é diferente. A idéia por trás do Licensator surgiu justamente em uma dessas sessões de codificação no <a href="http://clojure.org/repl_and_main">REPL</a>, o ambiente interativo da linguagem. Após alguns minutos brincando, vi que o problema era simples de resolver.</p>
<p>Apesar do elevado número de licenças, podemos facilmente extrair informações comuns a todas elas, como: se a licença é copyleft, se pode ser usada por código fechado (proprietário), entre outras coisas.</p>
<p>Por exemplo, vamos pegar a licença <a href="http://www.opensource.org/licenses/apache2.0.php">Apache v2.0</a>:</p>

<div class="wp_syntax"><div class="code"><pre class="lisp" style="font-family:monospace;"><span style="color: #66cc66;">&#40;</span>def *licenses*
     <span style="color: #66cc66;">&#91;</span><span style="color: #66cc66;">&#123;</span><span style="color: #66cc66;">:</span><span style="color: #555;">id</span> <span style="color: #66cc66;">:</span><span style="color: #555;">apl-v20</span>
       <span style="color: #66cc66;">:</span><span style="color: #555;">long-</span><span style="color: #b1b100;">name</span> <span style="color: #ff0000;">&quot;Apache License v2.0&quot;</span>
       <span style="color: #66cc66;">:</span><span style="color: #555;">short-</span><span style="color: #b1b100;">name</span> <span style="color: #ff0000;">&quot;Apache v2.0&quot;</span>
       <span style="color: #66cc66;">:</span><span style="color: #555;">url</span> <span style="color: #ff0000;">&quot;http://www.opensource.org/licenses/apache2.0.php&quot;</span>
       <span style="color: #66cc66;">:</span><span style="color: #555;">copyright</span> true
       <span style="color: #66cc66;">:</span><span style="color: #555;">patent</span> true
       <span style="color: #66cc66;">:</span><span style="color: #555;">closed-source-linking</span> true
       <span style="color: #66cc66;">:</span><span style="color: #555;">derivative-work</span> true
       <span style="color: #66cc66;">:</span><span style="color: #555;">affero</span> false
       <span style="color: #66cc66;">:</span><span style="color: #555;">copyleft</span> false
       <span style="color: #66cc66;">:</span><span style="color: #555;">charge-for-distribution</span> true
       <span style="color: #66cc66;">:</span><span style="color: #555;">charge-for-use</span> true
       <span style="color: #66cc66;">:</span><span style="color: #555;">compatible-with</span> <span style="color: #66cc66;">&#91;</span><span style="color: #66cc66;">:</span><span style="color: #555;">apl-v20</span> <span style="color: #66cc66;">:</span><span style="color: #555;">afl-v30</span> <span style="color: #66cc66;">:</span><span style="color: #555;">cddl-v10</span> <span style="color: #66cc66;">:</span><span style="color: #555;">epl-v10</span> <span style="color: #66cc66;">:</span><span style="color: #555;">freebsd</span>
                         <span style="color: #66cc66;">:</span><span style="color: #555;">new-bsd</span> <span style="color: #66cc66;">:</span><span style="color: #555;">mit</span> <span style="color: #66cc66;">:</span><span style="color: #555;">mpl-v11</span> <span style="color: #66cc66;">:</span><span style="color: #555;">public-domain</span><span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#125;</span><span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>A lista completa de licenças pode ser vista <a href="http://github.com/danielfm/licensator/blob/master/src/licensator/licenses.clj">aqui</a>.</p>
<p>Considerando que todas as licenças têm esse mesmo conjunto de informações, como podemos saber quais licenças não são recíprocas e possuem cláusulas explícitas de copyright?</p>

<div class="wp_syntax"><div class="code"><pre class="lisp" style="font-family:monospace;"><span style="color: #66cc66;">&#40;</span>map <span style="color: #66cc66;">:</span><span style="color: #555;">id</span>
  <span style="color: #66cc66;">&#40;</span>filter #<span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">and</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">:</span><span style="color: #555;">copyright</span> <span style="color: #66cc66;">%</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">not</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">:</span><span style="color: #555;">copyleft</span> <span style="color: #66cc66;">%</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> *licenses*<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
<span style="color: #66cc66;">=&gt;</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">:</span><span style="color: #555;">afl-v30</span> <span style="color: #66cc66;">:</span><span style="color: #555;">apl-v20</span> <span style="color: #66cc66;">:</span><span style="color: #555;">epl-v10</span> <span style="color: #66cc66;">:</span><span style="color: #555;">freebsd</span> <span style="color: #66cc66;">:</span><span style="color: #555;">mit</span> <span style="color: #66cc66;">:</span><span style="color: #555;">new-bsd</span> <span style="color: #66cc66;">:</span><span style="color: #555;">bsd</span><span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>Se você conhece um pouco sobre programação funcional, este código deve ser fácil de acompanhar. De qualquer forma, o que ele faz é retornar o <code>:id</code> de todas as licenças onde <code>:copyright</code> é verdadeiro e <code>:copyleft</code> é falso.</p>
<p>Outro exemplo: quais licenças são compatíveis com Apache v2.0 e <a href="http://www.opensource.org/licenses/cddl1.php">CDDL v1.0</a>?</p>

<div class="wp_syntax"><div class="code"><pre class="lisp" style="font-family:monospace;"><span style="color: #66cc66;">&#40;</span>use 'clojure<span style="color: #66cc66;">.</span><span style="color: #b1b100;">set</span><span style="color: #66cc66;">&#41;</span>
&nbsp;
<span style="color: #66cc66;">&#40;</span>map <span style="color: #66cc66;">:</span><span style="color: #555;">id</span>
  <span style="color: #66cc66;">&#40;</span>filter #<span style="color: #66cc66;">&#40;</span>subset? <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">set</span> <span style="color: #66cc66;">&#91;</span><span style="color: #66cc66;">:</span><span style="color: #555;">apl-v20</span> <span style="color: #66cc66;">:</span><span style="color: #555;">cddl-v10</span><span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#41;</span>
                    <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">set</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">:</span><span style="color: #555;">compatible-with</span> <span style="color: #66cc66;">%</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> *licenses*<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
<span style="color: #66cc66;">=&gt;</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">:</span><span style="color: #555;">apl-v20</span> <span style="color: #66cc66;">:</span><span style="color: #555;">cddl-v10</span> <span style="color: #66cc66;">:</span><span style="color: #555;">epl-v10</span><span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>Aqui usamos a namespace <a href="http://clojure.github.com/clojure/clojure.set-api.html">clojure.set</a>, que conta com algumas funções úteis para álgebra relacional. O código é muito parecido com o anterior; a mudança é que agora usamos a função <code>subset?</code> para buscar as licenças compatíveis com <code>[:apl-v20 :cddl-v10]</code>.</p>
<p>Último exemplo: quais licenças recíprocas são compatíveis com Apache v2.0?</p>

<div class="wp_syntax"><div class="code"><pre class="lisp" style="font-family:monospace;"><span style="color: #66cc66;">&#40;</span>map <span style="color: #66cc66;">:</span><span style="color: #555;">id</span>
  <span style="color: #66cc66;">&#40;</span>filter #<span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">and</span> <span style="color: #66cc66;">&#40;</span>subset? <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">set</span> <span style="color: #66cc66;">&#91;</span><span style="color: #66cc66;">:</span><span style="color: #555;">apl-v20</span><span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">set</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">:</span><span style="color: #555;">compatible-with</span> <span style="color: #66cc66;">%</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
                <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">:</span><span style="color: #555;">copyleft</span> <span style="color: #66cc66;">%</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> *licenses*<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
<span style="color: #66cc66;">=&gt;</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">:</span><span style="color: #555;">cddl-v10</span> <span style="color: #66cc66;">:</span><span style="color: #555;">agpl-v30</span> <span style="color: #66cc66;">:</span><span style="color: #555;">gpl-v30</span> <span style="color: #66cc66;">:</span><span style="color: #555;">lgpl-v30</span> <span style="color: #66cc66;">:</span><span style="color: #555;">mpl-v11</span><span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>Neste ponto já se pode perceber que não existe mágica nenhuma por trás do algoritmo; o que ele faz é filtrar as licenças com base numa função.</p>
<h3>A solução</h3>
<p>O código que acabamos de ver funciona, mas não é apropriado para resolver o problema uma vez que a lógica de consulta se encontra fixa no código.</p>
<p>O ideal seria se os critérios de busca fossem expressados como um map&#8230;</p>

<div class="wp_syntax"><div class="code"><pre class="lisp" style="font-family:monospace;"><span style="color: #66cc66;">&#40;</span>def cmap
     <span style="color: #66cc66;">&#123;</span><span style="color: #66cc66;">:</span><span style="color: #555;">patent</span> true<span style="color: #66cc66;">,</span> <span style="color: #66cc66;">:</span><span style="color: #555;">closed-source-linking</span> true<span style="color: #66cc66;">,</span> <span style="color: #66cc66;">:</span><span style="color: #555;">compatible-with</span> <span style="color: #66cc66;">&#91;</span><span style="color: #66cc66;">:</span><span style="color: #555;">mit</span> <span style="color: #66cc66;">:</span><span style="color: #555;">new-bsd</span><span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#125;</span><span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>&#8230;portanto precisamos de uma função que faça a filtragem das licenças com base nesse mapa, algo como:</p>

<div class="wp_syntax"><div class="code"><pre class="lisp" style="font-family:monospace;"><span style="color: #66cc66;">&#40;</span>defn find-matches <span style="color: #66cc66;">&#91;</span>cmap data<span style="color: #66cc66;">&#93;</span>
  <span style="color: #66cc66;">&#40;</span>filter <span style="color: #66cc66;">&#40;</span>where cmap<span style="color: #66cc66;">&#41;</span> data<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>No caso, essa função <code>where</code>, que ainda não definimos, deve retornar uma função que filtre os elementos (licenças) em <code>data</code> de acordo com o mapa de critérios <code>cmap</code>.</p>
<p>Vamos por partes. Quais condições em <code>cmap</code> são verdadeiras para a licença Apache v2.0?</p>

<div class="wp_syntax"><div class="code"><pre class="lisp" style="font-family:monospace;"><span style="color: #66cc66;">&#40;</span>defn criteria-matches? <span style="color: #66cc66;">&#91;</span>license <span style="color: #66cc66;">&#91;</span>kval cval<span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#93;</span>
  <span style="color: #ff0000;">&quot;Verifica se o critério 'centry' é verdadeiro para a licença 'license'.&quot;</span>
  <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">let</span> <span style="color: #66cc66;">&#91;</span>lval <span style="color: #66cc66;">&#40;</span>kval license<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#93;</span>
    <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">nil</span>? cval<span style="color: #66cc66;">&#41;</span>
      true
      <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span>coll? lval<span style="color: #66cc66;">&#41;</span>
        <span style="color: #66cc66;">&#40;</span>subset? <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">set</span> cval<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">set</span> lval<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
        <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">=</span> cval lval<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
&nbsp;
<span style="color: #66cc66;">&#40;</span>map <span style="color: #66cc66;">&#40;</span>partial criteria-matches? apl-v20<span style="color: #66cc66;">&#41;</span> cmap<span style="color: #66cc66;">&#41;</span>
<span style="color: #66cc66;">=&gt;</span> <span style="color: #66cc66;">&#40;</span>true true true<span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>Uma licença só pode ser considerada compatível com os critérios se a lista retornada contém apenas valores verdadeiros. Portanto, neste caso, a licença Apache v2.0 é considerada compatível com os critérios informados:</p>

<div class="wp_syntax"><div class="code"><pre class="lisp" style="font-family:monospace;"><span style="color: #66cc66;">&#40;</span>every? true? <span style="color: #66cc66;">&#40;</span>map <span style="color: #66cc66;">&#40;</span>partial criteria-matches? apl-v20<span style="color: #66cc66;">&#41;</span> cmap<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
<span style="color: #66cc66;">=&gt;</span> true</pre></div></div>

<p>Logo, uma possível implementação para a função <code>where</code> seria:</p>

<div class="wp_syntax"><div class="code"><pre class="lisp" style="font-family:monospace;"><span style="color: #66cc66;">&#40;</span>defn where
  <span style="color: #ff0000;">&quot;Retorna função que diz se todos os critérios em 'cmap' são verdadeiros para a licença 'lentry'.&quot;</span>
  <span style="color: #66cc66;">&#91;</span>cmap<span style="color: #66cc66;">&#93;</span>
  <span style="color: #66cc66;">&#40;</span>fn <span style="color: #66cc66;">&#91;</span>lentry<span style="color: #66cc66;">&#93;</span>
    <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">let</span> <span style="color: #66cc66;">&#91;</span>res <span style="color: #66cc66;">&#40;</span>map <span style="color: #66cc66;">&#40;</span>fn <span style="color: #66cc66;">&#91;</span>centry<span style="color: #66cc66;">&#93;</span>
		     <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">let</span> <span style="color: #66cc66;">&#91;</span>cval <span style="color: #66cc66;">&#40;</span>val centry<span style="color: #66cc66;">&#41;</span>
			   lval <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span>key centry<span style="color: #66cc66;">&#41;</span> lentry<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#93;</span>
		       <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">nil</span>? cval<span style="color: #66cc66;">&#41;</span>
			 true
			 <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span>coll? lval<span style="color: #66cc66;">&#41;</span>
			   <span style="color: #66cc66;">&#40;</span>subset? <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">set</span> cval<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">set</span> lval<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
			   <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">=</span> cval lval<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> cmap<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#93;</span>
      <span style="color: #66cc66;">&#40;</span>every? true? res<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>Este código é uma junção dos dois anteriores. A função <code>where</code> recebe o mapa <code>cmap</code> com os critérios de pesquisa, e retorna uma segunda função. Esta função recebe uma licença <code>lentry</code> e verifica se todos os critérios informados são verdadeiros para esta licença.</p>
<p>Como <code>where</code> é usada em conjunto com <code>filter</code> na função <code>find-matches</code>, isso fará com que todas as licenças compatíveis sejam retornadas:</p>

<div class="wp_syntax"><div class="code"><pre class="lisp" style="font-family:monospace;"><span style="color: #66cc66;">&#40;</span>map <span style="color: #66cc66;">:</span><span style="color: #555;">id</span> <span style="color: #66cc66;">&#40;</span>find-matches cmap *licenses*<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
<span style="color: #66cc66;">=&gt;</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">:</span><span style="color: #555;">afl-v30</span> <span style="color: #66cc66;">:</span><span style="color: #555;">apl-v20</span> <span style="color: #66cc66;">:</span><span style="color: #555;">cddl-v10</span> <span style="color: #66cc66;">:</span><span style="color: #555;">epl-v10</span> <span style="color: #66cc66;">:</span><span style="color: #555;">lgpl-v30</span> <span style="color: #66cc66;">:</span><span style="color: #555;">mpl-v11</span><span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>Uma das coisas legais de Clojure &#8212; e outras linguagens funcionais &#8212; é a quantidade ridícula de código necessário para resolver certos problemas. Este algoritmo, por exemplo, tem apenas 15 linhas (muito curtas) de código. Onde está seu Deus agora?! <img src='http://weblog.destaquenet.com/wp-includes/images/smilies/icon_razz.gif' alt=':-P' class='wp-smiley' /> </p>
<p>O <a href="http://github.com/danielfm/licensator">código da aplicação</a> está no Github para quem tiver interesse em ver o restante do código.</p>
]]></content:encoded>
			<wfw:commentRss>http://weblog.destaquenet.com/2010/10/05/entendendo-licencas-open-source-com-clojure/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Django Para Dispositivos Móveis</title>
		<link>http://weblog.destaquenet.com/2010/07/12/django-para-dispositivos-moveis/</link>
		<comments>http://weblog.destaquenet.com/2010/07/12/django-para-dispositivos-moveis/#comments</comments>
		<pubDate>Mon, 12 Jul 2010 11:10:21 +0000</pubDate>
		<dc:creator>Daniel Martins</dc:creator>
				<category><![CDATA[Português]]></category>
		<category><![CDATA[Programação]]></category>
		<category><![CDATA[Tutoriais]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[configuração]]></category>
		<category><![CDATA[deploy]]></category>
		<category><![CDATA[dispositivo]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[móvel]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[wsgi]]></category>

		<guid isPermaLink="false">http://weblog.destaquenet.com/?p=944</guid>
		<description><![CDATA[Estamos vivendo o que alguns chamam de &#8220;explosão mobile&#8221;, um tempo onde um número cada vez maior de dispositivos móveis &#8212; como tablets e smartphones &#8212; se tornam parte significante da Web. Esta é a razão pela qual ter seu &#8230; <a href="http://weblog.destaquenet.com/2010/07/12/django-para-dispositivos-moveis/">Continue lendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Estamos vivendo o que alguns chamam de &#8220;explosão mobile&#8221;, um tempo onde um número cada vez maior de dispositivos móveis &#8212; como tablets e smartphones &#8212; se tornam parte significante da Web. Esta é a razão pela qual ter seu website preparado para tais dispositivos é cada vez mais importante.</p>
<p>Felizmente, <a href="http://djangoproject.com/">Django</a> é um dos poucos frameworks web que tornam este um problema simples de solucionar.</p>
<p><span id="more-944"></span></p>
<h3>Como resolvemos este problema</h3>
<p>Um jeito simples é criar um módulo <code>settings.py</code> separado para a versão &#8220;mobile&#8221;. Isso nos permite rodar dois sites diferentes reusando a mesma base de código. Além disso, cada versão pode ter seu próprio diretório de templates, configurações de URL, etc.</p>
<p>Vamos fazer isso. No diretório-raíz do projeto, crie um arquivo <code>m_settings.py</code> com o seguinte conteúdo:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># Arquivo: myproject/m_settings.py</span>
&nbsp;
<span style="color: #483d8b;">&quot;&quot;&quot;Configurações para a versão &quot;mobile&quot; do website.
&quot;&quot;&quot;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Carrega as configurações padrão</span>
<span style="color: #ff7700;font-weight:bold;">from</span> settings <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #66cc66;">*</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Domínio &quot;m.mydomain.com&quot;</span>
SITE_ID = <span style="color: #ff4500;">2</span>
PREPEND_WWW = <span style="color: #008000;">False</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Usado em outras partes do código para determinar qual versão está rodando</span>
DEFAULT_VERSION = <span style="color: #008000;">False</span>
MOBILE_VERSION  = <span style="color: #008000;">True</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># URLs para a versão mobile</span>
ROOT_URLCONF  = <span style="color: #483d8b;">'myproject.m_urls'</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Templates para a versão mobile</span>
TEMPLATE_DIRS = <span style="color: black;">&#40;</span>
    <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">normpath</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">dirname</span><span style="color: black;">&#40;</span>__file__<span style="color: black;">&#41;</span> + <span style="color: #483d8b;">'/template/mobile'</span><span style="color: black;">&#41;</span>,
<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Outras configurações...</span></pre></div></div>

<p>O fato de os dois sites compartilharem a mesma base de código não significa que eles devem ter as mesmas configurações de URL. Aliás, o normal é que versões próprias para dispositivos móveis sejam mais simples, com uma quantidade reduzida de mapeamentos de URLs.</p>
<p>Para definir as configurações de URL da versão mobile, crie um arquivo <code>m_urls.py</code> com o seguinte conteúdo:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># Arquivo: myproject/m_urls.py</span>
&nbsp;
<span style="color: #483d8b;">&quot;&quot;&quot;Mapeamentos de URL para a versão &quot;mobile&quot;.
&quot;&quot;&quot;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">conf</span> <span style="color: #ff7700;font-weight:bold;">import</span> settings
<span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">conf</span>.<span style="color: black;">urls</span>.<span style="color: black;">defaults</span> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #66cc66;">*</span>
<span style="color: #808080; font-style: italic;"># from django.contrib import admin</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># admin.autodiscover()</span>
&nbsp;
handler404 = <span style="color: #483d8b;">'website.views.error_404_handler'</span>
handler500 = <span style="color: #483d8b;">'website.views.error_500_handler'</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># URLs</span>
urlpatterns = patterns<span style="color: black;">&#40;</span><span style="color: #483d8b;">''</span>,
    <span style="color: #808080; font-style: italic;"># I18N</span>
    <span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'^i18n/'</span>, include<span style="color: black;">&#40;</span><span style="color: #483d8b;">'django.conf.urls.i18n'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>,
&nbsp;
    <span style="color: #808080; font-style: italic;"># Apps internas</span>
    <span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'^contact/'</span>, include<span style="color: black;">&#40;</span><span style="color: #483d8b;">'contact.urls'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>,
&nbsp;
    <span style="color: #808080; font-style: italic;"># (r'^admin/doc/', include('django.contrib.admindocs.urls')),</span>
    <span style="color: #808080; font-style: italic;"># (r'^admin/', include(admin.site.urls)),</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Outras configurações...</span>
<span style="color: black;">&#41;</span></pre></div></div>

<p>Perceba que, neste exemplo em particular, a <a href="http://docs.djangoproject.com/en/dev/ref/contrib/admin/">app Admin</a> não é acessível através da versão mobile. Isso apenas serve para mostrar que temos total liberdade para estruturar ambas as versões de diferentes formas, sem muitas dificuldades.</p>
<h3>Desenvolvendo</h3>
<p>Você certamente já sabe como rodar o servidor de desenvolvimento para a versão padrão. O que a maioria dos desenvolvedores desconhece, entretanto, é que é possível escolher qual a porta e/ou módulo <code>settings.py</code> deve ser usado pelo script, o que nos permite rodar um servidor para cada versão do nosso site:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># Terminal 1: versão padrão</span>
$ python manage.py runserver <span style="color: #000000;">8000</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># Terminal 2: versão mobile</span>
$ python manage.py runserver <span style="color: #660033;">--settings</span>=m_settings <span style="color: #000000;">8001</span></pre></div></div>

<p>Pronto, agora é só continuar com o desenvolvimento da forma que você já está acostumado.</p>
<h3>Testando</h3>
<p>Você provavelmente notou que temos duas configurações que podem ser usadas para determinar qual versão do site está rodando, <code>DEFAULT_VERSION</code> e <code>MOBILE_VERSION</code>. </p>
<p>Por isso, é só uma questão de checar tais configurações quando for necessário fazer coisas diferentes em cada uma das versões do site. Isso é particularmente útil quando você tem uma app usada em ambas as versões e quer criar testes para cada uma das versões:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># Arquivo: myproject/myapp/tests/__init__.py</span>
&nbsp;
<span style="color: #483d8b;">&quot;&quot;&quot;Testes para MyApp.
&quot;&quot;&quot;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">conf</span> <span style="color: #ff7700;font-weight:bold;">import</span> settings
&nbsp;
<span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">getattr</span><span style="color: black;">&#40;</span>settings, <span style="color: #483d8b;">'DEFAULT_VERSION'</span>, <span style="color: #008000;">False</span><span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># Testa a versão padrão</span>
    <span style="color: #ff7700;font-weight:bold;">from</span> default_models_tests <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #66cc66;">*</span>
    <span style="color: #ff7700;font-weight:bold;">from</span> default_navigation_tests <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #66cc66;">*</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">getattr</span><span style="color: black;">&#40;</span>settings, <span style="color: #483d8b;">'MOBILE_VERSION'</span>, <span style="color: #008000;">False</span><span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># Testa a versão mobile</span>
    <span style="color: #ff7700;font-weight:bold;">from</span> mobile_models_tests <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #66cc66;">*</span>
    <span style="color: #ff7700;font-weight:bold;">from</span> mobile_navigation_tests <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #66cc66;">*</span></pre></div></div>

<p>Você pode rodar os testes para cada versão de uma forma semelhante a que fizemos com o comando <code>runserver</code>:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># Versão padrão</span>
$ python manage.py <span style="color: #7a0874; font-weight: bold;">test</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span>appname...<span style="color: #7a0874; font-weight: bold;">&#93;</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># Versão mobile</span>
$ python manage.py <span style="color: #7a0874; font-weight: bold;">test</span> <span style="color: #660033;">--settings</span>=m_settings <span style="color: #7a0874; font-weight: bold;">&#91;</span>appname...<span style="color: #7a0874; font-weight: bold;">&#93;</span></pre></div></div>

<h3>Colocando em produção</h3>
<p>Apesar do que você possa achar, esta é a parte fácil.</p>
<p>Uma vez que a forma recomendada de <a href="http://docs.djangoproject.com/en/dev/howto/deployment/modwsgi/">colocar Django em produção</a> é com <a href="http://apache.org">Apache</a> e <a href="http://code.google.com/p/modwsgi/">mod_wsgi</a>, é possível que você já tenha um arquivo WSGI parecido com o seguinte:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">os</span>, <span style="color: #dc143c;">sys</span>
&nbsp;
APPS_PATH   = <span style="color: #483d8b;">'/home/user/wsgi_apps'</span>
MYPROJECT_PATH = <span style="color: #483d8b;">'%s/myproject'</span> <span style="color: #66cc66;">%</span> APPS_PATH
&nbsp;
<span style="color: #808080; font-style: italic;"># Eggs de terceiros</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">site</span>
<span style="color: #dc143c;">site</span>.<span style="color: black;">addsitedir</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/home/user/.python/lib'</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #dc143c;">sys</span>.<span style="color: black;">path</span> += <span style="color: black;">&#91;</span>APPS_PATH, MYPROJECT_PATH<span style="color: black;">&#93;</span>
<span style="color: #dc143c;">os</span>.<span style="color: black;">environ</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'DJANGO_SETTINGS_MODULE'</span><span style="color: black;">&#93;</span> = <span style="color: #483d8b;">'myproject.settings'</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">import</span> django.<span style="color: black;">core</span>.<span style="color: black;">handlers</span>.<span style="color: black;">wsgi</span>
application = django.<span style="color: black;">core</span>.<span style="color: black;">handlers</span>.<span style="color: black;">wsgi</span>.<span style="color: black;">WSGIHandler</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Tudo que precisamos fazer é configurar um outro sub-domínio WSGI no nosso servidor (ex: m.mywebsite.com) que referencia o seguinte arquivo de configurações WSGI:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">os</span>, <span style="color: #dc143c;">sys</span>
&nbsp;
APPS_PATH   = <span style="color: #483d8b;">'/home/user/wsgi_apps'</span>
MYPROJECT_PATH = <span style="color: #483d8b;">'%s/myproject'</span> <span style="color: #66cc66;">%</span> APPS_PATH
&nbsp;
<span style="color: #808080; font-style: italic;"># Eggs de terceiros</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">site</span>
<span style="color: #dc143c;">site</span>.<span style="color: black;">addsitedir</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/home/user/.python/lib'</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #dc143c;">sys</span>.<span style="color: black;">path</span> += <span style="color: black;">&#91;</span>APPS_PATH, MYPROJECT_PATH<span style="color: black;">&#93;</span>
<span style="color: #dc143c;">os</span>.<span style="color: black;">environ</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'DJANGO_SETTINGS_MODULE'</span><span style="color: black;">&#93;</span> = <span style="color: #483d8b;">'myproject.m_settings'</span> <span style="color: #808080; font-style: italic;"># Esta linha</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">import</span> django.<span style="color: black;">core</span>.<span style="color: black;">handlers</span>.<span style="color: black;">wsgi</span>
application = django.<span style="color: black;">core</span>.<span style="color: black;">handlers</span>.<span style="color: black;">wsgi</span>.<span style="color: black;">WSGIHandler</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>A única diferença entre esses dois arquivos WSGI é que cada um aponta para um módulo <code>settings.py</code> diferente. E não, você não precisa ter uma cópia do site para cada versão, afinal estamos usando a mesma base de código para ambas as versões, lembra? <img src='http://weblog.destaquenet.com/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<h3>Minimizando o tráfego</h3>
<p>Por incrível que pareça, nem todo mundo dispõe de conexões ultra-rápidas. Por isso, é muito importante que você mantenha seus sites tão leves quanto possível.</p>
<p>Existem vários projetos open source que podem ajudar nessa parte. Um deles é o <a href="http://code.google.com/p/django-compress/">django-compress</a>, uma app Django que fornece um sistema automatizado para compressão de arquivos CSS e JavaScript.</p>
<p>Aliás, não importa se seus websites são para dispositivos móveis ou não; você deve <em>sempre</em> tentar minimizar o tráfego.</p>
<h3>O que falta?</h3>
<p>Ainda temos um pequeno problema: quando alguém visita a versão padrão do site através de um dispositivo móvel, ou vice-versa, eles não são redirecionados para a versão apropriada. Mas isso é assunto para um próximo artigo!</p>
]]></content:encoded>
			<wfw:commentRss>http://weblog.destaquenet.com/2010/07/12/django-para-dispositivos-moveis/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Em Tempos de Copa do Mundo&#8230;</title>
		<link>http://weblog.destaquenet.com/2010/06/15/em-tempos-de-copa-do-mundo/</link>
		<comments>http://weblog.destaquenet.com/2010/06/15/em-tempos-de-copa-do-mundo/#comments</comments>
		<pubDate>Tue, 15 Jun 2010 11:00:16 +0000</pubDate>
		<dc:creator>Daniel Martins</dc:creator>
				<category><![CDATA[Português]]></category>
		<category><![CDATA[Programação]]></category>
		<category><![CDATA[aposta]]></category>
		<category><![CDATA[bolão]]></category>
		<category><![CDATA[clojure]]></category>
		<category><![CDATA[copa do mundo]]></category>
		<category><![CDATA[futebol]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[meme]]></category>
		<category><![CDATA[programa]]></category>
		<category><![CDATA[solução]]></category>

		<guid isPermaLink="false">http://weblog.destaquenet.com/?p=898</guid>
		<description><![CDATA[Há quem ache &#8212; e eu concordo &#8212; que a UEFA Champions League é um torneio mais relevante do que a Copa do Mundo, mas não podemos negar que o Mundial mexe com a nossa rotina. Mesmo quem não é &#8230; <a href="http://weblog.destaquenet.com/2010/06/15/em-tempos-de-copa-do-mundo/">Continue lendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Há quem ache &#8212; e eu concordo &#8212; que a <a href="http://www.uefa.com/uefachampionsleague/index.html">UEFA Champions League</a> é um torneio mais relevante do que a <a href="http://www.fifa.com/worldcup/index.html">Copa do Mundo</a>, mas não podemos negar que o Mundial mexe com a nossa rotina. Mesmo quem não é apaixonado pelo esporte passa a prestar atenção nas seleções, nas partidas, na festa.</p>
<p>E com a Copa do Mundo vem os bolões. Muitos bolões.</p>
<p>Todo mundo já sabe como funciona um bolão, embora a mecânica possa mudar de um lugar para outro:</p>
<ol>
<li>Cada palpite tem um valor fixo (ex: R$2,00).</li>
<li>Cada um pode dar quantos palpites quiser.</li>
<li>No final, o montante arrecadado é dividido igualmente entre os vencedores. Se não houverem vencedores: (a) o bolão &#8220;acumula&#8221;<sup class='footnote'><a href='#fn-898-1' id='fnref-898-1'>1</a></sup>, ou (b) todo mundo recebe seu dinheiro de volta, ou (c) sua-regra-maluca-aqui.</li>
</ol>
<p>Esse tipo de bolão é interessante, mas ele podia ser melhor em alguns aspectos.</p>
<p>Primeiro, o organizador acaba perdendo muito tempo correndo atrás de troco, afinal não é todo mundo que anda com dinheiro trocado na carteira. Além disso, valor fixo de palpite é muito chato, pois o valor arrecadado é dividido por igual entre os ganhadores. O bolão fica muito mais interessante quando o valor do palpite é variável e o valor arrecadado é dividido proporcionalmente entre os ganhadores. Assim, no caso de vários ganhadores, ganha mais quem apostar mais.</p>
<p>O problema de se fazer bolões com palpite variável é ter que ficar calculando o valor proporcional a ser dado a cada ganhador. Portanto eis o desafio: criar um programa que receba uma lista com todos os palpites e retorne uma lista com os palpites vencedores juntamente com o valor proporcional a ser pago a cada ganhador.</p>
<p>E aí, topa?</p>
<p><span id="more-898"></span></p>
<h3>Resolvendo o problema&#8230; em Clojure</h3>
<p>Como escrever mais código do que necessário está saindo de moda, optei por codificar uma possível solução em <a href="http://clojure.org">Clojure</a>. Por ser uma <a href="http://weblog.destaquenet.com/2009/06/16/programacao-funcional-vale-a-pena-aprender/">linguagem funcional</a>, Clojure é excelente para esse tipo de tarefa. Basta iniciar o <a href="http://clojure.org/repl_and_main">REPL</a> e mãos à obra!</p>
<p>Primeiramente, devemos definir como um palpite deve ser representado:</p>

<div class="wp_syntax"><div class="code"><pre class="lisp" style="font-family:monospace;"><span style="color: #66cc66;">&#40;</span>defstruct bet <span style="color: #66cc66;">:</span><span style="color: #b1b100;">name</span> <span style="color: #66cc66;">:</span><span style="color: #555;">amount</span> <span style="color: #66cc66;">:</span><span style="color: #555;">guess</span> <span style="color: #66cc66;">:</span><span style="color: #555;">rate</span><span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>Todos os palpites possuem o mesmo conjunto de informações, por isso definimos um <a href="http://clojure.org/data_structures#Data%20Structures-StructMaps">StructMap</a> com as chaves <code>:name</code>, <code>:amount</code>, <code>:guess</code> e <code>:rate</code>.</p>
<p>Abaixo, uma possível lista de palpites:</p>

<div class="wp_syntax"><div class="code"><pre class="lisp" style="font-family:monospace;"><span style="color: #66cc66;">&#40;</span>def pool
     <span style="color: #66cc66;">&#91;</span><span style="color: #66cc66;">&#40;</span>struct bet <span style="color: #ff0000;">&quot;Daniel&quot;</span>  <span style="color: #cc66cc;">2.0</span> <span style="color: #66cc66;">&#91;</span><span style="color: #cc66cc;">2</span> <span style="color: #cc66cc;">0</span><span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #808080; font-style: italic;">;; Daniel aposta R$2,00 no placar 2x0</span>
      <span style="color: #66cc66;">&#40;</span>struct bet <span style="color: #ff0000;">&quot;Antônio&quot;</span> <span style="color: #cc66cc;">4.0</span> <span style="color: #66cc66;">&#91;</span><span style="color: #cc66cc;">0</span> <span style="color: #cc66cc;">0</span><span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #808080; font-style: italic;">;; Antônio aposta R$4,00 no placar 0x0</span>
      <span style="color: #66cc66;">&#40;</span>struct bet <span style="color: #ff0000;">&quot;Marcela&quot;</span> <span style="color: #cc66cc;">1.0</span> <span style="color: #66cc66;">&#91;</span><span style="color: #cc66cc;">2</span> <span style="color: #cc66cc;">0</span><span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #808080; font-style: italic;">;; Marcela aposta R$1,00 no placar 2x0</span>
     <span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>Certo, já sabemos como os palpites são representados. Agora, como saber o montante total de uma lista de palpites (a.k.a. bolão)? Simples, basta calcular o somatório dos valores de todos os palpites:</p>

<div class="wp_syntax"><div class="code"><pre class="lisp" style="font-family:monospace;"><span style="color: #66cc66;">&#40;</span>defn pool-amount <span style="color: #66cc66;">&#91;</span>poolseq<span style="color: #66cc66;">&#93;</span>
  <span style="color: #66cc66;">&#40;</span>reduce<span style="color: #66cc66;"> + </span><span style="color: #66cc66;">&#40;</span>map <span style="color: #66cc66;">:</span><span style="color: #555;">amount</span> poolseq<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;">;; testando</span>
<span style="color: #66cc66;">&#40;</span>pool-amount pool<span style="color: #66cc66;">&#41;</span>
<span style="color: #66cc66;">=&gt;</span> <span style="color: #cc66cc;">7.0</span></pre></div></div>

<p>Beleza, mas quanto cada palpite representa em relação ao total arrecadado? Afinal, precisamos calcular o valor proporcional a ser pago a cada ganhador.</p>
<p>Sem problemas, basta dividir o valor de cada palpite pelo montante total:</p>

<div class="wp_syntax"><div class="code"><pre class="lisp" style="font-family:monospace;"><span style="color: #66cc66;">&#40;</span>defn pool-rates <span style="color: #66cc66;">&#91;</span>poolseq<span style="color: #66cc66;">&#93;</span>
  <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">let</span> <span style="color: #66cc66;">&#91;</span>sum <span style="color: #66cc66;">&#40;</span>pool-amount poolseq<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#93;</span>
    <span style="color: #66cc66;">&#40;</span>map #<span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">assoc</span> <span style="color: #66cc66;">%</span> <span style="color: #66cc66;">:</span><span style="color: #555;">rate</span> <span style="color: #66cc66;">&#40;</span>/ <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">:</span><span style="color: #555;">amount</span> <span style="color: #66cc66;">%</span><span style="color: #66cc66;">&#41;</span> sum<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> poolseq<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;">;; testando</span>
<span style="color: #66cc66;">&#40;</span>map <span style="color: #66cc66;">:</span><span style="color: #555;">rate</span> <span style="color: #66cc66;">&#40;</span>pool-rates pool<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
<span style="color: #66cc66;">=&gt;</span> <span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">0.285</span> <span style="color: #66cc66;">...,</span> <span style="color: #cc66cc;">0.571</span> <span style="color: #66cc66;">...,</span> <span style="color: #cc66cc;">0.142</span> <span style="color: #66cc66;">...</span><span style="color: #66cc66;">&#41;</span>
&nbsp;
<span style="color: #66cc66;">&#40;</span>reduce<span style="color: #66cc66;"> + </span><span style="color: #66cc66;">&#40;</span>map <span style="color: #66cc66;">:</span><span style="color: #555;">rate</span> <span style="color: #66cc66;">&#40;</span>pool-rates pool<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
<span style="color: #66cc66;">=&gt;</span> <span style="color: #cc66cc;">1.0</span></pre></div></div>

<p>Repare que, se todos os participantes ganhassem um bolão, o valor recebido pelo Antônio seria o dobro do valor recebido pelo Daniel, que seria o dobro do valor recebido pela Marcela. Justiça, finalmente!</p>
<p>Pronto, agora só falta uma função para filtrar os ganhadores da lista de participantes e calcular o valor proporcional a ser pago a cada um deles:</p>

<div class="wp_syntax"><div class="code"><pre class="lisp" style="font-family:monospace;"><span style="color: #66cc66;">&#40;</span>defn pool-winners <span style="color: #66cc66;">&#91;</span>poolseq result<span style="color: #66cc66;">&#93;</span>
  <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">let</span> <span style="color: #66cc66;">&#91;</span>sum <span style="color: #66cc66;">&#40;</span>pool-amount poolseq<span style="color: #66cc66;">&#41;</span>
        winners <span style="color: #66cc66;">&#40;</span>filter #<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">:</span><span style="color: #555;">guess</span> <span style="color: #66cc66;">%</span><span style="color: #66cc66;">&#41;</span> result<span style="color: #66cc66;">&#41;</span> poolseq<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#93;</span>
    <span style="color: #66cc66;">&#40;</span>map #<span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">assoc</span> <span style="color: #66cc66;">%</span> <span style="color: #66cc66;">:</span><span style="color: #555;">amount</span> <span style="color: #66cc66;">&#40;</span>double <span style="color: #66cc66;">&#40;</span>* <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">:</span><span style="color: #555;">rate</span> <span style="color: #66cc66;">%</span><span style="color: #66cc66;">&#41;</span> sum<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#40;</span>pool-rates winners<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;">;; testando</span>
<span style="color: #66cc66;">&#40;</span>pool-winners pool <span style="color: #66cc66;">&#91;</span><span style="color: #cc66cc;">1</span> <span style="color: #cc66cc;">0</span><span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #808080; font-style: italic;">;; sem ganhadores</span>
<span style="color: #66cc66;">=&gt;</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>
&nbsp;
<span style="color: #66cc66;">&#40;</span>pool-winners pool <span style="color: #66cc66;">&#91;</span><span style="color: #cc66cc;">0</span> <span style="color: #cc66cc;">0</span><span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #808080; font-style: italic;">;; apenas um ganhador</span>
<span style="color: #66cc66;">=&gt;</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#123;</span><span style="color: #66cc66;">:</span><span style="color: #b1b100;">name</span> <span style="color: #ff0000;">&quot;Antônio&quot;</span><span style="color: #66cc66;">,</span> <span style="color: #66cc66;">:</span><span style="color: #555;">amount</span> <span style="color: #cc66cc;">7.0</span><span style="color: #66cc66;">,</span> <span style="color: #66cc66;">:</span><span style="color: #555;">guess</span> <span style="color: #66cc66;">&#91;</span><span style="color: #cc66cc;">0</span> <span style="color: #cc66cc;">0</span><span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">,</span> <span style="color: #66cc66;">:</span><span style="color: #555;">rate</span> <span style="color: #cc66cc;">1.0</span><span style="color: #66cc66;">&#125;</span><span style="color: #66cc66;">&#41;</span>
&nbsp;
<span style="color: #66cc66;">&#40;</span>pool-winners pool <span style="color: #66cc66;">&#91;</span><span style="color: #cc66cc;">2</span> <span style="color: #cc66cc;">0</span><span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #808080; font-style: italic;">;; vários ganhadores</span>
<span style="color: #66cc66;">=&gt;</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#123;</span><span style="color: #66cc66;">:</span><span style="color: #b1b100;">name</span> <span style="color: #ff0000;">&quot;Daniel&quot;</span><span style="color: #66cc66;">,</span> <span style="color: #66cc66;">:</span><span style="color: #555;">amount</span> <span style="color: #cc66cc;">4.66</span> <span style="color: #66cc66;">...,</span> <span style="color: #66cc66;">:</span><span style="color: #555;">guess</span> <span style="color: #66cc66;">&#91;</span><span style="color: #cc66cc;">2</span> <span style="color: #cc66cc;">0</span><span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">,</span> <span style="color: #66cc66;">:</span><span style="color: #555;">rate</span> <span style="color: #cc66cc;">0.66</span> <span style="color: #66cc66;">...</span><span style="color: #66cc66;">&#125;</span>
    <span style="color: #66cc66;">&#123;</span><span style="color: #66cc66;">:</span><span style="color: #b1b100;">name</span> <span style="color: #ff0000;">&quot;Marcela&quot;</span><span style="color: #66cc66;">,</span> <span style="color: #66cc66;">:</span><span style="color: #555;">amount</span> <span style="color: #cc66cc;">2.33</span> <span style="color: #66cc66;">...,</span> <span style="color: #66cc66;">:</span><span style="color: #555;">guess</span> <span style="color: #66cc66;">&#91;</span><span style="color: #cc66cc;">2</span> <span style="color: #cc66cc;">0</span><span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">,</span> <span style="color: #66cc66;">:</span><span style="color: #555;">rate</span> <span style="color: #cc66cc;">0.33</span> <span style="color: #66cc66;">...</span><span style="color: #66cc66;">&#125;</span><span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>Uma grande vantagem dessa solução é que ela permite que você aposte em qualquer coisa. Quer apostar no sexo de um bebê logo após a boa notícia (ou má notícia, sei lá)?</p>

<div class="wp_syntax"><div class="code"><pre class="lisp" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">;; :male = masculino, :female = feminino</span>
<span style="color: #66cc66;">&#40;</span>def pool <span style="color: #66cc66;">&#91;</span><span style="color: #66cc66;">&#40;</span>struct bet <span style="color: #ff0000;">&quot;Daniel&quot;</span>  <span style="color: #cc66cc;">3.0</span> <span style="color: #66cc66;">:</span><span style="color: #555;">male</span><span style="color: #66cc66;">&#41;</span>
           <span style="color: #66cc66;">&#40;</span>struct bet <span style="color: #ff0000;">&quot;Antônio&quot;</span> <span style="color: #cc66cc;">5.0</span> <span style="color: #66cc66;">:</span><span style="color: #555;">female</span><span style="color: #66cc66;">&#41;</span>
           <span style="color: #66cc66;">&#40;</span>struct bet <span style="color: #ff0000;">&quot;Fran&quot;</span>    <span style="color: #cc66cc;">1.0</span> <span style="color: #66cc66;">:</span><span style="color: #555;">female</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#41;</span>
&nbsp;
<span style="color: #66cc66;">&#40;</span>pool-winners pool <span style="color: #66cc66;">:</span><span style="color: #555;">female</span><span style="color: #66cc66;">&#41;</span> <span style="color: #808080; font-style: italic;">;; testando</span>
<span style="color: #66cc66;">=&gt;</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#123;</span><span style="color: #66cc66;">:</span><span style="color: #b1b100;">name</span> <span style="color: #ff0000;">&quot;Antônio&quot;</span><span style="color: #66cc66;">,</span> <span style="color: #66cc66;">:</span><span style="color: #555;">amount</span> <span style="color: #cc66cc;">7.5</span><span style="color: #66cc66;">,</span> <span style="color: #66cc66;">...</span><span style="color: #66cc66;">&#125;</span> <span style="color: #66cc66;">&#123;</span><span style="color: #66cc66;">:</span><span style="color: #b1b100;">name</span> <span style="color: #ff0000;">&quot;Fran&quot;</span><span style="color: #66cc66;">,</span> <span style="color: #66cc66;">:</span><span style="color: #555;">amount</span> <span style="color: #cc66cc;">1.5</span><span style="color: #66cc66;">,</span> <span style="color: #66cc66;">...</span><span style="color: #66cc66;">&#125;</span><span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>Aí está, uma solução simples para um problema simples. Como deveria ser sempre.</p>
<h3>Minha solução, na íntegra</h3>
<p>Embora seja possível resolver isso com um one-liner em Lisp/Clojure (afinal o <a href="http://clojure.org/reader">Reader</a> não trabalha com linhas, mas com <strong>estruturas de dados</strong>), eu optei por escrever um código que fosse o mais legível possível para quem não conhece ou está aprendendo Clojure:</p>

<div class="wp_syntax"><div class="code"><pre class="lisp" style="font-family:monospace;"><span style="color: #66cc66;">&#40;</span>defstruct bet <span style="color: #66cc66;">:</span><span style="color: #b1b100;">name</span> <span style="color: #66cc66;">:</span><span style="color: #555;">amount</span> <span style="color: #66cc66;">:</span><span style="color: #555;">guess</span> <span style="color: #66cc66;">:</span><span style="color: #555;">rate</span><span style="color: #66cc66;">&#41;</span>
&nbsp;
<span style="color: #66cc66;">&#40;</span>defn pool-amount <span style="color: #66cc66;">&#91;</span>poolseq<span style="color: #66cc66;">&#93;</span>
  <span style="color: #66cc66;">&#40;</span>reduce<span style="color: #66cc66;"> + </span><span style="color: #66cc66;">&#40;</span>map <span style="color: #66cc66;">:</span><span style="color: #555;">amount</span> poolseq<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
&nbsp;
<span style="color: #66cc66;">&#40;</span>defn pool-rates <span style="color: #66cc66;">&#91;</span>poolseq<span style="color: #66cc66;">&#93;</span>
  <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">let</span> <span style="color: #66cc66;">&#91;</span>sum <span style="color: #66cc66;">&#40;</span>pool-amount poolseq<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#93;</span>
    <span style="color: #66cc66;">&#40;</span>map #<span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">assoc</span> <span style="color: #66cc66;">%</span> <span style="color: #66cc66;">:</span><span style="color: #555;">rate</span> <span style="color: #66cc66;">&#40;</span>/ <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">:</span><span style="color: #555;">amount</span> <span style="color: #66cc66;">%</span><span style="color: #66cc66;">&#41;</span> sum<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> poolseq<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
&nbsp;
<span style="color: #66cc66;">&#40;</span>defn pool-winners <span style="color: #66cc66;">&#91;</span>poolseq result<span style="color: #66cc66;">&#93;</span>
  <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">let</span> <span style="color: #66cc66;">&#91;</span>sum <span style="color: #66cc66;">&#40;</span>pool-amount poolseq<span style="color: #66cc66;">&#41;</span>
        winners <span style="color: #66cc66;">&#40;</span>filter #<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">:</span><span style="color: #555;">guess</span> <span style="color: #66cc66;">%</span><span style="color: #66cc66;">&#41;</span> result<span style="color: #66cc66;">&#41;</span> poolseq<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#93;</span>
    <span style="color: #66cc66;">&#40;</span>map #<span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">assoc</span> <span style="color: #66cc66;">%</span> <span style="color: #66cc66;">:</span><span style="color: #555;">amount</span> <span style="color: #66cc66;">&#40;</span>double <span style="color: #66cc66;">&#40;</span>* <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">:</span><span style="color: #555;">rate</span> <span style="color: #66cc66;">%</span><span style="color: #66cc66;">&#41;</span> sum<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#40;</span>pool-rates winners<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span></pre></div></div>

<h3>Levando adiante</h3>
<p>Você programa em Haskell? Python? Ruby? <a href="http://en.wikipedia.org/wiki/Brainfuck">Brainfuck</a>? Qual seria a sua solução para este problema de extrema importância para o desenvolvimento da raça humana? <img src='http://weblog.destaquenet.com/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' /> </p>
<p><strong>Atualização (03/11/2010).</strong> Solução em Common Lisp, usando <code>copy-*</code> para evitar mutabilidade:</p>

<div class="wp_syntax"><div class="code"><pre class="lisp" style="font-family:monospace;"><span style="color: #66cc66;">&#40;</span>defstruct bet <span style="color: #b1b100;">name</span> amount guess rate<span style="color: #66cc66;">&#41;</span>
&nbsp;
<span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">defun</span> pool-amount <span style="color: #66cc66;">&#40;</span>pool<span style="color: #66cc66;">&#41;</span>
  <span style="color: #66cc66;">&#40;</span>reduce #'+ <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">mapcar</span> #'bet-amount pool<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
&nbsp;
<span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">defun</span> pool-rates <span style="color: #66cc66;">&#40;</span>pool<span style="color: #66cc66;">&#41;</span>
  <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">let</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span>sum <span style="color: #66cc66;">&#40;</span>pool-amount pool<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
    <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">mapcar</span> <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">lambda</span> <span style="color: #66cc66;">&#40;</span>bet<span style="color: #66cc66;">&#41;</span>
              <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">let</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span>x <span style="color: #66cc66;">&#40;</span>copy-bet bet<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
                <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">setf</span> <span style="color: #66cc66;">&#40;</span>bet-rate x<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#40;</span>/ <span style="color: #66cc66;">&#40;</span>bet-amount x<span style="color: #66cc66;">&#41;</span> sum<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
                x<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> pool<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
&nbsp;
<span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">defun</span> pool-winners <span style="color: #66cc66;">&#40;</span>pool result<span style="color: #66cc66;">&#41;</span>
  <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">let</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span>sum <span style="color: #66cc66;">&#40;</span>pool-amount pool<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
        <span style="color: #66cc66;">&#40;</span>winners <span style="color: #66cc66;">&#40;</span>loop for bet in pool <span style="color: #b1b100;">when</span> <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">equal</span> <span style="color: #66cc66;">&#40;</span>bet-guess bet<span style="color: #66cc66;">&#41;</span> result<span style="color: #66cc66;">&#41;</span> collect bet<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
    <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">mapcar</span> <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">lambda</span> <span style="color: #66cc66;">&#40;</span>winner<span style="color: #66cc66;">&#41;</span>
              <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">let</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span>x <span style="color: #66cc66;">&#40;</span>copy-bet winner<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
                <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">setf</span> <span style="color: #66cc66;">&#40;</span>bet-amount x<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#40;</span>* <span style="color: #66cc66;">&#40;</span>bet-rate x<span style="color: #66cc66;">&#41;</span> sum<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
                x<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#40;</span>pool-rates winners<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span></pre></div></div>

<div class='footnotes'>
<div class='footnotedivider'></div>
<ol>
<li id='fn-898-1'>Todo o montante recebido continua disponível no próximo bolão, mas os participantes devem pagar um novo palpite. <span class='footnotereverse'><a href='#fnref-898-1'>&#8617;</a></span></li>
</ol>
</div>
]]></content:encoded>
			<wfw:commentRss>http://weblog.destaquenet.com/2010/06/15/em-tempos-de-copa-do-mundo/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Django-Flash e o Novo Framework de Mensagens</title>
		<link>http://weblog.destaquenet.com/2010/05/21/django-flash-e-o-novo-framework-de-mensagens/</link>
		<comments>http://weblog.destaquenet.com/2010/05/21/django-flash-e-o-novo-framework-de-mensagens/#comments</comments>
		<pubDate>Fri, 21 May 2010 02:36:14 +0000</pubDate>
		<dc:creator>Daniel Martins</dc:creator>
				<category><![CDATA[Português]]></category>
		<category><![CDATA[Programação]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[django-flash]]></category>
		<category><![CDATA[open source]]></category>
		<category><![CDATA[project]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://weblog.destaquenet.com/?p=890</guid>
		<description><![CDATA[No começo da semana, depois de vários meses de trabalho duro e algum atraso, a versão 1.2 do Django foi finalmente lançada. Este talvez seja o lançamento mais aguardado do framework desde seu surgimento, e inclui recursos há muito aguardados, &#8230; <a href="http://weblog.destaquenet.com/2010/05/21/django-flash-e-o-novo-framework-de-mensagens/">Continue lendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>No começo da semana, depois de vários meses de trabalho duro e algum atraso, a versão 1.2 do Django <a href="http://www.djangoproject.com/download/">foi finalmente lançada</a>. Este talvez seja o lançamento mais aguardado do framework desde seu surgimento, e inclui recursos há muito aguardados, como <a href="http://docs.djangoproject.com/en/dev/releases/1.2/#support-for-multiple-databases">suporte a múltiplos bancos de dados</a> e um <a href="http://docs.djangoproject.com/en/dev/releases/1.2/#messages-framework">framework de &#8220;mensagens&#8221;</a>.</p>
<p>Sim, eu disse que o Django 1.2 traz incluso um framework de &#8220;mensagens&#8221;. Bom, né? Django realmente precisava vir acompanhado de uma app para resolver essa questão. Isso não significa, no entanto, que <a href="http://djangoflash.destaquenet.com/">Django-Flash</a> será descontinuado ou abandonado.</p>
<p>Então, se você usa Django-Flash em seus projetos, não se preocupe! Nada mudará. Django-Flash já é compatível com Django 1.2, e nós ocontinuaremos a mantê-lo por algumas razões.</p>
<p>A primeira delas é que nos importamos com quem usa nosso software. Nós não quebraremos seus projetos se você decidir fazer o upgrade para uma versão mais recente do Django &#8211; ou se decidir continuar usando uma versão anterior.</p>
<p>A outra é a liberdade de escolha. Você sabe, não existe uma única forma de se resolver todos os problemas. As pessoas devem ser livres para escolher a ferramenta apropriada a uma determinada situação.</p>
<p>Por exemplo, baseado nas minhas primeiras impressões, existem algumas coisas que eu realmente não gostei no novo framework de &#8220;mensagens&#8221;:</p>
<ol>
<li>Ele é <em>verboso</em> mesmo nos casos de uso mais simples</li>
<li>Ele associa mensagens a números de prioridade, encorajando os usuários a usá-lo como um framework de logging/debugging. Quero dizer, um framework de &#8220;mensagens&#8221; não é um framework de logging/debugging, certo?</li>
</ol>
<p>Mas essa é apenas a minha opinião. Talvez seja isso que faz do open source algo tão formidável!</p>
]]></content:encoded>
			<wfw:commentRss>http://weblog.destaquenet.com/2010/05/21/django-flash-e-o-novo-framework-de-mensagens/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Python para S60: Trabalho em Andamento?</title>
		<link>http://weblog.destaquenet.com/2010/02/17/python-para-s60-trabalho-em-andamento/</link>
		<comments>http://weblog.destaquenet.com/2010/02/17/python-para-s60-trabalho-em-andamento/#comments</comments>
		<pubDate>Wed, 17 Feb 2010 12:30:29 +0000</pubDate>
		<dc:creator>Daniel Martins</dc:creator>
				<category><![CDATA[Português]]></category>
		<category><![CDATA[Programação]]></category>
		<category><![CDATA[celular]]></category>
		<category><![CDATA[nokia]]></category>
		<category><![CDATA[pys60]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[python for s60]]></category>
		<category><![CDATA[s60]]></category>
		<category><![CDATA[smartphone]]></category>
		<category><![CDATA[symbian]]></category>

		<guid isPermaLink="false">http://weblog.destaquenet.com/?p=846</guid>
		<description><![CDATA[Eu fui um dos sortudos que perderam o celular a alguns meses atrás, durante aquele show maluco do AC/DC. Surpreendentemente, isso não me deixou aborrecido; apesar de não ser um heavy user, essa foi a oportunidade perfeita para eu comprar &#8230; <a href="http://weblog.destaquenet.com/2010/02/17/python-para-s60-trabalho-em-andamento/">Continue lendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Eu fui um dos sortudos que perderam o celular a alguns meses atrás, durante aquele <a href="http://weblog.destaquenet.com/2009/10/05/use-web-scraping-para-acompanhar-seus-pedidos-na-ticketmaster/">show maluco do AC/DC</a>. Surpreendentemente, isso não me deixou aborrecido; apesar de não ser um heavy user, essa foi a oportunidade perfeita para eu comprar meu primeiro smartphone.</p>
<p>No fim das contas eu acabei com um <a href="http://europe.nokia.com/find-products/devices/nokia-5800-xpressmusic">Nokia 5800 XpressMusic</a>, um smartphone relativamente barato e com features interessantes. Especificamente, o fato de poder rodar aplicações <a href="http://python.org">Python</a> nesse aparelho foi um fator decisivo!</p>
<p>Mas, o que exatamente podemos fazer com <a href="https://garage.maemo.org/projects/pys60/">Python para S60</a>? Eu decidi implementar uma aplicação não trivial para ver exatamente o que pode ser feito com ele. A aplicação em questão é um controle remoto Bluetooth chamado <a href="http://github.com/danielfm/pytriloquist">Pytriloquist</a>. (veja também <a href="http://www.flickr.com/photos/daniel_tritone/4313716091/in/set-72157623183881993/">screenshots</a> e <a href="http://www.youtube.com/watch?v=2IVXMAJHwI8">vídeo</a> de demonstração.)</p>
<p><span id="more-846"></span></p>
<h3>O que é Bom</h3>
<p><strong>Independência de Plataforma.</strong> A <a href="http://www.forum.nokia.com/Tools_Docs_and_Code/Tools/Platforms/S60_Platform_SDKs/">SDK para S60</a> só roda em Windows (que novidade). Isso obviamente é ruim para quem costuma usar outros sistemas operacionais. Felizmente, você não precisa de uma SDK gigante para desenvolver e distribuir aplicações para S60 se você escrevê-las em Python; tudo o que você precisa é do Python para S60, um editor de texto e um aparelho para testes.</p>
<p><strong>Linguagem e Biblioteca Padrão.</strong> Python é uma linguagem excelente: compacta, bonita, poderosa e tem uma biblioteca padrão <em>sensacional</em>. A boa notícia é que a maioria dos módulos rodam bem no S60. Por exemplo, é possível até localizar suas aplicações usando o módulo <code>gettext</code>!</p>
<h3>O que é Ruim</h3>
<p><strong>Trabalho em Andamento.</strong> Python para S60, até onde me consta, é um trabalho em andamento. Isso significa que a linguagem em si funciona bem, mas você pode dar falta de certos módulos ou <a href="https://garage.maemo.org/tracker/?atid=3201&#038;group_id=854&#038;func=browse">encontrar bugs</a> na biblioteca padrão. Por exemplo, enquanto eu escrevia o código Bluetooth para minha applicação, eu dei de cara com um <a href="https://garage.maemo.org/tracker/index.php?func=detail&#038;aid=3947&#038;group_id=854&#038;atid=3201">bug muito chato</a> onde você só pode chamar <code>btsocket.bt_discovert()</code> uma vez!</p>
<p><strong>Código Multi-Módulos.</strong> Se você está testando sua aplicação com Python ScriptShell, tudo irá funcionar de cara desde que você mantenha todo o código dentro de um único &#8212; e enorme &#8212; módulo. Se você quebrar seu código em vários módulos (ou pior, pacotes), você não poderá ter módulos importando uns aos outros, a menos que você ajuste o <code>PYTHON_PATH</code> de acordo.</p>
<p><strong>Documentação Incompleta e Desatualizada.</strong> Existem alguns PDFs e algumas documentações de API disponíveis, mas elas estão incompletas e desatualizadas, o que é ruim quando se trata de uma linguagem dinâmica; nós não temos um compilador para nos dizer o que há de errado com nosso código. Esse é o motivo pelo qual desenvolvedores Python são tão cuidadosos com documentação pra começo de conversa.</p>
<h3>O que é Feio</h3>
<p><strong>Acesso Limitado a Recursos Nativos.</strong> Especialmente em se tratando do sistema de UI nativo: você não pode mudar o texto das duas soft keys padrão, nem adicionar soft keys, nem adicionar mais que duas abas, nem ter um <code>Listbox</code> vazio, nem um monte de outras coisas. Você pode escrever UIs simples sem muito esforço, isso é verdade, mas essas deficiências todas tornam Python para S60 simplesmente inutilizável em projetos mais complexos.</p>
<p><strong>Inatividade do Projeto.</strong> O projeto parece estar em modo &#8220;stand by&#8221;. Novos bug reports são enviados de tempos em tempos, mas nenhum bug foi fechado há mais de <a href="https://garage.maemo.org/project/stats/?group_id=854">seis meses</a>.</p>
<h3>Conclusão</h3>
<p>Espero que as coisas mudem para melhor após o último <a href="http://www.symbian.org/symbian-feature-set/symbian-is-open-source">anúncio</a> feito pela Fundação Symbian, mas, enquanto isso, se você pretende criar aplicações sérias para S60, o faça em C++.</p>
]]></content:encoded>
			<wfw:commentRss>http://weblog.destaquenet.com/2010/02/17/python-para-s60-trabalho-em-andamento/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>JSP e tag files: criando templates em 10 minutos</title>
		<link>http://weblog.destaquenet.com/2009/12/17/jsp-e-tag-files-criando-templates-em-10-minutos/</link>
		<comments>http://weblog.destaquenet.com/2009/12/17/jsp-e-tag-files-criando-templates-em-10-minutos/#comments</comments>
		<pubDate>Thu, 17 Dec 2009 12:30:41 +0000</pubDate>
		<dc:creator>Daniel Martins</dc:creator>
				<category><![CDATA[Português]]></category>
		<category><![CDATA[Programação]]></category>
		<category><![CDATA[Tutoriais]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[jsp]]></category>
		<category><![CDATA[layout]]></category>
		<category><![CDATA[servlet]]></category>
		<category><![CDATA[tag]]></category>
		<category><![CDATA[tagfiles]]></category>
		<category><![CDATA[taglib]]></category>
		<category><![CDATA[template]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://weblog.destaquenet.com/?p=801</guid>
		<description><![CDATA[Este mês têm sido bastante curioso pelo fato de três pessoas terem me feito a mesma pergunta: &#8220;- Você largou o Java de vez?&#8221;. A resposta é não, mas, para não deixar dúvidas, eu resolvi voltar a escrever sobre Java. &#8230; <a href="http://weblog.destaquenet.com/2009/12/17/jsp-e-tag-files-criando-templates-em-10-minutos/">Continue lendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Este mês têm sido bastante curioso pelo fato de três pessoas terem me feito a mesma pergunta: &#8220;- Você largou o Java de vez?&#8221;. A resposta é <strong>não</strong>, mas, para não deixar dúvidas, eu resolvi voltar a escrever sobre Java. O assunto foge um pouco do que costumo escrever, mas é algo que considero importante.</p>
<p>Ultimamente, tenho visto a forma como certos desenvolvedores escrevem seus JSPs, e o que me preocupou foi ver o quanto eles desconhecem a tecnologia. Não é raro achar páginas cheias de <a href="http://java.sun.com/javaee/5/docs/tutorial/doc/bnaou.html">scriptlets</a>, includes malucos, código du-tri-quadri-plicado e nenhuma taglib além da fornecida pelo framework web em uso.</p>
<p>É muito fácil escrever JSPs da forma errada, mas fazer as coisas de um jeito melhor é mais fácil ainda. Ao contrário do que muitos pensam, é possível sim criar JSPs limpos sem o uso de qualquer framework de layout (como <a href="http://www.opensymphony.com/sitemesh/">Sitemesh</a>) ou biblioteca (com exceção da <a href="http://java.sun.com/products/jsp/jstl/reference/docs/index.html">JSTL</a>, é claro).</p>
<p><span id="more-801"></span></p>
<h3>Um exemplo</h3>
<p>O primeiro passo é definir o template base para as páginas da aplicação. Considere o seguinte exemplo de XHTML e sua representação gráfica:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #00bbdd;">&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot;</span>
<span style="color: #00bbdd;">    &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;&gt;</span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;html</span> <span style="color: #000066;">xmlns</span>=<span style="color: #ff0000;">&quot;http://www.w3.org/1999/xhtml&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;head<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;meta</span> <span style="color: #000066;">http-equiv</span>=<span style="color: #ff0000;">&quot;content-type&quot;</span> <span style="color: #000066;">content</span>=<span style="color: #ff0000;">&quot;text/html; charset=UTF-8&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;meta</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;keywords&quot;</span>    <span style="color: #000066;">content</span>=<span style="color: #ff0000;">&quot;keyword1, keyword2, keyword3&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;meta</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;description&quot;</span> <span style="color: #000066;">content</span>=<span style="color: #ff0000;">&quot;Page description&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;title<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Page title<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/title<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
&nbsp;
        <span style="color: #808080; font-style: italic;">&lt;!-- Essential scripts --&gt;</span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;link</span> <span style="color: #000066;">rel</span>=<span style="color: #ff0000;">&quot;stylesheet&quot;</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;text/css&quot;</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">&quot;css/style.css&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;script</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;text/javascript&quot;</span> <span style="color: #000066;">src</span>=<span style="color: #ff0000;">&quot;js/query.js&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/script<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
&nbsp;
        <span style="color: #808080; font-style: italic;">&lt;!-- Extra header --&gt;</span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;script</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;text/javascript&quot;</span> <span style="color: #000066;">src</span>=<span style="color: #ff0000;">&quot;js/util.js&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/script<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/head<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #808080; font-style: italic;">&lt;!-- Main --&gt;</span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;div</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;wrapper&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;div</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;header&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/div<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;div</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;content&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/div<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;div</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;footer&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/div<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/div<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> <span style="color: #808080; font-style: italic;">&lt;!-- Main --&gt;</span>
&nbsp;
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;script</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;text/javascript&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
            // Other scripts (e.g. Google Analytics)
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/script<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/html<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<div id="attachment_803" class="wp-caption aligncenter" style="width: 310px"><a href="http://weblog.destaquenet.com/wp-content/uploads/2009/12/layout.gif"><img src="http://weblog.destaquenet.com/wp-content/uploads/2009/12/layout-300x156.gif" alt="Representação gráfica do layout" title="layout" width="300" height="156" class="size-medium wp-image-803" /></a><p class="wp-caption-text">Representação gráfica do layout</p></div>
<p>O que costuma acontecer, mesmo em um layout simples como esse, é o alto índice de duplicação de código entre as diferentes páginas, principalmente em função do uso de <a href="http://en.wikipedia.org/wiki/Copy_and_paste_programming">Copy and Paste Programming</a>. Muitos desenvolvedores por aí escreveriam o seguinte JSP para representar o layout proposto:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #00bbdd;">&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot;</span>
<span style="color: #00bbdd;">    &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;&gt;</span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;html</span> <span style="color: #000066;">xmlns</span>=<span style="color: #ff0000;">&quot;http://www.w3.org/1999/xhtml&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;head<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;meta</span> <span style="color: #000066;">http-equiv</span>=<span style="color: #ff0000;">&quot;content-type&quot;</span> <span style="color: #000066;">content</span>=<span style="color: #ff0000;">&quot;text/html; charset=UTF-8&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;meta</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;keywords&quot;</span>    <span style="color: #000066;">content</span>=<span style="color: #ff0000;">&quot;keyword1, keyword2, keyword3&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;meta</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;description&quot;</span> <span style="color: #000066;">content</span>=<span style="color: #ff0000;">&quot;Page description&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;title<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Page title<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/title<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
&nbsp;
        <span style="color: #808080; font-style: italic;">&lt;!-- Essential scripts --&gt;</span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;jsp:include</span> <span style="color: #000066;">page</span>=<span style="color: #ff0000;">&quot;scripts.jsp&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
&nbsp;
        <span style="color: #808080; font-style: italic;">&lt;!-- Extra header --&gt;</span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;script</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;text/javascript&quot;</span> <span style="color: #000066;">src</span>=<span style="color: #ff0000;">&quot;js/util.js&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/script<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/head<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #808080; font-style: italic;">&lt;!-- Main --&gt;</span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;div</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;wrapper&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;jsp:include</span> <span style="color: #000066;">file</span>=<span style="color: #ff0000;">&quot;header.jsp&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;div</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;content&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>Page content here<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/div<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;jsp:include</span> <span style="color: #000066;">page</span>=<span style="color: #ff0000;">&quot;footer.jsp&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/div<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> <span style="color: #808080; font-style: italic;">&lt;!-- Main --&gt;</span>
&nbsp;
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;script</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;text/javascript&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
            // Other scripts
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/script<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/html<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>Viu o problema? De nada adianta separar os pedaços com <jsp:include> e continuar duplicando código. O ideal seria traduzir o layout em algo assim:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;">&lt;%@ taglib <span style="color: #000066;">tagdir</span>=<span style="color: #ff0000;">&quot;/WEB-INF/tags/layout&quot;</span> <span style="color: #000066;">prefix</span>=<span style="color: #ff0000;">&quot;layout&quot;</span> %<span style="color: #000000; font-weight: bold;">&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;layout:page</span> <span style="color: #000066;">title</span>=<span style="color: #ff0000;">&quot;Title&quot;</span> <span style="color: #000066;">description</span>=<span style="color: #ff0000;">&quot;Page description&quot;</span> <span style="color: #000066;">keywords</span>=<span style="color: #ff0000;">&quot;keyword1, keyword2, keyword3&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;jsp:attribute</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;extraHeader&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;script</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;text/javascript&quot;</span> <span style="color: #000066;">src</span>=<span style="color: #ff0000;">&quot;js/util.js&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/script<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/jsp:attribute<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;jsp:attribute</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;extraBottom&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
        // Other scripts (e.g. Google Analytics)
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/jsp:attribute<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;jsp:body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        Page content here
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/jsp:body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/layout:page<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>A boa notícia é que isso é possível, através de tag files.</p>
<h3>Reúso de conteúdo com tag files</h3>
<p>Existem pelo menos três formas de se criar custom tags em JSP, cada qual com seu propósito: <a href="http://java.sun.com/javaee/5/docs/tutorial/doc/bnaow.html#bnaoy">classic tag handlers</a>, <a href="http://java.sun.com/javaee/5/docs/tutorial/doc/bnann.html">simple tag handlers</a> e <a href="http://java.sun.com/javaee/5/docs/tutorial/doc/bnama.html">tag files</a>. Neste post tratarei somente das tag files, mas saber como e quando utilizar simple tag handlers também é extremamente recomendado a todos que usam JSP no dia-a-dia.</p>
<p>A primeira coisa a fazer é criar o diretório <code>WEB-INF/tags/layout</code>. É nesse diretório que as tag files referentes ao template devem ficar. Agora, crie dois arquivos neste diretório, um para o cabeçalho e outro para o rodapé:</p>
<p><strong>header.tag</strong></p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;">&lt;%@ tag <span style="color: #000066;">body-content</span>=<span style="color: #ff0000;">&quot;empty&quot;</span> <span style="color: #000066;">description</span>=<span style="color: #ff0000;">&quot;Header tag file&quot;</span> %<span style="color: #000000; font-weight: bold;">&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;div</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;header&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
    <span style="color: #808080; font-style: italic;">&lt;!-- Header section here --&gt;</span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/div<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p><strong>footer.tag</strong></p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;">&lt;%@ tag <span style="color: #000066;">body-content</span>=<span style="color: #ff0000;">&quot;empty&quot;</span> <span style="color: #000066;">description</span>=<span style="color: #ff0000;">&quot;Footer tag file&quot;</span> %<span style="color: #000000; font-weight: bold;">&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;div</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;footer&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
    <span style="color: #808080; font-style: italic;">&lt;!-- Footer section here --&gt;</span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/div<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>Como podemos ver, as tag files são como JSPs, mas com algumas propriedades especiais.</p>
<p>A última tag file, <strong>page.tag</strong>, define o esqueleto das páginas da aplicação:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;">&lt;%@ tag <span style="color: #000066;">description</span>=<span style="color: #ff0000;">&quot;Page layout&quot;</span> %<span style="color: #000000; font-weight: bold;">&gt;</span></span>
&nbsp;
<span style="color: #009900;">&lt;%@ attribute <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;title&quot;</span>       <span style="color: #000066;">required</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">description</span>=<span style="color: #ff0000;">&quot;Page title&quot;</span> %<span style="color: #000000; font-weight: bold;">&gt;</span></span>
<span style="color: #009900;">&lt;%@ attribute <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;keywords&quot;</span>    <span style="color: #000066;">required</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">description</span>=<span style="color: #ff0000;">&quot;Page keywords to improve SEO&quot;</span> %<span style="color: #000000; font-weight: bold;">&gt;</span></span>
<span style="color: #009900;">&lt;%@ attribute <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;description&quot;</span> <span style="color: #000066;">required</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">description</span>=<span style="color: #ff0000;">&quot;Page description&quot;</span> %<span style="color: #000000; font-weight: bold;">&gt;</span></span>
&nbsp;
<span style="color: #009900;">&lt;%@ attribute <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;extraHeader&quot;</span> <span style="color: #000066;">fragment</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">description</span>=<span style="color: #ff0000;">&quot;Extra code to put before &lt;/head&gt;</span></span>&quot; %&gt;
<span style="color: #009900;">&lt;%@ attribute <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;extraBottom&quot;</span> <span style="color: #000066;">fragment</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">description</span>=<span style="color: #ff0000;">&quot;Extra code to put before &lt;/body&gt;</span></span>&quot; %&gt;
&nbsp;
<span style="color: #009900;">&lt;%@ taglib <span style="color: #000066;">tagdir</span>=<span style="color: #ff0000;">&quot;/WEB-INF/tags/layout&quot;</span> <span style="color: #000066;">prefix</span>=<span style="color: #ff0000;">&quot;layout&quot;</span> %<span style="color: #000000; font-weight: bold;">&gt;</span></span>
&nbsp;
<span style="color: #00bbdd;">&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot;</span>
<span style="color: #00bbdd;">    &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;&gt;</span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;html</span> <span style="color: #000066;">xmlns</span>=<span style="color: #ff0000;">&quot;http://www.w3.org/1999/xhtml&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;head<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;meta</span> <span style="color: #000066;">http-equiv</span>=<span style="color: #ff0000;">&quot;content-type&quot;</span> <span style="color: #000066;">content</span>=<span style="color: #ff0000;">&quot;text/html; charset=UTF-8&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
&nbsp;
        <span style="color: #808080; font-style: italic;">&lt;!-- Displaying the attributes using EL --&gt;</span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;meta</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;keywords&quot;</span>    <span style="color: #000066;">content</span>=<span style="color: #ff0000;">&quot;${keywords}&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;meta</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;description&quot;</span> <span style="color: #000066;">content</span>=<span style="color: #ff0000;">&quot;${description}&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;title<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>${title}<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/title<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
&nbsp;
        <span style="color: #808080; font-style: italic;">&lt;!-- Essential scripts --&gt;</span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;link</span> <span style="color: #000066;">rel</span>=<span style="color: #ff0000;">&quot;stylesheet&quot;</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;text/css&quot;</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">&quot;css/style.css&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;script</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;text/javascript&quot;</span> <span style="color: #000066;">src</span>=<span style="color: #ff0000;">&quot;js/query.js&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/script<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
&nbsp;
        <span style="color: #808080; font-style: italic;">&lt;!-- Process the given input fragment --&gt;</span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;jsp:invoke</span> <span style="color: #000066;">fragment</span>=<span style="color: #ff0000;">&quot;extraHeader&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/head<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #808080; font-style: italic;">&lt;!-- Main --&gt;</span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;div</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;wrapper&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
            <span style="color: #808080; font-style: italic;">&lt;!-- Renders the page header --&gt;</span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;layout:header</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
&nbsp;
            <span style="color: #808080; font-style: italic;">&lt;!-- Renders the tag body inside a DIV --&gt;</span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;div</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;content&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;jsp:doBody</span><span style="color: #000000; font-weight: bold;">/&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/div<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
&nbsp;
            <span style="color: #808080; font-style: italic;">&lt;!-- Renders the page footer --&gt;</span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;layout:footer</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/div<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> <span style="color: #808080; font-style: italic;">&lt;!-- Main --&gt;</span>
&nbsp;
        <span style="color: #808080; font-style: italic;">&lt;!-- Process the given input fragment --&gt;</span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;jsp:invoke</span> <span style="color: #000066;">fragment</span>=<span style="color: #ff0000;">&quot;extraBottom&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/html<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>Esta última tag file é mais complexa que as anteriores, pois recebe dados e blocos de código (através de <a href="http://java.sun.com/javaee/5/docs/tutorial/doc/bnaln.html#bnalq">fragments</a>). Além disso, ela aceita um corpo, que é executado com <code>&lt;jsp:doBody/&gt;</code>.</p>
<p>O exemplo usado aqui é razoavelmente simples e, por isso, não precisamos apelar para outros recursos mais avançados como <a href="http://java.sun.com/javaee/5/docs/tutorial/doc/bnaln.html#bnaly">variables</a> e <a href="http://java.sun.com/javaee/5/docs/tutorial/doc/bnaln.html#bnaly">dynamic attributes</a>. De qualquer forma, procure conhecer bem a tecnologia, pois você nunca sabe quando um ou outro recurso lhe pode ser útil.</p>
<h3>Exemplo de uso</h3>
<p>Novamente, um exemplo de uso das tags que criamos:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;">&lt;%@ taglib <span style="color: #000066;">tagdir</span>=<span style="color: #ff0000;">&quot;/WEB-INF/tags/layout&quot;</span> <span style="color: #000066;">prefix</span>=<span style="color: #ff0000;">&quot;layout&quot;</span> %<span style="color: #000000; font-weight: bold;">&gt;</span></span>
<span style="color: #009900;">&lt;%@ taglib <span style="color: #000066;">uri</span>=<span style="color: #ff0000;">&quot;http://java.sun.com/jsp/jstl/core&quot;</span> <span style="color: #000066;">prefix</span>=<span style="color: #ff0000;">&quot;c&quot;</span> %<span style="color: #000000; font-weight: bold;">&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;layout:page</span> <span style="color: #000066;">title</span>=<span style="color: #ff0000;">&quot;Index page&quot;</span> <span style="color: #000066;">description</span>=<span style="color: #ff0000;">&quot;This is the index page of my amazing app&quot;</span> <span style="color: #000066;">keywords</span>=<span style="color: #ff0000;">&quot;amazing, app&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;jsp:attribute</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;extraHeader&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;script</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;text/javascript&quot;</span> <span style="color: #000066;">src</span>=<span style="color: #ff0000;">&quot;js/util.js&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/script<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;script</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;text/javascript&quot;</span> <span style="color: #000066;">src</span>=<span style="color: #ff0000;">&quot;js/some_jquery_plugin.js&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/script<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/jsp:attribute<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;jsp:attribute</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;extraBottom&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
        $(function() {
            // Call some JQuery function here, specific for this page
        });
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/jsp:attribute<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;jsp:body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        Welcome to my amazing app!<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;br</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        1+1 = ${1+1}
&nbsp;
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;ul<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;c:forEach</span> <span style="color: #000066;">items</span>=<span style="color: #ff0000;">&quot;${objects}&quot;</span> <span style="color: #000066;">var</span>=<span style="color: #ff0000;">&quot;obj&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>${obj.attr}<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/c:forEach<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/ul<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/jsp:body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/layout:page<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>Embora a aplicação como um todo siga um mesmo padrão visual, cada página pode necessitar de recursos adicionais (JavaScript, CSS, etc). Isso não chega a ser um problema, pois nosso template contempla a inclusão de conteúdo extra, se necessário.</p>
<p>Outra vantagem é que as tag files permitem o uso de custom tags e <a href="http://java.sun.com/javaee/5/docs/tutorial/doc/bnahq.html">unified EL</a>, mas <strong>proíbem o uso de scriptlets</strong>, o que já é meio caminho andado rumo a um JSP mais limpo.</p>
<h3>Leitura recomendada</h3>
<ul>
<li><a href="http://java.sun.com/javaee/5/docs/tutorial/doc/">The Java EE 5 Tutorial</a>;</li>
<li><a href="http://www.amazon.com/Head-First-Servlets-JSP-Certified/dp/0596516681/ref=sr_1_1?ie=UTF8&#038;s=books&#038;qid=1260993372&#038;sr=8-1">Head First Servlets &#038; JSP</a>;</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://weblog.destaquenet.com/2009/12/17/jsp-e-tag-files-criando-templates-em-10-minutos/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Use web scraping para acompanhar seus pedidos na Ticketmaster</title>
		<link>http://weblog.destaquenet.com/2009/10/05/use-web-scraping-para-acompanhar-seus-pedidos-na-ticketmaster/</link>
		<comments>http://weblog.destaquenet.com/2009/10/05/use-web-scraping-para-acompanhar-seus-pedidos-na-ticketmaster/#comments</comments>
		<pubDate>Mon, 05 Oct 2009 12:30:43 +0000</pubDate>
		<dc:creator>Daniel Martins</dc:creator>
				<category><![CDATA[Off Topic]]></category>
		<category><![CDATA[Português]]></category>
		<category><![CDATA[Programação]]></category>
		<category><![CDATA[acdc]]></category>
		<category><![CDATA[brasil]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[pynotify]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[scraping]]></category>
		<category><![CDATA[script]]></category>
		<category><![CDATA[show]]></category>
		<category><![CDATA[ticketmaster]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://weblog.destaquenet.com/?p=710</guid>
		<description><![CDATA[A legendária banda de rock&#8217;n'roll AC/DC irá pousar em solo brasileiro pela segunda vez em Novembro, para o que é considerado o show da década por aqui! Os ingressos para a única apresentação, vendidos pela Ticketmaster, se esgotaram em menos &#8230; <a href="http://weblog.destaquenet.com/2009/10/05/use-web-scraping-para-acompanhar-seus-pedidos-na-ticketmaster/">Continue lendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>A legendária banda de rock&#8217;n'roll <a href="http://acdc.com/">AC/DC</a> irá pousar em solo brasileiro pela segunda vez em Novembro, para o que é considerado o show da década por aqui! Os ingressos para a única apresentação, vendidos pela <a href="http://www.ticketmaster.com.br/">Ticketmaster</a>, se esgotaram em menos de 48 horas. Esse show será incrível!</p>
<p>Muita coisa aconteceu nessas 48 horas. O pessoal da Ticketmaster teve trabalho para manter o website no ar e, em razão da enorme carga, é possível que apenas poucos milhares de fãs tenham sido sortudos o bastante para comprar seus ingressos através da internet.</p>
<p>Além disso, a Ticketmaster admite que os e-mails de notificação podem não ser enviados, o que significa que não podemos depender deles para acompanhar nossos pedidos. Na verdade, eles até recomendam que seus clientes chequem os pedidos diariamente, na mão. Caramba&#8230;</p>
<p>Eu odeio fazer certas tarefas manualmente, especialmente as que podem ser automatizadas. Então, neste post eu mostrarei uma ferramenta escrita em <a href="http://www.python.org">Python</a> que mostra a situação dos seus pedidos Ticketmaster na tela<sup class='footnote'><a href='#fn-710-1' id='fnref-710-1'>1</a></sup>, usando uma técnica conhecida como <a href="http://en.wikipedia.org/wiki/Web_scraping">web scraping</a>.</p>
<p><span id="more-710"></span></p>
<p>O código, que também está disponível <a href="http://github.com/danielfm/ticketmaster-order-status">no Github</a>, pode ser visto abaixo:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">#!/usr/bin/env python</span>
<span style="color: #808080; font-style: italic;">#-*- coding:utf-8 -*-</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">urllib</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">urllib2</span>
<span style="color: #ff7700;font-weight:bold;">import</span> pynotify
&nbsp;
&nbsp;
_BASE_URL  = <span style="color: #483d8b;">'https://ticketing.ticketmaster.com.br'</span>
_LOGIN_URI = <span style="color: #483d8b;">'%s/shwLogin.cfm'</span> <span style="color: #66cc66;">%</span> _BASE_URL
_ORDER_URI = <span style="color: #483d8b;">'%s/shwCompraDetalhe.cfm?pedidoID=%%s'</span> <span style="color: #66cc66;">%</span> _BASE_URL
&nbsp;
_ORDERS_LINK = <span style="color: #483d8b;">'&lt;a href=&quot;%s&quot;&gt;More...&lt;/a&gt;'</span> <span style="color: #66cc66;">%</span> _LOGIN_URI
&nbsp;
_PRIORITY_LOW      = pynotify.<span style="color: black;">URGENCY_LOW</span>
_PRIORITY_NORMAL   = pynotify.<span style="color: black;">URGENCY_NORMAL</span>
_PRIORITY_CRITICAL = pynotify.<span style="color: black;">URGENCY_CRITICAL</span>
&nbsp;
_NOTIFICATION_TITLE = <span style="color: #483d8b;">'Ticketmaster Order %s'</span>
_STATUS_CODES = <span style="color: black;">&#123;</span>
    <span style="color: #483d8b;">'Livre'</span>      : <span style="color: black;">&#40;</span><span style="color: #483d8b;">'Not processed yet'</span>      , _PRIORITY_LOW<span style="color: black;">&#41;</span>,
    <span style="color: #483d8b;">'StdReserva'</span> : <span style="color: black;">&#40;</span><span style="color: #483d8b;">'Reserving your tickets'</span> , _PRIORITY_NORMAL<span style="color: black;">&#41;</span>,
    <span style="color: #483d8b;">'StdCobranca'</span>: <span style="color: black;">&#40;</span><span style="color: #483d8b;">'Charging your tickets'</span>  , _PRIORITY_NORMAL<span style="color: black;">&#41;</span>,
    <span style="color: #483d8b;">'VendaOk'</span>    : <span style="color: black;">&#40;</span><span style="color: #483d8b;">'Billed'</span>                 , _PRIORITY_CRITICAL<span style="color: black;">&#41;</span>,
    <span style="color: #483d8b;">'Recusada'</span>   : <span style="color: black;">&#40;</span><span style="color: #483d8b;">'Rejected'</span>               , _PRIORITY_CRITICAL<span style="color: black;">&#41;</span>
<span style="color: black;">&#125;</span>
&nbsp;
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> initialize_notification_system<span style="color: black;">&#40;</span>app_title<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> pynotify.<span style="color: black;">init</span><span style="color: black;">&#40;</span>app_title<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">sys</span>
        <span style="color: #dc143c;">sys</span>.<span style="color: black;">exit</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> display_message<span style="color: black;">&#40;</span>title, message, priority=_PRIORITY_CRITICAL<span style="color: black;">&#41;</span>:
    message = pynotify.<span style="color: black;">Notification</span><span style="color: black;">&#40;</span>title, message<span style="color: black;">&#41;</span>
    message.<span style="color: black;">set_urgency</span><span style="color: black;">&#40;</span>priority<span style="color: black;">&#41;</span>
    message.<span style="color: black;">show</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> check_orders<span style="color: black;">&#40;</span><span style="color: #dc143c;">email</span>, password, order_ids<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">try</span>:
        opener = <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">build_opener</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">urllib2</span>.<span style="color: black;">HTTPCookieProcessor</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
        login<span style="color: black;">&#40;</span>opener, <span style="color: #dc143c;">email</span>, password<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">try</span>:
            <span style="color: #ff7700;font-weight:bold;">for</span> order_id <span style="color: #ff7700;font-weight:bold;">in</span> order_ids:
                show_order_status<span style="color: black;">&#40;</span>opener, order_id<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">except</span>:
            title = _NOTIFICATION_TITLE <span style="color: #66cc66;">%</span> order_id
            display_message<span style="color: black;">&#40;</span>title, <span style="color: #483d8b;">'Cannot check status'</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">except</span>:
        display_message<span style="color: black;">&#40;</span><span style="color: #483d8b;">'Ticketmaster'</span>, <span style="color: #483d8b;">'Login failed'</span><span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> login<span style="color: black;">&#40;</span>opener, <span style="color: #dc143c;">email</span>, password<span style="color: black;">&#41;</span>:
    params = <span style="color: #dc143c;">urllib</span>.<span style="color: black;">urlencode</span><span style="color: black;">&#40;</span><span style="color: black;">&#123;</span><span style="color: #483d8b;">'email'</span>: <span style="color: #dc143c;">email</span>, <span style="color: #483d8b;">'senha'</span>: password<span style="color: black;">&#125;</span><span style="color: black;">&#41;</span>
    response = opener.<span style="color: #008000;">open</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'%s?tentaLogin=1'</span> <span style="color: #66cc66;">%</span> _LOGIN_URI, params<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Invalid credentials check</span>
    <span style="color: #ff7700;font-weight:bold;">if</span> response.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">find</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'senha incorreta'</span><span style="color: black;">&#41;</span> <span style="color: #66cc66;">&gt;</span>= <span style="color: #ff4500;">0</span>:
        <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">Exception</span>
&nbsp;
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> show_order_status<span style="color: black;">&#40;</span>opener, order_id<span style="color: black;">&#41;</span>:
    response = opener.<span style="color: #008000;">open</span><span style="color: black;">&#40;</span>_ORDER_URI <span style="color: #66cc66;">%</span> order_id<span style="color: black;">&#41;</span>
    content = response.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Search for the order status codes</span>
    <span style="color: #ff7700;font-weight:bold;">for</span> key, value <span style="color: #ff7700;font-weight:bold;">in</span> _STATUS_CODES.<span style="color: black;">items</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">if</span> content.<span style="color: black;">find</span><span style="color: black;">&#40;</span>key<span style="color: black;">&#41;</span> <span style="color: #66cc66;">&gt;</span>= <span style="color: #ff4500;">0</span>:
            title = _NOTIFICATION_TITLE <span style="color: #66cc66;">%</span> order_id
            message = <span style="color: #483d8b;">'%s. %s'</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>value<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span>, _ORDERS_LINK<span style="color: black;">&#41;</span>
            display_message<span style="color: black;">&#40;</span>title, message, value<span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">break</span>
    <span style="color: #ff7700;font-weight:bold;">else</span>:
        display_message<span style="color: black;">&#40;</span>_NOTIFICATION_TITLE <span style="color: #66cc66;">%</span> order_id, <span style="color: #483d8b;">'Status not found'</span><span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> main<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    initialize_notification_system<span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Ticketmaster Order Status&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">optparse</span>
    p = <span style="color: #dc143c;">optparse</span>.<span style="color: black;">OptionParser</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Required command line options</span>
    p.<span style="color: black;">add_option</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'--email'</span>    , <span style="color: #483d8b;">'-e'</span>, \
        <span style="color: #008000;">help</span>=<span style="color: #483d8b;">'E-mail address used in your Ticketmaster credentials.'</span><span style="color: black;">&#41;</span>
    p.<span style="color: black;">add_option</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'--password'</span> , <span style="color: #483d8b;">'-p'</span>, \
        <span style="color: #008000;">help</span>=<span style="color: #483d8b;">'Password used in your Ticketmaster credentials.'</span><span style="color: black;">&#41;</span>
    p.<span style="color: black;">add_option</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'--order-ids'</span>, <span style="color: #483d8b;">'-o'</span>, \
        <span style="color: #008000;">help</span>=<span style="color: #483d8b;">'Order IDs to be checked, separated by collons.'</span><span style="color: black;">&#41;</span>
&nbsp;
    options = p.<span style="color: black;">parse_args</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span>
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> options.<span style="color: #dc143c;">email</span> <span style="color: #ff7700;font-weight:bold;">or</span> <span style="color: #ff7700;font-weight:bold;">not</span> options.<span style="color: black;">password</span> <span style="color: #ff7700;font-weight:bold;">or</span> <span style="color: #ff7700;font-weight:bold;">not</span> options.<span style="color: black;">order_ids</span>:
        p.<span style="color: black;">print_help</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">else</span>:
        order_ids = <span style="color: #008000;">map</span><span style="color: black;">&#40;</span><span style="color: #ff7700;font-weight:bold;">lambda</span> s: s.<span style="color: black;">strip</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>, options.<span style="color: black;">order_ids</span>.<span style="color: black;">split</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">','</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
        check_orders<span style="color: black;">&#40;</span>options.<span style="color: #dc143c;">email</span>, options.<span style="color: black;">password</span>, order_ids<span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
<span style="color: #ff7700;font-weight:bold;">if</span> __name__ == <span style="color: #483d8b;">'__main__'</span>:
    main<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>A razão pela qual eu optei por web scrapping é porque a Ticketmaster não fornece uma API da mesma forma que o <a href="http://flickr.com">Flickr</a> fornece, por exemplo. Ainda assim, o código é bastante simples.</p>
<p>Como você pode ver, ele primeiro envia uma requisição HTTP para a URI de login com o objetivo de validar as credenciais do usuário. Se a autenticação for bem sucedida, nosso <code>opener</code> receberá os cookies de sessão do servidor e os usará nas requisições seguintes, que buscam a situação de cada um dos pedidos informados.</p>
<p>Rodando o script agora:</p>
<div id="attachment_763" class="wp-caption aligncenter" style="width: 310px"><a href="http://weblog.destaquenet.com/wp-content/uploads/2009/10/order_status1.png"><img src="http://weblog.destaquenet.com/wp-content/uploads/2009/10/order_status1-300x104.png" alt="Current order status" title="order_status" width="300" height="104" class="size-medium wp-image-763" /></a><p class="wp-caption-text">Current order status</p></div>
<p>Finalmente, inclua uma nova entrada no seu <code>crontab</code> para que o script rode sempre que necessário (ex: a cada 10 minutos):</p>
<pre>*/10 * * * * python ticketmaster_order_status.py --email=seu@email.com --password=senha --order-ids=1234</pre>
<p>Boa sorte e <em>let there be rock</em>! <img src='http://weblog.destaquenet.com/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' /> </p>
<div class='footnotes'>
<div class='footnotedivider'></div>
<ol>
<li id='fn-710-1'>O script usa a biblioteca <a href="http://www.galago-project.org/news/index.php">libnotify</a> para mostrar as notificações na tela, portanto não esqueça de instalá-la. <span class='footnotereverse'><a href='#fnref-710-1'>&#8617;</a></span></li>
</ol>
</div>
]]></content:encoded>
			<wfw:commentRss>http://weblog.destaquenet.com/2009/10/05/use-web-scraping-para-acompanhar-seus-pedidos-na-ticketmaster/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Linux + Python: Script para checar o status dos seus sites</title>
		<link>http://weblog.destaquenet.com/2009/07/20/linux-python-script-para-checar-o-status-dos-seus-sites/</link>
		<comments>http://weblog.destaquenet.com/2009/07/20/linux-python-script-para-checar-o-status-dos-seus-sites/#comments</comments>
		<pubDate>Mon, 20 Jul 2009 16:54:01 +0000</pubDate>
		<dc:creator>Daniel Martins</dc:creator>
				<category><![CDATA[Português]]></category>
		<category><![CDATA[Programação]]></category>
		<category><![CDATA[cron]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[pynotify]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[script]]></category>
		<category><![CDATA[site]]></category>
		<category><![CDATA[status]]></category>

		<guid isPermaLink="false">http://weblog.destaquenet.com/?p=624</guid>
		<description><![CDATA[Os serviços de hosting que você utiliza estão meio ruim das pernas? Vez ou outra você descobre que seus sites estão fora do ar e ninguém te notificou a respeito? Infelizmente, coisas assim estão acontecendo por aqui com uma certa &#8230; <a href="http://weblog.destaquenet.com/2009/07/20/linux-python-script-para-checar-o-status-dos-seus-sites/">Continue lendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Os serviços de <em>hosting</em> que você utiliza <a href="http://statusblog.locaweb.com.br/">estão meio ruim das pernas</a>? Vez ou outra você descobre que seus sites estão fora do ar e <em>ninguém</em> te notificou a respeito?</p>
<p>Infelizmente, coisas assim estão acontecendo por aqui com uma certa frequência. Por isso, resolvi escrever o <code>script</code> abaixo, cuja função é mostrar uma mensagem de notificação sempre que algum dos sites pré-determinados saiam do ar: <sup class='footnote'><a href='#fn-624-1' id='fnref-624-1'>1</a></sup></p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">#!/usr/bin/env python</span>
<span style="color: #808080; font-style: italic;"># -*- coding: utf-8 -*-</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">httplib</span>
<span style="color: #ff7700;font-weight:bold;">import</span> pynotify
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> display_message<span style="color: black;">&#40;</span>title, message<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">if</span> pynotify.<span style="color: black;">init</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Website Status'</span><span style="color: black;">&#41;</span>:
        n = pynotify.<span style="color: black;">Notification</span><span style="color: black;">&#40;</span>title, message<span style="color: black;">&#41;</span>
        n.<span style="color: black;">show</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> check_status<span style="color: black;">&#40;</span><span style="color: #66cc66;">*</span>websites, <span style="color: #66cc66;">**</span>kwargs<span style="color: black;">&#41;</span>:
    timeout = kwargs.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'timeout'</span>, <span style="color: #ff4500;">5</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">for</span> website <span style="color: #ff7700;font-weight:bold;">in</span> websites:
        conn = <span style="color: #dc143c;">httplib</span>.<span style="color: black;">HTTPConnection</span><span style="color: black;">&#40;</span>website, timeout=timeout<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">try</span>:
            conn.<span style="color: black;">request</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'GET'</span>, <span style="color: #483d8b;">'/'</span><span style="color: black;">&#41;</span>
            response = conn.<span style="color: black;">getresponse</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> response.<span style="color: black;">status</span> <span style="color: #66cc66;">!</span>= <span style="color: #ff4500;">200</span>:
                <span style="color: #ff7700;font-weight:bold;">raise</span> Error<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">except</span>:
           display_message<span style="color: black;">&#40;</span>website, <span style="color: #483d8b;">'Web site could not be reached!'</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">if</span> __name__ == <span style="color: #483d8b;">'__main__'</span>:
    check_status<span style="color: black;">&#40;</span><span style="color: #483d8b;">'www.awebsite.com'</span>, <span style="color: #483d8b;">'www.anotherwebsite.com'</span><span style="color: black;">&#41;</span></pre></div></div>

<p><span id="more-624"></span></p>
<p>O <em>script</em> em funcionamento:</p>
<div id="attachment_628" class="wp-caption aligncenter" style="width: 463px"><a href="http://weblog.destaquenet.com/wp-content/uploads/2009/07/notification.png"><img src="http://weblog.destaquenet.com/wp-content/uploads/2009/07/notification.png" alt="Exemplo de notificação" title="Exemplo de notificação" width="453" height="166" class="size-full wp-image-628" /></a><p class="wp-caption-text">Exemplo de notificação</p></div>
<p>Para completar, se você deseja que esse <code>script</code> seja executado uma vez a cada 5 minutos, basta inserir a linha abaixo no seu <code>crontab</code>:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">*/</span><span style="color: #000000;">5</span> <span style="color: #000000; font-weight: bold;">*</span> <span style="color: #000000; font-weight: bold;">*</span> <span style="color: #000000; font-weight: bold;">*</span> <span style="color: #000000; font-weight: bold;">*</span> <span style="color: #000000; font-weight: bold;">/</span>path<span style="color: #000000; font-weight: bold;">/</span>to<span style="color: #000000; font-weight: bold;">/</span>script.py</pre></div></div>

<p>Pronto! Agora, se o seu serviço de <em>hosting</em> continuar deixando a desejar, talvez a melhor solução seja mesmo mudar para outro lugar&#8230;</p>
<div class='footnotes'>
<div class='footnotedivider'></div>
<ol>
<li id='fn-624-1'>A biblioteca <code>python-notify</code> precisa estar instalada para que o <em>script</em> funcione. <span class='footnotereverse'><a href='#fnref-624-1'>&#8617;</a></span></li>
</ol>
</div>
]]></content:encoded>
			<wfw:commentRss>http://weblog.destaquenet.com/2009/07/20/linux-python-script-para-checar-o-status-dos-seus-sites/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>JsHamcrest: um alívio à dor de se testar código JavaScript</title>
		<link>http://weblog.destaquenet.com/2009/07/13/jshamcrest-um-alivio-a-dor-de-se-testar-codigo-javascript/</link>
		<comments>http://weblog.destaquenet.com/2009/07/13/jshamcrest-um-alivio-a-dor-de-se-testar-codigo-javascript/#comments</comments>
		<pubDate>Mon, 13 Jul 2009 14:10:21 +0000</pubDate>
		<dc:creator>Daniel Martins</dc:creator>
				<category><![CDATA[Português]]></category>
		<category><![CDATA[Programação]]></category>
		<category><![CDATA[Tutoriais]]></category>
		<category><![CDATA[destaquenet]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[jshamcrest]]></category>
		<category><![CDATA[jstestdriver]]></category>
		<category><![CDATA[jsunittest]]></category>
		<category><![CDATA[jsunity]]></category>
		<category><![CDATA[open source]]></category>
		<category><![CDATA[projeto]]></category>
		<category><![CDATA[qunit]]></category>
		<category><![CDATA[teste]]></category>
		<category><![CDATA[yuitest]]></category>

		<guid isPermaLink="false">http://weblog.destaquenet.com/?p=584</guid>
		<description><![CDATA[Há não muito tempo atrás, escrever testes automatizados era coisa para poucos. Nem tanto por obstáculos técnicos, mas porque, na verdade, ninguém se importava muito com isso. A boa notícia é que a importância dos testes automatizados vem aumentando com &#8230; <a href="http://weblog.destaquenet.com/2009/07/13/jshamcrest-um-alivio-a-dor-de-se-testar-codigo-javascript/">Continue lendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Há não muito tempo atrás, escrever testes automatizados era coisa para poucos. Nem tanto por obstáculos técnicos, mas porque, na verdade, ninguém se importava muito com isso.</p>
<p>A boa notícia é que a importância dos testes automatizados vem aumentando com o tempo e hoje, felizmente, já não é mais necessário &#8220;vender&#8221; a idéia. O aumento absurdo de ferramentas destinadas a facilitar a aplicação desta prática é uma prova disso.</p>
<p>Falando em ferramentas, neste texto mostrarei o <a href="http://jshamcrest.destaquenet.com/">JsHamcrest</a>, um projeto <em>open source</em> desenvolvido pela <a href="http://www.destaquenet.com/">Destaquenet</a> cujo objetivo é fornecer uma versão incrementada, em JavaScript, da biblioteca <a href="http://code.google.com/p/hamcrest/">Hamcrest</a>. Para quem não conhece, Hamcrest é  uma <a href="http://code.google.com/p/hamcrest/wiki/Tutorial">biblioteca de <em>matchers</em></a> que permite que regras sejam definidas declarativamente para uso em outros <em>frameworks</em> e bibliotecas.</p>
<p><span id="more-584"></span></p>
<h3>Para apreciar é preciso antes viver sem</h3>
<p>Para dar uma idéia do quão útil JsHamcrest pode ser, segue abaixo um exemplo de suite de testes criado com <a href="http://docs.jquery.com/QUnit">QUnit</a>, ainda sem apoio do JsHamcrest, onde testamos o funcionamento de algumas funcionalidades da classe <a href="https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Global_Objects/Array">Array</a>:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">$<span style="color: #009900;">&#40;</span>document<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">ready</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
    test<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;Literal&quot;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #003366; font-weight: bold;">var</span> arr <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
        ok<span style="color: #009900;">&#40;</span>arr <span style="color: #000066; font-weight: bold;">instanceof</span> Array<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        equals<span style="color: #009900;">&#40;</span>arr.<span style="color: #660066;">length</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    test<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;Reverse&quot;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #003366; font-weight: bold;">var</span> arr <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span><span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">2</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">3</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">4</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">5</span><span style="color: #009900;">&#93;</span>.<span style="color: #660066;">reverse</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        equals<span style="color: #009900;">&#40;</span>arr.<span style="color: #660066;">length</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">5</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #006600; font-style: italic;">// This assertion fails</span>
        <span style="color: #006600; font-style: italic;">// equals(arr, [5, 4, 3, 2, 1]);</span>
&nbsp;
        <span style="color: #006600; font-style: italic;">// These assertions work, but in an ideal world you shouldn't do such a thing</span>
        <span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> i <span style="color: #339933;">=</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">,</span> j <span style="color: #339933;">=</span> <span style="color: #CC0000;">5</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;</span> arr.<span style="color: #660066;">length</span><span style="color: #339933;">;</span> i<span style="color: #339933;">++,</span> j<span style="color: #339933;">--</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            equals<span style="color: #009900;">&#40;</span>arr<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> j<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    test<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;Slice&quot;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #003366; font-weight: bold;">var</span> arr <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span><span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">2</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">3</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">4</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">5</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">6</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">7</span><span style="color: #009900;">&#93;</span>.<span style="color: #660066;">slice</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">2</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">5</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        equals<span style="color: #009900;">&#40;</span>arr.<span style="color: #660066;">length</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">3</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #006600; font-style: italic;">// This assertion fails</span>
        <span style="color: #006600; font-style: italic;">// equals(arr, [3, 4, 5]);</span>
&nbsp;
        <span style="color: #006600; font-style: italic;">// These assertions work, but in an ideal world you shouldn't do such a thing</span>
        <span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> i <span style="color: #339933;">=</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;</span> arr.<span style="color: #660066;">length</span><span style="color: #339933;">;</span> i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            equals<span style="color: #009900;">&#40;</span>arr<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> i<span style="color: #339933;">+</span><span style="color: #CC0000;">3</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
&nbsp;
        <span style="color: #006600; font-style: italic;">// Another example of complex assertion</span>
        <span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> i <span style="color: #339933;">=</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;</span> arr.<span style="color: #660066;">length</span><span style="color: #339933;">;</span> i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            ok<span style="color: #009900;">&#40;</span>arr<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span> <span style="color: #339933;">&gt;=</span> <span style="color: #CC0000;">3</span> <span style="color: #339933;">&amp;&amp;</span> arr<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span> <span style="color: #339933;">&lt;=</span> <span style="color: #CC0000;">5</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>O código, mesmo sendo feio e confuso, funciona:</p>
<div id="attachment_591" class="wp-caption aligncenter" style="width: 315px"><a href="http://weblog.destaquenet.com/wp-content/uploads/2009/07/test_suite_qunit1.png"><img class="size-full wp-image-591 " title="Primeira versão da suite de testes" src="http://weblog.destaquenet.com/wp-content/uploads/2009/07/test_suite_qunit1.png" alt="Primeira versão da suite de testes" width="305" height="314" /></a><p class="wp-caption-text">Primeira versão da suite de testes</p></div>
<p>O código desta suite de testes está <a href="http://weblog.destaquenet.com/wp-content/uploads/2009/07/qunit_testsuite.zip">disponível para download</a>.</p>
<h3>(Muitas) Limitações</h3>
<p>O primeiro teste, que verifica o funcionamento do literal <code>[]</code>, foi muito simples de implementar até porque não há praticamente nada a ser testado. Mas não fique feliz; no mundo real, as chances de seus testes serem assim tão simples são muito baixas.</p>
<p>Isso começa a ficar evidente à partir do segundo teste, onde é preciso apelar para o bom (?) e velho <code>for</code> para conferir o conteúdo do array, uma vez que QUnit não os suporta em comparações de igualdade.</p>
<p>Obviamente a mesma coisa também acontece no terceiro teste. E para mostrar que a a sitiuação só tende a piorar, ainda no terceiro teste temos um outro exemplo de asserção (tão feio quanto) que verifica  se todos os elementos do array estão num determinado intervalo.</p>
<p>Infelizmente, a &#8220;feiura&#8221; não é a única coisa que incomoda nesse código. Para ilustrar, suponha que o terceiro teste estivesse quebrado:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">test<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;Slice&quot;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #003366; font-weight: bold;">var</span> arr <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span><span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">2</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">3</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">4</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">5</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">6</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">7</span><span style="color: #009900;">&#93;</span>.<span style="color: #660066;">slice</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">2</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">5</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    equals<span style="color: #009900;">&#40;</span>arr.<span style="color: #660066;">length</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">3</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #006600; font-style: italic;">// ...</span>
&nbsp;
    <span style="color: #006600; font-style: italic;">// Another example of complex assertion</span>
    <span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> i <span style="color: #339933;">=</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;=</span> arr.<span style="color: #660066;">length</span><span style="color: #339933;">;</span> i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        ok<span style="color: #009900;">&#40;</span>arr<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span> <span style="color: #339933;">&gt;=</span> <span style="color: #CC0000;">3</span> <span style="color: #339933;">&amp;&amp;</span> arr<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span> <span style="color: #339933;">&lt;=</span> <span style="color: #CC0000;">5</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Como esperado, ao rodar os testes, o relatório mostra a ocorrência de um erro. O problema é que esse relatório faz um <em>péssimo</em> trabalho ao tentar mostrar o que de fato falhou:</p>
<div id="attachment_592" class="wp-caption aligncenter" style="width: 317px"><a href="http://weblog.destaquenet.com/wp-content/uploads/2009/07/test_suite_qunit_error1.png"><img class="size-full wp-image-592 " title="Relatório de erro não muito amigável" src="http://weblog.destaquenet.com/wp-content/uploads/2009/07/test_suite_qunit_error1.png" alt="Relatório de erro não muito amigável" width="307" height="248" /></a><p class="wp-caption-text">Relatório de erro não muito amigável</p></div>
<p>Uma forma de se amenizar este problema é passar um texto descritivo aos métodos <code>ok()</code> e <code>equals()</code>:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">ok<span style="color: #009900;">&#40;</span>num1 <span style="color: #339933;">&gt;=</span> <span style="color: #CC0000;">3</span> <span style="color: #339933;">&amp;&amp;</span> num1 <span style="color: #339933;">&lt;=</span> <span style="color: #CC0000;">5</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;Expected num1 between 3 and 5&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
equals<span style="color: #009900;">&#40;</span>num2<span style="color: #339933;">,</span> <span style="color: #CC0000;">10</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;Checking value of num2&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>O problema é que, ao fazer isso, passa a ser necessário um certo cuidado para manter os textos descritivos em sincronia com o código das asserções.</p>
<h4>Se QUnit é assim tão ruim&#8230;</h4>
<p>&#8230;por que não o trocar por outra coisa?</p>
<p>Apesar de existirem várias alternativas ao QUnit, nenhuma delas parece ser capaz de resolver problemas como os mostrados aqui. Portanto, trocar de <em>framework</em>, por enquanto, não é a solução.</p>
<p>Mas nem tudo está perdido.</p>
<h3>Viva melhor  com JsHamcrest</h3>
<p>O código mostrado anteriormente pode ser facilmente adaptado para usar JsHamcrest:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #006600; font-style: italic;">// Integrates JsHamcrest with QUnit</span>
JsHamcrest.<span style="color: #660066;">Integration</span>.<span style="color: #660066;">QUnit</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
$<span style="color: #009900;">&#40;</span>document<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">ready</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
    test<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;Literal&quot;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #003366; font-weight: bold;">var</span> arr <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
        assertThat<span style="color: #009900;">&#40;</span>arr<span style="color: #339933;">,</span> <span style="color: #000066; font-weight: bold;">instanceOf</span><span style="color: #009900;">&#40;</span>Array<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        assertThat<span style="color: #009900;">&#40;</span>arr<span style="color: #339933;">,</span> empty<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    test<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;Reverse&quot;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #003366; font-weight: bold;">var</span> arr <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span><span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">2</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">3</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">4</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">5</span><span style="color: #009900;">&#93;</span>.<span style="color: #660066;">reverse</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        assertThat<span style="color: #009900;">&#40;</span>arr<span style="color: #339933;">,</span> hasSize<span style="color: #009900;">&#40;</span><span style="color: #CC0000;">5</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        assertThat<span style="color: #009900;">&#40;</span>arr<span style="color: #339933;">,</span> equalTo<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#91;</span><span style="color: #CC0000;">5</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">4</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">3</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">2</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">1</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    test<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;Slice&quot;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #003366; font-weight: bold;">var</span> arr <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span><span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">2</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">3</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">4</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">5</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">6</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">7</span><span style="color: #009900;">&#93;</span>.<span style="color: #660066;">slice</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">2</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">5</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        assertThat<span style="color: #009900;">&#40;</span>arr<span style="color: #339933;">,</span> hasSize<span style="color: #009900;">&#40;</span><span style="color: #CC0000;">3</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        assertThat<span style="color: #009900;">&#40;</span>arr<span style="color: #339933;">,</span> equalTo<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#91;</span><span style="color: #CC0000;">3</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">4</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">5</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        assertThat<span style="color: #009900;">&#40;</span>arr<span style="color: #339933;">,</span> everyItem<span style="color: #009900;">&#40;</span>between<span style="color: #009900;">&#40;</span><span style="color: #CC0000;">3</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">and</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">5</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Gostou? <img src='http://weblog.destaquenet.com/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>A primeira coisa que salta aos olhos é a simplicidade do código. Basta uma olhada rápida para saber exatamente o que ele faz. Note que mesmo asserções mais complexas como as mostradas nos dois últimos testes são implementadas com facilidade.</p>
<p>O resultado:</p>
<div id="attachment_588" class="wp-caption aligncenter" style="width: 315px"><a href="http://weblog.destaquenet.com/wp-content/uploads/2009/07/test_suite_qunit_jshamcrest.png"><img class="size-full wp-image-588  " title="Relatório com dados detalhados das asserções" src="http://weblog.destaquenet.com/wp-content/uploads/2009/07/test_suite_qunit_jshamcrest.png" alt="Testes com dados detalhados das asserções" width="305" height="239" /></a><p class="wp-caption-text">Relatório com dados detalhados das asserções</p></div>
<p>O código desta suite de testes está <a href="http://weblog.destaquenet.com/wp-content/uploads/2009/07/qunit_jshamcrest_testsuite.zip">disponível para download</a>.</p>
<p>E não é só isso. Ao mesmo tempo em que temos um vocabulário <em>riquíssimo</em> de asserções, JsHamcrest também fornece informações detalhadas sobre as mesmas, numa linguagem fácil de entender. E isso tudo isso sem <em>nenhum</em> esforço!</p>
<p>Mais informações sobre a  API podem ser encontradas no pacote de documentação do projeto, também <a href="http://github.com/danielfm/jshamcrest/downloads">disponível para download</a>.</p>
<p>Mas, e quanto ao problema do relatório de erro? Vamos quebrar uma asserção e  ver o que acontece:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">test<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;Slice&quot;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #003366; font-weight: bold;">var</span> arr <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span><span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">2</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">3</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">4</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">5</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">6</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">7</span><span style="color: #009900;">&#93;</span>.<span style="color: #660066;">slice</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">2</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">5</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    assertThat<span style="color: #009900;">&#40;</span>arr<span style="color: #339933;">,</span> hasSize<span style="color: #009900;">&#40;</span><span style="color: #CC0000;">3</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    assertThat<span style="color: #009900;">&#40;</span>arr<span style="color: #339933;">,</span> equalTo<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#91;</span><span style="color: #CC0000;">3</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">4</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">5</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    assertThat<span style="color: #009900;">&#40;</span>arr<span style="color: #339933;">,</span> everyItem<span style="color: #009900;">&#40;</span>between<span style="color: #009900;">&#40;</span><span style="color: #CC0000;">3</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">and</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">4</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>O resultado:</p>
<div id="attachment_590" class="wp-caption aligncenter" style="width: 319px"><a href="http://weblog.destaquenet.com/wp-content/uploads/2009/07/test_suite_qunit_jshamcrest_error.png"><img class="size-full wp-image-590 " title="Mensagem de erro amigável" src="http://weblog.destaquenet.com/wp-content/uploads/2009/07/test_suite_qunit_jshamcrest_error.png" alt="Mensagem de erro amigável" width="309" height="202" /></a><p class="wp-caption-text">Mensagem de erro amigável</p></div>
<p>Muito melhor! Basta olhar a mensagem de erro para descobrir o que está errado.</p>
<h3>Posso usar JsHamcrest com outro <em>framework</em>?</h3>
<p>Atualmente, JsHamcrest integra com cinco <em>frameworks</em>: <a href="http://code.google.com/p/js-test-driver/">JsTestDriver</a>, <a href="http://jsunittest.com/">JsUnitTest</a>, <a href="http://jsunity.com/">jsUnity</a>, <a href="http://developer.yahoo.com/yui/yuitest/">YUITest</a> e QUnit.</p>
<p>Outra coisa legal é que integração feita pelo JsHamcrest leva em conta as convenções definidas pelo <em>framework</em> escolhido. Veja, por exemplo, como ficaria o código se tivéssemos optado pelo YUITest em vez do QUnit:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #006600; font-style: italic;">// Integrates JsHamcrest and YUITest</span>
JsHamcrest.<span style="color: #660066;">Integration</span>.<span style="color: #660066;">YUITest</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
YAHOO.<span style="color: #003366; font-weight: bold;">namespace</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;array&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
YAHOO.<span style="color: #660066;">array</span>.<span style="color: #660066;">TestCase</span> <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">new</span> YAHOO.<span style="color: #660066;">tool</span>.<span style="color: #660066;">TestCase</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span>
    <span style="color: #000066;">name</span> <span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Array tests&quot;</span><span style="color: #339933;">,</span>
&nbsp;
    testLiteral<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #003366; font-weight: bold;">var</span> arr <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
        Assert.<span style="color: #660066;">that</span><span style="color: #009900;">&#40;</span>arr<span style="color: #339933;">,</span> <span style="color: #000066; font-weight: bold;">instanceOf</span><span style="color: #009900;">&#40;</span>Array<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        Assert.<span style="color: #660066;">that</span><span style="color: #009900;">&#40;</span>arr<span style="color: #339933;">,</span> empty<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
&nbsp;
    testReverse<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #003366; font-weight: bold;">var</span> arr <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span><span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">2</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">3</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">4</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">5</span><span style="color: #009900;">&#93;</span>.<span style="color: #660066;">reverse</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        Assert.<span style="color: #660066;">that</span><span style="color: #009900;">&#40;</span>arr<span style="color: #339933;">,</span> hasSize<span style="color: #009900;">&#40;</span><span style="color: #CC0000;">5</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        Assert.<span style="color: #660066;">that</span><span style="color: #009900;">&#40;</span>arr<span style="color: #339933;">,</span> equalTo<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#91;</span><span style="color: #CC0000;">5</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">4</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">3</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">2</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">1</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
&nbsp;
    testSlice<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #003366; font-weight: bold;">var</span> arr <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span><span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">2</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">3</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">4</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">5</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">6</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">7</span><span style="color: #009900;">&#93;</span>.<span style="color: #660066;">slice</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">2</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">5</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        Assert.<span style="color: #660066;">that</span><span style="color: #009900;">&#40;</span>arr<span style="color: #339933;">,</span> hasSize<span style="color: #009900;">&#40;</span><span style="color: #CC0000;">3</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        Assert.<span style="color: #660066;">that</span><span style="color: #009900;">&#40;</span>arr<span style="color: #339933;">,</span> equalTo<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#91;</span><span style="color: #CC0000;">3</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">4</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">5</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        Assert.<span style="color: #660066;">that</span><span style="color: #009900;">&#40;</span>arr<span style="color: #339933;">,</span> everyItem<span style="color: #009900;">&#40;</span>between<span style="color: #009900;">&#40;</span><span style="color: #CC0000;">3</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">and</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">5</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<h4>Mas meu <em>framework</em> predileto não está nessa lista&#8230;</h4>
<p>JsHamcrest pode vir a suportar outros <em>frameworks</em> no futuro. Se seu <em>framework</em> predileto não está na lista dos atualmente suportados, entre em contato conosco.</p>
<h3>E aí, o que achou?</h3>
<p>Gostou? Odiou? Tem sugestões de melhorias? Gostaríamos muito de ouvir sua opinião!</p>
]]></content:encoded>
			<wfw:commentRss>http://weblog.destaquenet.com/2009/07/13/jshamcrest-um-alivio-a-dor-de-se-testar-codigo-javascript/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Fabric + VirtualEnv: uma combinação explosiva (no bom sentido)</title>
		<link>http://weblog.destaquenet.com/2009/07/01/fabric-virtualenv-uma-combinacao-explosiva-no-bom-sentido/</link>
		<comments>http://weblog.destaquenet.com/2009/07/01/fabric-virtualenv-uma-combinacao-explosiva-no-bom-sentido/#comments</comments>
		<pubDate>Wed, 01 Jul 2009 04:20:01 +0000</pubDate>
		<dc:creator>Daniel Martins</dc:creator>
				<category><![CDATA[Português]]></category>
		<category><![CDATA[Programação]]></category>
		<category><![CDATA[Tutoriais]]></category>
		<category><![CDATA[automatização]]></category>
		<category><![CDATA[debian]]></category>
		<category><![CDATA[django-flash]]></category>
		<category><![CDATA[fabric]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[pypi]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[setuptools]]></category>
		<category><![CDATA[teste]]></category>
		<category><![CDATA[ubuntu]]></category>
		<category><![CDATA[virtualenv]]></category>

		<guid isPermaLink="false">http://weblog.destaquenet.com/?p=554</guid>
		<description><![CDATA[Escreveu uma super-hiper-biblioteca ou aplicação em Python mas quer se certificar de que ela funciona em diferentes versões do interpretador? Embora isso possa ser resolvido através da execução manual dos testes com os vários interpretadores, isso é chato e improdutivo. &#8230; <a href="http://weblog.destaquenet.com/2009/07/01/fabric-virtualenv-uma-combinacao-explosiva-no-bom-sentido/">Continue lendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Escreveu uma super-hiper-biblioteca ou aplicação em <a href="http://python.org">Python</a> mas quer se certificar de que ela funciona em diferentes versões do interpretador? Embora isso possa ser resolvido através da execução <em>manual</em> dos testes com os vários interpretadores, isso é chato e improdutivo. Além do mais, cada versão do Python pode ter diferentes bibliotecas instaladas, o que pode acabar influenciando no resultado dos testes.</p>
<p>Temos portanto dois problemas a serem resolvidos. O primeiro problema, relacionado a automatização de tarefas repetitivas, pode ser facilmente solucionado com <a href="http://docs.fabfile.org/">Fabric</a>, uma ferramenta muito útil para criação de scripts de build e deployment de aplicações. Já escrevemos <a href="http://weblog.destaquenet.com/2008/10/05/deployment-de-aplicacoes-python-com-fabric/">um texto introdutório</a> sobre a mesma, não deixe de conferir.</p>
<p>O segundo problema, entretanto, é um pouco mais complicado de se resolver, mas não é nenhum bicho de sete cabeças. Com <a href="http://pypi.python.org/pypi/virtualenv/">VirtualEnv</a>, é possível criar ambientes Python isolados com o objetivo de testar e executar aplicações em uma espécie de sandbox onde temos total controle sobre as bibliotecas ali instaladas.</p>
<p><span id="more-554"></span></p>
<h3>Instalando as diferentes versões do Python</h3>
<p>O primeiro passo é instalar as versões do Python a serem usadas nos testes. Rode o comando abaixo para instalar os diferentes interpretadores, supondo que você utilize <a href="http://www.debian.org/">Debian</a> e sua aplicação precise funcionar nas versões 2.4, 2.5 e 2.6 do Python:</p>
<pre>$ sudo apt-get install python2.4 python2.4-dev \
    python2.5 python2.5-dev \
    python2.6 python2.6-dev</pre>
<p>A versão atual do Ubuntu já inclui o Python 2.6 por padrão. Veja também que aproveitamos para instalar os arquivos de desenvolvimento para cada versão, pois eventualmente precisamos deles para compilar bibliotecas com extensões escritas em C.</p>
<h3>Instalando Fabric e VirtualEnv</h3>
<p>Da mesma forma:</p>
<pre>$ sudo apt-get install python-setuptools</pre>
<p>Após a instalação do <a href="http://pypi.python.org/pypi/setuptools/">SetupTools</a>, execute o seguinte comando para instalar o Fabric e o VirtualEnv:</p>
<pre>$ sudo easy_install Fabric virtualenv</pre>
<h3>Configurando ambientes isolados para sua aplicação</h3>
<p>O próximo passo é criar ambientes de execução isolados para sua aplicação, sendo que cada ambiente deve usar uma versão diferente do interpretador do Python. Para fazer isso, execute os comandos abaixo, substituindo o <code>APP</code> pelo nome da sua aplicação ou biblioteca:</p>
<pre>$ mkdir ~/.virtualenvs
$ cd ~/.virtualenvs
$ virtualenv --python=/usr/bin/python2.6 --no-site-packages APP-py2.6
$ virtualenv --python=/usr/bin/python2.5 --no-site-packages APP-py2.5
$ virtualenv --python=/usr/bin/python2.4 --no-site-packages APP-py2.4</pre>
<p>Primeiramente criamos o diretório <code>~/.virtualenvs</code>, que é por convenção o diretório padrão para armazenamento dos ambientes. Em seguida, criamos três ambientes para nossa aplicação <code>APP</code>. A flag <code>--no-site-packages</code> é <em>opcional</em> e indica que as bibliotecas instaladas no diretório <code>site-packages</code> do Python em questão não devem ser visíveis ao ambiente sendo criado.</p>
<p>Finalmente, não esqueça de instalar, em cada um dos ambientes, as dependências exigidas pela sua aplicação:</p>
<pre>$ source ~/.virtualenvs/APP-py2.6/bin/activate
(APP-py2.6) $ easy_install biblioteca1 biblioteca2 ... bibliotecaN
(APP-py2.6) $ source ~/.virtualenvs/APP-py2.5/bin/activate
(APP-py2.5) $ easy_install biblioteca1 biblioteca2 ... bibliotecaN
(APP-py2.5) $ source ~/.virtualenvs/APP-py2.4/bin/activate
(APP-py2.4) $ easy_install biblioteca1 biblioteca2 ... bibliotecaN</pre>
<p>Supondo que sua aplicação utilize o SetupTools para a configuração dos metadados do projeto (através do script <code>setup.py</code>), os comandos abaixo devem indicar se a aplicação funciona nos ambientes que criamos:</p>
<pre>$ source ~/.virtualenvs/APP-py2.6/bin/activate
(APP-py2.6) $ python setup.py test
...
(APP-py2.6) $ source ~/.virtualenvs/APP-py2.5/bin/activate
(APP-py2.5) $ python setup.py test
...
(APP-py2.5) $ source ~/.virtualenvs/APP-py2.4/bin/activate
(APP-py2.4) $ python setup.py test
...</pre>
<h3>Automatizando!</h3>
<p>Se tudo funcionou até aqui, estamos prontos para criar um script que nos permita rodar os testes de forma automática, nos diferentes ambientes.</p>
<p>Supondo que sua aplicação utilize o SetupTools para a configuração dos metadados do projeto, o exemplo abaixo resolve o problema:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># -*- coding: utf-8 -*-</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Environment info</span>
config.<span style="color: black;">project</span> = <span style="color: #483d8b;">'APP'</span>
config.<span style="color: black;">virtualenv_dir</span> = <span style="color: #483d8b;">'~/.virtualenvs'</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Supported Python versions</span>
config.<span style="color: black;">versions</span> = <span style="color: black;">&#40;</span><span style="color: #483d8b;">'2.4'</span>, <span style="color: #483d8b;">'2.5'</span>, <span style="color: #483d8b;">'2.6'</span>,<span style="color: black;">&#41;</span>
config.<span style="color: black;">default_version</span> = <span style="color: #483d8b;">'2.6'</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> setup<span style="color: black;">&#40;</span>command, version=config.<span style="color: black;">default_version</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot;Executes the given setup command with a virtual Python installation.
    &quot;&quot;&quot;</span>
    local<span style="color: black;">&#40;</span><span style="color: #483d8b;">'%s/%s-py%s/bin/python setup.py %s'</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>config.<span style="color: black;">virtualenv_dir</span>, config.<span style="color: black;">project</span>, version, command<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #dc143c;">test</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot;Runs all tests in different Python versions.
    &quot;&quot;&quot;</span>
    <span style="color: #ff7700;font-weight:bold;">for</span> version <span style="color: #ff7700;font-weight:bold;">in</span> config.<span style="color: black;">versions</span>:
        setup<span style="color: black;">&#40;</span><span style="color: #483d8b;">'test'</span>, version<span style="color: black;">&#41;</span></pre></div></div>

<p>Agora é só alegria:</p>
<pre>$ fab test
Fabric v. 0.1.1.
Running test...
[localhost] run: ~/.virtualenvs/APP-py2.4/bin/python setup.py test
...
[localhost] run: ~/.virtualenvs/APP-py2.5/bin/python setup.py test
...
[localhost] run: ~/.virtualenvs/APP-py2.6/bin/python setup.py test
...</pre>
<p>Devo lembrar que o script mostrado é só um exemplo. Você pode (e <strong>deve</strong>) modificá-lo para que este atenda às suas necessidades.</p>
<h3>(Bônus!) Distribuindo sua aplicação para diferentes versões do Python</h3>
<p>Com mais algumas linhas de código, podemos criar tasks que nos permitam gerar arquivos para distribuição da aplicação para diferentes versões do Python:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> dist_src<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot;Create source archive.
    &quot;&quot;&quot;</span>
    setup<span style="color: black;">&#40;</span><span style="color: #483d8b;">'sdist'</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> dist_eggs<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot;Create binary archives, one for each Python version.
    &quot;&quot;&quot;</span>
    <span style="color: #ff7700;font-weight:bold;">for</span> version <span style="color: #ff7700;font-weight:bold;">in</span> config.<span style="color: black;">versions</span>:
        setup<span style="color: black;">&#40;</span><span style="color: #483d8b;">'bdist_egg'</span>, version<span style="color: black;">&#41;</span></pre></div></div>

<h3>(Bônus!) Automatizando geração de documentação e upload para o PyPI</h3>
<p>Ainda acha pouco? <a href="http://github.com/danielfm/django-flash/blob/master/fabfile.py">Este outro exemplo</a> de script vai além e mostra, numa aplicação real, como automatizar o registro e upload dos pacotes para o <a href="http://pypi.python.org/pypi/">PyPI</a>, atualizar site de documentação, entre outras coisas.</p>
]]></content:encoded>
			<wfw:commentRss>http://weblog.destaquenet.com/2009/07/01/fabric-virtualenv-uma-combinacao-explosiva-no-bom-sentido/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

