22 de abril de 2013

Estruturas de Dados com Delphi - parte II : Pilhas

No meu último post, comecei a falar sobre estruturas de dados e como o Delphi lida com as estruturas mais comuns, como as filas. Neste post, eu mostro o conceito de outra das estruturas padronizadas que o Delphi trata de forma inerente : pilhas.

A diferença central entre filas e pilhas está na ordem em que os elementos são retirados da estrutura. No caso das filas, o primeiro elemento inserido será o primeiro a ser retirado, mecanismo conhecido como FIFO (First In, First Out). Para as pilhas, o último elemento inserido é retirado primeiro; isto é, pilhas implementam o LIFO (Last In, First Out). Para compreender esse conceito, imagine que você guarde os pratos de sua casa empilhados no armário. Sempre que você precisa de um prato, retira o que está no topo da pilha. Quando vai guardá-los, os pratos são postos no topo da pilha novamente, disponíveis para o próximo uso.

Uma situação computacional prática onde o uso de pilhas se adequa é o cálculo do custo de um produto fabricado. Por exemplo, para calcular o custo de fabricação de um computador, temos que calcular o custo da CPU, do monitor e do teclado. No entanto, obter o custo da CPU requer que se calcule antes o custo da placa-mãe, transistores, capacitores, etc. A placa-mãe também é composta por outros itens, e assim sucessivamente.

Nessa estrutura, podemos somar o custo individual de cada componente até encontrar um que também seja composto. O item composto é incluído no topo da pilha enquanto se calcula seu custo. Tal processo deve ser feito recursivamente até que haja apenas itens simples. Nesse momento, o custo do último item adicionado à pilha está determinado e ele pode ser removido da pilha, prosseguindo o cálculo com o item seguinte.

Para implementarmos com as classes nativas do Delphi uma solução para essa situação, considere as classes abaixo:
TWProduto = class
public
Codigo: String;
Custo : Double;
Componentes: TList;

Constructor Create(ACodigo:String;ACusto: Double);
Destructor Destroy;override;
End;

TWContexto=class
public
produto: TWProduto;
indice : integer;
custo : double;

Constructor Create(AProduto: TWProduto);
end;

{ ... }

Constructor TWProduto.Create(ACodigo:String;ACusto: Double);
begin
Codigo := ACodigo;
Custo := ACusto;
Componentes:= TList.Create;
end;

Destructor TWProduto.Destroy;
begin
{ ... }
Componentes.Free;
inherited;
end;

Constructor TWContexto.Create(AProduto: TWProduto);
begin
produto := AProduto;
indice := 0; { iniciar cálculo nesse índice }
custo := 0.0; { custo inicial do produto }
end;
A primeira classe (TWProduto) representa um produto que pode ser composto de outros produtos, incluindo outros produtos compostos. Já a classe TWContexto serve para controlar o cálculo do custo de um único produto composto. Além do próprio produto, ela armazena o índice do último componente considerado pelos cálculos bem como o custo obtido até o momento.

No quadro a seguir, eu simulo manualmente a montagem simplificada de um computador. O resultado é um exemplo de estruturação complexa usando a classe de produto descrita acima e cujo custo poderá ser calculado com uma rotina usando pilha:
function TForm1.MontaComputador : TWProduto;
var computador, compon, subcompon: TWProduto;
begin
computador := TWProduto.Create('Computador', 0.0);

compon := TWProduto.Create('Teclado', 20.0);
computador.Componentes.Add(compon);

compon := TWProduto.Create('Monitor', 235.0);
computador.Componentes.Add(compon);

{ A CPU é um produto composto }
compon := TWProduto.Create('CPU', 0.0);
subcompon := TWProduto.Create('Placa-mãe', 250.0);
compon.Componentes.Add(subcompon);
subcompon := TWProduto.Create('Cooler', 32.0);
compon.Componentes.Add(subcompon);
computador.Componentes.Add(compon);

Result := Computador;
end;
A rotina abaixo usa pilha para controlar o cálculo do custo de um produto - no caso, o computador estruturado no quadro anterior. Em Delphi, a classe TStack implementa as operações necessárias para se trabalhar com uma pilha.
procedure TForm1.btnCalcularCustoClick(Sender: TObject);
var i : integer;
interromper : boolean;
Pilha: TStack;
contexto, ctxAux : TWContexto;
computador : TWProduto;
begin
computador := MontaComputador;
contexto := TWContexto.Create (computador);

{ Inicia a pilha com o produto original no contexto : o computador }
Pilha:= TStack.Create;
Pilha.Push(contexto);

