<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
 
 <title>Fabrício Tavares de Oliveira</title>
 <link href="http://fabriciotav.org/atom.xml" rel="self"/>
 <link href="http://fabriciotav.org/"/>
 <updated>2016-03-31T22:34:48+00:00</updated>
 <id>http://fabriciotav.org/</id>
 <author>
   <name>Fabrício Tavares de Oliveira</name>
   <email>fabriciotavareso@gmail.com</email>
 </author>

 
 <entry>
   <title>Lines of Code</title>
   <link href="http://fabriciotav.org/snippets/2013/10/29/lines-of-code.html"/>
   <updated>2013-10-29T00:00:00+00:00</updated>
   <id>http://fabriciotav.org/snippets/2013/10/29/lines-of-code</id>
   <content type="html">&lt;h1&gt;Lines of Code&lt;/h1&gt;

&lt;p&gt;Atualmente uso o seguinte para ver o tamanho dos meus projetos:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git ls-files | xargs cat | wc -l&lt;/code&gt;&lt;/pre&gt;
</content>
 </entry>
 
 <entry>
   <title>.mongorc.js</title>
   <link href="http://fabriciotav.org/snippets/2013/09/27/mongorcjs.html"/>
   <updated>2013-09-27T00:00:00+00:00</updated>
   <id>http://fabriciotav.org/snippets/2013/09/27/mongorcjs</id>
   <content type="html">&lt;h1&gt;.mongorc.js&lt;/h1&gt;

&lt;p&gt;Para não ter que ficar sempre digitando &lt;code&gt;db.collections.find().pretty()&lt;/code&gt; no mongo shell, basta criar o arquivo &lt;code&gt;$HOME/.mongorc.js&lt;/code&gt; e adicionar:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;javascript&quot;&gt;DBQuery.prototype._prettyShell = true&lt;/code&gt;&lt;/pre&gt;
</content>
 </entry>
 
 <entry>
   <title>Node dependency</title>
   <link href="http://fabriciotav.org/snippets/2013/09/05/node-dependency.html"/>
   <updated>2013-09-05T00:00:00+00:00</updated>
   <id>http://fabriciotav.org/snippets/2013/09/05/node-dependency</id>
   <content type="html">&lt;h1&gt;Node dependency&lt;/h1&gt;

&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;npm install dependency --save
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Instala a dependência e salva no arquivo &lt;code&gt;package.json&lt;/code&gt;.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Meetup - Visualização de Dados e d3.js</title>
   <link href="http://fabriciotav.org/blog/2013/09/04/meetup-visualizacao-de-dados-d3js.html"/>
   <updated>2013-09-04T00:00:00+00:00</updated>
   <id>http://fabriciotav.org/blog/2013/09/04/meetup-visualizacao-de-dados-d3js</id>
   <content type="html">&lt;h1&gt;Meetup - Visualização de Dados e d3.js&lt;/h1&gt;

&lt;hr&gt;

&lt;p&gt;Ontem, 3 de setembro de 2013, aconteceu o primeiro &lt;a href=&quot;http://www.meetup.com/d3js-BH/&quot;&gt;meetup sobre d3.js de Belo Horizonte&lt;/a&gt; (do Brasil?) e contou com a presença de onze pessoas. Fiquei bem satisfeito. Apesar do foco ser &lt;a href=&quot;http://d3js.org/&quot;&gt;d3.js&lt;/a&gt;, o objetivo do meetup foi reunir pessoas interessadas no lado mais técnico de visualização de dados.&lt;/p&gt;

&lt;p&gt;Foi bacana ver pessoas com formações diferentes interessadas no tema — algumas já trabalhando na área, outras querendo começar a trilhar esse caminho. Acredito que demos um pequeno passo para a construção de uma comunidade de visualização de dados no país.&lt;/p&gt;

&lt;h2&gt;Mas afinal, o que é um meetup?&lt;/h2&gt;

&lt;p&gt;Um meetup é um encontro local, organizado pelos participantes, que pode ter qualquer tópico como tema, onde um dos objetivos é compartilhar conhecimento.&lt;/p&gt;

&lt;p&gt;Participar de um meetup permite que se conheça, face a face, outras pessoas que tem interesses em comum. Foge um pouco da &amp;quot;frieza&amp;quot; de fóruns e grupos de discussão, além de permitir uma informalidade maior.&lt;/p&gt;

&lt;h2&gt;E agora?&lt;/h2&gt;

&lt;p&gt;Visualização de dados não é um campo novo ou &amp;quot;moderno&amp;quot;. No século XVIII William Playfair já criava visualizações.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://upload.wikimedia.org/wikipedia/commons/5/52/Playfair_TimeSeries-2.png&quot; alt=&quot;Playfair Time Series&quot;&gt;&lt;/p&gt;

&lt;hr&gt;

&lt;p&gt;Nos últimos três/quatro anos, entretanto, houve um crescimento exponencial na visibilidade e no número de pessoas dedicando ao estudo e à prática da criação de &amp;quot;gráficos bonitos&amp;quot;. Explodiu a quantidade de material disponível sobre o tema: de posts em blogs à livros publicados.&lt;/p&gt;

&lt;p&gt;Em português? Praticamente nada.&lt;/p&gt;

&lt;p&gt;O meetup é um bom ponto de partida para começar a movimentar um campo que, até o momento, anda meio desconhecido de brasileiros que, no fundo, &amp;quot;precisam&amp;quot; de visualização de dados no dia a dia.&lt;/p&gt;

&lt;p&gt;Espero poder contribuir, juntamente com os demais participantes do meetup &lt;a href=&quot;http://www.meetup.com/d3js-BH/&quot;&gt;d3js-BH&lt;/a&gt;, com o crescimento do uso de técnicas, conceitos e ferramentas que auxiliem a retirada de informação dessa massa cada vez maior de dados.&lt;/p&gt;

&lt;p&gt;Tem interesse em participar? &lt;a href=&quot;http://www.meetup.com/d3js-BH/&quot;&gt;Confere lá a data do próximo encontro!&lt;/a&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Podcast</title>
   <link href="http://fabriciotav.org/blog/2013/08/28/podcast.html"/>
   <updated>2013-08-28T00:00:00+00:00</updated>
   <id>http://fabriciotav.org/blog/2013/08/28/podcast</id>
   <content type="html">&lt;h1&gt;Podcast&lt;/h1&gt;

&lt;hr&gt;

&lt;p&gt;Vez ou outra, quando comento com amigos sobre algo que ouvi em algum podcast, a reação é quase sempre a mesma: &amp;quot;que que é isso? Podcast?!oO?&amp;quot;&lt;/p&gt;

&lt;h2&gt;O que é, afinal?&lt;/h2&gt;

&lt;p&gt;Podcasts são programas de áudio, frequentemente episódicos, distribuídos em formato mp3. Existem podcasts sobre os mais diversos assuntos, que variam tanto em &amp;quot;densidade&amp;quot; do conteúdo abordado, quanto em tempo; é comum encontrar podcasts de 2min à 2h. Quer aprender francês? Tem. Design? Tem também. Quer saber sobre baratas? Yep.&lt;/p&gt;

&lt;p&gt;Se quiser saber um pouco mais, confere na Wikipedia: &lt;a href=&quot;http://pt.wikipedia.org/wiki/Podcast&quot;&gt;Podcast&lt;/a&gt; e &lt;a href=&quot;http://pt.wikipedia.org/wiki/http://pt.wikipedia.org/wiki/Podcasting&quot;&gt;Podcasting&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;O que ouvir&lt;/h2&gt;

&lt;p&gt;Acredito que o tempo que gastamos em deslocamento, seja dentro de carro, ônibus ou a pé, deve ser melhor aproveitado. Alguns gostam de ouvir música no rádio, outros aproveitam pra ler (dor de cabeça, alguém?) ou cochilar. Eu não vejo forma melhor de valorizar essas horas do que ouvindo algum programa interessante, aprendendo algo novo, ou simplesmente dando risada.&lt;/p&gt;

