Unix and Me

Dmitry's blog

DWM for president

2014-09-23 07:58:00 -0300

O DWM é um "tiling window manager" minimalista, i. e., é um gerenciador de janelas lado a lado minimalista.

Confesso que sempre achei muito estranho usar todas as janelas maximizadas, mas como gosto de testar, principalmente para melhorar meu uso do PC, resolvi usar os "tiling wm" por um tempo.

O primeiro que testei foi o Awesome com seus arquivos de configuração em Lua, estava interessado em Lua, não necessariamente para me tornar exímio programador nela, mas apenas para ampliar um pouco meus conhecimentos.

Depois testei o xmonad, que é em Haskell, pelo mesmo motivo acima, por causa da linguagem que é feito.

Awesome tinha muitas opções de configuração, particularmente não gosto disso :/, e parei de usar xmonad apenas por que eu parei um tempo de estudar Haskell, mas eu já havia pego o gosto pelos "tiling wm", procurando um pouco achei o dwm, por seu carater minimalista e por sua leveza logo me agradou muito.

Instalação e Configuração

Primeiro git clone:

% git clone http://git.suckless.org/dwm

Copie o arquivo config.def.h para config.h:

% cp config.def.h config.h

Edite-o e faça as suas configurações (falarei delas mais adiante).

Para terminar a instalação, falta apenas:

% make && make install

Se quiser, pode instalar num PREFIX diferente:

% make && make PREFIX=/opt/dwm install

O último passo da instalação é criar o arquivo /usr/share/xsessions/dwm.desktop com o seguinte conteúdo:

[Desktop Entry]
Encoding=UTF-8
Name=dwm
Comment=Dynamic window manager
Exec=/usr/local/bin/dwm
Icon=dwm
Type=XSession

Nota: Edite o Exec acima de acordo com seu make install.

Agora o dwm já deve aparecer no seu gerenciador de login gráfico (KDM, GDM, LightDM, …).

Uma dica é você instalar pelo seu gerenciador de pacotes da sua distro o dmenu para chamar os programas, sem precisar abrir um terminal.

Configuração

A configuração é a parte mais chata, pelo único fato de que você:

  • Faz a configuração editando o config.h;
  • Compila e "instala" novamente :/;
  • Reinicia o X;

Pelas minhas pesquisas tem como não precisar reiniciar o X, mas como eu não vou ficar fazendo os processos acima todo os dias da minha vida, resolvi não mudar nada nesse fluxo.

Teclas de atalho básicas (Estou usando um teclado apple, então a tecla abaixo command deve ser o equivalente ao alt para você):

  • command+shit+q, para fechar o dwm;
  • command+shit+c, para fechar a janela atual;
  • command+p, para chamar o dmenu (para executar os programas);
  • command+return, para chamar o terminal (que por padrão é o st, edite o config.h e mude para o que você usa);
  • command+N (onde N é um número de 1-9) para mudar a "tag" (algo como os ambientes de trabalho virtual no gnome/kde/xfce);
  • command+shift+N (onde N é um número de 1-9) para mandar a janela atual para outra tag;
  • command+j (ou command+k) para mudar entre as janelas da tag atual.

Abra o arquivo config.h para ver mais teclas e também para customizar.

Usage

O dwm não trabalha somente com as janelas maximizadas, mas ele pode também colocar uma ao lado da outra (gerenciador de janelas lado a lado, sacou?), ou deixar você livre para escolher o tamanho e disposições delas.

Devo adimitir que nesse ponto o xmonad (não lembro sobre o awesome, pois faz muito tempo que usei) se sai melhor, mas para as minhas necessidade ele faz o que preciso.

As combinações de tecla para isso são:

  • command+t, coloca uma do lado da outra, neste modo pode-se usar o command+i para mudar para vertical ou o command+d para ficar na horizontal;
  • command+f, float mode, modo "flutuante", aqui as janelas tem o comportamento "normal" dos outros gereciadores de janelas;
  • command+m, modo de janela única, i. e., somente uma janela por vez é mostrada e ela fica maximizada sempre, para mudar entre janelas, use o command+j (ou command+k);

