sexta-feira, 21 de dezembro de 2007

Embebe em álcool e põe

Não foi a situação mais constrangedora pela qual já passei, mas é o máximo de constrangimento que eu me atrevo a passar neste blog.

Aconteceu há alguns meses. Fui à dentista pra dar uma olhada num dente que estava me incomodando. Conheço-a há muitos anos e o nosso papo é sempre bem agradável. Cheguei e esperei um pouco enquanto ela terminava uma consulta. Na minha vez ela me pediu um tempinho pra arrumar as coisas, já que era tarde e sua secretária já havia ido embora. Aproveitei pra iniciar o papo falando do assunto padrão: filhos. Os meus estavam gripados e tiveram febre naquele dia.

Eu falava disso em pé, na porta da sala do consultório, enquanto ela ia de um lado pro outro arrumando as coisas. Quando eu falei de febre ela parou, me encarou seriamente e disse:

- Sabe, eu fiquei sabendo esses dias de uma técnica ótima pra tirar a febre sem precisar de remédio.

Parecia importante e eu prestei atenção enquanto ela explicava:

- Você pega uma meia, embebe em álcool e põe.
- No ânus? Eu perguntei assustado.
- Não! Ela retorquiu encabulada. No pé!


(Podem terminar de rir... Eu espero.)


Eu sei... parece inacreditável que eu tenha dito aquilo. Mas depois de ter um acesso de riso na frente dela que durou uns dois minutos eu consegui me acalmar e tentei colocar panos quentes. Nessas horas é melhor ficar quieto pra não piorar as coisas. Mas eu não me lembrei disso e falei:

- É. Se fosse, curava tudo, né?

Não podia ficar muito pior do que isso. Durante toda a consulta eu me esforcei pra prestar atenção à conversa mas sem muito sucesso. Virava e mexia e lá vinha aquela risada impossível de evitar. Uma semana depois do incidente eu ainda tinha ataques de riso nos momentos menos convenientes. Minha esposa já não agüentava mais.

Mas eu tentei aproveitar este tempo pra entender como é que aquilo pôde acontecer.
Não, justificar não, pois é impossível. Mas eu queria encontrar uma explicação pra aquela idéia estapafúrdia ter passado pela minha cabeça.

A explicação que encontrei é a seguinte. Em primeiro lugar, quando ela começou a falar da tal "técnica" eu tive a nítida impressão de que ela havia abaixado a voz, como se estivesse tomando cuidado pra não falar alto demais. É bem possível que isso não tenha ocorrido de verdade e que tenha sido uma falsa impressão decorrente do fato de ela ter parado de fazer o que estava fazendo pra falar do assunto. Pode ser, também, que eu simplesmente tenha construído esta memória na tentativa de encontrar alguma explicação pra minha escorregada. Não sei. Mas alguma coisa na atitude dela sinalizou pra mim que poderia haver algo de "inusitado" na técnica que ela estava pra me explicar.

Em segundo lugar, quando ela disse "embebe em álcool e põe" ela fez um movimento insinuante com a mão direita. Primeiro ela uniu as pontas dos cinco dedos e os apontou pra baixo. Depois ela fez um movimento rápido de rotação com o pulso fazendo os dedos apontarem para o teto. Não sei quanto à vocês, mas por mais que eu pense sobre o assunto eu não consigo imaginar alguém fazendo este movimento pra calçar uma meia.

Nos poucos décimos de segundo que se passaram entre ela dizer "e põe" e eu responder "no ânus?" meu cérebro construiu uma imagem inusitada e totalmente diferente da que ela tentava representar. E diante do espanto que a imagem me causou, não houve tempo para eu me censurar e me impedir de proferir aquela obcenidade.

Mas não foi tão ruim como pode parecer. Afinal, nós nos conhecemos há bastante tempo. A única coisa que me incomoda agora é não saber o que ela ficou pensando depois. Quer dizer, ela também deve ter construído a sua própria teoria sobre a minha reação. Espero que eu não tenha ficado muito mal na fita...

