A Matemática Analítica e o Cálculo Variacional

M. Le Blanc, pseudônimo de Marie-Sophie Germain (1776-1831), deixou grandes contribuições para a teoria dos números com seu trabalho sobre o Último Teorema de Fermat e seus estudos sobre as superfícies elásticas. Inspirada pelo formalismo da Mecânica Analítica de Lagrange, ela estabeleceu um método para descobrir a equação da curva mais adequada dadas determinadas restrições.

d/dt[∂ℒ/∂qo] – ∂ℒ/∂q = 0

Figura 1 – Lagrangeano ℒ(t,q,qo) – energia – domínio da física

(d/dx)[∂f/∂yo] – ∂f/∂y = 0

Figura 2 – Mleblancano f(x,y,yo) – forma – domínio da matemática

O cálculo variacional estabelece que, entre todas as funções admissíveis, aquela que maximiza ou minimiza o funcional é a solução do problema em determinado espaço regido pelo funcional. O método variacional fornece uma maneira relativamente fácil de se construir as equações que governam um sistema, uma vez que uma formulação variacional considera grandezas escalares ao invés de vetoriais [2]. Esse método é uma generalização do cálculo de máximos e mínimos de funções reais de uma variável. O cálculo ordinário lida com funções e o cálculo das variações lida com os funcionais – mais especificamente, com o núcleo desses funcionais.

Um conceito fundamental do cálculo variacional é o funcional, que é uma grandeza escalar; função de funções, que assume um valor particular dependente da função nele utilizada [1]; é um operador que mapeia as funções admissíveis no espaço dos números reais:

n → ℜ*

No caso de funções com mais de uma variável surgem as derivadas parciais, que são derivadas direcionais particulares. O conceito de derivada funcional (ou variacional) desempenha para funcionais o mesmo papel que o conceito de derivada direcional desempenha para funções de n variáveis [3].

Funcionais podem, por exemplo, ser formados por integrais envolvendo uma função incógnita e suas derivadas. O interesse está em funções extremas – aquelas que fazem o funcional atingir um valor máximo ou mínimo – ou de funções fixas – aquelas onde a taxa de variação do funcional é zero.

A imagem abaixo resume o objetivo do cálculo variacional. Note que entre os pontos A e B há várias curvas candidatas à otimizadoras da Integral I, mas elas têm variações (δy≠0). Nos pontos A e B não há variações (δy|A=0 e δy|B=0). Queremos encontrar a curva que liga esses dois pontos e que não apresenta variações.

Figura 3 – Curvas candidatas

Terapêutica Variacional

O método de M. Le Blanc visa encontrar a curva que maximiza ou minimiza um funcional através de uma dentre quatro “terapêuticas” utilizadas para classificar e tratar o problema. Na medicina, terapêutica é um meio usado para tratar determinada doença ou estado patológico. Em cálculo variacional, terapêutica é uma forma de classificar um problema e tratá-lo com o funcional mais adequado, observando certas condições em seu núcleo, para encontrar a melhor equação de curva para aquele caso. O núcleo do funcional deve ser escrito em termos de x (espaço), y (função) e y0 (primeira derivada da função y).

Terapêutica Variacional de Caso I

Caso: se o funcional estiver escrito em termos de x, y, yo:

Terapêutica: deve-se aplicar a seguinte terapêutica:

(d/dx)[∂f/∂yo] – ∂f/∂y = 0

Terapêutica Variacional de Caso II

Caso: se o funcional estiver escrito em termos yo:

(d/dx)[∂f/∂yo] – ∂f/∂y = 0
(d/dx)[∂f/∂yo] – 0 = 0
(d/dx)[∂f/∂yo] = 0

Terapêutica: deve-se aplicar a seguinte terapêutica:

∂f/∂yo = constante

Terapêutica Variacional de Caso III

Caso: se o funcional estiver escrito em termos de y e yo:

Terapêutica: deve-se aplicar a seguinte terapêutica:

(d/dx)[∂f/∂yo] – ∂f/∂y = 0

Terapêutica Variacional do Caso IV

Caso: se o funcional estiver escrito em termos de x e yo:

