Python II

Entretanto, depois de ler o manual com a sintaxe de base, pesquisei para ver como escrever programas em Python para a Web. E fiquei desiludido. O Python é como o Perl e o Java, etc. O HTML é gerado em código, é sempre processado. Isso fica mais pesado para o servidor.

No site do Python, apresentam várias soluções para integrar o Python no Apache: CGI, mod_python, FastCGI, SCGI, mod_wsgi e WSGI. Este último parece ser a solução mais leve e funcional, mas com tanta literatura e referências a frameworks, decidi testar a versão mais simples: o CGI.

Ainda sobre o HowTo do Python acerca de Web Servers: o documento perde-se com considerações sobre persistência de dados, caching, programas que não correm como era esperado, falta de escalabilidade, frameworks para poder gerir projetos em MVC, etc. Coisas que o PHP já resolveu há mais de 15 anos. Aliás, nunca vi referências a esses problemas na documentação do PHP. Fiquei desiludido.

Mas quis testar o Python no Apache e configurei este último, numa máquina de testes, para correr o Python como CGI.

No ficheiro httpd.conf, descomentei a linha que inibe o uso do CGI

LoadModule cgi_module lib64/httpd/modules/mod_cgi.so

e acrescentei as linhas seguintes na configuração da diretoria do CGI

<Directory "/srv/httpd/cgi-bin">
    Options +ExecCGI
    DirectoryIndex index.py
</Directory>
AddHandler cgi-script .py

Depois, criei os dois programas seguintes, na diretoria /srv/httpd/cgi-bin aos quais foi necessário dar permissões de execução:

chmod 755 /srv/httpd/cgi-bin/fatorial.py
chmod 755 /srv/httpd/cgi-bin/form.py

/srv/httpd/cgi-bin/fatorial.py

#!/usr/bin/python

import cgi
import cgitb; cgitb.enable()  # for troubleshooting

print "Content-type: text/html"
print

print """
<html>
<head><title>Fatorial em Python</title></head>
<body>
  <h3> Fatorial em Python </h3>
"""

def mul(x,y): return x*y

def fat(w): return reduce(mul, range(1,w+1))

def prt(x): print fat(x)

map(prt, range(2,11))

print """

</body>
</html>
"""

/srv/httpd/cgi-bin/form.py

#!/usr/bin/python

import cgi
import cgitb; cgitb.enable()  # for troubleshooting

print "Content-type: text/html"
print

print """
<html>
<head><title>Sample CGI Script</title></head>
<body>
  <h3> Sample CGI Script </h3>
"""

form = cgi.FieldStorage()
message = form.getvalue("message", "(no message)")

print """
  <p>Previous message: %s</p>
  <p>form
  <form method="post" action="form.py">
    <p>message: <input type="text" name="message"/></p>
  </form>
</body>
</html>
""" % cgi.escape(message)

O primeiro programa calcula os fatoriais dos números 2 até 10, enquanto o segundo tem um formulário que submete um campo de texto para o próprio ficheiro.

Python

Tenho tanta coisa para fazer que decidir sentar-me no sofá a lançar aviões de papel…

Estive a ler um manual de Python e criei algumas funções. Por exemplo a função fatorial. Aqui vai:

>>> def mul(x,y): return x*y
...
>>> def fat(w): return reduce(mul, range(1,w+1))
...
>>> fat(3)
6
>>> fat(4)
24
>>> fat(5)
120
>>> fat(6)
720

Até parece fácil 🙂

Quando o slackpkg pendura

Eis a lista de comandos que utilizo no Slackware para fazer update das minhas máquinas, a partir de um mirror que tenho e que é atualizado diariamente.

slackpkg update
slackpkg update gpg
slackpkg install-new
slackpkg upgrade-all
slackpkg clean-system

De vez em quando, e ainda não percebi porquê, o slackpkg pendura. A máquina que estava a ser atualizada deixa de responder. Não sei se é por fazer muitas atualizações em simultâneo, todas a ler no mesmo mirror, se é demasiado peso na rede a carregar os pacotes para as atualizações… Duvido que a causa seja uma destas, mas ainda não consegui descobrir a origem dos problemas.

Algumas vezes tenho que mandar a máquina abaixo, embora nem sempre. Mas uma consequência chata destes penduranços é que os pacotes que estavam a ser atualizados são considerados instalados, apesar de não estarem. Ainda demorei algum tempo a encontrar solução para este problema, por isso fica aqui para consulta futura.