&lt;p&gt;Ao longo do tempo fui descobrindo novos programas e abandonando outros tantos. Atualmente consigo preencher todo o tempo que gasto dentro do carro ouvindo à algum episódio. Abaixo segue a lista dos que, por enquanto, estão na estante (em ordem alfabética).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.brainstorm9.com.br/anticast/&quot; title=&quot;Anticast&quot;&gt;Anticast&lt;/a&gt; (pt)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.brainstorm9.com.br/braincast9/&quot; title=&quot;Braincast&quot;&gt;Braincast&lt;/a&gt; (pt)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://cbn.globoradio.globo.com/comentaristas/max-gehringer/MAX-GEHRINGER.htm&quot; title=&quot;CBN Max Gehringer&quot;&gt;CBN Max Gehringer&lt;/a&gt; (pt)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.cinemaemcena.com.br/plus/modulos/noticias/?cdcategoria=31&quot; title=&quot;Cinema em Cena&quot;&gt;Cinema em Cena&lt;/a&gt; (pt)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://radiolingua.com/shows/spanish/coffee-break-spanish/&quot; title=&quot;Coffee Break Spanish&quot;&gt;Coffee Break French&lt;/a&gt; (en)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://radiolingua.com/shows/spanish/coffee-break-spanish/&quot; title=&quot;Coffee Break Spanish&quot;&gt;Coffee Break Spanish&lt;/a&gt; (en)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://datastori.es/&quot; title=&quot;Data Stories&quot;&gt;Data Stories&lt;/a&gt; (en)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://carreirasolo.org/falafreela&quot; title=&quot;FalaFreela&quot;&gt;FalaFreela&lt;/a&gt; (pt)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://freakonomics.com/radio/&quot; title=&quot;Freakonomics Radio&quot;&gt;Freakonomics Radio&lt;/a&gt; (en)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://itunes.apple.com/us/podcast/history-in-five-minutes-podcast/id646702774&quot; title=&quot;History in Five Minutes&quot;&gt;History in Five Minutes&lt;/a&gt; (en)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.desiringgod.org/&quot; title=&quot;John Piper&quot;&gt;John Piper&lt;/a&gt; (en)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://jovemnerd.ig.com.br/categoria/nerdcast/&quot; title=&quot;Nerdcast&quot;&gt;Nerdcast&lt;/a&gt; (pt)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://blog.stackoverflow.com/category/podcasts/&quot; title=&quot;StackExchange&quot;&gt;StackExchange&lt;/a&gt; (en)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.stuffyoushouldknow.com/podcasts/&quot; title=&quot;Stuff You Should Know&quot;&gt;Stuff You Should Know&lt;/a&gt; (en)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Como acompanhar&lt;/h2&gt;

&lt;p&gt;É difícil, pra não dizer impossível, acompanhar tantos programas simplesmente acessando os sites, verificando se tem algo novo, e fazendo os downloads dos episódios. Então é comum a utilização de algum aplicativo, para celular ou PC, que faça a gestão dos podcasts. Quando tem algo novo, o aplicativo avisa e, dependendo da configuração, faz o download automaticamente.&lt;/p&gt;

&lt;p&gt;Ainda não estou satisfeito com o que tenho usado, mas atualmente uso o Podkicker (Android) e o RSSRadio (iOS) — o padrão da Apple para iPhone e iPod Touch, o &amp;quot;Podcasts&amp;quot;, trava demais.&lt;/p&gt;

&lt;hr&gt;

&lt;p&gt;Ouve algum podcast bacana, que não está na minha lista? Qual?&lt;/p&gt;

&lt;p&gt;Ah, se souber de aplicativos melhores do que os que eu citei, dá a dica!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Precompilando templates Handlebars para aplicações Ember.js</title>
   <link href="http://fabriciotav.org/blog/2013/05/31/precompilando-template-handlebars-para-aplicacoes-ember.html"/>
   <updated>2013-05-31T00:00:00+00:00</updated>
   <id>http://fabriciotav.org/blog/2013/05/31/precompilando-template-handlebars-para-aplicacoes-ember</id>
   <content type="html">&lt;h1&gt;Precompilando templates Handlebars para aplicações Ember.js&lt;/h1&gt;

&lt;hr&gt;

&lt;p&gt;O &lt;a href=&quot;http://emberjs.com/&quot; title=&quot;Ember.js&quot;&gt;Ember.js&lt;/a&gt; utiliza, como padrão, o &lt;a href=&quot;http://handlebarsjs.com/&quot; title=&quot;Handlebars.js&quot;&gt;Handlebars&lt;/a&gt; para 
especificações de templates JavaScript. É possível utilizar outras formas de 
templating client-side, mas perde-se uma infinidade de vantagens já existentes, 
como helpers e bindings.&lt;/p&gt;

&lt;p&gt;Quando o tamanho da aplicação não é maior do que alguns routes (diria algo em 
torno de 5), podemos facilmente lidar com todos os templates da seguinte forma:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;html&quot;&gt;&amp;lt;script type=&quot;text/x-handlebars&quot; data-template-name=&quot;application&quot;&amp;gt;
Esse é o template padrão.

{{ outlet }}
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

Ao integrar mais funcionalidades no Web App, consequentemente aumentando o número
de templates, esse modelo fica estremamente difícil de manter. Não é difícil 
chegar a mais de 100 templates em um Web App comercial.

Quando isso acontece, precisa-se de uma forma de manter a ordem, e uma saída 
interessante (diria obrigatória) é a precompilação dos templates que serão 
utilizados.
Dessa forma consegue-se separar cada template em um arquivo (criando uma estrutura
mais fácil de entender e manter), e aumenta-se a performance da aplicação, já 
que, quando requisitado, o template já estará pré-compilado.

Além disso, só é necessário colocar o runtime do Handlebars como dependência, que
na versão 1.0.0-rc.4 tem apenas 10kb (60kb a menos do que a versão com o compilador 
embutido).

Ok, mas como fazer?

Se você já está familiarizado com o [Node.js][nodejs], basta instalar o pacote
[em-hbs-precompiler][em-hbs-precompiler].

&lt;pre&gt;
  npm install -g em-hbs-precompiler
&lt;/pre&gt;

&lt;p&gt;A utilização é extremamente simples. Informa-se o diretório onde estão os 
templates, e o nome do arquivo que conterá os templates compilados.&lt;/p&gt;

&lt;pre&gt;
  precompilehbs -s diretorio/com/os/templates/ -o compilados.js
&lt;/pre&gt;

&lt;p&gt;Pronto. Agora todos seus templates estarão pré-compilados e com nome correto.&lt;/p&gt;

&lt;p&gt;Caso haja sub diretórios no seu diretório de templates, a nomeação será como padrão do 
Ember.js: &lt;strong&gt;resource&lt;/strong&gt; ou, em caso de templates em subdiretórios,
&lt;strong&gt;resource/route&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Dúvidas ou sugestões, coloque aí nos comentários!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Usando uma instância EC2 como git</title>
   <link href="http://fabriciotav.org/blog/2013/05/20/repositorio-git-na-amazon-ec2.html"/>
   <updated>2013-05-20T00:00:00+00:00</updated>
   <id>http://fabriciotav.org/blog/2013/05/20/repositorio-git-na-amazon-ec2</id>
   <content type="html">&lt;h1&gt;Usando uma instância EC2 como git&lt;/h1&gt;

&lt;hr&gt;

&lt;p&gt;Provavelmente você, assim como eu, já abandonou ftp e scp em favor de uma forma
bem mais eficiente e, porque não, elegante de subir arquivos para o servidor.&lt;/p&gt;

&lt;p&gt;Caso nunca tenha ouvido falar do &lt;a href=&quot;http://git-scm.com/&quot; title=&quot;Git&quot;&gt;Git&lt;/a&gt;, recomendo o &lt;a href=&quot;http://gitimmersion.com/&quot; title=&quot;Git Immersion&quot;&gt;Git Immersion&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Se você ainda está se acostumando ao &lt;a href=&quot;https://github.com/&quot; title=&quot;GitHub&quot;&gt;GitHub&lt;/a&gt; e ainda não possui uma conta
paga — o que permite respositórios privados, ou se simplesmente não precisa de 
muitos repositórios privados, acho interessante &lt;/p&gt;

&lt;h2&gt;Na Instância Amazon&lt;/h2&gt;

&lt;p&gt;Configurando o repositório na instância (usado e testado no Debian):&lt;/p&gt;

&lt;pre&gt;
mkdir project.git
cd project.git
git --bare init
&lt;/pre&gt;

&lt;p&gt;Caso apareça essa mensagem de erro:&lt;/p&gt;

&lt;pre&gt;
fatal: GIT_WORK_TREE (or --work-tree=&lt;directory&gt;) not allowed without specifying GIT_DIR (or --git-dir=&lt;directory&gt;)
&lt;/pre&gt;

&lt;p&gt;Basta checar algumas variáveis de ambiente:&lt;/p&gt;

&lt;pre&gt;
env|grep GIT
&lt;/pre&gt;

&lt;p&gt;e &amp;quot;unset&amp;quot; elas:&lt;/p&gt;

&lt;pre&gt;
unset GIT_WORK_TREE
&lt;/pre&gt;

&lt;p&gt;Onde &lt;code&gt;project.git&lt;/code&gt; é o nome do diretório do seu projeto.&lt;/p&gt;

&lt;p&gt;Crie um post-receive hook:&lt;/p&gt;

&lt;pre&gt;
cat &gt; hooks/post-receive
#!/bin/sh
GIT_WORK_TREE=/home/admin/git/ansee.git
export GIT_WORK_TREE
git checkout -f
&lt;/pre&gt;

&lt;h2&gt;Na máquina local&lt;/h2&gt;

&lt;p&gt;Adicione a chave pública que você usa para se conectar à instância EC2 para o path correto:&lt;/p&gt;

&lt;pre&gt;
ssh-add /path/da/sua/chave.pem 
&lt;/pre&gt;

&lt;p&gt;Crie o diretório local:&lt;/p&gt;