Acho que não. Afinal, eu escrevi este post alguns dias depois do incidente, quando a memória ainda estava vívida. Desde então já estive no consultório dela outra vez e não houve nenhuma rememoração constrangedora. Só por isso resolvi finalmente publicar minha história.

Agora é com vocês. Ajudem-me a me sentir melhor contando as suas próprias experiências constrangedoras e fazendo-me acreditar que todo mundo passa por isso uma vez ou outra.

sexta-feira, 14 de dezembro de 2007

Futuro Maquiavel

A dor de barriga do meu filho continuou hoje. Os exames de ontem não mostraram nada, mas ainda havia uma possibilidade de ser apendicite. Liguei pro médico e fomos vê-lo no final da tarde. Desta vez ele foi taxativo dizendo que não há mais possibilidade de ser apendicite, porque depois de 48 horas já deveríamos ver outros sintomas. O negócio é tomar canja-de-galinha e Luftal.

Enquando voltávamos pra casa fomos conversamos sobre feedback. Hoje cedo eu fui à escola pra reunião final do 4º ano. Mais uma vez saí de lá todo orgulhoso. O professor o elogiou bastante e eu confesso, com certo embaraço, que cheguei a gostar de algumas das poucas críticas, como a de que ele tem aumentado as "brincadeiras" em classe por estar-se tornando "muito popular".

Por coincidência hoje eu também fui avaliado pelo meu chefe. Aproveitei pra contar pro meu filho como foi esta experiência, explicando que a maioria das pessoas é "avaliada" a vida toda e que, embora às vezes isso seja desconfortável, é melhor tentarmos encarar as críticas como oportunidades. E blá, blá, blá... eu juro que ele estava interessado. :-)

Antes de chegar em casa, passamos na farmácia pra comprar umas coisinhas. A essa altura o papo já tinha ido fundo e eu não me lembro exatamente o que foi que eu disse que mereceu os seguintes comentários dele, que eu fiz questão de anotar num papelzinho pra não esquecer:

- Se você não sabe mentir você não sabe ganhar.
- Hein?
- A sinceridade nem sempre é o melhor caminho.
- Onde é que você leu isso, filhão?
- Eu não li. Eu raciocinei.

Pode?

Já dei uma batida no quarto dele mas não achei nenhuma cópia escondida de "O Príncipe". Não sei, não... estamos lendo juntos o "Pai Rico, Pai Pobre" e isso pode não estar sendo muito educativo. Preciso ser mais cuidadoso. :-)

Confundindo a anatomia

Ontem levei meu filho ao médico porque ele estava sentindo dor de barriga desde a noite anterior. O doutor apertou, escutou, perguntou, brincou e me pediu pra fazer uma radiografia e uma ultra-sonografia só pra descartar a possibilidade de ser um apendicite. Sempre achei que a dor de um apendicite era do lado direito mais pra baixo do umbigo e a dor que ele sentia era mais pra cima. Mas o doutor explicou que em alguns casos o apêndice fica virado pra trás, o que atrasa os sintomas e muda a posição da dor. Como ele não tinha tido febre ainda, o doutor não estava muito preocupado, mas o fato de ele estar andando meio curvado pra frente era sintomático.

Meu filho ficou um tanto encucado. Enquanto íamos pro laboratório pediu pra eu explicar o que era "aquilo que o médico falou" e eu aproveitei pra lhe dar uma aula grátis sobre A Teoria da Evolução e a Inutilidade do Apêndice.

Ele se acalmou e não falamos mais sobre o assunto. Esperamos, fizemos a radiografia, esperamos mais um tanto e fomos pra sala da ultra-sonografia. A enfermeira o deitou e nos deixou à vontade dizendo que o médico viria logo. Mas ele não veio. Demorou uns dez minutos, no mínimo.