Fonte

“Tiling Window Manager.” Wikipedia, the Free Encyclopedia, September 20, 2014. http://en.wikipedia.org/w/index.php?title=Tiling_window_manager&oldid=613735109.

Instalando LaTeX "manualmente"

2014-09-13 21:59:00 -0300

Usei Arch Linux para estes testes, mas acredito que funcione em qualquer outra distribuição.

Na verdade deveria ser: "Instalando o LaTeX sem usar o gerenciador de pacotes da distribuição" :P.

Baixe o arquivo install-tl-unx.tar.gz de http://www.tug.org/texlive/acquire-netinstall.html.

Para iniciar a instalação basta extrair o tar.gz e executar o script install-tl:

% tar xfz install-tl-unx.tar.gz
% cd install-tl-20140911
% ./install-tl

Será extraido um diretório nesse padrão: install-tl-YYYYMMDD, para mim é o diretório acima, para você pode ser que mude.

O script install-tl, vai mostrar um menu com algumas opções, você pode escolher a opção I para iniciar a instalação, mas eu gosto de instalar apenas o pacote básico e no meu espaço de usuário.

Para instalar somente o básico escolha a opção S e depois escolha:

e [X] minimal scheme (plain only)

Tecle R para voltar ao menu anterior.

Agora vou configurar para instalar no meu espaço de usuário, escolha a opção D, depois a opção 1 e por fim digite o caminho de instalação, normalmente eu coloco:

~/local/texlive/2014

R para voltar ao menu anterior. E depois I para iniciar a instalação.

Adicione ao seu $PATH o caminho ~/local/texlive/2014/bin/x86_64-linux.

Pacotes extras

Para completar a instalação do LaTeX eu instalo ainda esses pacotes

% tlmgr install latex latex-bin latexconfig latex-fonts amsmath babel \
carlisle ec geometry graphics hyperref lm marvosym oberdiek parskip \
pdftex-def url babel babel-portuges mathtools tools

Basicamente todo arquivo que crio usam esses pacotes.

Se tiver algum problema em rodar o comando para gerar o PDF tente pesquisar usando o tlmgr:

% tlmgr search --global PKG

Para procurar por um arquivo:

% tlmgr search --global --file ARQUIVO.EXT

Após todos esses passos minha instalação do LaTeX ficou em cerca de 228M.

Fonte

“LaTeX/Installation - Wikibooks, Open Books for an Open World.” Accessed September 12, 2014. https://en.wikibooks.org/wiki/LaTeX/Installation

Aprendendo Python com testes automatizados

2014-07-02 18:19:00 -0300

Estou aprendendo ainda Python, então se o código puder ser melhorado, pode comentar ;)

Então… Eu estava assistindo as aulas do Python for Zumbies e me deparei com alguns códigos para fazer. Porém quando se inicia o aprendizado de alguma linguagem você quer ver seu código funcionando, para mim existem duas forma de ver meu software funcionando:

  • Automatizar os testes com o software;
  • Entregar o projeto para o usuário (que pode até mesmo ser eu).

Eu como usuário gosto de usar software apenas "funcional", i. e., para que que eu vou usar uma Sequência de Fibonacci ou um software que contabiliza médias de notas se eu não estou tendo aulas?

Então a melhor forma que resolvi testar foi criando testes automatizados.

Sequência de Fibonacci

Primeiro vou criar o arquivo de teste:

Após estudar um pouco cheguei no seguinte código:

import unittest
from fib import fib

class FibTestCase(unittest.TestCase):
  def test_fib1(self):
    self.assertEqual(fib(1), 1)

  def test_fib0(self):
    self.assertEqual(fib(0), 0)

  def test_fib6(self):
    self.assertEqual(fib(6), 8)

  def test_fib6_again(self):
    self.assertTrue(fib(6) == 8)

unittest.main()

Se esse código for executado gera o seguinte erro:

% python fib_test.py
Traceback (most recent call last):
  File "fib_test.py", line 2, in <module>
    from fib import fib