&lt;pre&gt;
mkdir project
cd project
git remote add origin ssh://admin@&lt;ip-da-instância&gt;/home/admin/project.git
&lt;/pre&gt;

&lt;p&gt;Para o primeiro commit, faça&lt;/p&gt;

&lt;pre&gt;
git push origin +master:refs/heads/master
&lt;/pre&gt;

&lt;p&gt;Para todos os outros:&lt;/p&gt;

&lt;pre&gt;
git push origin master
&lt;/pre&gt;

&lt;p&gt;Dúvidas? Só colocar nos comentários.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Ember.js snippets para Sublime Text 2</title>
   <link href="http://fabriciotav.org/blog/2013/03/25/emberjs-snippets.html"/>
   <updated>2013-03-25T00:00:00+00:00</updated>
   <id>http://fabriciotav.org/blog/2013/03/25/emberjs-snippets</id>
   <content type="html">&lt;h1&gt;Ember.js snippets para Sublime Text 2&lt;/h1&gt;

&lt;hr&gt;

&lt;p&gt;Considero o &lt;a href=&quot;http://www.sublimetext.com/2&quot; title=&quot;Sublime Text 2&quot;&gt;Sublime Text 2&lt;/a&gt; o melhor editor de texto atualmente para trabalhar 
com JavaScript e Python. Resolvi, então, disponibilizar os snippets de &lt;a href=&quot;http://fabriciotav.org/blog/2013/02/20/conceitos-basicos-do-emberjs.html&quot; title=&quot;Conceitos básicos do Ember.js&quot;&gt;Ember.js&lt;/a&gt; 
que utilizo atualmente como um plugin para o Sublime Text 2.&lt;/p&gt;

&lt;p&gt;No Mac OS, o atalho para instalação do plugin é &lt;code&gt;shift + command + p&lt;/code&gt;, depois 
&lt;code&gt;Package Control: Install Package&lt;/code&gt;, e aí é só buscar por &lt;code&gt;Ember.js Snippets&lt;/code&gt;. 
Se você ainda não tem o Package Control, você pode baixá-lo &lt;a href=&quot;http://wbond.net/sublime_packages/package_control&quot; title=&quot;Package Control&quot;&gt;aqui&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A lista dos snippets pode ser encontrada no repositório no &lt;a href=&quot;https://github.com/fabriciotav/ember-snippets-for-sublime-text-2&quot; title=&quot;GitHub: Ember.js snippets for Sublime Text 2&quot;&gt;GitHub&lt;/a&gt;. 
Se utiliza algum outro snippet com frequência, sinta-se livre para forkar o 
repositório!&lt;/p&gt;

&lt;p&gt;Dúvidas ou sugestões, coloque aí nos comentários!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Estrutura</title>
   <link href="http://fabriciotav.org/draft/2013/02/22/estrutura-dos-arquivos-de-um-emberjs-app.html"/>
   <updated>2013-02-22T00:00:00+00:00</updated>
   <id>http://fabriciotav.org/draft/2013/02/22/estrutura-dos-arquivos-de-um-emberjs-app</id>
   <content type="html">&lt;h1&gt;Estrutura&lt;/h1&gt;

&lt;hr&gt;
</content>
 </entry>
 
 <entry>
   <title>Convenções de Nomenclatura no Ember.js</title>
   <link href="http://fabriciotav.org/draft/2013/02/21/convencoes-de-nomenclatura-no-ember.html"/>
   <updated>2013-02-21T00:00:00+00:00</updated>
   <id>http://fabriciotav.org/draft/2013/02/21/convencoes-de-nomenclatura-no-ember</id>
   <content type="html">&lt;h1&gt;Convenções de Nomenclatura no Ember.js&lt;/h1&gt;

&lt;p&gt;Muito do que o Ember automaticamente faz por você depende dos nomes utilizados
para classes, objetos e &lt;em&gt;properties&lt;/em&gt;. Portanto, é fundamental conhecer a forma
que o Ember espera encontrar tais nomes. Vamos lá.&lt;/p&gt;

&lt;h2&gt;Classes&lt;/h2&gt;

&lt;p&gt;Todas as classes devem ser &lt;a href=&quot;http://en.wikipedia.org/wiki/CamelCase&quot;&gt;&lt;em&gt;CamelCase&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Routes&lt;/em&gt;, &lt;em&gt;views&lt;/em&gt; e &lt;em&gt;controllers&lt;/em&gt; devem ter essa especificação após o nome. Por 
exemplo, um &lt;em&gt;resource&lt;/em&gt; (existem &lt;em&gt;Routes&lt;/em&gt; do tipo &lt;em&gt;resource&lt;/em&gt; e do tipo &lt;em&gt;route&lt;/em&gt;) 
com nome &lt;code&gt;people&lt;/code&gt;, deve gerar:&lt;/p&gt;

&lt;pre class=&quot;prettyprint linenums&quot;&gt;
App.PeopleRoute = Ember.Route.extend({});
App.PeopleController = Ember.ObjectController.extend({});
// ou 
// App.PeopleController = Ember.ArrayController.extend({});
App.PeopleView = Ember.View.extend({});
&lt;/pre&gt;

&lt;p&gt;Um model com nome &lt;em&gt;people&lt;/em&gt; deve ser da seguinte forma:&lt;/p&gt;

&lt;pre class=&quot;prettyprint linenums&quot;&gt;
App.People = Ember.Object.extend({});
// ou, no caso do Ember Data
App.People = DS.Model.extend({});
&lt;/pre&gt;

&lt;p&gt;Mixins possuem nomes como os models.&lt;/p&gt;

&lt;h2&gt;Instâncias&lt;/h2&gt;

&lt;p&gt;O Ember cria automaticamente instâncias das classes na inicialização da
aplicação. Então não há necessidade de fazer algo como:&lt;/p&gt;

&lt;pre class=&quot;prettyprint linenums&quot;&gt;
App.PeopleView = Ember.View.create({});
&lt;/pre&gt;

&lt;p&gt;Nos casos em que seja necessário, os nomes devem ser &lt;a href=&quot;http://en.wikipedia.org/wiki/CamelBack&quot;&gt;&lt;em&gt;camelBack&lt;/em&gt;&lt;/a&gt;.
Como no exemplo abaixo.&lt;/p&gt;

&lt;pre class=&quot;prettyprint linenums&quot;&gt;
App.peopleView = Ember.View.create({});
&lt;/pre&gt;

&lt;h2&gt;Templates&lt;/h2&gt;

&lt;p&gt;Templates de resources, devem ter como nome o nome do resource. No caso de um
resource com nome &lt;code&gt;people&lt;/code&gt;:&lt;/p&gt;

&lt;pre class=&quot;prettyprint linenums&quot;&gt;
&amp;lt;script type=&quot;text/x-handlebars&quot; data-template-name=&quot;people&quot;&amp;gt;
&amp;lt;/script&amp;gt;
&lt;/pre&gt;

&lt;p&gt;Routes do tipo &lt;code&gt;route&lt;/code&gt; devem vir após o nome do resource &amp;quot;pai&amp;quot;, da seguinte
forma:&lt;/p&gt;

&lt;pre class=&quot;prettyprint linenums&quot;&gt;
// No caso do route padrão
&amp;lt;script type=&quot;text/x-handlebars&quot; data-template-name=&quot;people/index&quot;&amp;gt;
&amp;lt;/script&amp;gt;

// No caso de um route com nome `new`
&amp;lt;script type=&quot;text/x-handlebars&quot; data-template-name=&quot;people/new&quot;&amp;gt;
&amp;lt;/script&amp;gt;
&lt;/pre&gt;

&lt;h2&gt;Properties&lt;/h2&gt;

&lt;p&gt;Todas properties devem ser camelBack.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Handlebars Helpers com Ember.js</title>
   <link href="http://fabriciotav.org/blog/2013/02/20/handlebars-helpers-com-emberjs.html"/>
   <updated>2013-02-20T00:00:00+00:00</updated>
   <id>http://fabriciotav.org/blog/2013/02/20/handlebars-helpers-com-emberjs</id>
   <content type="html">&lt;h1&gt;Handlebars Helpers com Ember.js&lt;/h1&gt;

&lt;hr&gt;

&lt;p&gt;&lt;a href=&quot;http://handlebarsjs.com/&quot; title=&quot;Handlebars.js website&quot;&gt;Handlebars&lt;/a&gt; é um ótimo &lt;em&gt;template engine&lt;/em&gt; JavaScript construído 
sobre o &lt;a href=&quot;http://mustache.github.com/&quot; title=&quot;Mustache website&quot;&gt;Mustache&lt;/a&gt;. Se ainda não conhece, dá uma olhada no 
&lt;a href=&quot;http://handlebarsjs.com/&quot; title=&quot;Handlebars.js website&quot;&gt;site&lt;/a&gt;, dá pra ter uma noção bem bacana do que ele é capaz.&lt;/p&gt;

&lt;h2&gt;Criando um Helper&lt;/h2&gt;

&lt;hr&gt;

