Archive

Arquivo por Autor

As Cotas Racias

O Facebook é o lar dos corajosos; daqueles que querem mudar o mundo, mas não aceitam arrumar a própria cama; do viés autoritário de esquerda carregado de ranço ideológico. Há coisas engraçadas lá, mas a ausência de conteúdo de qualidade me mantém fora daquela rede social por semanas e até meses.

Acessei minha conta faz alguns dias para verificar se tinha alguma coisa útil ou interessante na minha rede de “amigos”. Vi que um colega compartilhou um vídeo com uma conversa entre o apresentador Serginho Groisman e um estudante universitário. O que foi dito ali me incomodou. Outra coisa que me incomodou foi a postura do companheiro que originalmente postou o vídeo – que é um esquerdista de boutique – aproveitando a oportunidade para lançar um desafio a quem não pensa como ele:

Olhem os argumentos de quem é Contra as Cotas Raciais, e de como é fácil de destruir tais argumentos!

Figura 1 – Cher Guevara, a rainha da esquerda de boutique

Esse comentário e o vídeo estão lá no Facebook. Não vale a pena tentar contra-argumentar, pois não se trata de um argumento sólido, mas vou tecer alguns comentários e tentar fazer as perguntas certas para que se possa conversar a respeito desse assunto visando aumentar o entendimento. Para começar, acho que não se deve tratar assuntos em termos de “destruição” ou qualquer tipo de aniquilação. Para que exista o diálogo, é necessário parar de ruminar e aprender a ouvir, a ler o que os outros escrevem e a falar com eloquência e embasamento sólido.

É curiosíssimo que o autor do comentário do vídeo assuma que um estudante universitário tenha conhecimento e experiência para falar com autoridade sobre esse tema. Isso é apenas desonestidade intelectual a serviço da desinformação. Entortar e torturar a realidade para fazê-la caber em uma visão de mundo é uma estratégia típica das esquerdas, mas vamos analisar o conteúdo do vídeo.

O estudante universitário disse que cotas raciais não deveriam existir por se tratar de uma falta de respeito com o ser humano. Segundo ele:

(…) do mesmo jeito que o negro tem direito, o branco também tem…o amarelo (…)

Vou utilizar direita e esquerda nesse artigo porque será mais fácil analisar nesse micro contexto, mas essa não é a forma mais adequada de agrupar visões de mundo as mais diversas – talvez nem exista uma forma geral, mas apenas formatos atrelados a um contexto, como liberais, liberais democratas, conservadores, reacionários, legalistas, socialistas, comunistas, desenvolvimentistas, progressistas, ambientalistas, “coitadistas”, alienistas, etc. O problema é que o rapaz usa o argumento raso da direita. Dessa forma, ele é facilmente contra-atacado pelo apresentador, que usa dialética erística para enfeitar os argumentos rasos da esquerda:

Quantos negros têm na sua classe?

Essa é a pergunta óbvia que um esquerdista faria, pois ele se acha detentor de todas as virtudes. Defender causas raciais está dentro daquela ideia de que existem oprimidos e opressores e isso faz parte do pacote de “serviços” prestados à humanidade pelas esquerdas. Uma vez um esquerdista não declarado exigiu minha opinião sobre um outro assunto, mas utilizando um formato muito parecido com esse. Apenas acenei com a cabeça e preferi não responder, pois percebi que ele não estava aberto ao diálogo; só queria se impor para me “vencer” como se eu tratasse conversas em termos de vitória e derrota. Ao vencedor, as batatas.

Vamos ajudar o rapaz a pensar sobre o tema. A simples existência de cotas raciais já é um peso para o estado, ou melhor, para os pagadores de impostos. O Estado é um ente nascido para cumprir a vontade do povo, que “assina” um contrato social. Os administradores públicos, eleitos via voto direto, fazem escolhas com base nas necessidades do povo e no prazo em que essas necessidades devem ser atendidas. Será que utilizar o dinheiro dos pagadores de impostos para abrir as portas das faculdades para todos sem a justiça do teste de conhecimentos é uma decisão correta para com a maioria? É justo para quem estudou e se preparou para competir pela vaga? Isso vale também para cargos públicos. Parece até que os burocratas do Estado se esquecem que as pessoas, independente da origem e do grupo étnico em que estão classificadas, têm o direito de lutar pelo que quiserem – utilizando os meios legais, é claro, e estudando, é lógico. Elas são tratadas como incapazes que necessitam da tutela do papai Estado.