Durante esse tempo, meu filho ficou deitado e rindo de umas piadas sem graça que eu ia contando. Mas, sua cabecinha não tinha parado de pensar "naquilo que o médico falou" e ele estava é com um nervosismo contido.

Depois de uma pausa entre uma piada e outra ele começou a apalpar a barriga.

- Tá doendo, filhão?
- Só um pouquinho, pai.

Ele foi apalpando até embaixo do umbigo.

- Pai. Onde é que fica o útero?
- Hein?
- O útero. Onde é que fica?

Cheguei a pensar que a escola estava dando aulas de educação sexual antes da hora.

- Bem... nas mulheres o útero fica aí embaixo do umbigo, onde você está apalpando.
- Qué dizê... aquele negócio que o médico falou que eu posso ter.
- Rá. É apendicite: uma inflamação no apêndice, que fica aí embaixo do umbigo, do lado direito.
- Ah. E o que que é útero?
- É onde os bebês crescem na barriga das mulheres.

Rimos bastante, até quase o médico chegar.

Depois da ultra-sonografia, fomos esperar o resultado e ficamos vendo umas revistas. Depois de uns minutos ele perguntou:

- Pai, o que é aprose?
- Hein?
- Aquilo que eu posso ter?
- É "apendicite", não aprose.
- Ah!
- Deixa eu anotar essas barbaridades que você tá dizendo num papelzinho aqui pra eu não esquecer e poder contar pra mamãe.



domingo, 9 de dezembro de 2007

Splitting hairs

split hairs: to argue about whether unimportant details are correct

Sou fã de Perl porque me permite ser sucinto como em nenhuma outra linguagem.

Esta semana descobri um bug num velho script que eu uso pra processar o relatório produzido pelo comando " bpdbjobs -report -all_columns" do NetBackup. O relatório é um arquivo texto no qual cada linha tem um número variável de campos separados por vírgulas.

Até aí, nada demais. Se eu tiver a linha na variável $line, a função "split" separa os campos nas vírgulas e os atribui ao array @fields trivialmente:

@fields = split /,/, $line;

Só que alguns campos deste relatório podem conter vírgulas, as quais são "escapadas" com barras invertidas, i.e., "\,". O split anterior não entende essas vírgulas escapadas e vai tratá-las indevidamente como separadoras de campos.

O que queremos, então, é quebrar a linha nas vírgulas, mas apenas naquelas que não sejam precedidas de uma barra invertida. Sem problemas... hora de complicar um pouquinho a expressão regular.

@fields = split /(?<!\\),/, $line;

O "ruído" entre parêntesis é um zero-width negative lookbehind (ZWiNLoB). Ele indica que antes da vírgula não pode haver uma barra invertida. Note que o caractere com o qual o ZWiNLoB vai "casar" não fará parte do separador de linha, que continuará a ser somente a vírgula.

Muito bem, parecia tudo certo até que eu rodei novamente o script e percebi que ainda havia problemas. Algumas linhas ainda não estavam sendo quebradas corretamente. Desta vez o problema eram alguns campos que terminavam com uma barra invertida, a qual também era escapada por outra barra invertida. Por exemplo:

...,C:\\,...

Note que a vírgula não está escapada, sendo efetivamente um separador de campo.

E agora? A primeira coisa que pensei foi em usar um ZWiNLoB que case com uma barra não precedida por outra.

@fields = split /(?<![^\\]\\),/, $line;

Hmmm... mas não iria funcionar. E se o campo terminasse em duas barras?

...,C:\\\\,...

Por outro lado, se o campo termina em uma ou mais barras, como cada uma delas deve ser escapada o número total de barras antes da vírgula deve ser necessariamente par, certo? Portanto, o que eu preciso é de um ZWiNLoB que case com um número ímpar de barras. (Lembre que o ZWiNLoB é "negativo".)