&lt;p&gt;Para criar um novo handlebar helper para, por exemplo, um botão de 
submit form, usa-se o seguinte:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;javascript&quot;&gt;Handlebars.registerHelper(&#39;submitButton&#39;, function(text) {
    return new Handlebars.SafeString(
        &#39;&amp;lt;button type=&quot;submit&quot;&amp;gt;&#39; + text + &#39;&amp;lt;/button&amp;gt;&#39;
    );
});
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Entretanto, às vezes é interessante usar um helper para algum tipo de 
formatação, como, por exemplo, centavos para real:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;javascript&quot;&gt;Handlebars.registerHelper(&#39;real&#39;, function(centavos) {
    var real = Math.floor(centavos / 100);

    return real;
});
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Template:
&lt;pre class=&quot;html&quot;&gt;&lt;code&gt;&amp;lt;div&amp;gt;
    R$ {{real totalCost}}
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;

&lt;p&gt;Saída HTML:
&lt;pre class=&quot;html&quot;&gt;&lt;code&gt;&amp;lt;div&amp;gt;
    R$ 150,43
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;

&lt;p&gt;Se o valor da variável &lt;code&gt;totalCost&lt;/code&gt; for alterado, o helper só imprimirá o novo 
valor se a página for recarregada. O que não é bem o que queremos quando 
estamos usando o Ember.js.&lt;/p&gt;

&lt;h2&gt;Criando um Bound Helper&lt;/h2&gt;

&lt;hr&gt;

&lt;p&gt;Em situações onde queremos que o helper seja chamado toda vez que o valor da 
variável for modificado, utilizamos o &lt;code&gt;Ember.Handlebars.registerBoundHelper&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;javascript&quot;&gt;Ember.Handlebars.registerBoundHelper(&#39;real&#39;, function(centavos) {
    var real = Math.floor(centavos / 100);

    return real;
});
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Dessa forma, sempre que o valor da variável alterar, o helper será chamado.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Conceitos básicos do Ember.js</title>
   <link href="http://fabriciotav.org/blog/2013/02/20/conceitos-basicos-do-emberjs.html"/>
   <updated>2013-02-20T00:00:00+00:00</updated>
   <id>http://fabriciotav.org/blog/2013/02/20/conceitos-basicos-do-emberjs</id>
   <content type="html">&lt;h1&gt;Conceitos básicos do Ember.js&lt;/h1&gt;

&lt;hr&gt;

&lt;p&gt;&lt;img src=&quot;/img/posts/emberjs/outdated.png&quot; alt=&quot;Post desatualizado&quot;&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Atenção!&lt;/strong&gt; Esse post está desatualizado, e utiliza a versão v.1.0.0-rc.1.&lt;/p&gt;

&lt;hr&gt;

&lt;p&gt;&lt;strong&gt;Obs. 1:&lt;/strong&gt; Esse post assume um conhecimento básico de JavaScript.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Obs. 2:&lt;/strong&gt; Decidi não traduzir vários termos em inglês para o português por serem
conceitos fundamentais ao Ember. Quando possível, utilizo de termos em português.
Entretanto, não se preocupe, pois todos os conceitos estão explicados. Qualquer dúvida
quanto a isso, coloque nos comentários.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Obs. 3:&lt;/strong&gt; Este não pretende ser um guia completo, apenas uma introdução. 
Trabalharei conceitos mais avançados em futuros posts.&lt;/p&gt;

&lt;h2&gt;O que é o Ember.js?&lt;/h2&gt;

&lt;hr&gt;

&lt;p&gt;Do próprio &lt;a href=&quot;http://emberjs.com/&quot; title=&quot;Ember.js Website&quot;&gt;site&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A framework for creating ambitious web applications.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Em uma tradução livre: Um framework para criação de grandes aplicações web.&lt;/p&gt;

&lt;p&gt;Vou falar sobre os conceitos básicos necessários para a criação de um micro
aplicativo (lista de pessoas e seus frameworks favoritos), que será construído ao longo do texto. A versão final está &lt;a href=&quot;http://bl.ocks.org/fabriciotav/raw/4980834/&quot;&gt;aqui&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Por quê utilizar o Ember?&lt;/h2&gt;

&lt;hr&gt;

&lt;p&gt;Se você já teve a experiência de criar uma página web, com várias requisições
ajax e modificações da interface de usuário, sabe que, em pouco tempo, o código
vira um espaguete. Extremamente complicado de manter, principalmente quando
há mais de uma pessoa trabalhando no projeto.&lt;/p&gt;

&lt;p&gt;Portanto, se há a necessidade de ações CRUD - &lt;em&gt;create&lt;/em&gt; (criar), &lt;em&gt;read&lt;/em&gt; (ler), &lt;em&gt;update&lt;/em&gt;
(alterar) e &lt;em&gt;delete&lt;/em&gt; (remover) - na página, e você deseja melhorar a performance,
evitando recarregamento a cada ação, o padrão de arquitetura 
&lt;abbr title=&quot;Model View Controller&quot;&gt;MVC&lt;/abbr&gt;, adotado pelo Ember, vai 
facilitar sua vida.&lt;/p&gt;

&lt;p&gt;É claro que é possível ter código bem estruturado sem a utilização de um
framework. Entretanto, quando a sua base de código começar a crescer e crescer,
e quando começar projetos novos, vai perceber que estará escrevendo as
mesmas funções para cada uma das aplicações.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&amp;quot;Trivial choices are the enemy&amp;quot; - &lt;a href=&quot;http://twitter.com/wycats/&quot;&gt;Yehuda Katz&lt;/a&gt;, Ember Core Team&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ember se apóia bastante no paradigma &lt;em&gt;convention over configuration&lt;/em&gt;.
Quase sempre o que é necessário para a aplicação será gerado automaticamente, em
memória, sem precisar, explicitamente, instanciar classe alguma.&lt;/p&gt;

&lt;p&gt;Isso não significa que não seja possível configurá-lo para ficar exatamente da
forma como te agrada. Apenas elimina as decisões triviais que toda aplicação
requer ao longo do seu desenvolvimento.&lt;/p&gt;

&lt;h2&gt;Padrão de arquitetura &lt;abbr title=&quot;Model View Controller&quot;&gt;MVC&lt;/abbr&gt;&lt;/h2&gt;

&lt;hr&gt;

&lt;p&gt;MVC significa Model View Controller. Não vou entrar em detalhes sobre a história
desse padrão, nem sua evolução ao longo dos anos. Falarei apenas dos conceitos
necessários para entender e construir uma aplicação com Ember.&lt;/p&gt;

&lt;p&gt;MVC no Ember é como MVC em aplicações desktop. Portanto, se você já utiliza 
algum framework MVC no servidor, como Django, Zend ou Ruby on Rails, deixe de 
lado por um momento os conceitos que você já sabe.&lt;/p&gt;

&lt;h2&gt;Application&lt;/h2&gt;

&lt;hr&gt;

&lt;p&gt;Para criar uma aplicação, primeiramente é necessário instanciar a classe 
&lt;code&gt;Ember.Application&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;javascript&quot;&gt;window.App = Ember.Application.create();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;App&lt;/code&gt; será o &lt;em&gt;namespace&lt;/em&gt; do aplicativo. Aqui usei a palavra App, mas pode ser
qualquer outra. A convenção é que o nome comece com letra maiúscula.&lt;/p&gt;

&lt;p&gt;Todas as classes serão instanciadas sob esse namespace.&lt;/p&gt;

&lt;h2&gt;Templates&lt;/h2&gt;

&lt;hr&gt;

&lt;p&gt;Toda a interface de usuário residirá nos templates. O Ember utiliza, por padrão,
o &lt;a href=&quot;http://handlebarsjs.com/&quot;&gt;Handlebars&lt;/a&gt;. É possível utilizar outro template, mas, a não ser
que você saiba bem o que está fazendo, não recomendo. Ganhamos várias coisas
ao utilizar o Handlebars, sem precisar preocupar com coisas triviais.&lt;/p&gt;

&lt;p&gt;O template default do aplicativo é chamado &lt;code&gt;application&lt;/code&gt;, e é criado da
seguinte forma:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;html&quot;&gt;&amp;lt;script type=&quot;text/x-handlebars&quot; data-template-name=&quot;application&quot;&amp;gt;
Esse é o template padrão.

{{ outlet }}
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Esse é o &lt;a href=&quot;http://bl.ocks.org/fabriciotav/4988275/&quot;&gt;menor aplicativo possível&lt;/a&gt;, criado com Ember. Muita 
coisa está acontecendo nos &amp;quot;bastidores&amp;quot;. Vejamos:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;o aplicativo é inicializado;&lt;/li&gt;
&lt;li&gt;o template &lt;code&gt;application&lt;/code&gt; é renderizado;&lt;/li&gt;
&lt;li&gt;automaticamente é criado um route, que reflete o estado do
aplicativo na URL.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;O &lt;code&gt;{{ outlet }}&lt;/code&gt; serve como um espaço reservado para outros 
templates.&lt;/p&gt;