ImportError: No module named 'fib'

Até aí tudo bem, eu ainda não criei o código fibonacci, vamos criar então:

# fib.py
def fib(n):
  if n < 2:
    return(n)

  a = fib(n-1)
  b = fib(n-2)

  return(a+b)

E executando, temos:

% python fib_test.py
....
----------------------------------------------------------------------
Ran 4 tests in 0.000s

OK

Orientação a objetos

Depois que aprendi a orientação a objetos em python eu fiz alguns exemplos, entre eles:

Primeiro o teste:

import unittest
from televisao import Televisao

class TelevisaoTestCase(unittest.TestCase):
  def setUp(self):
    self.tv_sala = Televisao('Sala')

  def test_uma_nova_televisao_deve_ser_desligada(self):
    self.assertFalse(self.tv_sala.ligada)

  def test_eu_posso_mudar_o_status_para_ligada(self):
    self.tv_sala.ligada = True
    self.assertTrue(self.tv_sala.ligada)

  def test_eu_posso_mudar_o_canal(self):
    self.tv_sala.canal_mais_um
    selft.assertEqual(self.tv_sala.canal, 2)

unittest.main()

Agora a classe:

class Televisao:
  def __init__(self, local):
    self.ligada = False
    self.canal = 1
    self.local = local

Esse exemplo da classe Televisao eu fiz ao estilo TDD, criava o teste e depois o código.

Ficou faltando um método na classe Televisao, se estiver estudando semelhante a mim, adiciona lá ;)

Confira o Python for Zumbies tem várias vídeo aula em português e diversos exercícios bem práticos!

Fontes

“26.3. Unittest — Unit Testing Framework — Python 3.4.1 Documentation.” Accessed September 1, 2014. https://docs.python.org/3/library/unittest.html.

“Python Para Zumbis Com Fernando Masanori.” Accessed September 2, 2014. http://pycursos.com/python-para-zumbis/.

Envio de e-mail com ssmtp

2014-05-20 12:19:00 -0300

Nota: Todos os comandos eu executei como root, caso não seja root use o sudo antes dos comandos.

Enviando e-mail de máquina unix usando o ssmtp.

No ubuntu instale com o apt-get:

# apt-get install ssmtp

Depois basta configurar para usar o Amazon SES no arquivo /etc/ssmtp/ssmtp.conf:

root=username@mydomain.com
mailhub=email-smtp.us-east-1.amazonaws.com:465
hostname=myserver.mydomain.com

FromLineOverride=YES

AuthUser=AAAAABBBBBCCCCCDDDDD
AuthPass=AAAAABBBBBCCCCCDDDDDEEEEEFFFFFGGGGGHHHHHIIII
UseTLS=YES
AuthMethod=LOGIN

Se for usando o Gmail1:

root=username@gmail.com
mailhub=smtp.gmail.com:587
hostname=myserver.mydomain.com

FromLineOverride=YES

UseSTARTTLS=YES
AuthUser=username@gmail.com
AuthPass=MyPassword

Depois de fazer a configuração tem ainda que deixar as permissões corretas:

# chmod 640 /etc/ssmtp/ssmtp.conf
# chown root:mail /etc/ssmtp/ssmtp.conf

Se quiser que algum usuário envie e-mail, basta adicioná-lo ao grupo mail, editando diretamente o /etc/group ou:

# gpasswd -a username mail

Enviando e-mail

Para testar (caso seu usuário não seja do grupo mail use o sudo antes do ssmtp):

# echo "Testing" | /usr/sbin/ssmtp username@gmail.com

Ou se quiser use um arquivo, por exemplo:

From: username@mydomain.com
Subject: This is Sparta!

Hi.

E chamando via linha de comando:

# ssmtp username@mydomain.com < /tmp/mail.txt

Rails

Para configurar no Rails basta usar algum arquivo de configuração no initializers semelhante a:

Rails.application.configure do
  config.action_mailer.delivery_method = :sendmail
  config.action_mailer.sendmail_settings = { :arguments => '-i' }
  config.action_mailer.default_url_options  = { :host => "mydomain.com" }