Para refletir: qual é a porcentagem de melanina que uma pessoa deveria ter para ser considerada negra? E quanto aos filhos de pais mulatos? Se tiverem mais melanina que os pais serão considerados negros ou o fato de terem DNA europeu em sua família os descredencia? Se o filho nascer mais branco, ele terá menos direitos que o irmão que tem mais melanina? Racismo também é tentar classificar um povo tão heterogêneo quanto o nosso. Somos todos brasileiros.

Se você expandir a questão das cotas para além dos negros, causará uma grande confusão na mente dos esquerdopatas. Se a ideia é ser justo com todas as raças que compõem nosso povo, é necessário que cada sala de aula tenhas mais de 200 milhões de vagas, pois essa é a única forma de ser verdadeiramente justo na composição de um grupo racial heterogênico. Pense nisso: nem todo mundo consegue se assumir como membro de um grupo étnico – o agrupamento é forçado por critérios subjetivos. Quando uma minoria passa a ter privilégios especiais do Estado, é óbvio que muita gente tentará se enquadrar naquela minoria para usufruir dos privilégios. Afinal, somos todos brasileiros.

Percebeu que não apresentei solução alguma para esse problema? Meu objetivo era fazer mais perguntas para tentar jogar um pouco de luz no debate, mas conclui que pelo menos três coisas ficam claras quando esse assunto aparece em uma discussão: esquerdistas não entendem nada de economia, são preconceituosos e parciais quando alegam estar fazendo justiça e não toleram aqueles que ousam questionar suas visões de mundo uma vez que monopolizam as virtudes.

Como Habilitar o Ehcache no Shiro

O Shiro oferece um mecanismo de cache para diminuir o tempo de respostas das operações de segurança, mas as implementações disponibilizadas podem ser utilizadas para propósitos fora do escopo do framework de segurança.

Figura 1 – Arquitetura do Shiro

Várias implementações do CacheManager estão disponíveis. Nesse artigo, mostraremos como habilitar o EhCacheManager, o que permite utilizar o Ehcache. Antes de continuar, sugiro que você veja o artigo de introdução ao Shiro que escrevi e um outro artigo sobre a integração do Ehcache ao Spring, onde faço algumas considerações sobre o cache em si.

Comecemos pela configuração das dependências do Maven:

   <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-core</artifactId>
      <version>1.3.2</version>
   </dependency>
   <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-web</artifactId>
      <version>1.3.2</version>
    </dependency>
    <dependency>
      <groupId>org.ehcache</groupId>
      <artifactId>ehcache</artifactId>
      <version>3.3.1</version>
    </dependency>  
    <dependency>
      <groupId>javax.cache</groupId>
      <artifactId>cache-api</artifactId>
      <version>1.0.0</version>
    </dependency>

Em seguida, vamos configurar o arquivo shiro.ini

[main]
[main]
apprealm = br.com.app.autorizacao.AppRealm
securityManager.realms = $apprealm
cacheManager = org.apache.shiro.cache.ehcache.EhCacheManager
securityManager.cacheManager = $cacheManager

Uma vez definido um CacheManager, o Shiro o entrega para as classes que implementam a interface CacheManagerAware. Nosso AppRealm é um SimpleAccountRealm. Sendo assim, já estamos implementando aquela interface.

Referências