&lt;p&gt;Ao estender o controller abaixo, tornamos disponível alguns dados para o
template &lt;code&gt;application&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;javascript&quot;&gt;App.ApplicationController = Ember.ObjectController.extend({
    nome: &#39;Eddard&#39;,
    sobrenome: &#39;Stark&#39;
});
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&quot;html&quot;&gt;&amp;lt;script type=&quot;text/x-handlebars&quot; data-template-name=&quot;application&quot;&amp;gt;
Olá, {{ nome }} {{ sobrenome }}!

{{ outlet }}
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;O resultado HTML será:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;html&quot;&gt;&amp;lt;div id=&quot;ember151&quot; class=&quot;ember-view&quot;&amp;gt;
    Olá, Eddard Stark!
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Não se preocupe com os atributos HTML &lt;code&gt;id&lt;/code&gt; e &lt;code&gt;class&lt;/code&gt; por enquanto.&lt;/p&gt;

&lt;h2&gt;Router&lt;/h2&gt;

&lt;hr&gt;

&lt;p&gt;O router é responsável pela manutenção do &lt;a href=&quot;http://pt.wikipedia.org/wiki/M%C3%A1quina_de_estados_finitos/&quot;&gt;estado&lt;/a&gt;
do aplicativo. Como estamos construindo um aplicativo web, que roda em um
navegador, seria ótimo se o estado ativo fosse refletido na URL.&lt;/p&gt;

&lt;p&gt;Bem, o Ember faz isso automaticamente.&lt;/p&gt;