cd /var/lib/slackpkg/
rm ChangeLog.txt

E depois já posso recomeçar os updates.

Maior ficheiro

Agora que já tenho o disco redimensionado para o dobro, vou tentar descobrir qual foi a causa do problema do disco virtual de 160GB encher.

Para já vou correr dois comandos de Linux em consola para descobrir quais os dez maiores ficheiros e as dez maiores diretorias. (sacados do site superuser)

# To find the largest 10 files (linux/bash):
find . -type f -print0 | xargs -0 du | sort -n | tail -10 | cut -f2 | xargs -I{} du -sh {}

# To find the largest 10 directories:
find . -type d -print0 | xargs -0 du | sort -n | tail -10 | cut -f2 | xargs -I{} du -sh {}

# Only difference is -type {d:f}

Já descobri o problema: Alguns backups não estavam a ser transferidos para os discos de rede e iam ficando na diretoria /mnt/baks, onde os discos remotos deviam estar pendurados. Eram quase 30 ficheiros, salteados, desde maio de 2012, que somavam 133GB. Por algum motivo o NFS não estava ativo e os ficheiros ficavam na diretoria local ao invés de serem transferidos. Tenho que monitorizar isto.

Expandir disco no VirtualBox e mudar nome da máquina

O antigo servidor do Chornal atingiu ontem o limite dos 160GB. Era o tamanho do disco virtual. Nunca pensei que enchesse, mas encheu. Tenho que descobrir o que é que está a ocupar tanto espaço – talvez as contas de email – mas para já vou aumentar o disco para o dobro. As instruções estão indicadas abaixo.

Nota 1: O disco virtual está com tamanho dinâmico, por isso os comandos são apenas estes. Se o disco estiver com tamanho fixo, ou se houver dúvidas, é melhor consultar uma outra crónica.

Nota 2: Este processo só funciona com a máquina virtual completamente desligada. É necessário fazer halt na consola. Não pode ser aplicado com a máquina em estado Saved pois, neste caso, as últimas alterações estão guardadas num Snapshot e perdem-se.

VBoxManage modifyhd terra.vdi --resize 320000

Depois deste primeiro passo de expansão do disco virtual, é necessário estender a partição. Para isso, descarreguei o GParted em formato ISO e associei-o ao leitor de CD da máquina virtual. Depois arranquei com a máquina e fi-la arrancar de CD.
Nas opções de arranque do GParted escolhi o arranque automático. Desta forma, a máquina entra automaticamente no GParted, em modo gráfico. A interface é simples de compreender: basta estender a partição e mandar aplicar o comando. (ver mais abaixo)

Vou, também, aproveitar para mudar o nome da máquina virtual com a solução do site superuser.

VBoxManage modifyvm ORIGNAL_NAME --name NEW_NAME

Utilização do GParted

Selecionar a partição original e no menu, escolher: Partition – Resize/Move

gp1

Esticar a partição até ao máximo e premir o botão Resize/Move

gp2

Por fim, no menu selecionar: Edit – Apply All Operations

gp3

Kernel 4.1.12, VirtualBox 5.0.10 e o novo SSHD

Mais uma atualização das máquinas. Desta vez para o kernel 4.1.12, assim como muitas atualizações de outras aplicações, nomeadamente o KDE 4.13.3. São 18 máquinas: esperemos que corra bem.

O VirtualBox também tem uma nova versão (5.0.10), pelo que preciso de o recompilar e reinstalar.

A nova configuração do SSHD não permite o acesso de clientes à conta “root”. Para permitir, é necessário, antes do último reboot, colocar a linha seguinte no ficheiro /etc/ssh/sshd_config:
PermitRootLogin yes

No fim vou ter que reiniciar os hosts das máquinas virtuais com os comandos que usei das últimas vezes. Estes comandos são necessários para recompilar o VirtualBox para a nova versão do Kernel do Linux.

cd /root
bat/vboxes stop
cd /usr/local/
VBoxManage extpack uninstall "Oracle VM VirtualBox Extension Pack"
reboot
exit
cd /usr/local/
chmod +x ./VirtualBox-5.0.10-104061-Linux_amd64.run
./VirtualBox-5.0.10-104061-Linux_amd64.run
VBoxManage extpack install Oracle_VM_VirtualBox_Extension_Pack-5.0.10-104061.vbox-extpack
cd -
bat/vboxes start