1. [https://shiro.apache.org/caching.html]
2. [https://shiro.apache.org/static/1.3.0/apidocs/org/apache/shiro/cache/Cache.html]
3. [https://shiro.apache.org/static/1.3.0/apidocs/org/apache/shiro/cache/ehcache/EhCacheManager.html]
4. [http://www.ehcache.org/]

Prova Computacional do Problema de Monty Hall

O Problema de Monty Hall, que outrora apresentei, é um jogo probabilístico em que um apresentar pede que uma dentre três portas seja escolhida. Uma porta contém um prêmio e as outras têm alguma bizarrice. A imagem abaixo resume as possibilidades de escolha depois que uma porta é aberta pelo apresentador:

Figura 1 – Síntese das escolhas

Para sermos mais didáticos, podemos utilizar a árvore de decisão abaixo, que mostra que temos 2/3 de chances de vencer trocando de porta:

Figura 2 – Árvore de decisão

O blog O Desafio: Aprender apresentou o problema de Monty Hall e citou minha explicação da solução. Revisitar o problema me fez pensar em ir um pouco além e desenvolver um pequeno algoritmo em Java para provar a solução já conhecida do problema.

Escrevi rapidamente um código que utilizava listas de strings e mapas de portas para totais de escolhas. Funcionou, mas depois gastei um tempo reescrevendo com orientação a objetos visando criar abstrações mais claras para que pudesse ser didático. Primeiro, criei uma classe que representa uma porta e o total de vezes que ela foi escolhida:


public class Porta {
    private String nome;
    private long totalEscolhas;
 
    public Porta(String nome) {
        this.nome = nome;
    }
 
    public void escolher() {
        totalEscolhas++;
    }
 
    public long getTotalEscolhas() {
        return totalEscolhas;
    }
 
    public String getNome() {
        return nome;
    }
};

Sabemos que o problema começa quando uma porta é escolhida e outra é aberta pelo apresentador. Sabemos também que a porta aberta e aquela que permanece fechada e que você não escolheu formam um grupo.

Figura 3 – Grupos de portas

Para o problema, isso significa que, se a porta aberta for escolhida pelo algoritmo de escolhas aleatórias, a escolha será transferida para a porta do mesmo grupo que permaneceu fechada. Pensando assim, criei uma abstração para a porta aberta que estende a porta comum e recebe uma referência para a porta fechada. Pensei no padrão Decorator:

public class PortaAberta extends Porta {
   private Porta portaDelegada;

   public PortaAberta(String nome, Porta portaDelegada) {
      super(nome);
      this.portaDelegada = portaDelegada;
   }

   public void escolher() {
      portaDelegada.escolher();
   }

};

O algoritmo que escrevi faz três coisas:

  1. Cria as portas fechadas e a porta aberta e as adiciona em uma lista;
  2. Escolhe aleatoriamente uma das portas e incrementa o total de escolhas em cada instância de porta;
  3. Exibe a porcentagem de vezes que cada porta foi escolhida.
public class MontyHall {
   private List<Porta> portas;

   public void executar(long totalEscolhas) {
      configurarPortas();
      escolher(totalEscolhas);
      exibir(totalEscolhas);
   }

   private void configurarPortas() {
      /*
      * Porta 1 do Grupo A (A1)
      */
      Porta portaA1 = new Porta("A1");
      /*
      * Porta 1 do Grupo B (B1)
      */
      Porta portaB1 = new Porta("B1");
      /*
      * Porta 2 do Grupo B (B2)
      * 
      * Essa e a porta que foi aberta pelo apresentador.
      * Se ela for escolhida pelo sistema, a escolha sera 
      * delegada para a outra porta do mesmo grupo, que e a porta B1
      */
      Porta portaB2 = new PortaAberta("B2", portaB1);
      portas = Arrays.asList(portaA1, portaB1, portaB2);
   }

   private void escolher(long totalEscolhas) {
      Random escolhaAleatoria = new Random();
      for (int escolha = 0; escolha < totalEscolhas; escolha++) {
         int indicePortaEscolhida = escolhaAleatoria.nextInt(portas.size());
         Porta porta = portas.get(indicePortaEscolhida);
         porta.escolher();
      }
   }
   private void exibir(long totalEscolhas) {
      System.out.println("\n" + totalEscolhas + " tentativas\n");
      NumberFormat totalEscolhasFormat = NumberFormat.getPercentInstance();
      totalEscolhasFormat.setMinimumFractionDigits(4);
      for (Porta porta : portas) {
        String totalPorta = totalEscolhasFormat.format(
           (double) porta.getTotalEscolhas() / totalEscolhas);
         System.out.println(porta.getNome() + ": " + totalPorta);
      }
   }
}

Agora, vamos testar nosso código para algumas configurações de quantidades de tentativas:

@RunWith(JUnit4.class)
public class TesteMontyHall {
   @Test
   public void teste() {
      MontyHall montyHall = new MontyHall();	
      montyHall.executar(10);
      montyHall.executar(100);
      montyHall.executar(1000);		
      montyHall.executar(1000000);
      montyHall.executar(1000000000);
   }
}

A saída do programa para as configurações anteriores mostra que quanto maior a quantidade de tentativas, mais evidente fica a tendência dos resultados:

10 tentativas
A1: 40,0000%
B1: 60,0000%
B2: 0,0000%

100 tentativas
A1: 38,0000%
B1: 62,0000%
B2: 0,0000%

1000 tentativas
A1: 33,7000%
B1: 66,3000%
B2: 0,0000%

1000000 tentativas
A1: 33,3255%
B1: 66,6745%
B2: 0,0000%

1000000000 tentativas
A1: 33,3360%
B1: 66,6640%
B2: 0,0000%

Esse algoritmo não funcionaria bem para mais de 3 portas. Eu modificaria a abstração da porta aberta: é necessário que ela receba todas as outras portas do grupo das portas não escolhidas e que estão fechadas e, quando a porta aberta for escolhida aleatoriamente, é necessário escolher aleatoriamente uma das portas desses grupo.

Como Adicionar um Filtro HTTPBasicAuthFilter em um Cliente Jersey

O HTTPBasicAuthFilter é uma classe utilitária do Jersey que adiciona um cabeçalho de autenticação HTTP se a request que está sendo montada ainda não o possuir:

Client client = Client.create();
client.addFilter(new HTTPBasicAuthFilter("usuario", "senha"));

Vamos modificar nosso exemplo de cliente Jersey para autenticação HTTP:

public Autorizacao autenticar() throws Exception  {
   Client client = Client.create();
   client.addFilter(new HTTPBasicAuthFilter("usuario", "senha"));

   JSONObject jsonInput = new JSONObject();
   jsonInput.put("usuario", "usuario");
   jsonInput.put("senha", "senha");

   WebResource target = client.
    resource("http://localhost:8080").
    path("/autenticar/");
   ClientResponse response = target.
    type(MediaType.APPLICATION_JSON).
    post(ClientResponse.class, jsonInput.toString());

   String value = response.readEntity(String.class);
   response.close();
   ObjectMapper map = new ObjectMapper();
   return map.readValue(value, Autorizacao.class);
}

public List<Usuario> listarUsuarios(Autorizacao autorizacao)
   throws Exception {
   Client client = Client.create();
   client.addFilter(new HTTPBasicAuthFilter("usuario", "senha"));

   WebResource target = client.
    resource("http://localhost:8080").
    path("/usuario/listar/");

   ClientResponse response = target.
      accept(MediaType.APPLICATION_JSON).
      header("Token", autorizacao.getToken()).get(ClientResponse.class);

   String value = response.readEntity(String.class);
   response.close();
   ObjectMapper map = new ObjectMapper();
   Map<String, List<Usuario>> mapItens = map.
     readValue(value,
      new TypeReference<Map<String, List<Usuario>>>() {
     });
   return mapItens.get("usuarios");
}
Categorias:Programação

Java 8 Collections

Os métodos padrão introduzidos no Java 8 permitiram que novas funcionalidades fossem agregada à API de Collections. Vamos ver um pouco do poder dessa API melhorada através de um exemplo. Suponha que você precisa descobrir que Pessoa em uma lista de pessoas tem a maior idade:

List<Pessoa> pessoas = new ArrayList<Pessoa>();
pessoas.add(new Pessoa("Mario", 83));
pessoas.add(new Pessoa("Rita", 70));
pessoas.add(new Pessoa("Maria", 50));
pessoas.add(new Pessoa("Ana", 48));
pessoas.add(new Pessoa("Tadeu", 43));

Sabendo que a lista de pessoas está em ordem decrescente de idade, podemos fazer simplesmente assim:

pessoas.get(0);

Ou, de forma mais elegante, podemos fazer um filtro:

pessoas.stream().filter(pessoa -> e.getIdade() == idade).findFirst().get();

Para complicar um pouco, vamos embaralhar a lista antes de fazer a pesquisa:

Collections.shuffle(pessoas);

Poderíamos organizar a lista com um Comparator de idade para garantir a ordem e depois utilizar um dos métodos anteriores para obter o primeiro item. Vamos modificar o problema para deixá-lo um pouco mais complexo.

Map<Sala, Integer> map = new HashMap<>();
pessoas.forEach(pessoa -> map.put(pessoa, idade));

Adicionei todas as pessoas em um Map e quero aquela que tem a maior idade. Supondo que não temos a lista de Pessoas original, você poderia sugerir que criássemos uma lista à partir do Map e a ordenássemos. É o que eu faria antigamente, mas no Java 8 dá pra fazer algo mais ineteressante com Stream:

Map.Entry<Pessoa, Integer> max = map.entrySet().stream()
.max(Map.Entry.comparingByValue(Integer::compareTo)).get();

System.out.println(max.getKey() + " tem " + max.getValue() + " anos");

Referências

1. [http://blog.caelum.com.br/o-minimo-que-voce-deve-saber-de-java-8/]
2. [https://zeroturnaround.com/rebellabs/java-8-explained-applying-lambdas-to-java-collections/]
3. [https://www.infoq.com/br/news/2013/10/tudo-sobre-java-8]

Categorias:Programação

Como Utilizar o Detector de Tipos de Arquivo do Apache Tika

O Tika é uma biblioteca da Apache que detecta e extrai metadados de diferentes tipos de arquivos. Já utilizei o Tika em dois projetos e tive pouco trabalho para configurar do jeito que eu precisava. No último projeto, eu precisava detectar se a extensão de um arquivo era xls ou xlsx.

Já vi muito código que apenas extraia a extensão à partir do nome do arquivo. Esses códigos vão desde simples parsers à partir do separador de extensão de arquivos até a utilização do FilenameUtils do Commons IO, que faz a mesma coisa. Porém, e se o arquivo não tiver extensão? E se alguém simplesmente alterar a extensão original do arquivo? Dependendo da sua regra de negócio, você poderia simplesmente invalidar arquivos sem extensão ou com extensão inválida, mas o Tika extrai as extensões do metadado, ou melhor, da assinatura do tipo do arquivo que está no próprio arquivo. Dessa forma, ele poderia até ser utilizado para análise forense computacional.

Nesse artigo, vamos demonstrar como utilizar o Apache Tika para determinar se um arquivo é uma planilha do tipo xls ou xlsx, que é uma extensão típica do MS-Office. Comecemos pelas dependências:

<dependency>
   <groupId>org.apache.tika</groupId>
   <artifactId>tika-core</artifactId>
   <version>1.14</version>
</dependency>
<dependency>
   <groupId>org.apache.tika</groupId>
   <artifactId>tika-parsers</artifactId>
   <version>1.4</version>
</dependency>
<dependency>
   <groupId>xerces</groupId>
   <artifactId>xercesImpl</artifactId>
   <version>2.11.0</version>
</dependency>

É importante observar que você deve utilizar a versão mais recente do xerces, pois algumas versões antigas estão levantando exceção ao tentar fazer parse de algum xml. Poderíamos utilizar diretamente os detectores do Tika, mas vamos fazer algo mais genérico. Vamos implementar um DirectoryStream.Filter[T], que é uma interface do java que permite decidir se um determinado arquivo deve ser aceito. O interessante é que nossa classe pode ser utilizada sozinha para testar o tipo de um arquivo ou pode ser combinada com filtros de diretório.

public class XLSFilter implements DirectoryStream.Filter<Path> {
   private Detector detector;
   private static final List<String> EXTENSIONS = Arrays.asList(".xls", ".xlsx");

   public XLSFilter() {
         List<Detector> detectors = new ArrayList<Detector>();
         /*
          * Detector especializado em analisar metadados do MS-Office.
          */
          detectors.add(new POIFSContainerDetector());
         /*
          * Detectores padrao.
          */
          detectors.add(MimeTypes.getDefaultMimeTypes());
         /*
          * Detector composto pelos detectores acima.
          */
          detector = new CompositeDetector(detectors);
    }

    @Override
    public boolean accept(Path path) throws IOException {
       BasicFileAttributes attrs = Files.readAttributes(path, 
          BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS);
       if (!attrs.isRegularFile()) {
          return false;
       }
       String extension = "";
       try {
          extension = detectarExtensao(path);
       } catch (MimeTypeException e) {
          e.printStackTrace();
       }
       return EXTENSIONS.contains(extension.toLowerCase());
   }

   private String detectarExtensao(Path path) 
         throws IOException, MimeTypeException {
      MediaType mediaType = detectarMediaType(path);
      TikaConfig config = TikaConfig.getDefaultConfig();
      MimeType mimeType = config.getMimeRepository().forName(mediaType.toString());
      return mimeType == null ? "" : mimeType.getExtension();
   }

   private MediaType detectarMediaType(Path path) 
          throws IOException, MimeTypeException {
       Metadata metadata = new Metadata();
       TikaInputStream inputStream = TikaInputStream.get(path);
       return detector.detect(inputStream, metadata);
   }
}

Agora, vamos utilizar nosso detector para filtrar arquivos em um diretório:

   Path folder = Paths.get(PATH_DIR).resolve(SUB_DIR);
   DirectoryStream.Filter<Path> filter = XLSFilter();
   DirectoryStream<Path> stream = Files.newDirectoryStream(folder, filter);
   for (Path path : stream) {
      System.ou.println(path.toFile().getName());
   }

Referências

1. [https://tika.apache.org/]
2. [http://www.programcreek.com/java-api-examples/index.php?api=org.apache.tika.mime.MediaType]

Categorias:Programação

Regras Propostas Para a Vida Diária

Carl Sagan, no capítulo 16 (“As Regras do Jogo”) do livro Bilhões e Bilhões, elenca regras que regem a vida diária:

1. Regra de Ouro: “faz aos outros o que desejas que te façam”.

2. Regra de Prata: “não faças aos outros o que não desejas que te façam”.

3. Regra de Bronze: “faz aos outros o que te fazem”.

4. Regra de Ferro: “faz aos outros o que quiseres, antes que te façam o mesmo”.

5. Regra “Tit-for-Tar”: “coopera com os outros primeiro, depois faz aos outros o que te fazem”.

A proposição de regras que condensam comportamentos não ajuda a lidar com a complexidade dos relacionamentos humanos. Bruce Lee, em sua “filosofia marcial”, dizia que temos que nos adaptar aos adversários e não atacá-los ou nos defendermos de uma forma padronizada, assim como a água que se adapta ao recipiente que preenche: “Não tenha formato, contornos…seja água, meu amigo”, dizia ele.

É impossível adotarmos uma daquelas regras como filosofia de vida. As regras “douradas”, assim como as regras de “latão banhado”, implodem com o tempo: é impossível ser 100% bom em 100% das ocasiões ou totalmente espertalhão em todas as ocasiões. Comportamentos extremistas obviamente não se sustentam.

Estou convencido de que é necessário levar em conta o contexto e as próprias pessoas com quem nos relacionamos para encontrar a melhor forma de agir. Talvez possamos começar sendo cordiais até que “mudanças ambientais” forcem nossa mudança de atitude.

Ainda assim, sem me contradizer, não acho que exista uma situação em que ser espertalhão ou malicioso seja uma opção. Isso não é por causa de alguma religião ou falso moralismo. O esperto, trambiqueiro e oportunista fica sem ambiente para trabalhar, pois cria inimizades e acaba sendo vítima do próprio veneno. Quem tem esse perfil sempre se arrisca a infringir leis e regras de convivência em grupo (ética). Mais cedo ou mais tarde terá que pagar por suas escolhas.

Categorias:Atitude