end

Ou então colocar em config/environments/production.rb.

Exemplo de scripting

O script abaixo eu coloquei num servidor para me enviar um e-mail com as atualizações que são necessárias, no meu caso coloquei uma vez por dia no crontab:

#!/bin/bash

apt-get update >/dev/null 2>/dev/null
count=$(/usr/lib/update-notifier/apt-check --human-readable | grep -v ^0 | wc -l)

if [ $count -ne 0 ]
then
  file=/tmp/updates-notify-$$

  echo -e "To: username@mydomain.com
From: $(hostname)@mydomain.com
Subject: $(hostname -f) has updates

The server $(hostname -f) has updates:

$(/usr/lib/update-notifier/apt-check --human-readable)

$(apt-get -s -o Debug::NoLocking=true upgrade | grep 'Inst' | cut -d' ' -f2)
" >> $file

  ssmtp username@mydomain.com < $file
  rm $file
fi

Fontes

"SSMTP - ArchWiki". ArchWiki. Accessed May 19, 2014. https://wiki.archlinux.org/index.php/SSMTP.

"How to Use GMail as a Free SMTP Server and Overcome Captcha". Accessed May 19, 2014. http://stackoverflow.com/questions/1607828/how-to-use-gmail-as-a-free-smtp-server-and-overcome-captcha.

"Rails & Sendmail Recipients with -T Option Not Supported." Accessed May 31, 2014. http://stackoverflow.com/questions/6456205/rails-sendmail-recipients-with-t-option-not-supported.


1 Cuidado que o gmail tem um problema de autenticação, caso toda sua configuração esteja certa e mesmo assim receba erro de autenticação, visite: http://www.google.com/accounts/DisplayUnlockCaptcha ou https://www.google.com/a/yourdomain.com/UnlockCaptcha para autorizar o envio de e-mail pelo seu servidor.

Recomendação de Leitura: A Dança do Universo

2014-04-02 21:21:00 -0300

Livro de linguagem acessível sobre as teorias da criação do universo. Muito recomendado para quem gosta de ciência e teorias sobre a criação/existência do universo.

Antes de iniciar a leitura recomendo ouvir esses dois episódios do podcast Dragões de Garagem.

O primeiro fala claramente do livro, mas não achei que possar ter expoliers, até por que o livro fala de teorias científicas e querendo ou não você já ouviu falar de algumas delas, o que pode é não lembrar.

Foi até por causa do episódio #23 que iniciei a leitura.

Local para comprar:

Se gosta da série Cosmos recomendo o livro e o podcast.

Ip estático no Ubuntu/Debian

2013-12-30 14:07:00 -0300

O primeiro a fazer é editar o arquivo /etc/network/interfaces, inicialmente ele deve ser assim:

# interfaces(5) file used by ifup(8) and ifdown(8)
auto lo
iface lo inet loopback

Modifique-o para que fique similar a:

# interfaces(5) file used by ifup(8) and ifdown(8)

auto lo eth0
iface lo inet loopback
iface eth0 inet static
    address 192.168.10.100
    netmask 255.255.255.0
    gateway 192.168.10.1

Substitua eth0 conforme sua máquina.

Agora basta reiniciar o serviço de rede:

# restart networking
networking start/running

E para as opções de DNS edite o arquivo /etc/resolvconf/resolv.conf.d/head adicionando o seguinte conteúdo ao final:

nameserver 8.8.8.8
nameserver 8.8.4.4

E reiniciar o serviço relacionado:

# restart resolvconf
resolvconf start/running

Fonte: Linux Basics - Set A Static IP On Ubuntu.

Rotina

2013-09-10 12:50:00 -0300

Eventualmente acordo as 6h para fazer cooper, mas não está na minha rotina ainda.

Costumo a "entrar para trabalhar" as 8h, então reservo de 7h até as 8h para alguma tarefa criativa, por exemplo:

  • Feed 0 (não tenho problema com inbox 0);
  • Aquela funcionalidade de software que não estou conseguindo fazer funcionar;
  • Entre outras…

