Syntax coloring

sexta-feira, 27 de março de 2015

Java / GWT development with tmpfs (or, why is my development slower because I've switched to Arch Linux)

I've recently switched from Ubuntu to Arch Linux (Antergos, really, as it provides a decent installer and nice defaults, and is just Arch in the end).
Arch uses systemd (the controversial init system that has caused lots of debates, but I have personally loved it), and since the upcoming 15.04 version, Ubuntu will use it too.
And systemd by default mounts the /tmp directory files using a tmpfs, which is mounted on RAM, limited by default to half the physical available memory. Also, in my installation (don't know if this is Arch's or Antergos' default), the /etc/fstab file also had the /tmp to be mounted as tmpfs.
This might be nice for most people, but if you run applications that store huge amounts of data in /tmp, it can be terrible.
In my case it is GWT which writes hundreds of megabytes to the temporary folder.
Result? When GWT is compiling Java to JavaScript code, things get SLOOOOOW, because:
  • Eclipse uses1.0-1.5GB of RAM
  • The GWT SuperDevMode, together with the running application, takes another 1.0-1.5GB
  • Chrome uses 1.0-2.0GB of RAM with several open tabs (and when dev tools is open, it eats a lot of RAM too)
Counting up to 4GB (max) of tmpfs, and the desktop environment (Cinnamon in my case), Skype, DropBox and others, my 8GB quickly get short.

At least I found that I can improve things by disabling mounting /tmp as tmpfs.
To do that I've resorted, as usual, to the excellent Arch Wiki (by the way, one of the best pieces of documentation for any project I've ever seen): https://wiki.archlinux.org/index.php/Tmpfs.

I have removed the line in /etc/fstab which declares /tmp as tmpfs and created the /etc/tmpfiles.d/tmp.conf file with the following content:

# see tmpfiles.d(5)
# always enable /tmp folder cleaning
D! /tmp 1777 root root 0

# remove files in /var/tmp older than 10 days
D /var/tmp 1777 root root 10d

# namespace mountpoints (PrivateTmp=yes) are excluded from removal
x /tmp/systemd-private-*
x /var/tmp/systemd-private-*
X /tmp/systemd-private-*/tmp
X /var/tmp/systemd-private-*/tmp

Then we need to tell systemd to not mount /tmp as tmpfs automatically, with the following command:
systemctl mask tmp.mount

Afterwards, just rebooted the system and.... magic! I can nicely work with GWT compilation again.

As Ubuntu 15.04 will switch to systemd, and systemd by default mounts /tmp as tmpfs even without anything defined in /etc/fstab, this might affect Ubuntu too in the future. The same is true to other major distributions.

quarta-feira, 12 de novembro de 2014

Generating DDL with EclipseLink JPA and PostgreSQL

I normally say that either the project I work on (http://www.cyclos.org) is too special or we're just unlucky with the default operation in most libraries we use.
As we need streaming BLOBs (we don't want to load entire images into memory), and EclipseLink by default doesn't handle streaming.

So I had to do a subclass of org.eclipse.persistence.platform.database.PostgreSQLPlatform. The following methods were implemented:

    @Override
    public Object getObjectFromResultSet(ResultSet resultSet, int columnNumber, int type, AbstractSession session) throws SQLException {
        String name;
        if (type == Types.BIGINT) {
            // May be a number or an OID
            name = resultSet.getMetaData().getColumnTypeName(columnNumber);
            if ("OID".equalsIgnoreCase(name)) {
                return resultSet.getBlob(columnNumber);
            }
        }
        return super.getObjectFromResultSet(resultSet, columnNumber, type, session);
    }

    @Override
    public void setParameterValueInDatabaseCall(Object parameter, PreparedStatement statement, int index, AbstractSession session) throws SQLException {
        if (parameter instanceof DatabaseField) {
            DatabaseField field = (DatabaseField) parameter;
            if (Blob.class.equals(field.getType())) {
                statement.setBlob(index, (Blob) null);
            } else {
                super.setParameterValueInDatabaseCall(parameter, statement, index, session);
            }
        } else if (parameter instanceof Blob) {
            statement.setBlob(index, ((Blob) parameter));
        } else {
            super.setParameterValueInDatabaseCall(parameter, statement, index, session);
        }
    }

    @Override
    public boolean shouldUseCustomModifyForCall(DatabaseField field) {
        if (Blob.class.equals(field.getType())) {
            return true;
        }
        return super.shouldUseCustomModifyForCall(field);
    }

    @Override
    @SuppressWarnings({ "rawtypes", "unchecked" })
    protected Hashtable buildFieldTypes() {
        Hashtable types = super.buildFieldTypes();
        types.put(Blob.class, new FieldTypeDefinition("OID", false));
        return types;
    }

This way we can control: small binary data is mapped in entities via byte[]. Large binary data, via java.sql.Blob.

Then, to generate the schema:

    EntityManagerFactoryImpl emf = (EntityManagerFactoryImpl) realEMF;
    DatabaseSessionImpl databaseSession = emf.getDatabaseSession();

    StringWriter sw = new StringWriter();
    SchemaManager schemaManager = new SchemaManager(databaseSession);
    schemaManager.outputDDLToWriter(sw);

    DefaultTableGenerator tableGenerator = new DefaultTableGenerator(databaseSession.getProject()) {
        @Override
        protected void resetFieldTypeForLOB(DirectToFieldMapping mapping) {
            // Hack to avoid the workaround for oracle 4k thin driver bug
        }
    };
    TableCreator tableCreator = tableGenerator.generateDefaultTableCreator();
    tableCreator.createTables(databaseSession, schemaManager);

    String script = sw.toString();

That DefaultTableGenerator inner class took me some hours debugging EclipseLink to figure out. The method comments says it is there to fix issues with oracle 4k thin driver. And it messed up the other use cases, as Blob was being handled as Byte[], and we want OID type specifically for Blobs.

Congratulations, Oracle! (facepalm)

sábado, 2 de fevereiro de 2013

The beauty of Querydsl: calling database functions

It's a common pattern to have a self-referencing table, in order to model an hierarchy tree. Now, sorting results by hierarchy, is an entirely different subject. Some databases, like Oracle, has the start with / connect by clauses. But to bring that to the JPA world is another different story. And imagine that with the über ugly JPA 2 criteria queries. I was already using Querydsl with JPA (using EclipseLink), and it allowed a very clean solution.

First, I brought database functions to the rescue, and wrote a function which receives an entity id, a table name, the name column and the parent id column. So, the function can be reused on any type of entity. As the DB is Postgres, here comes the code:

create or replace function name_hierarchy
    (p_id bigint, 
     p_table varchar, 
     p_name_col varchar, 
     p_parent_id_col varchar)
    returns varchar
    as $$
        declare
            sql text;
            current_id bigint;
            v_name varchar;
            v_parent_id bigint;
            path varchar[];
        begin
            current_id := p_id;
            while current_id is not null loop
                sql := 'select id, ' 
                     || p_name_col || ', ' 
                     || p_parent_id_col
                     || ' from ' || p_table 
                     || ' where id = ' || current_id;
                execute sql into current_id, v_name, v_parent_id;
                path := array_prepend(v_name, path);
                current_id := v_parent_id;
            end loop;
            return array_to_string(path, ' > ');
        end;
    $$ language plpgsql
    stable;

Then, I needed to create a Querydsl operator to represent the function. It contains a name and the argument types.

public class CustomOperators {
    public static final Operator<String>
        NAME_HIERARCHY = new OperatorImpl<String>(
            "name_hierarchy", 
            Long.class, String.class, String.class, String.class);
}

There was also a custom Querydsl templates class to actually convert that operator into JPQL code (note that EclipseLink uses FUNC('name', args...) to invoke native database functions):

    public static class CustomTemplates
        extends EclipseLinkTemplates {

        private static final CustomTemplates INSTANCE = 
            new CustomTemplates();

        public static CustomTemplates getInstance() {
            return INSTANCE;
        }

        private CustomTemplates() {
            add(CustomOperators.NAME_HIERARCHY, 
                "FUNC('name_hierarchy', {0}, {1}, {2}, {3})");
        }
    }

As the example entity is Configuration, the final plumbing needed is a method annotated with @QueryDelegate(Configuration.class), so the extension method can be created in any class:

    @QueryDelegate(Configuration.class)
    public static StringExpression 
        nameHierarchy(EntityPath<Configuration> configuration) {
        NumberPath<Long> id = (NumberPath<Long>)
            FieldUtils.readField(configuration, "id");
        return StringOperation.create(
            CustomOperators.NAME_HIERARCHY, 
            id,
            StringTemplate.create("'configurations'"),
            StringTemplate.create("'name'"),
            StringTemplate.create("'parent_id'"));
    }

Finally, I can use the nameHierarchy method anywhere on queries, like:

QConfiguration c = QConfiguration.configuration;
List<Configuration> configs = new JPAQuery()
    .from(c)
    .orderBy(c.nameHierarchy.asc())
    .list(c);

Looks like that nameHierarchy method was always there, doesn't it? And the same idea can be reused on any other function, seamlessly blending them on the query metamodel. Now try to make something similar with JPA's criteria api!

domingo, 20 de janeiro de 2013

Replaced Hibernate as JPA provider... To never look back!!!

Hibernate is probably the most well-known ORM tool for Java. I first used it on version 1.X back on 2002. It even influenced the JPA (Java Persistence API), which is a standard ORM API.
The problem is: the application (has about 200 entities) was taking up +- 350MB of heap size on startup right after forcing a garbage collect (using jvisualvm).
That was too much. But things would improve. There was a setting which I've always mislooked as a batch size equivalent, called hibernate.default_batch_fetch_size, which we had with value 20.
After some investigation, I found it was used to load several records at once, at the expense of memory. So, just to test out, I changed it to 1 and, surprise... The same application was now taking up +- 150MB! What a change for something misunderstood!
But I was not satisfied, and decided to try another JPA provider. From some researches, I decided to go with EclipseLink. Result? The same application now starts up (after a garbage collection) with +- 35 MB!!!
Ok, what a huge difference! But performance should be worst, shouldn't it? No!!! On the load tests I did, EclipseLink was actually 2.5x faster than Hibernate!
There were some bumps, several queries were done with some non-standard (from JPA's point of view) elements, and so on. But they all could be resolved, one at a time.
Conclusion: After being a loyal Hibernate user for several years (well, not that loyal, as some projects I did with plain JDBC using Querydsl SQL module), I'll now try to avoid it as much as possible, and use EclipseLink instead. Even a future possibility is Batoo JPA, which claims to be 15-20x faster than Hibernate. However, as it cannot be used with Spring's LocalContainerEntityManagerFactoryBean (at least for now, as it requires a persistence.xml, and I like bootstrapping things programmatically), I'll stick with EclipseLink for now.

quarta-feira, 6 de junho de 2012

Tutorial: Instalando o Cyanogen Mod no LG Optimus ME (P-350) pelo Linux

Tenho um telefone LG Optimus ME (P-350, pecan), e o sistema dele ficou progressivamente mais lento, ao ponto de me fazer aventurar pelo mundo dos ROMs customizadas.
Procurei por aí e só vi tutoriais para aquele sistema operacional da tela azul. Como ele não é muito bem vindo por aqui, tive que experimentar um pouco, e resolvi reportar os passos aqui.
Se você tem este telefone, usa o Linux e quer instalar o Cyanogen Mod, aqui vão os passos. Eles foram realizados no Ubuntu 12.04 Precise Pangolin, mas podem facilmente ser adaptados a outras distribuições.

Atenção: como de costume, estes passos funcionaram para mim, e não me responsabilize caso algo não dê certo... Além disso, obter acesso root no aparelho provavelmente invalide a garantia do aparelho. Siga por sua conta e risco.
Atenção 2: ao realizar este processo, TODOS os dados (contatos, aplicativos, etc) do telefone serão perdidos. Faça um backup de seus dados antes.

1. Acesso root no aparelho

Baixe o aplicativo Gingerbreak, versão 1.20 em http://forum.xda-developers.com/showthread.php?t=1044765. Para instalá-lo, você necessita da opção de permitir instalar aplicativos de fontes desconhecidas. Se preferir, baixe o apk usando o seu computador, copie-o para o cartão SD e instale-o com um aplicativo como o AppInstaller.

Uma vez instalado, Habilite o debug por USB em Configurações > Aplicações > Desenvolvimento e certifique-se de ter um cartão SD montado. Rode o aplicativo, selecionando a opção de root. Depois disso, o aparelho vai reiniciar, já com o acesso root obtido.

2. Obtendo e configurando o ADB

O ADB é um comando que permite executar comandos no celular quando ele está conectado por USB ao computador. Seguindo o que está descrito em http://forum.xda-developers.com/showthread.php?t=1067273, baixe o arquivo http://forum.xda-developers.com/attachment.php?attachmentid=588859&d=1304719623 e extraia o zip para um caminho executável, por exemplo, com o comando:
sudo unzip fastboot-and-adb.zip -d /usr/bin

Depois, é necessário configurar o UDEV para reconhecer o dispositivo. Para tal, baixe o arquivo http://www.joescat.com/linux/51-android.rules, copie-o para o local correto e edite-o, com os seguintes comandos:
sudo cp 51-android.rules /etc/udev/rules.d/
sudo chown root:root /etc/udev/rules.d/51-android.rules
sudo chmod 644 /etc/udev/rules.d/51-android.rules
gksu gedit /etc/udev/rules.d/51-android.rules

Agora, com o editor de textos, remova o comentário na linha logo abaixo do fabricante LG, para que fique assim:
# LG Ally/Optimus One/Vortex/P500 618f, 618e=(debug)
ATTRS{idVendor}=="1004", ATTRS{idProduct}=="618e", ENV{adb_matched}="yes"

Depois, execute sudo /etc/init.d/udev restart

Talvez seja necessário instalar a versão 32 bits do libncurses se você estiver usando o Linux em 64 bits. Caso tenha algum problema executando o adb, rode sudo apt-get install libncurses5:i386

Teste o adb com o telefone conectado por USB. Depois, rode no console: adb devices
Você deve ver 1 linha abaixo de "List of devices attached".

3. Obtendo o custom recovery e a ROM

Primeiro, baixe o custom recovery. Neste caso, usei o AmonRA custom recovery. Para o p350, pode-se usar o seguinte link: http://leaveme.in/wp/wp-content/uploads/2012/01/recovery-RA-pecan-2.2.1-GNM-drap.img_.zip.
Dentro do zip, tem os arquivos flash_image e recovery-RA-pecan-2.2.1-GNM-drap.img. Copie ambos para a raiz do cartão SD.

Você também vai precisar da ROM do Cyanogenmod e do Google Apps (para ter acesso, por exemplo, ao Google Play). Baixe ambos. O GApps, conforme o wiki do próprio Cyanogenmod pode ser baixado de http://cmw.22aaf3.com/gapps/gapps-gb-20110828-signed.zip. Já a ROM eu usei esta aqui: http://forum.xda-developers.com/showthread.php?t=1610605.

Copie também ambos os arquivos zip (do Google Apps e do ROM) para a raiz do cartão SD, sem extrair nenhum.

4. Flash da imagem e acesso ao custom recovery

Com o flash_image, o .img do AmonRA recovery e os zips do ROM do Cyanogenmod e do Google Apps todos na raiz do cartão SD, vamos aos comandos pelo ADB. O debug USB tem que estar ativo.
$ adb shell
su
mount -o remount,rw -t yaffs2 /dev/block/mtdblock1 /system
cat /sdcard/flash_image > /system/bin/flash_image
chmod 755 /system/bin/flash_image
sync
flash_image recovery /sdcard/recovery-RA-pecan-2.2.1-GNM-drap.img
sync
reboot recovery

Você vai ver a tela do recovery, que é um menu com algumas opções que podem ser navegadas com as teclas de volume, e confirmadas com o botão menu.

Faça um backup da sua imagem atual (tem essa opção no menu inicial do recovery). Depois, temos que limpar os dados anteriores do telefone. Isto é muito importante, o telefone pode não bootar sem isto!
Vá na opção Wipe e selecione as seguintes opções, uma a uma:
Wipe ALL data/factory resetWipe Dalvik-cache
Wipe battery stats

Com o botão voltar no telefone, volte ao menu anterior e selecione 
Flash zip menu, e depois Choose zip from sdcard. Selecione o zip com o ROM do Cyanogenmod.
Espere terminar e novamente selecione Choose zip from sdcard e selecione o zip com o Google Apps.
Depois, volte e selecione Reboot system now.

Você verá o pinguinzinho do Linux e depois o splash do Cyanogenmod. O primeiro boot demora bastante. Dá uma tensão, mas é assim mesmo. Depois disso, bem vindo ao seu novo sistema!!!

5. Dica: atualizando o ROM

Você pode ficar monitorando a página do ROM para ver se saiu uma nova versão. Caso tenha saído, basta baixá-la e colocá-la na raiz do cartão SD (apague a anterior caso ainda esteja lá para não se confundir). Depois, pressione o botão de desligar por alguns segundos, selecione Reiniciar > Recuperação.

Após o boot, aparecerá a tela do recovery. Limpe o Dalvik cache, na opção Wipe (isto é muito importante!!!), e vá no Flash zip menu, selecionando o arquivo zip contendo o ROM. Reinicie e pronto!

6. Dica: aumentando a duração da bateria

É possível fazer uma recalibragem da bateria. Basta carregar até 100% (não se engane pelo ícone verde, vá em Configurações, Sobre o telefone, Status e veja se está totalmente carregada). Depois reinicie no recovery (da mesma forma como no item anterior) e selecione Wipe, Wipe battery stats. Reinicie o telefone (de preferência com o carregador ainda ligado).

Quando o telefone tiver iniciado totalmente, remova o carregador e deixe a bateria acabar totalmente (o telefone desligar por causa dela). Depois carregue-o e use-o normalmente. No meu caso, tenho cerca de 5 dias com cada carga.

Considerações finais

Espero ter ajudado. Muitos tutoriais por aí ensinam a fazer este processo pelo Windows, mas pra que precisar de um Windows para configurar o telefone que roda Linux? ;-)

sexta-feira, 30 de setembro de 2011

Yet another Internet Explorer issue: Java applets created by JavaScript

In Cyclos, I've been working to implement support for printing in a local receipt printer.
We found the jZebra project which is a Java applet that prints in a receipt printer on the local computer.
So, as this is an optional feature, and will only be used by few users, we didn't want to load the applet on every page. Instead, only when the user clicks print, the applet tag is created and appended to the document with JavaScript (using document.createElement("applet") and friends).
Then, the usual sequence:
  • Test in Firefox: check.
  • Test in Chrome: check.
  • Test in Opera: check.
  • Find a computer running windows somewhere to test in Internet Exporer: fail.
Why I wasn't surprised?
When adding the applet through JavaScript, MSIE somehow doesn't makes the public applet methods visible for JavaScript. So, no .findPrinter(), no .append(), no .print(). 
Result? As this feature won't be used by most users, we decided to disable it on MSIE, at least until some workaround is found. ..

What a revange!

sábado, 24 de setembro de 2011

Atualizando o firmware do LG Optimus ME (P350) com VirtualBox no Linux

Eu comprei recentemente um celular LG Optimus ME (P350), que vem com o Android 2.2.2.
O problema é que ele vem com o firmware bem desatualizado 10a. Ele tem um bug que, ao tocar na tela, a cpu vai lá em cima... Emfim.
Baseei-me neste post para realizar o procedimento: http://www.sleetherz.com/2011/09/how-to-update-lg-optimus-p350-to-firmware-v-10c/
Mas tem um detalhe extra: Como não tenho o windows instalado (uso somente o Linux), e o software é só para windows, temos um probleminha. Mas, como nem tudo é perfeito, tenho um VirtualBox com um winxp pra esses casos... Então tá.

Atenção! Este procedimento foi o que eu fiz, e funcionou para mim. Não me responsabilizo caso dê algo errado...

Primeiro: Quando o telefone está em modo de emergência, ele é detectado pelo Linux como um modem. Assim, o kernel sobe o módulo cdc_acm, para poder utilizar o dispositivo. O problema é que se o Linux usa o dispositivo, não tem como ele ser usado pelo VirtualBox. Então, a primeira coisa a fazer é impedir o carregamento desse módulo. Edite o arquivo /etc/modprobe.d/blacklist.conf e adicione a seguinte linha:
blacklist cdc_acm. Depois que o procedimento terminar, você pode remover essa linha.

Segundo
: Tenha o VirtualBox com o Extension Pack instalado. Dê uma olhada na página de downloads: http://www.virtualbox.org/wiki/Downloads.

Agora, execute estas operações dentro da máquina virtual:

  1. O artigo no qual me baseei recomenda que o micro esteja desconectado da Internet. No VirtualBox, basta ir em Dispositivos > Adaptadores de Rede e desmarcar o Cabo conectado.
  2. Baixe o firmware em http://www.lg-phones.org/lg-optimus-me-firmwares-download.html. Instalei o 10c por ser o último com suporte a português do Brasil. Mas tem até o 10f.
  3. Baixe o driver da LG para o telefone: http://www.mediafire.com/?qvdbresp5nntb6x.
  4. Baixe o KDZ firmware uploader: http://www.unclenet.de/files/KDZ_FW_UPD_EN.7z.
  5. Instale o driver da LG.
  6. Extraia o KDZ_FW_UPD_EN.7z.
  7. Instale o msxml.msi que está dentro do arquivo do KDZ.
  8. Com o telefone desligado e desconectado da porta usb, segure as teclas de aumentar volume, baixar volume e ligar ao mesmo tempo.
  9. O telefone vai iniciar em modo de emergência.
  10. Conecte o telefone no micro pela porta USB.
  11. Passe o controle do dispositivo USB para o VirtualBox: No menu Dispositivos > Dispositivos USB, Marque o telefone LG.
  12. Execute o programa KDZ_FW_UPD.exe, que está dentro do arquivo do KDZ.
  13. Selecione as opções  3GQCT no “Type” e DIAG no “PhoneMode”.
  14. Selecione o arquivo do firmware (V10C_00.KDZ no meu caso).
  15. Inicie a atualização. O post no qual eu me baseei diz que caso haja algum problema, pode-se tentar com o telefone sem a bateria.
  16. No meio da atualização, o telefone é desligado. O controle do dispositivo deve novamente ser passado para o VirtualBox (Dispositivos > Dispositivos USB, como anteriormente). Não sei quanto tempo você tem para fazer isso antes que o KDZ desista, portanto, esteja atento!
  17. Agora ele deve ir até o fim...
A primeira vez que o telefone é ligado, demora bastante para iniciar. Paciência!
Ah, não esqueça de remover a linha no /etc/modprobe.d/blacklist.conf.

Era isso.

domingo, 3 de julho de 2011

The day I've faced a kernel panic in Linux

I've been tempted to switch back from Unity to KDE for several days.
So, today I decided to actually do it.
Everything was fine, then, at some point, after setting up everything, I restarted and...
kernel panic!!!
Wow. For those who haven't seen it, it kind of scares. The numlock and capslock leds on the keyboard keep blinking and nothing else works.
I rebooted again. Same thing. Then again. Sometimes, it was even a hard freeze: not even the blinking leds.
All this happened right after entering the login password in KDM.
Then, I just decided to reinstall everything (I had just installed kubuntu-desktop and uninstalled everything from gnome, as explained here.
After reinstalling, upgrading, configuring... Guess what?
The same thing.
Then I just realized it was when connecting to the wireless network that the system froze.
So, my guess was the wireless card driver. Bingo!!!
I have a Dell Vostro 3300, which comes with a Broadcom  BCM4313 board. The default driver for it is brcm80211.
I had seen several days before in the Hardware Drivers program that another driver was available for it: Broadcom STA driver.
As I had nothing to loose, I just tried, and it worked! \o/
So, here is my tip if anyone encounters a hard freeze or a kernel panic and has the same hardware: install the Broadcom STA driver!
Just as a note, neither KDE nor Kubuntu are to blame here: it was the wireless driver's fault.

terça-feira, 10 de maio de 2011

Não usa Internet Explorer? Você não é mais bem-vindo ao www.smiles.com.br

Sou usuário Linux (o último Windows que usei foi o XP).

Até algum tempo atrás eu acessava sem problemas o site do Smiles (www.smiles.com.br).

Este fim-de-semana tentei acessar e me deparei com um erro, dizendo que eu precisava usar o Microsoft Internet Explorer.

Desiludido, entrei em contato com o "Fale conosco", e, realmente desisti do site.

Me mandaram baixar o Internet Explorer para o meu sistema operacional...

Credo.

Em pleno 2011 ver sites importantes depender de uma plataforma específica é algo que só se explica com ignorância ou mala preta...

Aqui o e-mail na íntegra (salvo os dados pessoais):

Prezado Senhor Luis Fernando:

N° de atendimento: 1-412064905.

Em atenção ao seu e-mail, orientamos verificar e se possível, baixar uma versão do navegador Internet Explorer compatível com seu sistema operacional, pois terá um melhor desempenho durante o acesso ao site Smiles.


Esclarecemos que estamos trabalhando incessantemente para a melhoria de nosso atendimento, com atualizações de sistemas e o Site Smiles.

Pedimos sua compreensão.

Estamos à sua disposição.

Atenciosamente,

Janaina Oliveira
Programa Smiles
VRG Linhas Aéreas S.A - Grupo GOL
www.smiles.com.br/smiles/content/faleconosco/index.htm
Central de Atendimento Smiles: 4003 7001 / 4003 7007
Para localidades não atendidas pelo serviço 4003 ligue para 0800-883-2245.

Favor não responder esta mensagem, caso seja necessário utilize Site “www.smiles.com.br” “My Smiles” “Fale Conosco”, ou utilize o link abaixo. “http://www.smilescom.br/smiles/content/faleconosco/index.htm”.

Texto confidencial para uso exclusivo do destinatário. Não divulgue e apague-o imediatamente se o recebeu por engano.
This is a confidential text to be exclusively used by the recipient. Do not disclose to anybody and delete it immediately if you received it by mistake.
Texto confidencial para uso exclusivo del destinatario. Si usted lo recibi por error no lo divulgue y exclúyalo inmediatamente
Antes de imprimir, pense em sua responsabilidade com o MEIO AMBIENTE.

----- Mensagem Original -----
De: smilesfaleconosco@golnaweb.com.br
Para: smiles.portugues@golnaweb.com.br
Enviada em: 09/05/2011 10:15:59
Assunto: Fale Conosco: Crítica

Fale Conosco - Crítica

Assunto: SITE

Nome: Luis Fernando

Sobrenome: Planella Gonzalez

CPF: XXXXXXX

E-mail: XXXXXXX

Numero Smiles: XXXXXXX

Contato: XXXXXXX

Localizador:

Origem:

Destino:

Data do vôo:

Número do vôo:

Data de ocorrência:

Número Protocolo:

Comentários: É lamentável que não posso mais acessar minha conta no Smiles porque agora o site exige o uso do Microsoft Internet Explorer.
De onde vocês tiraram a ideia infeliz de restringir o acesso a esse navegador, que é sabidamente o mais inseguro de todos?
Sou usuario Linux. Além de me excluir, excluiram os usuarios Mac, iPhone, iPad, Android, Blackbarry ou qualquer coisa que não seja Windows.
Vocês tomaram um passo na contramão da tecnologia, e, apesar de duvidar que isto possa ser solucionado a curto prazo (porque provavelmente investiram milhões no novo sistema mais "seguro"), pelo bem da própria empresa, espero que isto seja mudado algum dia.
As 40.000 milhas que tenho no programa (que ainda não consegui utilizar) serão as últimas investidas no smiles.
Lamentável.

terça-feira, 1 de março de 2011

An example of anti-code

When doing some code review, I've faced this:
var stateOptions = null;
var typeOptions = null;

function hideOptions() {
 if(stateOptions == null) {
  stateOptions = new Array();
  stateOptions[0] = document.getElementById('status').options[0];
  stateOptions[1] = document.getElementById('status').options[1];
  stateOptions[2] = document.getElementById('status').options[2];
  stateOptions[3] = document.getElementById('status').options[3];
  stateOptions[4] = document.getElementById('status').options[4];
  stateOptions[5] = document.getElementById('status').options[5];
 }
 document.getElementById('status').remove(1);
 document.getElementById('status').remove(1);
 document.getElementById('status').remove(1); 
}

function showOptions() {
 document.getElementById('status').remove(0);
 document.getElementById('status').remove(0);
 document.getElementById('status').remove(0);
 try {
  
  document.getElementById('status').add(stateOptions[0], null);
  document.getElementById('status').add(stateOptions[1], null);
  document.getElementById('status').add(stateOptions[2], null);
  document.getElementById('status').add(stateOptions[3], null);
  document.getElementById('status').add(stateOptions[4], null);
  document.getElementById('status').add(stateOptions[5], null);
  
 } catch(ex) {
  document.getElementById('status').add(stateOptions[0], 0);
  document.getElementById('status').add(stateOptions[1], 1);
  document.getElementById('status').add(stateOptions[2], 2);
  document.getElementById('status').add(stateOptions[3], 3);
  document.getElementById('status').add(stateOptions[4], 4);
  document.getElementById('status').add(stateOptions[5], 5);
 } 
}
...

OMG

segunda-feira, 14 de fevereiro de 2011

I must admit: I was poisoned outside KDE...

After having an awful experience with KDE 4.5.0 (described here), I returned to it, as the performance issues were resolved (as I said here).
However, after that experience, something has changed in me...
I was a KDE lover. I found it way better in anything else. But after that...
I've actually been using them both. Kubuntu (with KDE 4.6) at work and Ubuntu at home.
The main point is: KDE's flagship technology is Plasma, which is the desktop, the panel and their widgets (and a few more things). The widgets... All I use is a single panel with a Kickoff menu, a task manager, a pager, a notification area and a clock. Pretty basic, I know. But that's all I need. No desktop widgets. Just a clean desktop and a simple panel.
Kind of, KDE 4, with all it's technologies, is like an overkill.
On the other hand, I never liked GNOME too much. But it gets better with DockbarX and Gnomenu, though ;-)
I must say I'm currently not 100% satisfied by neither KDE nor GNOME.
However, a new kid on the block is getting my attention: Canonical's Unity. The current Maverick netbook interface sucks. It's very slow. But the one shaping up for Natty (to be released in April) is the one I'm looking forward. I've tested the Unity 2D in the current Ubuntu, and it's very fast. And has everything I need: a simple panel and a nice launcher / task manager. Besides, it's beautiful.
Unity has a long way to go, as there's are still 1 alpha and 2 betas before the final launch. I'm really, really anxious to see how Unity will behave as my main desktop in a few months...

domingo, 6 de fevereiro de 2011

Using Querydsl SQL to handle persistence in Java programs

After several years working with Hibernate (since version 1.X - about 2001/2002) and then JPA, I'm quite convinced that for new projects I'd try a new approach: Querydsl SQL. Why? Well, Even though full ORM solutions like Hibernate have several advantages (managing relationships, an easier query language and so on), they also have their drawbacks. I found out that:
  • What I really wanted is an easier way to manipulate databases / resultsets;
  • It always selects all attributes when dealing with entities. I know you CAN select individual attributes, but this is more an exception than a rule. People tend to just read the entire record, and then accessing the needed attributes. Some argue that this is not something which impacts performance, but after some fine tuning on my current project, I realized that every gain matters;
  • Pure OO in data manipulation is nice, but the impedance mismatch just can't be negleted. It will bite you sooner or later;
  • You always end up with a few cases where native query is needed, or the performance is just not acceptable. I think that programs are coded by developers, but those who really needed to be pleased are the end users. And poor performance just produces bad mood on users;
  • Even though JPA 2 has most of the features Hibernate has, it brings a problem: Just like most (all?) JCP specifications, it always has points left out of the specification. So, having a (relatively complex) system working with a JPA provider (say, Hibernate) and migrating it to another one (EclipseLink, OpenJPA, ...) is not failproof. This just leads to frustration...

Ok, I know no framework / library / technology is perfect, but I think Querydsl SQL is quite promising. Here are a few points:
  • You have full power of native queries, with type-safe queries. Java classes are generated based on the database tables, so you have the full power of IDE's (autocomplete, finding references, code analysis...). This is a boost on productivity;
  • Queries can return several types of data, like iterators, lists, maps or single objects. The projection type can be beans, arrays, tuples or custom expressions. Querydsl is very easy to extended;
  • It can also handle data manipulation (inserts, updates and deletes). This kind of removes all cases one would need to touch the connection;
  • Besides to generating the Q-types (Java classes representing the database tables), it is also possible to generate beans (DTOs) for the tables. This is nice for cases where you want all columns of the table, but optional. Using them can boost the productivity, as avoids having to create each bean by hand.

So, enough talking! Let's take a look on some code. The example here is of a simple blog: We have users, which can create posts and commenting existing posts. So, here is the DDL for MySQL:
drop table if exists comment;
drop table if exists post;
drop table if exists user;

create table user (
    id bigint not null,
    name varchar(100) not null,
    username varchar(20) not null,
    password varchar(20) not null,
    primary key (id)
) engine innodb;

create table post (
    id bigint not null,
    user_id bigint not null,
    title varchar(250) not null,
    date datetime not null,
    contents text not null,
    primary key (id),
    constraint fk_post_user foreign key (user_id) references user(id)
) engine innodb;

create table comment (
    id bigint not null,
    user_id bigint not null,
    post_id bigint not null,
    date datetime not null,
    comments text not null,
    primary key (id),
    constraint fk_comment_user foreign key (user_id) references user(id),
    constraint fk_comment_post foreign key (post_id) references post(id)
) engine innodb;

So, we need to invoke Querydsl to read the database tables and generate the Java classes. Beans will be generated as well:
Configuration configuration = new Configuration(new MySQLTemplates());
NamingStrategy namingStrategy = new DefaultNamingStrategy();
MetaDataExporter exporter = new MetaDataExporter();
exporter.setConfiguration(configuration);
exporter.setNamePrefix("Q");
exporter.setTargetFolder(new File("generated"));
exporter.setSerializer(new MetaDataSerializer("Q", namingStrategy));
exporter.setBeanSerializer(new BeanSerializer());
exporter.setNamingStrategy(namingStrategy);
exporter.setPackageName("demo.blog");
        
Connection connection = ... //Get connection
exporter.export(connection.getMetaData());

If you are in Eclipse, just refresh the project and add the generated folder as source folder. There you will find the QUser, QPost and QComment classes, as well as the beans: User, Post and Comment.

Before showing some data manipulation code, here are some methods used by the examples (the configuration can be created the same way as in the example above):
SQLDeleteClause delete(RelationalPath path) {
    return new SQLDeleteClause(
        getConnection(), getConfiguration(), path);
}

SQLQuery from(Expression from) {
    SQLQueryImpl query = new SQLQueryImpl(
        getConnection(), getConfiguration());
    query.from(from);
    return query;
}

SQLInsertClause insert(RelationalPath path) {
    return new SQLInsertClause(
        getConnection(), getConfiguration(), path);
}

SQLUpdateClause update(RelationalPath path) {
    return new SQLUpdateClause(
        getConnection(), getConfiguration(), path);
}

So, here are some examples for manipulating data:
QUser user = QUser.user; //Generated Q-type

// Create an user
User john = new User();
john.setName("John Smith");
john.setUsername("jsmith");
john.setPassword("john_secret");
Long johnId = insert(user)
    .populate(john)
    .executeWithKey(user.id);
john.setId(johnId);

// Create a post
QPost post = QPost.post;
Post newPost = new Post();
newPost.setDate(new Date());
newPost.setUserId(john.getId());
newPost.setTitle("A very interesting Java post!");
newPost.setContents("For more posts, visit http://freeit.inf.br");
Long postId = insert(post)
    .popupate(newPost)
    .executeWithKey(post.id);
newPost.setId(postId);

// Without using generated beans
Long maryId = 10L;
QComment comment = QComment.comment;
insert(comment)
    .set(comment.date, new Date())
    .set(comment.postId, post.getId())
    .set(comment.userId, maryId)
    .set(comment.comments, "Love your post... Keep on!")
    .execute();

// Then, john decides to edit the post title
update(post)
    .set(post.title, "Using Querydsl...")
    .set(post.contents, post.contents.concat("\\n\\n[updated]"))
    .where(post.id.eq(post.getId()))
    .execute();

// And Mary removes all her comments on all posts!
delete(comment)
    .where(comment.userId.eq(maryId)
    .execute();

Enough DML examples. Let's perform some queries (using the same user, post and comment variables from above):
//Listing comments using the generated bean
List<Comment> postComments = 
    from(comment)
    .where(comment.postId.eq(postId))
    .list(comment);

//Iterating through all users with comments
CloseableIterator<User> usersWithComments = 
    from(user)
    .rightJoin(comment.commentUserFk, user)
    .where(comment.id.isNotNull())
    .iterateDistinct(user);

On the last example, it's possible to see that even the foreign keys are imported into the model, and can be used on joins. You can also use subqueries, factory expressions to invoke custom SQL functions and so on. Visit www.querydsl.com for documentation and downloads.

So, here is my tip. If you are looking for an alternative in data access in Java, give Querydsl SQL a try.

sábado, 8 de janeiro de 2011

My [terrible] experiences with EJB

In the past (around 2004), I had worked with EJB 2. I hated it. Too much xml, too much complexity. Home / remote / local interfaces... So, at the time, as a workaround, I built a framework which implemented the command pattern, having a single EJB deployed, and passing the command and parameters for it. Not good.
Then, in my current project, we started with EJB 3 (in late-2008). Mostly because it's standard. It is surely much easier, with annotations and such. However, the project has security requirements way beyond the standard JAAS can handle. Besides roles (the only concept handled by JAAS in EJBs), we have permission sets, which can be applied to either groups or individual users, and they can be dynamically changed by the application admins. So we had to create some sort of custom mechanism to check permissions. However, we still need JAAS to propagate the user identity (we use remote EJB interfaces).
Ok, but why am I so disappointed with EJBs? Here are some points:

  • To propagate the caller identity we need JAAS. It is insufficient to the application I'm working on (and would be too for some others which I had already worked, so, either I'm too unlucky or the standard is weak).
  • Again on JAAS: For the application side, it's standard. However, for every application server out there, there is a distinct way to configure it. Ok, for applications which find users and plain or hashed passwords in a DB table, probably there is an easy way to configure some sort of login module with an SQL query. However, in our application, the credentials are dynamic as well, depends on the application configuration and on the application channel being accessed, and, as logic to validate all those is on the application, I'd like to use the application itself to validate users. However, in some containers, it's quite complicated to invoke the application to validate users. Go figure... 
  • Once again on JAAS: Because the JAAS configuration is specific for each application server, it's virtually impossible to just deploy an application in more than one application server without headache. So, if you code your application in an standard way, and cannot reliably deploy that same application on distinct standard-compliant application servers, then that standard is void and defective by design. In the other hand, a self-contained web application can be deployed on ANY web container (as long as you don't use that little friend, JAAS).
  • Application servers take a lot of time to startup and deploy the application. Even though they are faster than some years ago, they are still slow. Compare the startup time with a simple web application running on a Tomcat or Jetty - just (very) few seconds.
  • JPA has it's share of guilty in the slow startup times. For the current project, Hibernate alone takes about 30-40 seconds to map every entity (about 200 tables).
  • The runtime performance for EJBs is also likely to be slower than a regular web applications. You can cluster, I know. But there are way too much proxies, interceptors, lookups, injections... I can't prove with numbers. But common sense tells me that.
  • The standard API for type-safe queries in JPA (criteria API) is an abomination. But I had already discussed that, and solved it by using Querydsl.

Conclusions? For future projects I'll try to avoid EJBs as much as possible. Spring is likely to always be in the game for me, as it's a fantastic piece of software. Also, after so many years working with Hibernate (since 1.2.x) and later JPA, I'm pretty sure I would likely choose Querydsl SQL mode, which has no ORM, but has type-safe queries and DMLs (insers / updates / deletes). Also, it's metamodel is generated at compilation time, it has almost zero overhead on the application initialization (Hibernate as already stated, for us, takes 30-40 seconds just to initialize the persistence).
That is the beauty (but also for me, as a software architect, a frustration) of Java development. You have thousands of frameworks and libraries to choose from, and when most non-trivial projects are finished and set to production, they already use legacy technologies.

quinta-feira, 18 de novembro de 2010

Back to KDE

After the last post, may things have changed...
I've given KDE another try, and... I'm back!!!
They've managed to fix the performance problems I had with 4.5.0.
Whew! I was really missing my favorite desktop environment.
If you had similar problems, give KDE another chance... It's better than ever!

domingo, 15 de agosto de 2010

Switching to GNOME?!?

Things DO change. After years using KDE exclusively, I've now switched to GNOME both at work and at home.
My complaint has always been that GNOME was ugly.
However, the Ayatana guys (which are responsive to the appearance of Ubuntu) are doing a remarkable job.
I had kind of getting a bit upset a bit with KDE, and after installing KDE 4.5 on Kubuntu Lucid, a Core 2 Duo with 4GB of RAM started to feel sluggish... That was too much... Kwin, for example, was always using about 15% CPU, even when nothing special was happening.
There was nothing which I had really liked in KDE 4.5, for me, it was only slower!
So I decided to give Ubuntu Lucid a try, and liked it!
So far so good. Let's see how much will I stick with it...

domingo, 16 de maio de 2010

Vídeos do globo.com no Firefox e o AdBlock Plus

Uma dica: Quem usa o Firefox e tem o AdBlock instalado, e não consegue ver vídeos no globo.com, deve desativar a extensão neste site. Para isso, tem um ícone ABP. Desative o AdBlock Plus no globo.com e pronto! Os vídeos voltaram!

quarta-feira, 12 de maio de 2010

JPA 2 Criteria

One of the most expected features in JPA 2 is a Criteria API. Something that Hibernate has had for ages, but a notable absence in JPA 1.

Even better, JPA 2 criteria is compiled (generated from the source code) and type safe. So, for example, whenever an attribute is removed or changed on the entity, the queries stop compiling immediately, instead of having to wait until the application is running to detect errors. Neat, huh?

However, there's a problem. The way it is, queries are unusable. Well, usable, but very, VERY hard to code, read and maintain. Not for the JSR 317 expert group, of course, but everyone I've asked, has the same opinion as me.

Take a look (example extracted from this link, with little changes):
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Person> criteria = builder.createQuery(
    Person.class);
Root<Person> personRoot = criteria.from(Person.class);
criteria.select(personRoot);
ParameterExpression<String> eyeColorParam = builder.
    parameter(String.class);
criteria.where(builder.equal(personRoot.get(
    Person_.eyeColor), eyeColorParam));
TypedQuery<Person> query = em.createQuery(criteria);
query.setParameter(eyeColorParam, "brown");
List<Person> people = query.getResultList();

Is this example anything close to 'easy'? The very same query in JPQL would be:
String jpql = 
    "select p from Person p where p.eyeColor = :eyeColor";
TypedQuery<Person> query =
    em.createQuery(jpql, Person.class);
query.setParameter("eyeColor", "brown");
List<Person> people = query.getResultList();

To make things a bit worse, the Query object returned from the em.createQuery(criteria) never has parameters already set. And parameters are only used when a ParameterExpression is created. Otherwise, the values are passed as literals (so, subject to things like SQL injection). Yikes! There's absolutely no reason for this. Even the plain old Hibernate criteria already converted given literals to bind parameters...

C'mon, how could an expert group do such terrible decisions, impacting the lives of thousands Java programmers out there having to live with this abomination?

Thanks God, there is a very nice solution. It's Querydsl. It has the main advantage of JPA 2 criteria: being type safe (an annotation processor is used to generate a meta model which is used on queries), uses fluent interfaces (code is very readable) and generates queries with bind parameters on all expressions. The Querydsl metamodel has a Q prefix, for example, QEntity, instead of JPA's Entity_. So, let's take a look on the same previous example in Querydsl:
JPAQuery query = new JPAQuery(em);
QPerson person = QPerson.person;
List<Person> people = query.from(person)
  .where(person.eyeColor.eq("brown"))
  .list(person);

Now, that's readable!!! Also, in the project I'm working, I've also extended the query (actually, extending AbstractJPAQuery) and added other useful methods, like page(currentPage, pageSize). Such things can't be done in JPA because all objects (Query, CriteriaQuery, CriteriaBuilder) are interfaces given by the JPA provider, and can't be easily extended.

So, here is my tip to anyone thinking about using a Criteria API: Give Querydsl a try! By the way, did I mention that it can also be used with JDO, Lucene, JDBC and even plain collections?

quinta-feira, 8 de abril de 2010

Dica: O que fazer após instalar o Kubuntu Linux

Como recentemente instalei o Kubuntu Lucid Lynx (beta 1) no meu netbook (tive que fazer algumas intervenções para que o hardware funcionasse 100%), resolvi fazer uma compilação de coisas a se fazer após a instalação:
  • A primeira dica começa ANTES da instalação: Achei o novo instalador do Lucid muito, mas MUITO lento! Então baixei o instalador mínimo (http://cdimages.ubuntu.com/netboot/lucid/) - o arquivo boot.img.gz, e depois. Este modo de instalação é modo texto (mas com menus bem fáceis), e baixa todos os pacotes da internet. Para isso, requer uma conexão de rede por cabo (o wireless vai funcionar só depois de instalado). Para instalar dessa forma, faça o seguinte:
    • Conecte um pen drive (TODOS os dados serão removidos).
    • Abra um terminal.
    • Digite dmesg, e veja em qual device ele foi reconhecido (normalmente sdb ou sdc). Às vezes demora alguns segundos até aparecer.
    • Descompacte a imagem: gunzip boot.img.gz
    • Copie a imagem para o pen drive: sudo dd if=boot.img of=/dev/sdX (sendo o mesmo reportado no final do dmesg). CUIDADO! Se usar o dispositivo que é o HD, babaus para os seus dados!
    • Depois é só iniciar o micro com o pen drive conectado. Normalmente tem que entrar em um menu de boot na inicialização ou no setup.
    • É só seguir os passos, e, no fim, escolher qual "forma" sua instalação vai ser: ubuntu desktop, ubuntu netbook, kubuntu desktop (minha favorita!), kubuntu netbook (não gostei da interface), xubuntu, lubuntu, server, ...
    • Ao reiniciar a máquina, o sistema vai estar devidamente instalado e atualizado. Considero este método melhor do que baixar o iso e depois ainda ter que baixar várias atualizações.
  • Instalar o suporte à tradução para o português: Configurações do Sistema (System Settings), Regional e Linguagem (Regional & Language), Instalar novo idioma (Install new language). Pacotes adicionais devem ser baixados. Depois, caso não esteja selecionado, selecione Português. Caso contrário, basta fechar. Aí, no Adicionar idioma (Add language), selecione Português do Brasil. Clique em aplicar. Será preciso sair do KDE e fazer login novamente para que todo o ambiente fique em português.
  • Instalação do firefox. O Kubuntu tem um instalador no Programas > Internet. Se quiser usar ele como navegador padrão, nas Configurações do sistema > Aplicativos padrão > Navegador web, selecione o firefox a partir do botão "...". Normalmente, também removo o Konqueror dos favoritos do menu e adiciono o Firefox.
  • Instalação de codecs de vídeos e flash: sudo apt-get install kubuntu-restricted-extras
  • Instalação do plugin java: Requer entrar no KPackageKit, configurações > Editar fontes de software > Outro software e marcar o repositório canonical partner. Depois, pode-se instalar o pacote com o sudo apt-get install sun-java6-plugin. ATENÇÃO: Não instale o java pelo KPackageKit, pois ele não sabe o que fazer quando os instaladores querem interagir com o usuário, e dá erro. Para instalar o java, é necessário aceitar sua licença.
    O Lucid por enquanto tem um bug, que mesmo com o pacote instalado, o firefox não enxerga o plugin. Para solucionar, rode: sudo ln -s /usr/lib/xulrunner-addons/plugins/libjavaplugin.so /usr/lib/mozilla/plugins
  • Instalação da biblioteca para ler DVDs de filmes, caso não seja um netbook: veja as instruções em https://help.ubuntu.com/community/Medibuntu. Basicamente:
  • Trocar o mouse para navegar em pastas com 2 clicks ao invés de 1: Configurações do sistema > Mouse e Teclado > Mouse > Clique duplo para abrir arquivos e pastas.
  • Instalar o Skype: Baixe o skype em http://www.skype.com e instale-o. 
  • Garantir que programas GTK rodados como root têm a mesma aparência que o resto do sistema. Isto é especialmente útil se você quiser instalar o synaptic: sudo ln -s $HOME/.gtkrc-2.0-kde4 /root/.gtkrc-2.0
Esta lista não é exaustiva, nem todos os seus passos servem para todo o mundo. Se alguém tiver dicas de outras coisas a serem feitas, comentários serão bem vindos!

    terça-feira, 6 de abril de 2010

    Netbook Philco PHN 10103 e o Linux

    Estes dias comprei um netbook da Philco, modelo PHN 10103, que veio com o Mandriva Linux pré-instalado.
    Uma das primeiras coisas que fiz foi instalar o Kubuntu Lucid (ainda em beta) nele.
    Tive alguns problemas com o hardware, mas todos eles têm solução. Estas dicas funcionam para qualquer variante do Ubuntu Lucid (Kubuntu no meu caso, mas funciona para Ubuntu, Xubuntu, Lubuntu...). Se você usa outras distribuições, pode adaptar estas dicas para elas.

    Webcam de cabeça para baixo:
    Para isto, deve-se instalar uma versão mais nova do pacote libv4l, mais o frontend para configurar:
    sudo add-apt-repository ppa:libv4l
    sudo apt-get update
    sudo apt-get install gtk-v4l libv4l-0

    Depois, rode o gtk-v4l e ajuste as opções de espelho horizontal e vertical. Para o skype, tive usar um script. No meu caso, o arquivo está no $HOME/bin/run-skype, com o seguinte conteúdo:
    #!/bin/bash
    LD_PRELOAD=/usr/lib/libv4l/v4l1compat.so skype

    Não esqueça de dar permissão de execução para esse arquivo, e alterar o lançador do menu para ele ao invés do comando padrão.

    Teclas de atalho que não funcionam:
    Para esta dica, gostaria de agradecer grandemente ao Corentin Chary, que é o desenvolvedor do módulo do kernel que suporta o ACPI nos notebooks da Asus, e este netbook é um deles. O Corentin foi muito prestativo e respondeu prontamente às perguntas até chegarmos à solução.

    Deve-se adicionar parâmetros no arquivo /etc/default/grub (abrir com o sudo). Procure a linha GRUB_CMDLINE_LINUX_DEFAULT e adicione, dentro das aspas, o seguinte: (sem aspas) "acpi.power_nocheck=1". No meu caso, essa linha ficou assim:
    GRUB_CMDLINE_LINUX_DEFAULT="splash quiet acpi.power_nocheck=1"

    Finalmente, rode no terminal: sudo update-grub e reinicie a máquina.

    A única função que não funcionou direto foi a de ligar / desligar o touchpad. Mas isso também tem solução! Vamos ao terminal:
    sudo apt-get install aosd-cat

    Depois, deve-se modificar o arquivo executado quando o evento de touchpad é detectado. Para isso, rode o seguinte:
    cd /etc/acpi
    sudo mv asus-touchpad.sh asus-touchpad.sh.orig
    sudo nano asus-touchpad.sh

    Então, cole o seguinte conteúdo:
    #!/bin/bash
    [ -f /usr/share/acpi-support/state-funcs ] || exit 0
    . /usr/share/acpi-support/power-funcs
    getXconsole
    DEVICE="AlpsPS/2 ALPS GlidePoint"
    PROPERTY="Device Enabled"
    QUERY=`xinput list-props "$DEVICE" | grep "$PROPERTY"`
    VALUE=${QUERY#*:}
    if [ $VALUE == "1" ]; then
            xinput set-int-prop "AlpsPS/2 ALPS GlidePoint" "Device Enabled" 8 0;
            echo "Touchpad desligado" | aosd_cat -p 7 -u 1000;
    else
            xinput set-int-prop "AlpsPS/2 ALPS GlidePoint" "Device Enabled" 8 1;
            echo "Touchpad ligado" | aosd_cat -p 7 -u 1000;
    fi
    exit 0

    Depois, torne-o executável e adicione o serviço acpid para ser executado ao iniciar a máquina:
    sudo chmod +x asus-touchpad.sh
    sudo update-rc.d acpid defaults
    sudo start acpid

    Repare que nesta última linha, o serviço acpid é iniciado. Assim, ao apertar Fn+F9, você verá uma mensagem na tela indicando o estado do touchpad.

    Assim, o netbook funcionou perfeitamente no Linux. Aliás, isso já era sabido, pois ele veio com o Linux instalado, mas precisou dessas intervenções manuais para funcionar tudo ok.

    quarta-feira, 27 de janeiro de 2010

    Fim do "distro-hopping"?

    Talvez seja a paternidade, eu não sei.
    Mas cansei da brincadeira de ficar instalando uma nova distribuição do Linux a cada alguns dias / semanas...
    Neste último mês, em especial, já instalei: openSUSE, Kubuntu Lucid Alpha 2, sidux e Arch Linux.
    Pronto, cheguei no meu limite!
    Acho que agora me aquietei: Voltei pro Kubuntu Karmic (versão estável), nos 2 computadores (desktop e laptop). Tem seus problemas, mas todos têm. Só que acho que no Kubuntu, as vantagens superam em muito os problemas.
    E a próxima versão, o Lucid, vai ter... (ops!, será que já estou tentado a atualizar para a versão alpha? argh, vou esperar pelo menos a RC...)