while (pilha.Count > 0) do begin
{ Obtém o contexto no topo, sem removê-lo }
contexto := pilha.Peek;
compon := contexto.produto;
i := contexto.indice;

{ Percorre os componentes desse produto, somando o custo de cada um para obter o custo do total do produto em si }
interromper := false;
while (i < compon.Componentes.Count) And (not interromper) do begin
subcompon := compon.Componentes.Items[i];

{ Esse produto é composto ? }
interromper := (subcompon.Componentes.Count > 0);
if (interromper) then begin
{ Inclui o subcomponente composto no topo da pilha pra calcular seu custo }
ctxAux := TWContexto.Create (subcompon);
Pilha.Push(ctxAux);

{ Quando desempilhar esse produto, inicie no componente seguinte }
contexto.indice := i + 1;
end
else
contexto.custo := contexto.custo + subcompon.Custo;

Inc (i);
end;

{ Conseguiu totalizar o custo do produto; então, remove-o do topo da pilha }
if not interromper then begin
Pilha.Pop;
compon.Custo := contexto.custo;
contexto.Free;

{ Adiciona o custo calculado ao custo do produto do qual esse componente é parte }
if pilha.Count > 0 then begin
contexto := pilha.Peek;
contexto.custo := contexto.custo + compon.Custo;
end;
end;
end;

{ Apresenta o custo obtido }
lblCusto.Caption := FormatFloat ('#,##0.00', computador.Custo);

Pilha.Free;
computador.Free;
end;
Assim como no caso da fila tratado no outro post, o constructor da pilha exige a especificação do tipo de dado com o qual a pilha será capaz de trabalhar. No exemnplo, a classe TWContexto é informada para que possamos controlar os produtos que já foram considerados no cálculo do custo.

As funções mais importantes na pilha são a que acrescenta e a que remove um elemento. Para inserir um novo elemento no topo da pilha, use o método Push e para extraí-lo use Pop, como mostrado no código acima.

É possível ainda obter o elemento que está no topo da pilha sem, no entanto, extraí-lo. Para isso, há o método Peek, também utilizado no exemplo.

Embora não tenha sido necessário aqui, o TStack permite interceptar a adição e remoção de elementos através do evento OnNotify. Ele é frequentemente utilizado para liberar a memória associada aos elementos da pilha.

26 de março de 2013

Estruturas de Dados com Delphi - parte I : Filas

Em maior ou menor grau, o trabalho de um programador de computadores envolve lidar com meios de organizar os dados internos de seus programas. Uma organização bem planejada é imprescindível para a implementação de algorítmos eficientes, o que afeta tanto a performance da aplicação quanto sua facilidade de manutenção. As formas de se organizar os dados em um programa são chamadas de Estruturas de Dados.

Pela sua importância, a maioria das linguagens de programação oferecem bibliotecas com implementações genéricas pré fabricadas para as formas tradicionais de organização de dados, tais como listas, pilhas e filas. No caso do Delphi, esses e outros mecanismos estão disponíveis na unit System.Generics.Collections. Neste post, começo a mostrar as principais estruturas existentes nessa biblioteca, complementando a explicação com exemplos práticos em Delphi.

Em primeiro lugar, precisamos compreender como funciona cada uma das estruturas para podermos decidir qual a mais apropriada para cada situação.

Por exemplo, as filas são desenhadas para o cenário onde precisamos tratar uma sequência de valores exatamente na mesma ordem em que esses valores vão surgindo. É o conceito da fila do caixa em uma loja: cada cliente é atendido sequencialmente de acordo com sua posição na fila; novos clientes entram no final da fila para serem atendidos. Em programação, esse conceito pode ser aplicado ao tratamento de requisições enviadas para execução num sistema. O quadro abaixo traz a declaração básica de uma classe Delphi representando uma requisição executável:
TWRequis = class
public
procedure Execute;virtual;abstract;
function Terminou : Boolean;virtual;abstract;
End;
As Collecions definidas pelo Delphi são estruturas de dados genéricas, mais ou menos como as STL do C++. Isso significa que, quando declaramos uma instância dessas estruturas, devemos informar o tipo de dado que essa Collection em particular vai tratar. Para deixar mais claro, veja a declaração da classe que controlará a execução de requisições em nosso exemplo de fila:
TWVerifRequis = class
{ ... }
public
Fila: TQueue<TWRequis>;
procedure DoOnNotify (Sender: TObject; const Item: TWRequis; Action: TCollectionNotification);