@fields = split /(?<![^\\](?:\\\\)*\\),/, $line;

Só que o Perl reclamou:

Variable length lookbehind not implemented in regex; marked by <-- HERE in m/(?<![^\\](?:\\\\)*\\), <-- HERE /

Os ZWiNLoBs têm uma restrição forte: eles devem especificar strings de tamanho fixo, o que significa que eu não vou conseguir usá-los pra indicar uma vírgula não precedida por um número ímpar de barras...

OK, o ZWiNLoB na expressão anterior tinha a função de garantir que eventuais barras invertidas em um campo não precedam uma vírgula escapando-a. Mas a expressão como um todo quer mesmo é casar com uma vírgula, i.e., com o separador dos campos, pois eu a estou usando como argumento da função split.

E se eu tentar uma abordagem inversa? E se ao invés de tentar encontrar os separadores eu tentasse encontrar os campos? Nesse caso, a parte de tamanho variável da expressão não estaria num ZWiNLoB.

Pensei de cara numa abordagem interativa:

push @fields, $1 while $line =~ s/(.*?(?<!\\)(?:\\\\)*),//;
push @fields, $line;

A primeira linha remove o primeiro campo de $line e o anexa ao array @fields, até que sobre apenas o último campo, que não é sucedido por uma vírgula, e que é anexado na segunda linha. Ainda há um ZWiNLoB, mas ele tem um tamanho fixo, casando com um caractere diferente de barra invertida.

Não gostei muito. Eu preferiria não ter que tratar o último campo de modo especial. Logo percebi que com um pequeno ajuste na expressão regular isso seria possível.

push @fields, $1 while $line =~ s/(.*?(?<!\\)(?:\\\\)*)(?:,|$)//;

Desse modo, os campos podem ser sucedidos por uma vírgula ou pelo final da string.

Eu estava quase satizfeito, pois a solução acabou tendo uma linha apenas, mas o split era tão mais simples...

De qualquer modo, eu ainda precisava testar. E qual não foi a minha surpresa quando o script passou a demorar dezenas de segundos a mais que a versão anterior. Por um lado ele parecia estar correto, o que era um avanço. Mas alguma coisa o havia tornado muito lento e só podia ser aquele loop.

O problema é que o relatório tem algumas linhas realmente grandes, com quase um milhão de caracteres. Como a cada iteração a linha tem um campo removido, toda essa manipulação de strings parece ser bastante pesada.

Mas eu não preciso realmente remover os campos. Basta começar a procurar um campo a partir do final do campo anterior. (Eu não estou sendo fiel à história aqui, pois não cheguei a pensar nessa solução antes de começar a escrever isso aqui. Mas, em retrospecto, acho que ela cabe logicamente entre as duas últimas.)

push @fields, $1 while $line =~ /(.*?(?<!\\)(?:\\\\)*)(?:,|$)/g;

A mudança é sutil. Troquei apanas o operador "s///" pelo "//g". Como a expressão está sendo avaliada num contexto escalar, a cada iteração a busca começa a partir do final do trecho encontrado na iteração anterior. A vantagem é que a linha não precisa ser modificada, o que deve evitar grande parte da ineficiência anterior.

Mas, se eu quero uma lista de campos eu não preciso necessariamente encontrá-los um a um. Afinal, a mesma expressão regular anterior, quando avaliada num contexto de lista, retorna de uma vez todos os trechos encontrados dentro dos parêntesis.

Et voilá, eis minha solução final.

@fields = $line =~ /(.*?(?<!\\)(?:\\\\)*)(?:,|$)/g;

Ah, mas é claro que no script eu não usei uma variável explícita chamada $line. A linha estava realmente na variável implítica $_, o que me permitiu escrever a solução assim.

@fields = /(.*?(?<!\\)(?:\\\\)*)(?:,|$)/g;

Linda, não? E sucinta. E eficiente também. Como convém a um script Perl que se preze.