Terapêutica: deve-se aplicar a seguinte terapêutica:

(d/dx)[∂f/∂yo] – ∂f/∂y = 0
(d/dx)[∂f/∂yo] – 0 = 0
∂f/∂yo = constante

Funcionais Matematizados

Para identificarmos a terapêutica variacional mais indicada para tratar cada caso, primeiro é necessário reescrevermos os funcionais mais comuns (comprimento, volume, superfície, área e tempo) em termos de x e yo.

Não vamos mostrar a dedução de cada funcional, pois foge a proposta desse artigo. Porém, o funcional da área, ou integral da área sob uma curva, foi muito bem deduzido em outro artigo.

Funcional do Comprimento da Curva

Funcional do Volume do Sólido

Funcional da Superfície (Área Lateral do Sólido)

Funcional da Área Abaixo da Curva

Funcional do Tempo

Exemplo

Vamos utilizar o formalismo de M. Le Blanc, que foi fortemente inspirada em Lagrange, para encontrar a curva y(x) que liga o ponto A ao ponto B através de uma superfície plana (euclidiana) com a menor distância possível. Como não há restrições, a solução é obviamente uma linha reta, mas vamos provar matematicamente. Em princípio, supomos que o objeto segue uma rota qualquer:

Figura 3 – Rota de A para B

Funcional

Núcleo do Funcional

f=[1 + y0 2]1/2

Terapêutica Variacional

Como o funcional do comprimento está escrito em termos de yo:

Recomenda-se a terapêutica variacional de caso II:

∂f/∂yo = c

Equação Diferencial

∂/∂yo [1 + y0 2]1/2 = c

Curva Solução

∂/∂yo [1 + y0 2]1/2 = c
1/2[1 + y0 2]-1/22y0 = c
y0/√(1 + y0 2) = c
y0 2/(1 + y0 2) = c2
y0 2 = c2 + c2y0 2
y0 2 – c2y0 2 = c2
y0 2[1 -c2] = c2
y0 2 = c2/[1 -c2]
√y0 2 = √(c2/[1 -c2])
y0=a

dy/dx = a
dy = adx
∫1dy = ∫adx

y = ax + b

Conclusão

A curva que minimiza a distância entre os pontos A e B – geodésica – em uma superfície plana é a reta ax + b.

Referências