constructor Create;
destructor Destroy;override;
procedure InsereRequis(ATipo: integer);
procedure Start;
end;
No exemplo, declarei a fila associada à classe de requisição. Se for necessário, também é permitido associar a tipos atômicos (como integer e string) ou a estruturas (record). Agora, vamos dar uma olhada no construtor da classe:
constructor TWVerifRequis.Create;
begin
Fila := TQueue<TWRequis>.Create();
Fila.OnNotify := DoOnNotify;
end;
Veja que também ao criar uma instância da fila (o TQueue) devemos especificar o tipo de dado com o qual ela está apta a trabalhar. Um outro detalhe é o evento OnNotify; interceptá-lo nos permite reagir a alterações na fila, tais como saber que um novo registro foi incluído ou acabou de ser removido. Em ambos os casos, podemos atualizar o status da fila para o usuário, avisando-o quantos registros restam e qual requisição está sendo processada. Repare ainda que a assinatura do evento reflete o tipo de dado que nossa fila trata, restringindo a resposta do OnNotify a este tipo específico:
procedure TWVerifRequis.DoOnNotify (Sender: TObject;const Item: TWRequis; Action: TCollectionNotification);
begin
{ A requisição que está no início da fila foi removida; então, ela deve ser executada }
if Action = cnRemoved then begin
{ Atualiza o status, notificando o usuário sobre que requisição está em processamento }
NotificaRequisAtual(Item);
Item.Execute;
Item.Free;
end;

{ Atualiza o status, notificando o usuário sobre quantas requisições restam na fila p/ executar }
NotificaQtd (Fila.Count);
end;
As funções mais importantes para essa estrutura de dado são a que acrescenta e a que remove um elemento da fila. Para incluir um novo item ao fim da fila, use o método Enqueue e para remover o elemento que está no início da fila, use Dequeue, como mostra o exemplo a seguir:
procedure TWVerifRequis.InsereRequis(ATipo: integer);
var lRequis : TWRequis;
begin
{ Invoca a factory para criar a requisição correta de acordo com o tipo informado }
lRequis := CriaNovaRequisicao(ATipo);

{ Acrescenta ao fim da lista a nova requsição criada }
Fila.Enqueue(lRequis);
end;

procedure TWVerifRequis.Start;
var lRequis : TWRequis;
begin
{ Enquanto não foi solicitado o término da execução, continua monitorando a fila }
while Not Terminou() do begin
{ Se há elemento na lista, remove-o aqui. Isso dispara o evento OnNotify, permitindo a execução dessa requisição }
if (Fila.Count > 0) then
lRequis := Fila.Dequeue
else
Sleep(1000);
end;
end;
A requisição poderia ter sido executada imediatamente após a chamada ao Dequeue, ao invés de dentro do evento OnNotify. Ambas são soluções aceitáveis e, portanto, optar por uma ou outra abordagem é uma questão de gosto.

Uma última consideração: se, por alguma razão, for preciso descobrir quem é o próximo item da fila sem, no entanto, removê-lo, use o método Extract. Uma aplicação disso é mostrar no status informações sobre a requisição que está aguardando para ser executada.

Esse exemplo foi construído com o Delphi XE2; não encontrei informação a respeito da presença da biblioteca Collection em versões anteriores ou em qual versão ela foi introduzida. No próximo post, falo sobre pilhas (ou stacks) e suas aplicações.

2 de janeiro de 2013

Mudanças no envio de e-mails entram em vigor em 1o de Janeiro de 2013

Com o intuito de reduzir o número de spams e melhorar a segurança no envio de e-mails, o CGI (Comitê Gestor da Internet no Brasil) vem recomendando alterações na forma de se enviar e-mails no país. Em acordo com a Anatel, a Associação Brasileira de Internet e o Sindicato Nacional das Empresas de Telefonia e de Serviço Móvel Celular e Pessoal, algumas alterações já foram implantadas.

Como parte desse acordo, a partir de 1º de Janeiro de 2013 os provedores externos de e-mail deverão desligar o envio de mensagens através da porta 25, substituindo-a pela porta 587. De forma simplificada, uma porta é um canal por onde um computador se comunica com outros computadores (ou com periféricos). São exemplos de provedores externos UOL, BOL, Terra, Zipmail, Speedy, Vivo, GMail e Hotmail. E-mails enviados via modem 3G também estão sujeitos à esta mudança.

A mudança afetará tanto o envio de e-mails através de programas tradicionais de mercado - como o Outlook - quanto aqueles programas que você mesmo tenha construído. É preciso verificar com o provedor do serviço de email utilizado se ele acatará as recomendações, adotando a porta 587 (ou outra) para envio das mensagens; em caso afirmativo, você terá que revisar as configurações dos seus aplicativos para evitar que funcionalidades dependentes do envio de e-mail deixem de operar corretamente.