Nesse ínterim procuro não ler e-mails. E durante o resto do dia configurei o software que me notifica de novos e-mails para verificar a cada 15min.

Inicio o trabalho para a empresa da qual presto serviço as 8h.

Como trabalho em home office eu gosto de me manter focado ao máximo, evito conversas em casa, evito sair para beber água e ficar de "convercê", pois se por um momento mínimo eu fizer isso as pessoas vão imaginar que isso é normal.

Para o almoço reservo apenas 1h, já notei que preciso apenas disso, não sei as outras pessoas, mas meu organismo funciona assim.

"Fico no trabalho" até as 17h.

Depois das 17h não tem rotina, faço as seguintes tarefas (as vezes apenas uma delas):

  • Leio feed;
  • Ouço podcast;
  • Leio livro(s) (descobri que ler dois livros por vez faz melhor para o cérebro);
  • Faço caça-palavras ou palavras cruzadas (do tipo diretas);
  • Assisto a séries;
  • Estudo assuntos diversos;

Rede social

Eu acompanhava 3 redes sociais: Twitter, Facebook e Google Plus, mas percebi no post Somos adultos, certo? A geração social media que eu não gero conteúdo apenas quero chamar atenção.

Assim eu acesso somente o Twitter e apenas duas vezes por dia.

Ao invés de querer chamar tanta atenção estou tentando gerar mais conteúdo (como este post por exemplo ;).

Exercício

Usando o software Workrave eu paro a cada uma hora para fazer alguns exercícios. Meu braço agradece.

Next?

Minhas aulas comecarão em Outubro então provavelmente minha rotiva vai mudar, se mudar muito crio um outro post caso contrário apenas atualizo este.

Dúvidas, sugestões e correções são bem-vindas.

Porque Prefiro Ebooks

2013-09-03 12:54:00 -0300

Motivo troll

O primeiro motivo e mais troll de todos:

Por que eu tenho um tablet.

Gosto de ler HQ no computador, mas só. Ler livros não é tão agradável.

Meu tablet está morrendo aos poucos então minha próxima compra vai ser um kobo. Escolhi o kobo pois ele aceita mais livros em formato aberto do que a Amazon. No kindle eu teria que converter a maioria dos que tenho e isso não me agrada muito.

Segundo motivo

O segundo é um motivo trágico:

As pessoas não cuidam tão bem dos livros quanto eu.

Não estou me gabando nem nada do tipo, apenas é um fato que comprovei: sempre que empresto um livro ele volta "modificado", com riscos, folhas amassadas, e nem preciso falar mais :|.

Terceiro motivo

O terceiro motivo é de logística:

Espaço para quardar.

Com livros em pdf/epub/mobi eu posso quardar num diretório no meu pc, enviar para "as nuvens" (no meu caso eu uso o dropbox) e catalogar (eu uso o calibre).

Ou seja: tenho meus ebooks em qualquer lugar do mundo (com internet) e organizados.

Catalogar meus livros sempre foi algo que eu quis fazer, mas com eles impressos não sei o porquê, mas nunca consegui.

DataMapper - Introdução

2013-07-31 07:15:00 -0300

Ultimamente tenho passado a usar cada vez menos MongoDb e voltado a usar banco de dados SQL.

Para usar SQL gosto do ActiveRecord ou o DataMapper. Já falei de ActiveRecord em posts como ActiveRecord sem Rails e hoje veremos um exemplo similar usando DataMapper.

Como de costume um Gemfile:

source 'http://rubygems.org'

gem 'data_mapper'
gem 'dm-sqlite-adapter'

Vamos criar nosso model de mensagem no arquivo message.rb:

class Message
  include DataMapper::Resource

  property :id, Serial
  property :content, String
  property :created_at, DateTime
end

Para se conectar ao banco de dados é necessário usar o DataMapper#setup:

DataMapper.setup(:default, "sqlite://#{File.expand_path('database.db')}")

Nesse caso vou usar um banco de dados sqlite, mas se for usar um PostgreSQL:

DataMapper.setup(:default, 'postgres://user:password@hostname/database')

Ao contrário do ActiveRecord não precisamos criar um arquivo de migration. Depois de fazer o require do model message.rb temos duas formas de levantar o banco de dados: DataMapper.auto_migrate! e o DataMapper.auto_upgrade!.

O DataMapper.auto_migrate! tem a característica de APAGAR as tabelas antes de tentar criá-las, já o DataMapper.auto_upgrade! apenas vai tentar fazer com que o schema "case" com o(s) model(s).

Vou criar agora um arquivo chamado database.rb que terá a função de "levantar" e migrar o banco de dados:

require 'data_mapper'

DataMapper::Logger.new($stdout, :debug)
DataMapper.setup(:default, "sqlite://#{File.expand_path('database.db')}")

Dir['./models/*.rb'].entries.each do |model|
  require model
end

DataMapper.auto_upgrade!

Usando o irb como "console" podemos testar:

% irb -r ./database.rb
 ~ (0.000308) PRAGMA table_info("messages")
 ~ (0.000026) SELECT sqlite_version(*)
 ~ (0.109057) CREATE TABLE "messages" ("id" INTEGER NOT NULL PRIMARY KEY AU
TOINCREMENT, "content" VARCHAR(50), "created_at" TIMESTAMP)
irb(main):001:0> Message.count
 ~ (0.000055) SELECT COUNT(*) FROM "messages"
=> 0
irb(main):002:0> Message.create(:content => "Hello from DataMapper")
 ~ (0.111596) INSERT INTO "messages" ("content", "created_at") VALUES ('Hel
lo from DataMapper', '2013-07-31T07:39:21-03:00')
=> #<Message @id=1 @content="Hello from DataMapper" @created_at=#<DateTime:
 2013-07-31T07:39:21-03:00 ((2456505j,38361s,436990591n),-10800s,2299161j)>
>
irb(main):003:0> Message.first
 ~ (0.000085) SELECT "id", "content", "created_at" FROM "messages" ORDER BY
 "id" LIMIT 1
=> #<Message @id=1 @content="Hello from DataMapper" @created_at=#<DateTime:
 2013-07-31T07:39:21-03:00 ((2456505j,38361s,0n),-10800s,2299161j)>>

O código está disponível no github em: https://github.com/dmitrynix/data-mapper-intro.

Strong Parameters

2013-07-18 12:46:00 -0300

Como parte da migração do Rails 3 para o Rails 4 pode-se adicionar a gem strong_parameters para mudar a forma como os atributos são protegidos.

O que, ao meu ver, é melhor, pois pode-se controlar quais atributos são permitidos em que situação (controller) ao invés de apenas definir globalmente.

Configurando

É necessário desativar o config.active_record.whitelist_attributes da aplicação, normalmente essa configuração fica no config/application.rb:

config.active_record.whitelist_attributes = false

E fazer o include do ActiveModel::ForbiddenAttributesProtection em cada model. Uma configuração alternativa (e mais prática) é fazer esse include em todos os models, para isso basta criar um arquivo no config/initializers/ com o seguinte conteúdo:

ActiveRecord::Base.send(:include, ActiveModel::ForbiddenAttributesProtection)

Usos

Encontrei os seguintes comportamentos:

  • Não aceita passar o type (pode ser usando para trabalhar com herança no ActiveRecord);
  • Quando passa um relacionamento has and belongs to many tem que colocar um array como possível atributo, algo como: :author_ids => [];
  • Quando passa um nested form tem que colocar o :id e o :_destroy, se não passar o :id, quando for editar, será feito uma tentativa de criar um novo objeto e se não passar o :_destroy nenhum objeto poderá ser apagado;

Algo que precisei foi um formulário iniciar com valores provenientes de um link, por exemplo:

link_to 'Criar subitens', new_item_path(:item => { :parent_id => @item.id })

Para funcionar fiz algo semelhante a isso na action new do controller:

def new
  @item = Item.new(params[:item].present? ? item_params : {})
end