1. [http://aquarius.ime.eb.br/~moniz/pdf/calc02.pdf]
2. [https://www.maxwell.vrac.puc-rio.br/17370/17370_4.PDF]
3. [http://www.df.ufcg.edu.br/~romulo/seminarios/wilson_hugo/calcvariac.pdf]
4. [https://repositorio.ufsc.br/xmlui/bitstream/handle/123456789/96389/Antonio_Joao.pdf?sequence=1&isAllowed=y]
5. [http://200.145.6.238/bitstream/handle/11449/94375/flores_apx_me_rcla.pdf?sequence=1&isAllowed=y]
6. [http://www.ime.unicamp.br/~valle/Teaching/MA211/Aula6.pdf]
7. [Material do Curso Prandiano – P2]

Aplicação de Derivada Parcial Com Vínculo

O formalismo de Lagrange permite que utilizemos as derivadas parciais e a ideia de solução ótima com restrição – ou a melhor solução possível dadas as restrições (vínculos) – para abordar até problemas simples que poderiam ser resolvidos por trivial derivação. Os vínculos deslocam a solução ótima em alguma direção:

Figura 1 – Solução ótima e solução vinculada

Problema

Propus um problema de otimização da área útil de uma horta em que utilizei simples derivada. Nesse artigo, vou utilizar o método de Lagrange para resolver o mesmo problema:

Queremos construir uma horta retangular de pequeno porte que disponibilize a maior área útil possível. Para isso, dispomos de apenas uma tábua de 20 metros de comprimento que deve ser cortada para delimitar a horta.

Figura 2 – Visualização da área hipotética

Funções do Problema

A = x.y

2x + 2y = 20
x + y = 10

x + y = 10 é o vínculo Φ que deve ser maximizado ou minimizado. Sendo assim, essa função deve ser explicitamente igualada à zero – a deixis am phantasma deve dar lugar a deixis ad oculos:

x + y = 10
x + y – 10 = 0
Φ = x + y – 10

Grande Função

G = x.y + λΦ
G = x.y + λ[x + y – 10]

Condições de Otimização

∂G/∂x = 1.y + λ[1 + 0 – 0] = 0 (A)
∂G/∂y = x.1 + λ[0 + 1 – 0] = 0 (B)
∂G/∂λ = 0 + 1.[x + y -10] = 0 (C)

Solução Otimizada

X* = 5

Y* = 5

λ = -5

Cálculo da Área Ótima

Vamos utilizar os valores obtidos para calcular a área ótima:

A = x.y
A = 5.5
A = 25m2

Conclusão

Como x é igual à y, concluimos, pelo método de Lagrange, que a solução ótima do problema é uma horta quadrada de lado 5.

Como Adicionar Eventos ao Outlook Programaticamente

A RFC5546 especifica o iTIP (iCalendar Transport-Independent Interoperability Protocol), que é um protocolo que oferece interoperabilidade de agendamentos entre diferentes sistemas de calendários, pois não é feita referência à um protocolo de transporte específico, como o SMTP.

Nesse artigo, vamos desenvolver um exemplo em Java que utiliza templates do Velocity para formatar os eventos que serão adicionado ao Outlook.

Figura 1 – Calendário do Outlook

Adicione a dependência do Xerces e do Velocity ao seu pom:

<dependency>
   <groupId>xerces</groupId>
   <artifactId>xercesImpl</artifactId>
   <version>2.11.0</version>
</dependency>
<dependency>
   <groupId>org.apache.velocity</groupId>
   <artifactId>velocity</artifactId>
   <version>1.7</version>
</dependency>

Vamos criar uma classe para enviar um e-mail com o evento para o destinatário. O mais importante dessa classe é o tipo “text/calendar” passado para o ByteArrayDataSource empacotado em um DataHandler. É esse tipo que fará com que o Outlook interprete o e-mail como um evento que deve ser adicionado ao calendário.

import java.io.IOException;
import java.util.Properties;
import javax.activation.DataHandler;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.util.ByteArrayDataSource;

public class RFC5546MailSender{
   private Properties properties;
   private String servidorEmail;
   public RFC5546MailSender() {
      this.servidorEmail = /*Seu servidor de e-mail*/
      properties = new Properties();
      properties.put("mail.smtp.host", this.servidorEmail);
      properties.put("mail.smtp.connectiontimeout", "10000");
      properties.put("mail.smtp.timeout", "15000");
      properties.put("mail.smtp.allow8bitmime", "false");
   }

   public void enviar(String remetente, String destinatario, 
     String assunto, String mensagem) throws MessagingException {
      Session session = Session.getDefaultInstance(properties);
      MimeMessage message = new MimeMessage(session);
      message.setFrom(new InternetAddress(remetente));
      message.addRecipient(Message.RecipientType.TO, new InternetAddress(destinatario));
      message.setSubject(assunto);
      BodyPart partBody = new MimeBodyPart();
      Transport tr = null;
      try {
         partBody.setHeader("Content-Class", "urn:content-classes:calendarmessage");
         partBody.setHeader("Content-ID", "calendar_message");
         partBody.setDataHandler(
           new DataHandler(new ByteArrayDataSource(mensagem, "text/calendar")));
         Multipart multipart = new MimeMultipart();
         multipart.addBodyPart(partBody);
         message.setContent(multipart);
         tr = session.getTransport("smtp");
         Transport.send(message, message.getAllRecipients());
      } catch (IOException e) {
         throw new MessagingException(e.getMessage());
      } catch (MessagingException e) {
         throw e;
      } finally {
         if (tr != null) {
            try {
               tr.close();
            } catch (MessagingException e) {
               throw e;
            }
         }
      }
   }
}

Poderíamos concatenar strings separando a propriedade e seu valor por “\n”, mas a manutenibilidade desse código seria bem complexa. Vamos utilizar o Velocity para carregar um template com as configurações padrão da solicitação de evento:

import java.io.StringWriter;
import java.util.Map;
import java.util.Properties;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.resource.loader.FileResourceLoader;

public class Velocity {
   private VelocityEngine engine;
   public Velocity() {
      Properties properties = new Properties();
      properties.put("file.resource.loader.path", "TEMPLATES_DIR");
      properties.put("file.resource.loader.cache", "false");
      properties.put("file.resource.loader.modificationCheckInterval", "10");
      properties.put("file.resource.loader.class", FileResourceLoader.class.getName());
      this.engine = new VelocityEngine(properties);
   }

   public String formatar(Map<String, Object> parameters, String nomeTemplete) {
      StringWriter sw = new StringWriter();
      Template template = engine.getTemplate(nomeTemplete, "UTF-8");
      VelocityContext context = new VelocityContext();
      for (String key : parameters.keySet()) {
         context.put(key, parameters.get(key));
      }
      template.merge(context, sw);
      return sw.toString();
   }
}

Agora, vamos criar um template do Velocity com as configurações do evento chamado “solicitacao_reuniao.vm”. Esse template deve ficar no diretório “TEMPLATES_DIR” que você configurou na classe utilitária do Velocity.

BEGIN:VCALENDAR
VERSION:2.0
METHOD:REQUEST
BEGIN:VEVENT
UID:$id
SUMMARY:$titulo
DTSTART:$inicio
DTEND:$fim
LOCATION:$localizacao
DESCRIPTION:$descricao
STATUS:CONFIRMED
SEQUENCE:${sequencial}
ORGANIZER:MAILTO:$remetente
ATTENDEE;ROLE=CHAIR;ROLE=REQ-PARTICIPANT;RSVP=FALSE;PARTSTAT=ACCEPTED:MAILTO:$destinatario
CLASS:PRIVATE
BEGIN:VALARM
TRIGGER:-PT15M
ACTION:DISPLAY
END:VALARM
END:VEVENT
END:VCALENDAR

Algumas coisas merecem destaque na estrutura acima. A primeira delas é o método REQUEST, que é uma função complexa que permite a configuração de várias informações, como quais serão as pessoas convidadas para o evento. O UID é o identificador único da mensagem. É através desse campo que o sistema de calendário vincula um evento recebido a outro existente. O campo SEQUENCE não é importante para criação de eventos, mas é essencial para a atualização deles. Ele permite definir a sequência de atualizações que um evento existente deve sofrer. O alarme, que no caso será disparado 15 minutos antes do início do evento (-PT15M), é opcional.

Vamos utilizar os artefatos criados até agora para enviar a solicitação de uma reunião para o usuário que tem o e-mail “eu@empresa.com.br”:

private void solicitarReuniao() throws MessagingException{
   RFC5546MailSender rfcMailSender = new RFC5546MailSender();
   SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'");
   dateFormatter.setTimeZone(TimeZone.getTimeZone("GMT"));
   Map<String, Object> parameters = new HashMap<String, Object>();
   parameters.put("id", "123");
   parameters.put("titulo", "Solicitação de Reunião");
   parameters.put("localizacao", "2° andar, Sala 03");
   parameters.put("inicio", dateFormatter.format(new Date()));
   parameters.put("fim", dateFormatter.format(new Date()));
   parameters.put("descricao", "Solicitação de Reunião");
   parameters.put("remetente", "sistema@empresa.com.br");
   parameters.put("destinatario", "eu@empresa.com.br");
   parameters.put("sequencial", "0");
   Velocity format = new Velocity();
   String corpoEmail = format.formatar(parameters, "br/com/mail/solicitacao_reuniao.vm");
   rfcMailSender.enviar("sistema@empresa.com.br", "eu@empresa.com.br", "Solicitação de Reunião", corpoEmail);
}

Em seguida, vamos enviar uma atualização da reunião identificada por “123” utilizando o mesmo template de criação “solicitacao_reuniao.vm”. Para atualizações, é necessário informar a ordem sequencial:

private void atualizarReuniao() throws MessagingException{
   RFC5546MailSender rfcMailSender = new RFC5546MailSender();
   SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'");
   dateFormatter.setTimeZone(TimeZone.getTimeZone("GMT"));
   Map<String, Object> parameters = new HashMap<String, Object>();
   parameters.put("id", "123");
   parameters.put("titulo", "Atualização do Horário da Reunião");
   parameters.put("localizacao", "2° andar, Sala 03");
   parameters.put("inicio", dateFormatter.format(new Date()));
   parameters.put("fim", dateFormatter.format(new Date()));
   parameters.put("descricao", "Atualização do Horário da Reunião");
   parameters.put("remetente", "sistema@empresa.com.br");
   parameters.put("destinatario", "eu@empresa.com.br");
   parameters.put("sequencial", "1");
   Velocity format = new Velocity();
   String corpoEmail = format.formatar(parameters, "br/com/mail/solicitacao_reuniao.vm");
   rfcMailSender.enviar("sistema@empresa.com.br", "eu@empresa.com.br", "Atualização do Horário da Reunião", corpoEmail);
}

Por fim, vamos definir o template de cancelamento de evento “cancelamento_reuniao.vm”:

BEGIN:VCALENDAR
VERSION:2.0
METHOD:CANCEL
BEGIN:VEVENT
UID:$id
SUMMARY:$titulo
DTSTART:$inicio
DTEND:$fim
LOCATION:$localizacao
DESCRIPTION:$descricao
STATUS:CANCELLED
ORGANIZER:MAILTO:$remetente
ATTENDEE;ROLE=CHAIR;ROLE=REQ-PARTICIPANT;RSVP=TRUE:MAILTO:$destinatario
CLASS:PRIVATE
END:VEVENT
END:VCALENDAR

Nessa estrutura, destacam-se o método CANCEL e o status CANCELLED.

private void cancelarReuniao() throws MessagingException{
   RFC5546MailSender rfcMailSender = new RFC5546MailSender();
   SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'");
   dateFormatter.setTimeZone(TimeZone.getTimeZone("GMT"));
   Map<String, Object> parameters = new HashMap<String, Object>();
   parameters.put("id", "123");
   parameters.put("titulo", "Cancelamento da Reunião");
   parameters.put("localizacao", "2° andar, Sala 03");
   parameters.put("inicio", dateFormatter.format(new Date()));
   parameters.put("fim", dateFormatter.format(new Date()));
   parameters.put("descricao", "Cancelamento da Reunião");
   parameters.put("remetente", "sistema@empresa.com.br");
   parameters.put("destinatario", "eu@empresa.com.br");
   parameters.put("sequencial", "2");
   Velocity format = new Velocity();
   String corpoEmail = format.formatar(parameters, "br/com/mail/cancelamento_reuniao.vm");
   rfcMailSender.enviar("sistema@empresa.com.br", "eu@empresa.com.br", "Cancelamento da Reunião", corpoEmail);
}

Calendário Compartilhado

Em nosso exemplo, os eventos serão adicionados ao próprio calendário do usuário. Se você enviar a estrutura do evento como um anexo de extensão .ics, ele será exibido no Outlook como um calendário compartilhado ao lado do calendário do usuário:

Figura 2 – Calendário compartilhado

Mais Customizações

A própria especificação [2] afirma que oferece uma “forma padrão para fazer coisas que não são padronizadas”. A Microsoft tem um documento [3,4,5,6] que mostra como utilizar as propriedades específicas do Outlook para formatar a descrição do evento, a prioridade, cores associadas ao evento e várias outras propriedades.

Referências

1. [https://tools.ietf.org/html/rfc5546]
2. [https://tools.ietf.org/html/rfc5545#section-3.8.8.2]
3. [https://stackoverflow.com/questions/41304898/how-do-i-create-an-html-formatted-ics-message-body-using-ical-net]
4. [https://msdn.microsoft.com/en-us/library/ee624921(v=exchg.80).aspx]
5. [https://msdn.microsoft.com/en-us/library/ee625053(v=exchg.80).aspx]
6. [https://msdn.microsoft.com/en-us/library/cc463911(v=exchg.80).aspx]

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