Empresas que usam servidor de e-mail próprio (como o Exchange) não precisam fazer a conversão, embora isso seja recomendado. Para adotar as recomendações nesse cenário, o TI de sua empresa precisará antes rever as configurações do servidor de e-mail, permitindo que ele envie as mensagens através da porta 587 e exija a autenticação do usuário que deseja fazer o envio.

Reproduzo abaixo matéria a esse respeito publicada no UOL:
Internautas que utilizam configurações antigas em programas de leitura e envio de e-mails, como o Outlook, Windows Mail, Apple Mail ou aqueles instalados no celular, podem não conseguir enviar mensagens a partir de 2013. O Comitê Gestor da Internet no Brasil (CGI) pretende reduzir o volume de spam gerado no país e, por esta razão, solicitou o fim de envios de mensagens sem autenticação, ou seja, sem que o usuário tenha de fornecer login e senha, em todo o território nacional.

A restrição será aplicada para os programas configurados para enviar mensagens (SMTP) pela "porta 25" do computador. Quem usa programas configurados com a "porta 587" ou acessa seus e-mails pelo site do provedor (webmail) não será afetado.

Mudança no envio de e-mails
Para que o envio de mensagens não seja interrompido, é preciso alterar configurações do programa de e-mail, modificando a porta de envio 25 para o valor 587, associado ao padrão SMTPS (protocolo seguro para envio de mensagens).

Gerência da Porta 25
O encerramento da porta 25 é uma recomendação do CGI para por fim a um método de envio de mensagens não solicitadas, os ‘spams’, que se aproveita de conexões não autenticadas.

A mudança foi sugerida em acordo com a Anatel, a Associação Brasileira de Internet (Abranet, que reúne provedores e outras prestadoras de serviço na rede) e o Sindicato Nacional das Empresas de Telefonia e de Serviço Móvel Celular e Pessoal (SindiTelebrasil).

Segundo Eduardo Nager, presidente da Abranet, os provedores estão preparados para a mudança há muito tempo, recomendando a utilização de conexões seguras e configurações atualizadas. Para Nager, a grande mudança em 1º de janeiro se dará na parte de acesso físico, a cargo das operadoras de telecomunicações.

Eduardo Levy, diretor executivo do SindiTelebrasil, informou que o prazo para fechamento da porta 25 é o dia 31 de dezembro, acordado entre as suas filiadas, que incluem Oi, Telefônica, GVT e Embratel, além da TIM. As operadoras Oi - responsável por Oi Velox e Oi Velox 3G - e Telefonica - que vende os serviços Vivo Speedy e Vivo 3G - informaram que já seguem as recomendações do CGI.

Apesar de o fechamento ficar a cargo das operadoras, a notifição aos usuários ficou sob responsabilidade dos provedores de e-mails. Os usuários dos e-mails UOL e BOL recebem comunicados regulares sobre as novas configurações desde 2010.

Além de reduzir o volume de spam enviado pelo Brasil (atualmente o sétimo país no ranking de origem de spams, segundo a empresa de segurança Sophos, e quinto, de acordo com levantamento da Kaspersky Labs), a utilização de conexões seguras pelas portas 587 ou 465 desafoga a conexão dos usuários afetados, seus provedores de acesso e dos serviços de e-mail.

Mais do que isso, a medida ajuda a aumentar a confiabilidade dos serviços de e-mails, ajuda nos esforços para criação de filtros cada vez melhores e pode tirar sites brasileiros de listas internacionais para bloqueio de mensagens indesejadas, segundo Nager.

19 de dezembro de 2012

Personalizando a apresentação de mapas com o Google Maps

Na maioria das vezes, as informações apresentadas num mapa produzido através da API do Google Maps são suficientes para que o usuário rapidamente consiga ver um endereço e seu entorno ou a rota a ser seguida para ir de um ponto a outro. Em certas situações, no entanto, pode ser necessário adicionar ao mapa outras informações para melhor transmitir a ideia correta que se deseja.

Esse tipo de necessidade foi exemplificado quando falei sobre o uso de marcações num mapa para apontar locais de interesse nas proximidades de um determinado endereço. O exemplo pode ser encontrado neste link.