O ficheiro bat/vboxes é um ficheiro de comandos que criei para gerir as máquinas virtuais do VirtualBox.

Entretanto, se alguma das máquinas falhar, posso recuperá-la da mesma forma que já aqui foi documentada antes.

Reiniciar a máquina virtual, ligando ao leitor de CD um ISO com a última versão do sistema operativo. Depois de arrancar e escolher o layout do teclado, executar os comandos seguintes.

mount /dev/sda2 /mnt
mount -t proc proc /mnt/proc (this was the magic step)
chroot /mnt
cd /boot
mkinitrd -c -k 4.1.12 -m ext3
# No ficheiro /etc/lilo.conf colocar a linha
initrd = /boot/initrd.gz
# no fim do ficheiro, logo após a linha
root = /dev/sda2
# depois, executar os comandos:
lilo
reboot 

Kernel 4.1.6 e VirtualBox 5.0.2

O Slackware deu um salto grande, o que não é muito usual: saltou para a versão 4 do kernel do Linux. Estive a instalar nalgumas máquinas. Vamos ver como corre.

O VirtualBox também tem uma nova versão (5.0.2), pelo que preciso de o recompilar e reinstalar.

No fim vou ter que reiniciar os hosts das máquinas virtuais com os comandos que usei das últimas vezes. Estes comandos são necessários para recompilar o VirtualBox para a nova versão do Kernel do Linux.

cd /root
bat/vboxes stop
cd /usr/local/
VBoxManage extpack uninstall "Oracle VM VirtualBox Extension Pack"
reboot
exit
cd /usr/local/
chmod +x ./VirtualBox-5.0.2-102096-Linux_amd64.run
./VirtualBox-5.0.2-102096-Linux_amd64.run
VBoxManage extpack install Oracle_VM_VirtualBox_Extension_Pack-5.0.2-102096.vbox-extpack
cd -
bat/vboxes start

O ficheiro bat/vboxes é um ficheiro de comandos que criei para gerir as máquinas virtuais do VirtualBox.

Entretanto, uma das máquinas que, por vezes, tinha problemas nas atualizações, voltou a falhar e vou ter que recuperá-la da mesma forma que já aqui foi documentada antes.

Reiniciar a máquina virtual, ligando ao leitor de CD um ISO com a última versão do sistema operativo. Depois de arrancar e escolher o layout do teclado, executar os comandos seguintes.

mount /dev/sda2 /mnt
mount -t proc proc /mnt/proc (this was the magic step)
chroot /mnt
cd /boot
mkinitrd -c -k 4.1.6 -m ext3
# No ficheiro /etc/lilo.conf colocar a linha
initrd = /boot/initrd.gz
# no fim do ficheiro, logo após a linha
root = /dev/sda2
# depois, executar os comandos:
lilo
reboot 

Upgrades das máquinas

Ontem, quando ia começar a trabalhar no projeto da estatística online, descobri que os servidores estavam inacessíveis via SSH.
Na noite anterior, tinha estado a fazer upgrades dos sistemas das várias máquinas. Mas o novo pacote do SSHD deixa as máquinas inacessíveis.
O upgrade demorou só uma hora. Para recuperar foram cinco.

Coloquei uma mensagem no alt.os.linux.slackware e houve um tipo que respondeu, com uma informação que eu já conhecia, mas que me ajudou a encontrar o caminho.

Além disso, enviei uma mensagem ao Patrick Volkerding que me respondeu com a solução.

Enquanto pesquisava acabei por descobrir a solução. Eis a mensagem que coloquei no newsgroup:

In debug mode I received the message:

debug1: Authentications that can continue: publickey,password,keyboard-interactive
Permission denied, please try again.

Searched google and found that I should set the following entries in /etc/ssh/sshd_config file:

#PasswordAuthentication yes
#PermitRootLogin yes

I didn’t check if both were needed, but it works. Curiously, all the previous versions of SSHD didn’t check those lines.

Mais tarde, acabei por descobrir que bastava a linha:

#PermitRootLogin yes

Foi essa, inclusive, a resposta do Pat

Upgrades das máquinas