&lt;p&gt;Vamos criar uma nova rota para listar as pessoas do nosso app.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;javascript&quot;&gt;App.Router.map(function(){
    this.resource(&#39;people&#39;);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&quot;html&quot;&gt;&amp;lt;script type=&quot;text/x-handlebars&quot; data-template-name=&quot;people&quot;&amp;gt;
&amp;lt;h1&amp;gt;Pessoas&amp;lt;/h1&amp;gt;
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Isso criará automaticamente a seguinte URL:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;http&quot;&gt;&lt;span class=&quot;request&quot;&gt;&lt;span class=&quot;string&quot;&gt;http://dominio.com/#/people&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    

&lt;p&gt;Ao ser acessada, o template &lt;code&gt;people&lt;/code&gt; será renderizado e adicionado no outlet 
do template &lt;code&gt;application&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Além da manutenção dos estados, o router é também responsável por atribuir
aos controllers a representação de um ou mais models, e lidar com eventos.&lt;/p&gt;

&lt;h3&gt;Resources e routes&lt;/h3&gt;

&lt;p&gt;Há duas formas de se criar um novo route:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;javascript&quot;&gt;App.Router.map(function(){
    // Cria um route e um novo namespace
    this.resource(&#39;people&#39;);

    // Cria um route no namespace que o route está aninhado
    this.route(&#39;new&#39;);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Ao criar um novo &lt;em&gt;resource&lt;/em&gt;, será criado também um novo namespace; quando
é criado um &lt;em&gt;route&lt;/em&gt;, o namespace é o do route &amp;quot;pai&amp;quot;. Isso vai afetar a forma
como se declara os nomes dos controllers, views e templates. Ao criar os routes 
como no código acima, temos o seguinte:&lt;/p&gt;

&lt;table class=&quot;table&quot;&gt;
    &lt;thead&gt;
        &lt;tr&gt;
            &lt;th&gt;URL&lt;/th&gt;
            &lt;th&gt;Nome do route&lt;/th&gt;
            &lt;th&gt;Controller&lt;/th&gt;
            &lt;th&gt;Route&lt;/th&gt;
            &lt;th&gt;Template&lt;/th&gt;
        &lt;/tr&gt;
    &lt;/thead&gt;
    &lt;tbody&gt;
        &lt;tr&gt;
            &lt;td&gt;&lt;code&gt;/&lt;/code&gt;&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;index&lt;/code&gt;&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;App.IndexController&lt;/code&gt;&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;App.IndexRoute&lt;/code&gt;&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;index&lt;/code&gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;&lt;code&gt;/people&lt;/code&gt;&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;people&lt;/code&gt;&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;App.PeopleController&lt;/code&gt;&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;App.PeopleRoute&lt;/code&gt;&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;people&lt;/code&gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;&lt;code&gt;/new&lt;/code&gt;&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;new&lt;/code&gt;&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;App.NewController&lt;/code&gt;&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;App.NewRoute&lt;/code&gt;&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;new&lt;/code&gt;&lt;/td&gt;
        &lt;/tr&gt;
    &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;A medida que a complexidade da aplicação aumenta, será necessário ter routes 
aninhados. Eles podem ser criados da seguinte forma:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;javascript&quot;&gt;App.Router.map(function(){
    this.resource(&#39;people&#39;, function() {
        this.route(&#39;new&#39;);
    });
});
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;E os nomes ficam assim:&lt;/p&gt;

&lt;table class=&quot;table&quot;&gt;
    &lt;thead&gt;
        &lt;tr&gt;
            &lt;th&gt;URL&lt;/th&gt;
            &lt;th&gt;Nome do route&lt;/th&gt;
            &lt;th&gt;Controller&lt;/th&gt;
            &lt;th&gt;Route&lt;/th&gt;
            &lt;th&gt;Template&lt;/th&gt;
        &lt;/tr&gt;
    &lt;/thead&gt;
    &lt;tbody&gt;
        &lt;tr&gt;
            &lt;td&gt;&lt;code&gt;/&lt;/code&gt;&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;index&lt;/code&gt;&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;App.IndexController&lt;/code&gt;&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;App.IndexRoute&lt;/code&gt;&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;index&lt;/code&gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;N/A&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;people&lt;/code&gt;&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;App.PeopleController&lt;/code&gt;&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;App.PeopleRoute&lt;/code&gt;&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;people&lt;/code&gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;&lt;code&gt;/people&lt;/code&gt;&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;people.index&lt;/code&gt;&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;App.PeopleIndexController&lt;/code&gt;&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;App.PeopleIndexRoute&lt;/code&gt;&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;people/index&lt;/code&gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;&lt;code&gt;/people/new&lt;/code&gt;&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;people.new&lt;/code&gt;&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;App.PeopleNewController&lt;/code&gt;&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;App.PeopleNewRoute&lt;/code&gt;&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;people/new&lt;/code&gt;&lt;/td&gt;
        &lt;/tr&gt;
    &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Veja que, ao aninhar o route &lt;code&gt;new&lt;/code&gt; ao resource &lt;code&gt;people&lt;/code&gt;, automaticamente
foi criado um novo route, o &lt;code&gt;index&lt;/code&gt;. Todo resource que tiver routes 
aninhados, terá um route index.&lt;/p&gt;

&lt;h3&gt;Dynamic segments&lt;/h3&gt;

&lt;p&gt;Ao acessar um determinado estado da aplicação a partir de uma URL, o route 
utiliza a informação da URL para determinar o model correspondente, e carregar
esse model para o controller.&lt;/p&gt;

&lt;p&gt;A versão final do router do nosso aplicativo será:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;javascript&quot;&gt;App.Router.map(function(){
    this.resource(&quot;people&quot;, function() {
        this.resource(&#39;person&#39;, { path: &#39;:person_id&#39; });
        this.route(&#39;new&#39;);
    });
});
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Repare que o valor da property &lt;code&gt;path&lt;/code&gt;, no resource person, possui um &lt;code&gt;:&lt;/code&gt;, 
seguido do nome do resource junto com um &lt;code&gt;_id&lt;/code&gt;. Isso faz com que, ao acessar a 
URL &lt;code&gt;/people/3&lt;/code&gt;, o router automaticamente busque pelo model &lt;code&gt;App.Person&lt;/code&gt; com id 
3.&lt;/p&gt;

&lt;p&gt;Caso haja interesse em ter uma URL com nome diferente do nome do route, como,
por exemplo, o nome &amp;quot;pessoas&amp;quot; para o route &lt;code&gt;people&lt;/code&gt;, é só adicionar o valor à 
property &lt;code&gt;path&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;javascript&quot;&gt;App.Router.map(function(){
    this.resource(&quot;people&quot;, { path: &#39;/pessoas&#39; }function() {
        this.resource(&#39;person&#39;, { path: &#39;:person_id&#39; });
        this.route(&#39;new&#39;);
    });
});
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Os nomes ficam assim:&lt;/p&gt;

&lt;table class=&quot;table&quot;&gt;
    &lt;thead&gt;
        &lt;tr&gt;
            &lt;th&gt;URL&lt;/th&gt;
            &lt;th&gt;Nome do route&lt;/th&gt;
            &lt;th&gt;Controller&lt;/th&gt;
            &lt;th&gt;Route&lt;/th&gt;
            &lt;th&gt;Template&lt;/th&gt;
        &lt;/tr&gt;
    &lt;/thead&gt;
    &lt;tbody&gt;
        &lt;tr&gt;
            &lt;td&gt;&lt;code&gt;/&lt;/code&gt;&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;index&lt;/code&gt;&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;App.IndexController&lt;/code&gt;&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;App.IndexRoute&lt;/code&gt;&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;index&lt;/code&gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;N/A&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;people&lt;/code&gt;&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;App.PeopleController&lt;/code&gt;&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;App.PeopleRoute&lt;/code&gt;&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;people&lt;/code&gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;&lt;code&gt;/people&lt;/code&gt;&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;people.index&lt;/code&gt;&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;App.PeopleIndexController&lt;/code&gt;&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;App.PeopleIndexRoute&lt;/code&gt;&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;people/index&lt;/code&gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;&lt;code&gt;/people/:id&lt;/code&gt;&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;person&lt;/code&gt;&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;App.PersonController&lt;/code&gt;&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;App.PersonRoute&lt;/code&gt;&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;person&lt;/code&gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;&lt;code&gt;/people/new&lt;/code&gt;&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;people.new&lt;/code&gt;&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;App.PeopleNewController&lt;/code&gt;&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;App.PeopleNewRoute&lt;/code&gt;&lt;/td&gt;
            &lt;td&gt;&lt;code&gt;people/new&lt;/code&gt;&lt;/td&gt;
        &lt;/tr&gt;
    &lt;/tbody&gt;
&lt;/table&gt;

&lt;h2&gt;Models&lt;/h2&gt;

&lt;hr&gt;

&lt;p&gt;Os models são responsáveis pelo controle dos dados da aplicação. São
completamente independentes da interface do usuário, apesar de serem
requisitados por ela. Ao sofrer atualização, o model notifica os &lt;em&gt;observers&lt;/em&gt;,
que traduz isso para a &lt;abbr title=&quot;User Interface&quot;&gt;UI&lt;/abbr&gt;.&lt;/p&gt;

&lt;p&gt;No Ember, os models são javascript objects ligeiramente modificados (para 
suportar &lt;em&gt;bindings&lt;/em&gt; e outras funcionalidades).&lt;/p&gt;

&lt;h3&gt;Definindo um &lt;em&gt;Model&lt;/em&gt;&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&quot;javascript&quot;&gt;App.Person = DS.Model.extend({
    firstName: DS.attr(&#39;string&#39;),
    lastName: DS.attr(&#39;string&#39;),
    fullName: function() {
        return this.get(&#39;firstName&#39;) + &#39; &#39; + this.get(&#39;lastName&#39;);
    }.property(&#39;firstName&#39;, &#39;lastName&#39;)
});
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Estou utilizando o Ember Data, uma biblioteca responsável por carregar
dados do servidor, fazer alterações no navegador, e salvar as alterações de 
volta ao servidor. Esta biblioteca ainda não está mesclada ao Ember, mas o será 
em breve.&lt;/p&gt;

&lt;p&gt;As properties &lt;code&gt;firstName&lt;/code&gt; e &lt;code&gt;lastName&lt;/code&gt; são carregadas diretamente do servidor 
através de alguma &lt;a href=&quot;http://fabriciotav.org/&quot;&gt;REST API&lt;/a&gt;, e serão persistidas ao 
servidor após as alterações. A property &lt;code&gt;fullName&lt;/code&gt; é uma &lt;em&gt;computed property&lt;/em&gt;, 
que tem seu valor determinado a partir de alguma função. No código acima,
ela é composta do nome e sobrenome (firstName e lastName).&lt;/p&gt;

&lt;p&gt;Toda vez que qualquer uma das properties do model &lt;code&gt;App.Person&lt;/code&gt; for alterada, 
a computed property também será.&lt;/p&gt;

&lt;h3&gt;Definindo uma &lt;em&gt;Store&lt;/em&gt;&lt;/h3&gt;

&lt;p&gt;A &lt;em&gt;Store&lt;/em&gt; é o repositório que contém todos os models já carregados, além 
de ser responsável pelo carregamento dos models que ainda não foram 
carregados.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;javascript&quot;&gt;App.Store = DS.Store.extend({
    revision: 11,
    adapter: DS.RESTAdapter.create();
});
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A property &lt;code&gt;revision&lt;/code&gt; é o número de revisão da API, utilizada para a
notificação de alterações que podem quebrar código já existente. O &lt;code&gt;adapter&lt;/code&gt; 
é responsável pela comunicação com o servidor.&lt;/p&gt;

&lt;p&gt;O Ember Data possui dois adapters padrões: &lt;code&gt;DS.FixtureAdapter&lt;/code&gt; e o &lt;code&gt;DS.RESTAdapter&lt;/code&gt;. 
O primeiro é utilizado para dados &lt;em&gt;hard coded&lt;/em&gt; (extremamente útil para prototipagem 
de uma aplicação, já que independe do backend), enquanto que o segundo é usado 
quando se tem um servidor REST.&lt;/p&gt;

&lt;p&gt;Para esse aplicativo, vamos usar uma REST API criada em node.js, que persiste os 
dados apenas no processo. Essa REST API possui apenas um resource:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;http&quot;&gt;
&lt;span class=&quot;request&quot;&gt;GET &lt;span class=&quot;string&quot;&gt;http://api.dadospublicos.org/people&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;request&quot;&gt;GET &lt;span class=&quot;string&quot;&gt;http://api.dadospublicos.org/people/:id&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;request&quot;&gt;POST &lt;span class=&quot;string&quot;&gt;http://api.dadospublicos.org/people&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;request&quot;&gt;DELETE &lt;span class=&quot;string&quot;&gt;http://api.dadospublicos.org/people/:id&lt;/span&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Para utilizá-la na aplicação, vamos configurar a sua url no adapter.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;javascript&quot;&gt;App.RESTSerializer = DS.RESTSerializer.extend({
    init: function() {
        this._super();

        this.map(&#39;App.Person&#39;, {
            frameworks: {embedded: &#39;always&#39;}
        });

        this.configure(&#39;plurals&#39;, {
            person: &#39;people&#39;
        });
    }
});

App.RESTAdapter = DS.RESTAdapter.extend({
    url: &#39;http://api.dadospublicos.org&#39;,
    bulkCommit: false,
    serializer: App.RESTSerializer.create()
});

App.Store = DS.Store.extend({
    revision: 11,
    adapter: App.RESTAdapter.create();
});
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Controllers&lt;/h2&gt;

&lt;hr&gt;

&lt;p&gt;Um controller é responsável por representar um model para um template e por
armazenar properties que não serão salvas no servidor.&lt;/p&gt;

&lt;p&gt;Para representar um único model, utiliza-se o &lt;code&gt;Ember.ObjectController&lt;/code&gt;. Quando
é necessário representar uma matriz (array) de models, utiliza-se o 
&lt;code&gt;Ember.ArrayController&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;É no route que se determina qual será o model que será representado no 
controller. Para carregar o model &lt;code&gt;App.Person&lt;/code&gt; no controller &lt;code&gt;App.PersonController&lt;/code&gt;,
utilizamos a property &lt;code&gt;model&lt;/code&gt;, como mostrado abaixo.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;javascript&quot;&gt;App.PeopleRoute = Ember.Route.extend({
    model: function() {
        return App.Person.find();
    }
});
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Adicionar pessoa à lista&lt;/h3&gt;

&lt;p&gt;O controller &lt;code&gt;App.PeopleNewController&lt;/code&gt; será o responsável por adicionar novas
pessoas à lista. Precisamos, então, configurar seu model. Como o route &lt;code&gt;people.new&lt;/code&gt;
é para a criação de uma nova pessoa, não há model algum sendo carregado.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;javascript&quot;&gt;App.PeopleNewRoute = Ember.Route.extend({
    model: function() {
        // Model vazio
        return null;
    },

    setupController: function(controller) {
        controller.startEditing();
    },

    exit: function() {
        this._super();
        this.controllerFor(&#39;people.new&#39;).stopEditing();
    }
});
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Toda a manipulação do model é feita no controller.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;javascript&quot;&gt;App.PeopleNewController = Ember.ObjectController.extend({
    startEditing: function() {
        this.transaction = this.get(&#39;store&#39;).transaction();
        this.set(&#39;content&#39;, this.transaction.createRecord(App.Person, {}));
    },

    stopEditing: function() {
        if (this.transaction) {
            this.transaction.rollback();
            this.transaction = null;
        }
    },

    save: function() {
        console.log( &quot;return&quot;, this.validate() );
        if (this.validate()) {
            this.transaction.commit();
            this.transaction = null;
        } else {
            alert(&#39;Nome inválido&#39;);
        }
    },

    validate: function() {
        var firstName, regex;

        regex = /^[A-ZÄÁÀËÉÈÍÌÖÓÒÚÙÑÇa-zäáàëéèíìöóòúùñç][A-ZÄÁÀËÉÈÍÌÖÓÒÚÙÑÇa-zäáàëéèíìöóòúùñç ]{1,70}[A-ZÄÁÀËÉÈÍÌÖÓÒÚÙÑÇa-zäáàëéèíìöóòúùñç]$/;
        firstName = this.get(&#39;content&#39;).get(&#39;firstName&#39;);
        firstNameOk = regex.exec(firstName);

        if (firstNameOk) {
            return true;
        } else {
            return false;
        }
    },

    transitionAfterSave: function() {
        if (this.get(&#39;content.id&#39;)) {
            this.transitionToRoute(&#39;people.index&#39;);
        }
    }.observes(&#39;content.id&#39;),

    cancel: function() {
        this.stopEditing();
        this.transitionToRoute(&#39;people.index&#39;);
    },

    addFramework: function() {
        this.get(&#39;content.frameworks&#39;).createRecord();
    },

    removeFramework: function(framework) {
        framework.deleteRecord();
    }
});
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;E no template temos:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;html&quot;&gt;
&amp;lt;script type=&quot;text/x-handlebars&quot; data-template-name=&quot;people/new&quot;&amp;gt;
&amp;lt;form {{action save on=&quot;submit&quot;}}&amp;gt;

&amp;lt;div&amp;gt;
    {{view Ember.TextField placeholder=&quot;nome&quot; valueBinding=&quot;firstName&quot;}}
    {{nameValidation firstName}}
&amp;lt;/div&amp;gt;
&amp;lt;div&amp;gt;
    {{ view Ember.TextField placeholder=&quot;sobrenome&quot; valueBinding=&quot;lastName&quot;}}
&amp;lt;/div&amp;gt;
&amp;lt;div&amp;gt;
    {{ view Ember.TextField placeholder=&quot;twitter&quot; valueBinding=&quot;twitter&quot;}}
&amp;lt;/div&amp;gt;

{{#each frameworks}}
    &amp;lt;div&amp;gt;
        {{view Ember.TextField placeholder=&quot;framework&quot; valueBinding=&quot;name&quot;}}
        &amp;lt;button {{action removeFramework this}}&amp;gt;-&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
{{/each}}

&amp;lt;div&amp;gt;&amp;lt;button {{action addFramework}}&amp;gt;Adicionar framework&amp;lt;/button&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;div&amp;gt;
    {{submitButton &quot;Salvar&quot;}}
    &amp;lt;button {{action &quot;cancel&quot;}}&amp;gt;Cancelar&amp;lt;/button&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/form&amp;gt;
&amp;lt;/script&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Views&lt;/h2&gt;

&lt;hr&gt;

&lt;p&gt;A responsabilidade da view é traduzir os eventos primitivos do navegador,
e.g. click, key press, em eventos que tenham algum significado para a sua 
aplicação.&lt;/p&gt;

&lt;p&gt;As views são utilizadas quando há necessidade de componentes reutilizáveis,
como inputs, e.g. &lt;code&gt;Ember.TextField&lt;/code&gt;, ou quando há eventos complexos.&lt;/p&gt;

&lt;p&gt;No nosso aplicativo, não precisamos alterar comportamento de view
alguma. Apesar disso, as seguintes views foram geradas automaticamente:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;javascript&quot;&gt;App.ApplicationView = Ember.View.extend();
App.PeopleView = Ember.View.extend();
App.PeopleIndexView = Ember.View.extend();
App.PeopleNewView = Ember.View.extend();
App.PersonView = Ember.View.extend();
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Juntando tudo&lt;/h2&gt;

&lt;hr&gt;

&lt;p&gt;Todo o código pode ser baixado &lt;a href=&quot;https://gist.github.com/fabriciotav/4980834/download&quot;&gt;aqui&lt;/a&gt; e o app pode ser visto 
&lt;a href=&quot;http://bl.ocks.org/fabriciotav/raw/4980834/&quot;&gt;aqui&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Coisas importantes que não foram vistas aqui&lt;/h2&gt;

&lt;hr&gt;

&lt;p&gt;Existem várias áreas extremamente importantes para o desenvolvimento de um 
aplicativo web, como:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;depuração de erros;&lt;/li&gt;
&lt;li&gt;testes;&lt;/li&gt;
&lt;li&gt;organização de arquivos;&lt;/li&gt;
&lt;li&gt;implementação em servidores.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;O objetivo desse post é somente fazer com que você coloque a mão na massa e 
conheça esse excelente framework javascript. Em futuros posts cobrirei outros 
tópicos.&lt;/p&gt;

&lt;p&gt;Dicas:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Utilize a versão não &amp;quot;minificada&amp;quot; do Ember durante o desenvolvimento.&lt;/li&gt;
&lt;li&gt;Mantenha o Chrome Developer Tools sempre aberto. Caso não saiba como 
utilizá-lo, corra atrás. É uma ferramenta indispensável para a criação de 
aplicações javascript.&lt;/li&gt;
&lt;/ol&gt;
</content>
 </entry>
 
 <entry>
   <title>vhost no node.js utilizando express</title>
   <link href="http://fabriciotav.org/blog/2013/02/18/vhost-no-nodejs.html"/>
   <updated>2013-02-18T00:00:00+00:00</updated>
   <id>http://fabriciotav.org/blog/2013/02/18/vhost-no-nodejs</id>
   <content type="html">&lt;h1&gt;vhost no node.js utilizando express&lt;/h1&gt;

&lt;p&gt;Sempre utilizo virtual hosts quando trabalho com Apache, o que permite, dentre
várias coisas, ter vários domínios apontando para a mesma porta de um ip.&lt;/p&gt;

&lt;p&gt;Como, nos últimos meses, praticamente abandonei o Apache em favor do node.js
como servidor, precisei achar uma alternativa.&lt;/p&gt;

&lt;p&gt;Utilizando o framework &lt;a href=&quot;http://expressjs.com/&quot; title=&quot;Express.js&quot;&gt;Express&lt;/a&gt;, o processo é muito simples.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;javascript&quot;&gt;var express;
express = require(&#39;express&#39;);

// Primeiro aplicativo
appOne = express();

// Segundo aplicativo
appTwo = express();

// Terceiro aplicativo
api = express();

// Aplicativo principal
app = express();

// Os parâmetros do express.vhost são o domínio e o aplicativo
app.use(express.vhost(&#39;app-one.com&#39;, appOne));
app.use(express.vhost(&#39;app-two.com&#39;, appTwo));
app.use(express.vhost(&#39;api.dominio.com&#39;, api));

app.listen(80);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;E voilà!&lt;/p&gt;

&lt;p&gt;O roteamento acontece da forma como você provavelmente está acostumado:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;javascript&quot;&gt;appOne.get(&#39;/&#39;, function(req, res) {
    res.send(&#39;Tudo funcionando!&#39;)
});
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Qualquer dúvida, coloca aí nos comentários.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>WhatsApp no Mac</title>
   <link href="http://fabriciotav.org/blog/2013/02/17/whatsapp-no-mac.html"/>
   <updated>2013-02-17T00:00:00+00:00</updated>
   <id>http://fabriciotav.org/blog/2013/02/17/whatsapp-no-mac</id>
   <content type="html">&lt;h1&gt;WhatsApp no Mac&lt;/h1&gt;

&lt;p&gt;Uso o &lt;a href=&quot;http://www.whatsapp.com/&quot;&gt;WhatsApp&lt;/a&gt;, um excelente aplicativo para celular para troca de mensagens, desde o início de 2011. Nos últimos meses vários amigos/familiares começaram a adotá-lo como fonte primária de comunicação rápida, deixando de lado SMS, email, etc.&lt;/p&gt;

&lt;p&gt;Como trabalho o dia inteiro na frente de um computador, nada mais sensato do que enviar mensagens pelo serviço de uma maneira mais rápida e prática, além do benefício em poder digitar as mensagens usando meu teclado físico.&lt;/p&gt;

&lt;p&gt;O problema é que, ao instalar o WhatsApp em algum aparelho celular, ele utiliza o número do telefone como nome de usuário; com isso vêm coisas bacanas, como automaticamente pesquisar quais contatos da sua agenda também possuem uma conta ativa. Ótimo.&lt;/p&gt;

&lt;p&gt;Solução: emular um OS de celular.&lt;/p&gt;

&lt;p&gt;O &lt;a href=&quot;http://www.bluestacks.com/&quot;&gt;BlueStacks&lt;/a&gt; é um emulador de Android, extremamente fácil de instalar e usar.&lt;/p&gt;

&lt;h2&gt;Como?&lt;/h2&gt;

&lt;h4&gt;Passo 1&lt;/h4&gt;

&lt;p&gt;Instale o &lt;a href=&quot;http://www.bluestacks.com/&quot;&gt;BlueStacks&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;Passo 2&lt;/h4&gt;

&lt;p&gt;Acesse http://www.whatsapp.com/android a partir do navegador do emulador. Como eu não consegui achar o navegador, acessei minha conta do Twitter (vem pré-instalado), e cliquei no link que havia postado.&lt;/p&gt;

&lt;h4&gt;Passo 3&lt;/h4&gt;

&lt;p&gt;Baixe a versão pra Android.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/posts/whatsapp-no-mac/1.png&quot;&gt;&lt;/p&gt;

&lt;h4&gt;Passo 4&lt;/h4&gt;

&lt;p&gt;Puxe para baixo a barra de notificações que fica no topo da janela.&lt;/p&gt;

&lt;h4&gt;Passo 5&lt;/h4&gt;

&lt;p&gt;Quando ver o &amp;quot;WhatsApp.apk : Download complete&amp;quot;, é só clicar pra instalar.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/posts/whatsapp-no-mac/2.png&quot;&gt;&lt;/p&gt;

&lt;h4&gt;Passo 6&lt;/h4&gt;

&lt;p&gt;Uma vez instalado, acesse o aplicativo e configure-o com seu número de celular.&lt;/p&gt;

&lt;h4&gt;Passo 7&lt;/h4&gt;

&lt;p&gt;Profit.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/posts/whatsapp-no-mac/3.png&quot;&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Dropbox como servidor Git</title>
   <link href="http://fabriciotav.org/blog/2012/11/23/dropbox-como-servidor-git.html"/>
   <updated>2012-11-23T00:00:00+00:00</updated>
   <id>http://fabriciotav.org/blog/2012/11/23/dropbox-como-servidor-git</id>
   <content type="html">&lt;h1&gt;Dropbox como servidor Git&lt;/h1&gt;

&lt;p&gt;Fazem quase 2 anos que utilizo o &lt;a href=&quot;http://git-scm.com/&quot;&gt;Git&lt;/a&gt; para várias coisas, &lt;em&gt;inclusive&lt;/em&gt; para controle de versão.&lt;/p&gt;

&lt;p&gt;Cheguei a utilizar repositórios privados do &lt;a href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt;, e funcionam muito bem. Entretanto possuem a limitação de espaço e quantidade (eu usava o plano Micro, que permite até 5 repositórios privados).&lt;/p&gt;

&lt;p&gt;A alternativa: &lt;a href=&quot;http://db.tt/p63Zbvf&quot;&gt;Dropbox&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Pressupostos&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Conta no Dropbox;&lt;/li&gt;
&lt;li&gt;Git instalado.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ou mais:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Instância amazon&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Dropbox em uma instância AWS EC2 Ubuntu 12.04 LTS&lt;/h2&gt;

&lt;p&gt;Acesse a instância por ssh.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;ssh -i sua_chave.pem ubuntu@seu_ip&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;É necessário baixar o Dropbox. Caso a versão do Ubuntu seja 64 bits:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-&quot; data-lang=&quot;&quot;&gt;cd ~ &amp;amp;&amp;amp; wget -O - &quot;https://www.dropbox.com/download?plat=lnx.x86_64&quot; | tar xzf -
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Se for 32 bits:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-&quot; data-lang=&quot;&quot;&gt;cd ~ &amp;amp;&amp;amp; wget -O - &quot;https://www.dropbox.com/download?plat=lnx.x86&quot; | tar xzf -
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Agora é necessário rodar o daemon do Dropbox que está na pasta recém criada.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;~/.dropbox-dist/dropboxd&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Você precisará copiar o link que aparece no seu navegador para adicionar o servidor à sua conta. Assim que você fizer isso, será criada a pasta &lt;code&gt;Dropbox&lt;/code&gt; no seu diretório &lt;code&gt;~&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Para controlar o Dropbox a partir da linha de comando, é só baixar esse CLI:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;mkdir -p ~/bin
wget -O ~/bin/dropbox.py &quot;http://www.dropbox.com/download?dl=packages/dropbox.py&quot;
chmod +x ~/bin/dropbox.py
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;E para utilizá-lo:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;~/bin/dropbox.py help&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Não sincronizar todas as pastas&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Eu não gosto de deixar todas as minhas pastas sincronizadas com o Dropbox da minha instância EC2, então eu removo aquelas que não desejo (na verdade removo todas, deixo apenas a pasta que fica os repositórios).&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;~/bin/dropbox.py exclude add NOME_DA_PASTA&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Para ver quais pastas estão excluídas da sincronização:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;~/bin/dropbox.py exclude list&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Problemas conhecidos com Dropbox no servidor&lt;/h2&gt;

&lt;p&gt;Caso o processo comece a dar problema, basta:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;$ ps -e | grep dropbox
3892 ? 00:01:07 dropbox
$ kill 3892
$ ~/bin/dropbox.py start
Starting Dropbox...Done!
&lt;/code&gt;&lt;/pre&gt;
</content>
 </entry>
 
 <entry>
   <title>Reiniciar o .profile</title>
   <link href="http://fabriciotav.org/snippets/2012/07/18/reiniciar-o-profile.html"/>
   <updated>2012-07-18T00:00:00+00:00</updated>
   <id>http://fabriciotav.org/snippets/2012/07/18/reiniciar-o-profile</id>
   <content type="html">&lt;h1&gt;Reiniciar o .profile&lt;/h1&gt;

&lt;p&gt;Para reiniciar o arquivo .profile, basta:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;source ~/.profile&lt;/code&gt;&lt;/pre&gt;
</content>
 </entry>
 
 <entry>
   <title>Iniciar um repo git</title>
   <link href="http://fabriciotav.org/snippets/2012/07/15/iniciar-um-repo-git.html"/>
   <updated>2012-07-15T00:00:00+00:00</updated>
   <id>http://fabriciotav.org/snippets/2012/07/15/iniciar-um-repo-git</id>
   <content type="html">&lt;h1&gt;Iniciar um repo git&lt;/h1&gt;

&lt;p&gt;Para iniciar um repositório git, com o propósito de servir como um repositório compartilhado:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;mkdir repositorio.git
cd repositorio.git/
git --bare init
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Agora, no seu repositório local:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-&quot; data-lang=&quot;&quot;&gt;git remote add origin /path/repositorio.git
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content>
 </entry>
 
 <entry>
   <title>chmod</title>
   <link href="http://fabriciotav.org/snippets/2012/07/15/chmod.html"/>
   <updated>2012-07-15T00:00:00+00:00</updated>
   <id>http://fabriciotav.org/snippets/2012/07/15/chmod</id>
   <content type="html">&lt;h1&gt;chmod&lt;/h1&gt;

&lt;p&gt;&lt;code&gt;chmod&lt;/code&gt; é um comando Unix que permite a configuração do acesso dos usuários à arquivos e diretórios.&lt;/p&gt;

&lt;p&gt;Para listar as permissões atuais de arquivos de um diretório, basta digitar &lt;code&gt;ls -l&lt;/code&gt; (o l significa &lt;code&gt;long&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;Suas permissões de arquivo&lt;/h2&gt;

&lt;hr&gt;

&lt;p&gt;Na primeira coluna, ao se usar o comando &lt;code&gt;ls -l&lt;/code&gt;, a primeira letra informa se é um diretório &lt;code&gt;d&lt;/code&gt; ou um arquivo &lt;code&gt;-&lt;/code&gt;. As próximas letras informam que tipo de acesso é permitido para o arquivo.&lt;/p&gt;

&lt;p&gt;As três primeiras letras se referem às permissões para ler, escrever e executar um arquivo (caso seja um diretório, a letra &lt;code&gt;x&lt;/code&gt; significa que é possível fazer buscas no diretório), do usuário dono do arquivo, (aquele que é listado pelo comando &lt;code&gt;ls -l&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;As próximas três letras se referem às permissões do grupo. As últimas três se referem às permissões de qualquer outro usuário.&lt;/p&gt;

&lt;h2&gt;Mudando a permissão de arquivos&lt;/h2&gt;

&lt;hr&gt;

&lt;p&gt;Usamos o comando &lt;code&gt;chmod&lt;/code&gt; para mudar o modo de acesso (&lt;strong&gt;ch&lt;/strong&gt;ange the access &lt;strong&gt;mod&lt;/strong&gt;e of a file).&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-&quot; data-lang=&quot;&quot;&gt;chmod who=permissions filename
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;u: o usuário dono do arquivo&lt;/li&gt;
&lt;li&gt;g: o grupo à que pertence o arquivo&lt;/li&gt;
&lt;li&gt;o: qualquer outro usuário&lt;/li&gt;
&lt;li&gt;a: todos os usuários&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Mudar o grupo de um arquivo&lt;/h2&gt;

&lt;hr&gt;

&lt;p&gt;Basta usr o comando &lt;code&gt;chgrp&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-&quot; data-lang=&quot;&quot;&gt;chgrp groupname filename
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content>
 </entry>
 
 <entry>
   <title>Salvar Screenshots no Mac OS X</title>
   <link href="http://fabriciotav.org/snippets/2012/07/07/salvando-screenshots-no-mac-os-x.html"/>
   <updated>2012-07-07T00:00:00+00:00</updated>
   <id>http://fabriciotav.org/snippets/2012/07/07/salvando-screenshots-no-mac-os-x</id>
   <content type="html">&lt;h1&gt;Salvar Screenshots no Mac OS X&lt;/h1&gt;

&lt;p&gt;Para alterar o local padrão de salvamento das screenshots tiradas no Mac, basta abrir o Terminal e digitar isso:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;
defaults write com.apple.screencapture location /path/
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Onde &lt;code&gt;/path/&lt;/code&gt; é o caminho da pasta que você escolher. Após essas mudanças é preciso digitar:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;
killall SystemUIServer
&lt;/code&gt;&lt;/pre&gt;
</content>
 </entry>
 
 
</feed>