A API do Google Maps nos permite acrescentar informações extras aos mapas através do conceito de camadas que são sobrepostas ao mapa, chamadas de overlays. Para isso, a API disponibiliza um conjunto de classes javascript. Além da já citada Marker, há classes para traçar linhas, delimitar áreas circulares ou retangulares e até mesmo para projetar uma imagem personalizada sobre uma área do mapa.

O overlay mais simples é o Polyline, usado para traçar linhas por sobre o mapa. O quadro abaixo traz código javascript que une com uma linha reta 2 pontos do mapa: a sede da ABC71 e a praça da Sé, em São Paulo:
var mapOptions = {zoom: 10,mapTypeId: google.maps.MapTypeId.ROADMAP};
map = new google.maps.Map(document.getElementById('map_canvas'), mapOptions);
geocoder = new google.maps.Geocoder();

var endDe = new google.maps.LatLng(-23.566146,-46.652579);
var endAte = new google.maps.LatLng(-23.550563,-46.633101);
var request = { location: endDe, region: 'BR'};

geocoder.geocode (request, function(response, status) {
if (status == google.maps.GeocoderStatus.OK) {
map.fitBounds (new google.maps.LatLngBounds(endDe, endAte));
/* ... */
var pontos = new google.maps.MVCArray ();
pontos.push (endDe);
pontos.push (endAte);

var rect = new google.maps.Polyline ({
path: pontos,
map:map,
strokeWeight: 5,
strokeColor: 'blue',
visible: true
});
}
});
Após as inicializações de praxe para o ambiente do Maps, o código solicita a geocodificação do endereço da ABC71 (na verdade, sua latitude/longitude).
Em resposta à conclusão da geocodificação, isto é, assim que o mapa com o endereço solicitado está pronto, eu crio uma lista MVCArray e adiciono a ela os dois pontos que definem a reta desejada.

Em seguida, instancio a classe Polyline propriamente dita, fornecendo-lhe a lista de pontos. Também indico o mapa onde a linha será traçada (map), a espessura da linha em pixels (strokeWeight) e a cor dela (strokeColor). As cores podem ser informadas tanto pelo nome HTML quanto pela notação RGB hexadecimal.

Posso, por exemplo, demarcar um bairro inteiro com esse recurso? Sim, mas você terá que montar a lista de pontos o mais completa possível para que o desenho resultante tenha uma precisão adequada. O Polyline produz linhas abertas; para traçar linhas fechadas com uma quantidade arbitrária de pontos use a classe Polygon.

A função fitBounds, usada no início da resposta, apenas aplica um nível de zoom apropriado para garantir que ambos os endereços sejam exibidos num único quadro, sem que o usuário precise interagir com ele.

O código analisado produz o mapa a seguir:
Imagine agora o caso de uma pizzaria que queira divulgar num mapa o raio de ação onde ela faz entregas. O overlay produzido pela classe Circle permite dar destaque a uma área circular, dado um centro e um raio em metros. Veja o exemplo:
var endDe = new google.maps.LatLng(-23.566146,-46.652579);
var request = { location: endDe, region: 'BR'};

geocoder.geocode (request, function(response, status) {
if (status == google.maps.GeocoderStatus.OK) {
map.setCenter(endDe);
/* ... */
var circleOpts = ({
map: map,
center: endDe,
editable: false,
fillColor: 'yellow',
fillOpacity: 0.4,
radius: 3500,
strokeColor: '#0099ff',
strokeWeight: 4,
visible: true });
var circle = new google.maps.Circle (circleOpts);
}
});
Como no caso da linha, para o círculo também valem as propriedades que indicam o mapa, a cor do traço e sua espessura. Mas, ao invés de uma lista de pontos, informamos apenas o centro; no código anterior, usei o próprio endereço da ABC71 para isso. A definição do círculo fica completa com a propriedade radius - o raio, fornecido em metros; no exemplo, o raio terá 3500 metros (ou 3,5 Km).

Outra configuração disponível diz respeito ao preenchimento da área delimitada pelo círculo. A propriedade fillColor determina a cor do preenchimento enquanto a fillOpacity controla o grau de transparência, sendo que o valor 1 significa totalmente opaco (o mapa sob o círculo não é visto) e o valor 0 suspende o preenchimento.

A propriedade editable, quando ativa, permite ao usuário redimensionar o círculo. Eu a desliguei pois ela não faz sentido no contexto do exemplo. O resultado é o mapa exibido no quadro abaixo:

Os mesmos conceitos valem para a classe Rectangle. Além disso, é permitido trabalhar com vários overlays num mesmo mapa, se for necessário. Os exemplos publicados nesse post podem ser acessados respectivamente nos seguintes links : Overlay com Linha e Overlay com Círculo.