Depois de um dia a limpar o bidé, comecei, logo ao início da noite, a fazer atualizações nos servidores Linux.

Os meus servidores utilizam todos o Linux Slackware versão current, desde sempre. Uso o Slackware desde a versão 2, mas quando criei os primeiros servidores, tinha acabado de sair a versão 7.

Já agora, e para os que não conhecem a história, o Slackware é a distribuição mais antiga de Linux que está ativa ainda. Eu usei a versão 2, a versão 4, e depois saltou para a 7 (por questões de marketing), que foi quando comecei a usá-lo diariamente.

Desta vez, as atualizações deram mais trabalho. O espelho de onde eu copiava os ficheiros, diariamente por um processo automático, está indisponível há uns meses (slackware.at). Quando me apercebi disso, redirecionei o copiador para o espelho slackware.no. Mas ontem percebi que as cópias automáticas não estavam efetivamente a ser feitas.

Para fazer a cópia do repositório do Slackware, tenho usado, há mais de 10 anos, o ftpcopy. É um replicador de pastas de servidores FTP, que tem funcionado bem, mas já é muito antigo. A última versão tem mais de 10 anos. Percebi ontem que ele não respondia a alguns comandos do servidor ftp.slackware.no e o processo de cópia parava. Substituí, então, o ftpcopy pelo lftp e esperei até os ficheiros estarem todos em sincronia.

Eis o comando utilizado:

lftp -u user,pass -e "mirror --only-newer --delete --parallel=3 --verbose /slackware/slackware64-current/ /data/slack64.no" ftp.slackware.no

Tive ainda que corrigir os links internos dos meus servidores para apontarem para o meu novo repositório e só depois pude começar as atualizações.

O Chornal esteve em baixo umas horas porque o servidor de bases de dados ficou isolado após as atualizações. O Slackware, por omissão, lança o mysql com o parâmetro “–skip-networking” e só corrigi isso hoje de manhã.

Depois dos servidores, atualizei o WordPress para a versão 4.2.3 nos servidores de blogs, e agora espero poder ter tempo para trabalho a sério.

R e Análise Fatorial

O R é uma ferramenta extremamente potente para fazer cálculos estatísticos. Para além das estatísticas de base, é possível adicionar outras estatísticas disponíveis em pacotes opcionais. Para a análise fatorial, por exemplo, é necessário instalar um pacote extra. Eu estou a usar o psych e instalei-o assim, dentro do ambiente do R:

install.packages("psych")

Para efetuar uma análise fatorial de componentes principais, estou a utilizar a função principal que tem os seguintes parâmetros:

principal(r, nfactors = 1, residuals = FALSE,rotate="varimax",n.obs=NA, covar=FALSE, scores=TRUE,missing=FALSE,impute="median",oblique.scores=TRUE,method="regression",...)

O primeiro parâmetro é o único obrigatório e pode ser uma matriz de dados com as variáveis a analisar, ou então a matriz de correlações das variáveis. No caso de ser a matriz de dados, a função calcula a matriz de correlações removendo os valores em falta (missing values) aos pares (pairwise), ou seja, para cada correlação entre duas variáveis, são removidos apenas os casos que contenham valores em falta nessas variáveis.

Ora, se formos efetuar o mesmo cálculo no SPSS, por omissão é utilizada a remoção listwise dos casos, ou seja, todos os casos que contenham valores em falta, em qualquer das variáveis usadas, são removidos previamente ao cálculo.

Portanto, havendo valores em falta nas variáveis, por omissão, o R e o SPSS produzem resultados diferentes para a mesma análise fatorial.

Para se obterem resultados iguais nos dois programas, é necessário que a técnica de remoção dos valores em falta seja a mesma. No caso do R, posso calcular a matriz de correlações previamente, usando a remoção listwise para os valores em falta, e depois forneço essa matriz à função principal.

Fica aqui a sequência de instruções desde o carregamento dos dados até à obtenção da análise fatorial.

1) Abrir o ficheiro de dados e criar a matriz (data.frame) com as variáveis a processar

X<-read.table('/tmp/FACT.txt',header=T)
attach(X)
dados<-data.frame(M1=M1, M2=M2, M3=M3, M4=M4, M5=M5, M6=M6, M7=M7, M8=M8, M9=M9, M10=M10, M11=M11, M12=M12, M13=M13, M14=M14, M15=M15, M16=M16, M17=M17, M18=M18, M19=M19, M20=M20, M21=M21, M22=M22)
library(psych)

O ficheiro de dados tem 22 variáveis com os nomes indicados acima, e com um aspeto semelhante ao seguinte:

M1      M2      M3      M4      M5     ...     M21     M22
4       5       5       4       4      ...     4       2
4       5       5       2       4      ...     5       3
5       5       4       5       4      ...     4       1
4       5       4       2       5      ...     4       4
4       5       4       4       5      ...     5       5
3       5       4       4       5      ...     4       4
5       5       4       3       4      ...     4       4
4       4       5       5       4      ...     4       3
4       2       4       3       5      ...     5       2
..     ...     ...     ...     ...     ...    ...     ...
4       4       2       4       4      ...     4       4

2) Todas as variáveis têm o 9 para representar o valor em falta. Por isso, criei uma função para substituir o 9 pelo NA (valor em falta no R) para todas as variáveis do data.frame.

poeNA <- function(v) {
	is.na(v) = v==9
	return(v)
}
dados<-apply(dados, 2, poeNA)

3) Calcular a matriz de correlação, removendo os valores em falta em listwise, e efetuar a análise fatorial, com extração de 5 fatores e rotação varimax.

cdados<-cor(dados, use="complete.obs")
temp.fit<-principal(cdados, nfactors=5, rotate="varimax")
print(temp.fit, digits=3, cutoff=.3)

Entretanto, tentei fazer outras rotações para além da Varimax e deparei com um problema: os resultados do R não coincidem com os do SPSS.

A rotação varimax está no pacote base e faz a normalização de Kaiser por omissão. As outras rotações estão noutros pacotes e tem que se pedir explicitamente para fazer a normalização de Kaiser. Para isso deve passar-se o parâmetro normalize=TRUE, quando se chama a função “principal”. Mas ainda assim só consegui acertar a rotação oblimin. A promax e a quartimax não coincidem com o SPSS. [1] [2]

Pesquisei mais e descobri que há uma função kaiser que pode ser invocada com dois parâmetros: a solução não rodada, e o tipo de rotação a fazer. Produz uma solução rodada com a normalização de Kaiser.
Consegui resolver todas as rotações exceto a promax, que vem no pacote psych e funciona de forma diferente.

temp.fit<-principal(cdados, nfactors=5, rotate="none")
temp.fit<-kaiser(temp.fit, rotate="quartimax")
print(temp.fit, digits=3, cutoff=.3)
temp.fit$loadings

temp.fit<-principal(cdados, nfactors=5, rotate="none")
temp.fit<-kaiser(temp.fit, rotate="oblimin")
print(temp.fit, digits=3, cutoff=.3)
temp.fit$loadings

Aplicações de R, com interpretação dos resultados em STAT.COOL

Sendmail e AUTH

Comecei a receber mensagens de correio eletrónico de volta, rejeitadas pelo Spamhaus PBL. Contrariamente às outras listas do Spamhaus, a lista PBL não é uma lista de spammers. É antes uma lista de servidores de email que eles consideram – por não conhecerem – que não são idóneos para enviar correio. Por exemplo, por estarem numa gama de IPs dinâmicos.

Passei imenso tempo a tentar configurar as soluções que eles apontam no site, antes de ir diretamente à solução – que eles não recomendavam – que era pedir para retirar o IP da lista.

Uma das soluções tentadas, e que foi uma configuração que ficou implementada no meu servidor, foi a autenticação com AUTH e SASL. Para isso, estive a noite toda a pesquisar, mas as informações importantes estão nos sítios seguintes:

Configurei usando estas ideias (mas modifiquei)
1) http://edc.tversu.ru/elib/inf/0047/0596004710_sendmailckbk-chp-7-sect-2.html
2) http://www.sendmail.org/~ca/email/auth.html
3) http://unix.stackexchange.com/questions/132711/using-port-587-with-sendmail

De notar que no link 2) acima, a configuração apresentada, relativa à linha seguinte, está obsoleta desde o sendmail 8.12
————————————————
define(`confDEF_AUTH_INFO’, `/etc/mail/auth/auth-info’)dnl
————————————————
No 8.13, deve usar-se a linha AuthInfo no ficheiro /etc/mail/access

Ver a minha configuração final:
http://escola.w3.pt/linux/Configurar_Sendmail_Auth.html

Com isto tudo, não avancei com o projeto STAT.COOL. Mas vou hoje tentar concluir a Análise Fatorial de Componentes Principais. Depois é só restruturar a interface e pôr em linha.

Sendmail collect: premature EOM: unexpected close

Há vários meses que estou a ter erros no Sendmail com mensagens provenientes de um endereço específico: o do meu contabilista.

Os erros são: “collect: premature EOM: unexpected close”
O servidor é: authsmtpXX.register.it

Já tentei várias “correções” para o problema, mas até agora não consegui resolver o problema. Há muitos comentários na net@ sobre isto que apontam para a consulta de DNS Blacklists desativadas. Removi todas as consultas às DNSBL mas o problema subsistiu.

Havia também alguns comentários que enviavam para as FAQs do Sendmail, mas os links estavam todos quebrados e nunca consegui chegar à FAQ indicada.

Agora, depois de uma pesquisa mais aturada, deparei com uma FAQ do Sendmail que talvez me possa ajudar: How do I solve “collect: I/O error on connection” or “reply: read error from host.name” errors?

Vou explorar isto e depois digo se o problema ficou resolvido.

HTML 5 e UTF8

No fim de semana passado, atualizei os servidores todos para as novas versões do Apache e do PHP. Essas atualizações causaram-me imensos problemas, nomeadamente por causa das funções de data/hora e por causa dos ficheiros codificados em iso-8859-1.

Atualmente, o PHP não confia nas definições de TIMEZONE do sistema (apesar de eu as configurar corretamente) e obriga a que todos os programas que façam uso de funções de data/hora definam previamente a zona de tempo:

date_default_timezone_set("Europe/Lisbon");

Por outro lado, foi necessário converter todos os ficheiros HTML e PHP, de ISO-8859-1 para UTF-8. Em alguns projetos antigos, tenho mais que 300 ficheiros e é impraticável alterá-los todos manualmente. Felizmente, em Linux é possível fazer essas conversões de uma só vez:

find . -name "*.php" -exec sh -c "iconv -f ISO-8859-1 -t UTF-8 {} > {}.utf8"  \; -exec mv "{}".utf8 "{}" \;

find . -name "*.html" -exec sh -c "iconv -f ISO-8859-1 -t UTF-8 {} > {}.utf8"  \; -exec mv "{}".utf8 "{}" \;

Kernel 3.18.11

Grandes alterações no Slackware. Devem estar a preparar a saída de próxima versão da distribuição mais antiga de Linux e, por isso, atualizaram praticamente todos os pacotes para as últimas versões. Eis a mensagem do Patrick:

Greetings! It has indeed been far too long. I apologize for the absence of updates lately, but we’ve been using the time to get some good work done.
This is not a beta (probably not even an alpha release yet), but it is also not a drill. 😉 We’ve spared you all most of the pain while we transitioned to a lot of new libraries that got major version number bumps, and have tested everything to ensure that this will be a smooth upgrade.
Still, I’d be surprised if all this didn’t introduce any regressions, so if you find any problems let us know. Huge thanks are due to Robby Workman, Heinz Wiesinger, Eric Hameleers, and Stuart Winter for all the help. Have fun!

Entre as alterações, vem um kernel com 4 versões major acima daquela que temos estado a usar. Vamos ver se isto não dá problemas. Vou aproveitar e instalo também a versão 4.3.26 do VirtualBox nos hosts das máquinas virtuais.

Ficam aqui os comandos que tenho que executar no fim do processo, e que são os que usei das últimas vezes. Estes comandos são necessários para recompilar o VirtualBox para a nova versão do Kernel do Linux.

cd /root
bat/vboxes stop
cd /usr/local/
VBoxManage extpack uninstall "Oracle VM VirtualBox Extension Pack"
reboot
exit
cd /usr/local/
chmod +x ./VirtualBox-4.3.26-98988-Linux_amd64.run
./VirtualBox-4.3.26-98988-Linux_amd64.run
VBoxManage extpack install Oracle_VM_VirtualBox_Extension_Pack-4.3.26-98988.vbox-extpack
cd -
bat/vboxes start

O ficheiro bat/vboxes é um ficheiro de comandos que criei para gerir as máquinas virtuais do VirtualBox.