You are on page 1of 34

editorial

O futuro (da pesquisa...)


Quando se fala em pesquisa decerto todos reconhecem o nome Google quase ao ponto de sinnimo, no apenas de pesquisa, mas mais importante que isso, de pesquisa com sucesso. Ao longo dos anos o Google tem sabido manter-se na ribalta do acesso ao conhecimento em todo o mundo, enveredando por outros projectos mas dando sempre a Coordenador Adjunto desde a 4 edio, actualmente o Coordenador da Revista Programar. Frequenta o curso de Engenharia Informtica e de Computadores, no IST.

ndice
3 4 7 notcias tema de capa a programar
- Estado de Visualizao em ASP.NET - Lucene: Programar um . motor de busca - Programas Circulares - Serializao e . Desserializaao de Objectos em C# - Manipulao de Datas - Internet Protocol Version 6

Miguel Pais

19 segurana 23 anlise 24 eventos 27 internet

equipa PROGRAMAR coordenador


Miguel Pais

devida ateno inovao (que os marcou desde o inicio) no seu produto principal. Menos conhecido, menos acedido e utilizado em terras lusas, mas igualmente popular a nvel mundial encontra-se o Digg, representando o conceito de website social relativo a notcias. O conceito trivial mas a ideia inovadora para a altura: notcias so submetidas por utilizadores sendo promovidas por votos positivos destes. O que tm em comum estes dois gigantes do seu ramo? Bem, nos ltimos dias (segunda semana de Julho) foi reportada peloTechCruch uma nova feature do Google que parece agregar o conceito do Digg s pesquisas de utilizadores, ou seja, cada um tem a possibilidade de enviar um resultado do Google para os confins da numerao de pginas, ou trazer outro para o topo. Alm disso h a possibilidade de comentar os websites e os seus respectivos comentrios, com um sistema de pontuao bastante semelhante ao do Digg. Com isto qualquer um poder pr o resultado que realmente lhe interessa como primeiro a ser retornado pelo Google para aquelas keywords, o que algo que faz bastante sentido. A maneira como esta componente social influenciar num todo no futuro os resultados do Google ser algo interessante de analisar. Posto isto algo desde logo salta vista: tudo o que antes recebamos como passivo est a evoluir para algo activo. O tempo em que o utilizador no tinha nada a dizer na informao que recebia acabou. J ningum quer receber passivamente informao sem ter voto na matria, os utilizadores querem a escolha e a deciso. E tudo isto faz sentido. Toda a Internet j percebeu isso, mas seria interessante que no s este meio virtual aderisse a este estilo. A televiso comea a ser menosprezada pela Internet, onde cada um v o que quer s horas que quer e a televiso no ganhar de novo a batalha se no se converter ao mesmo gnero. As mais recentes tentativas na rea da televiso em Portugal so boas, mas ainda no representam o estado real em que os utilizadores se encontram. A verdadeira televiso do futuro pode mostrar ao utilizador sempre que ele queira um programa da semana passada, instantaneamente e sem a construo de enfadonhos planos de gravao agendada. A prpria rdio usual j no faz sentido. Decerto utilizadores da Internet habituados a ouvirem apenas o que gostam em rdios de servios como o Last.fm devero j achar ridculo algum se submeter a ouvir algo que pode muito bem no corresponder em nada aos seus gostos. Seria importante que muita gente olhasse para a web e comeasse a aplicar o que l v s mais pequenas coisas da nossa sociedade, a nossa maneira de receber e lidar com a informao seria bem melhor. Veremos o que o futuro nos reserva 1) Referncia: http://www.techcrunch.com/2008/07/16/is-this-the-future-of-search/ 2) Uma nota para a mudana dos meses de publicao da revista, estes so agora os meses pares. Esperamos que a deciso no tenha prejudicado ningum e que continuem a conf iar neste projecto.

coordenador adjunto
Joel Ramos

editor

Pedro Abreu

redaco

Augusto Manzano Ciro Cardoso Joo Rodrigues Miguel Bento Miguel Alho Vitor Tomaz

colaboradores
Jos Fontainhas David Ferreira Pedro Teixeira

contacto

revistaprogramar @portugal-a-programar.org

website

www.revista-programar.info

<2>

notcias

Wii a nova lder de mercado nos EUA


A Wii j a consola mais vendida nos Estados Unidos. S em Junho foram comercializados 666 mil equipamentos, o que fixou o nmero total de dispositivos vendidos, desde Novembro de 2006, altura em que saiu para o mercado, nos 10,9 milhes de consolas. Os resultados foram recolhidos pelo NPD Group que concluiu na anlise ao mercado referindo que o equipamento da Nintendo j destronou a Xbox 360 da Microsoft, lanada um ano antes. Como em todos os segmentos de mercado, tambm neste as opinies divergem, com cada fabricante a defender o seu posicionamento no mercado. Todas afirmaram na Electronic Entertainment Expo (E3) que so as mais populares embora os nmeros dem a liderana das vendas Nintendo. A Wii foi concebida a pensar num tipo de divertimento diferente das consolas que j existiam no mercado. Introduziu uma nova forma de jogar graas aos comandos sem fios e jogos que apelam ao movimento do utilizador. A estratgia da Nintendo foi bem recebida pelo pblico de todas as idades, em todo o mundo, acabando por se revelar um caso de sucesso. Os nmeros no enganam e mostram o destaque que a consola alcanou no mercado norte-americano, onde as concorrentes PS3 e Xbox 360 venderam respectivamente 405,5 e 219,8 mil equipamentos. As vendas totais no mesmo mercado subiram 53 por cento face a Junho do ano passado, colocando o valor da indstria nos 1,69 mil milhes de dlares. J as vendas de jogos subiram 61 por cento, fixando-se agora nos 872,6 milhes de dlares.

SAPO Summerbits

Apple torna-se o terceiro maior fornecedor de computadores


A Apple tornou-se o terceiro maior fornecedor de computadores pessoais nos EUA, ultrapassando a Acer, de acordo com uma pesquisa da Gartner, que adiante um crescimento de 38,1% em vendas, no segundo trimestre de 2008. O mercado de PCs nos EUA apresentou um crescimento mdio de 4,2%, no ltimo trimestre, com a venda de 16,5 milhes de mquinas. S a empresa de Steve Jobs comercializou 1,4 milhes de desktops naquele perodo, enquanto a Acer registou 1,33 milhes de vendas. A Dell, que lidera o segmento, vendeu 2,5 milhes de unidades, seguida pela HP. Apesar do terceiro lugar, a Apple ainda tem uma participao tmida no mercado mundial de computadores, o que pode representar uma oportunidade de crescimento. No Japo, por exemplo, a marca vendeu 130 mil mquinas no primeiro trimestre, de acordo com a IDC.

J arrancou o SAPO Summerbits, um programa promovido pela empresa do Grupo PT em parceria com a Associao Ensino Livre que tem como objectivo promover bolsas para estudantes que desenvolvam cdigo para projectos de software livre. Os incentivos destinam-se a alunos que tenham mais de 18 anos e vnculos a qualquer grau de ensino ou tipo de escola, desde que nacional. No final, as 10 ideias que mais se destaquem, quer sigam linhas de tecnologias existentes ou sejam completamente novas, sero financiadas em 2.500 euros. A meta do SAPO Summerbits atingir um patamar de referncia entre as iniciativas acadmicas e junto das comunidades de software livre do pas. Os interessados em participar no programa devero inscrever-se at 19 de Julho deste ano na pgina oficial do evento.

<3>

tema de capa

Estado de Visualizao em ASP.NET

semelhante a uma tabela de hash mas tem a capacidade de registar alteraes (fazer tracking), ou seja, permite que sempre que um valor seja alterado na coleco seja tambm marcado como dirty. A funo de registo de alteraes pode estar ligada ou desligada, mas uma vez ligada no pode ser desligada. De modo a activar a funo use o mtodo TrackViewState(). Se a funo de tracking estiver ligada qualquer alterao a um objecto far com que esse objecto fique marcado como dirty. Podemos consultar se o objecto est marcado ou no atravs do mtodo IsItemDirty(string chave) ou forar a marcao atravs do mtodo SetItemDirty(string chave). O leitor tenha em ateno um pormenor, aps a activao de TrackViewState() qualquer alterao ser marcada, mesmo que o objecto seja alterado para o mesmo estado, como por exemplo:

Antes de entrar em pormenores sobre estado de visualizao necessrio compreender o que um controlo e como este funciona em ASP.NET. De certa forma o ASP.NET uma arquitectura baseada em controlos, j que uma pgina um controlo e qualquer controlo pode conter controlos filhos. A arquitectura semelhante arquitectura de janelas do Windows, onde o prprio ambiente de trabalho uma janela, que pode conter janelas filhas. Cada janela apresentada, apresentando primeiro o seu contedo e depois apresentando o contedo das janelas filhas. O mesmo se passa em ASP.NET em que cada controlo apresentado, apresentando primeiro o seu contedo e depois apresentando o contedo dos seus filhos. A apresentao de uma janela em Windows envolve o desenho de pixeis no ecr, enquanto que a apresentao de um controlo ASP.NET envolve a gerao de HTML para preencher uma parte da resposta a um pedido HTTP. Uma pgina serve como controlo raiz e tem trs controlos filhos imediatos: um controlo literal para gerar o texto de incio da pgina, um controlo do lado do servidor HtmlForm para representar o formulrio e todos os seus controlos filho, e por fim outro controlo literal para gerar o texto de fim da pgina. Todos os controlos adicionados a uma pgina estaro dentro do formulrio e portanto sero filhos do HtmlForm, em que a ordem pela qual esto definidos dentro desse controlo ser a ordem pela qual sero apresentados. Cada um destes controlos tem o seu prprio estado de visualizao. Todos os controlos que correspondem a elementos de formulrio tm a sua manuteno de estado suportada atravs do envio automtico do valor dos elementos quando o formulrio submetido (post back). Todos os outros tero que definir o seu mecanismo de persistncia de estado e ser sobre este assunto que iremos conversar. Em ASP.NET, o estado de visualizao entre post backs mantido atravs de uma coleco de pares nome/valor acessveis por qualquer controlo a partir da propriedade ViewState. Quase todo o estado do controlo, se no todo, fica guardado nesta coleco. Esta propriedade retorna uma instncia do tipo System.Web.UI.StateBag, que muito

stateBag["nome"] = "valor"; stateBag.IsItemDirty( "nome"); // falso stateBag.TrackViewState(); stateBag["nome"] = "valor"; stateBag.IsItemDirty( "nome"); // verdadeiro

A coleco ViewState, como j foi referido, guarda pares nome/valor, os pares podem ser indexados por string e ter qualquer object como valor. Exemplo:

ViewState["ViewStateVariableName" ] = 1;

Para ter acesso varivel guardada basta fazer a indexao com a chave e a respectiva converso.

int number = (int) ViewState["ViewStateVariable"];

Esta coleco tambm permite guardar os nossos prprios tipos quase to facilmente como os tipos bsicos. Para tal basta apenas o tipo ser serializvel, ou seja, consegue-se converter uma instncia desse tipo para uma sequncia de bytes e posteriormente fazer a sua recuperao. Vai compreender a necessidade de o tipo ser serializvel mais frente neste artigo quando falarmos de um campo de input oculto chamado __VIEWSTATE.

<4>

tema de capa

[Serializable] public class Pessoa { public string _nome; public int _idade; public Pessoa(string nome, int idade) { _nome = nome; _idade = idade; } } Como a classe Pessoa est marcada como serializvel pode ser guardada em ViewState: Pessoa p = new Pessoa( "Vitor", 25); ViewState["Cliente"] = p; Lembre-se que ter de efectuar a respectiva converso quando necessitar de obter o valor guardado.

valor padro, caso contrrio, retornar o valor obtido. public string Texto { get { return ViewState["Texto"] == null ? "Valor por Defeito" : (string)ViewState["Text"]; } set { ViewState["Texto"] = value; } } Repare que ao afectar com null uma propriedade definida com este padro essa propriedade passar a retornar o valor por defeito e no null como acontece com as propriedades ditas normais. Uma alternativa poder ser afectar a propriedade com String.Empty (um campo que representa um string vazia) em vez de null. De salientar ainda que cada controlo pode aceder sua coleco ViewState em qualquer momento e por qualquer razo, no apenas atravs de propriedades. Deve-se utilizar esta coleco quando as propriedades reflectem directamente tipos primitivos. No caso de controlos que tm pretendem manter um estado mais complexo, usando tipos prprios poder ser mais complicado utilizar a coleco ViewState. Como alternativa podemos sobrepor dois mtodos virtuais definidos na classe base Control sendo eles o SaveViewState() e o LoadViewState(). Estes mtodos permitem escrever e ler manualmente o estado do controlo a partir da stream ViewState. Para um objecto poder ser guardado nessa stream tem que ser serializvel. O mtodo SaveViewState(), como o nome indica, permite guardar o estado de visualizao. Note que este mtodo tambm responsvel por chamar o mtodo da base e guardar, no objecto a retornar, o resultado dessa chamada. protected override object SaveViewState() { ArrayList OsMeusDados = new ArrayList(); object [] vState = new object [2]; vState[0] = base.SaveViewState(); vState[1] = OsMeusDados; return vState; } O mtodo LoadViewState() permite recuperar o estado de visualizao. Note que este mtodo tambm responsvel por chamar o mtodo da base, passando ao mesmo os dados que lhe pertencem.

Pessoa p = (Pessoa) ViewState["Cliente"]; O protocolo HTTP stateless, ou seja, cada pedido executado independentemente e sem conhecimento de pedidos anteriores. Portanto cada pedido feito arquitectura ASP.NET ser servido por uma instncia diferente do controlo e por isso no possvel guardar estado de visualizao entre post backs em campos de instncia. Devido a isso as propriedades em ASP.NET tero um aspecto diferente j que devero usar a coleco ViewState para guardar qualquer valor: public int ValorInteiro { get { return (int)ViewState["ValorInteiro"]; } set { ViewState["ValorInteiro"] = value; } }

Nos casos em que necessrio ter um valor por defeito teremos tambm que ter em conta que estamos a utilizar a coleco ViewState. Tal como uma tabela de hash, uma StateBag ir retornar null se a coleco no contm uma entrada com essa chave. Portanto, se o valor retornado for nulo porque ainda no foi atribudo, ento deve retornar o

<5>

tema de capa

protected override void LoadViewState( object savedState) { if (savedState != null) { ArrayList OsMeusDados; // Obter o array de objectos guardados em SaveViewState object [] vState = (object[])savedState; if (vState[0] != null) base.LoadViewState(vState[ 0]); if (vState[1] != null) OsMeusDados = (ArrayList)vState[1]; } } O leitor certamente reconhece um padro de recursividade na chamada a estes mtodos e desta forma que a arquitectura ASP.NET constri uma estrutura de dados com todo o contedo de estado de visualizao. Como j foi referenciado, o protocolo HTTP no tem memria. Isso significa que o estado da pgina ter que ser guardado e posteriormente reposto no pedido seguinte. Os pares nome/valor colocados na coleco ViewState antes da apresentao da pgina so armazenados num campo de input oculto, __VIEWSTATE, e quando a pgina de novo acedida atravs de um pedido de POST, o contedo do campo __VIEWSTATE analisado e usado para reconstituir a coleco ViewState. Falta-nos agora perceber como mantido o estado dos controlos de formulrio. Como j foi dito anteriormente, todos os controlos que correspondem a elementos de formulrio tm a sua manuteno de estado suportada atravs do envio automtico do valor dos elementos quando o formulrio submetido (post back). Esta manuteno de estado realizada atravs da implementao da interface IPostBackDataHandler.

correspondem a controlos que implementam IPostBackDataHandler e de seguida invocado o mtodo LoadPostData para todos esses controlos. A string postDataKey, passado como argumento, contm o identificador nico associado ao controlo, que pode ser usado para indexar sobre postCollection para localizar o valor corrente do controlo dentro da coleco como se pode verificar no seguinte exemplo:

public virtual bool LoadPostData(string postDataKey, NameValueCollection postCollection) { string valorAntigo = Text; string valorNoPOST = postCollection[postDataKey]; if (!valorAntigo.Equals(valorNoPOST)){ Text = valorNoPOST; return true; } return false; }

public interface IPostBackDataHandler { bool LoadPostBackData(string postDataKey, NameValueCollection postCollection); void RaisePostDataChangedEvent(); }

O resultado deste mtodo deve ser true se mudou o valor do estado do controlo, caso contrrio, o mtodo deve devolver false. Para todos os controlos que retornam true neste mtodo chamado o RaisePostDataChangedEvent de cada um desses controlos de modo a poderem ser desencadeados eventos de alterao de estado. O leitor repare que o carregamento de dados de POST ocorre em duas fases, o mtodo LoadPostData ocorre antes do mtodo de Load da pgina e o mtodo de RaisePostDataChangedEvent ocorre depois do mtodo de Load. Isto permite que na altura em que as notificaes so geradas todos os controlos tenham o seu estado reposto. Note ainda que, para alm dos eventos de alterao de estado (eventos changed), como por exemplo alteraes do texto de uma caixa de texto ou a alterao do ndice seleccionado de uma DropDownList, tambm os eventos de reaco utilizam este mecanismo. Por exemplo, o evento de click de um boto detectado e lanado utilizando esta interface. Como se deve ter apercebido, a manuteno de estado de controlos de formulrio no usa o campo oculto __VIEWSTATE em nenhuma das suas fases e

Neste caso a arquitectura faz uma pesquisa no contedo do POST de modo a determinar se existem entradas que

<6>

tema de capa
completamente independente deste. por essa razo que, mesmo que o ViewState no esteja activo, todos os controlos de formulrio tm o seu estado automaticamente reposto. No entanto, na fase LoadPostData, necessrio saber o valor antigo de modo a poder compar-lo com o que vem no POST. Uma das formas usar o ViewState para previamente guardar esse valor, que depois ser usado na comparao com o valor recebido no POST. Note que, apesar da sua ligao prxima, so funcionalidades independentes. Voltando ao ViewState, a estrutura de dados com todo o contedo de estado de visualizao no directamente convertida para string e armazenada no campo __VIEWSTATE. Lembra-se de falarmos que uma StateBag permitia fazer tracking? Ora bem, apenas so salvos no campo oculto as entradas da StateBag que esto marcadas como dirty, ou seja, apenas as entradas em que os seus estados so diferentes do estado esttico ou estado por defeito. No faz sentido guardar estado que ser reposto automaticamente assim que exista um novo pedido e seja criada uma nova instncia do controlo para atender esse pedido. Neste momento o leitor poder estar a perguntar-se ento e os controlos definidos declarativamente? Podemos definir declarativamente um controlo, como por exemplo: chamado no evento Init do ciclo de vida de uma pgina e todas estas afectaes so feitas antes desse momento, ou seja, no sero consideradas dirty. Como referido, quando o ocorre a fase de Init chamado o TrackViewState(). Aps o TrackViewState() ser chamado para todas as StateBags chamado o LoadViewState(), que faz com que todo o estado dinmico de visualizao guardado seja reposto e, mais importante ainda, visto que neste momento o tracking j est activo todo o estado dinmico carregado ser considerado dirty. Esta sequncia far com que o estado dinmico de visualizao seja reposto e fique novamente persistente para futuros post backs, ou seja, faz com que seja novamente seriado para __VIEWSTATE. Atravs deste artigo espero que o leitor fique com uma ideia mais clara de como manter estado nos seus controlos tendo em ateno que quase todo, se no todo, o estado de visualizao de um controlo guardado em ViewState, mas apenas persistido entre post backs o estado dinmico. O estado por omisso que criado quando criada uma instncia desse controlo (estado esttico) no persistido.

Bibliografia
Essential ASP.NET with Examples in C# - Fritz Onion Addison Wesley Understanding ASP.NET View State http://msdn.microsoft.com/en-us/library/ms972976.aspx -

<asp:Label ID="Label1" runat="server" Text="Label"> No momento em que a arquitectura ASP.NET faz parse do formulrio, ao encontrar o atributo runat=server cria uma instncia desse controlo e tenta corresponder todos os atributos definidos a propriedades publicas do controlo. No exemplo anterior olhando para o atributo Text percebemos que a arquitectura vai afectar a propriedade pblica Text com o valor Label. Sabendo ns que quase todo o estado do controlo, se no todo, fica guardado em ViewState poderamos ser levados a pensar que estes dados seriam considerados dirty visto que estamos a mudar o seu estado. Tal no acontece porque o TrackViewState() s

ViewState in ASP.NET 2.0 http://www.beansoftware.com/ASP.NETTutorials/ViewState-In-ASP.NET.aspx TRULY Understanding ViewState http://weblogs.asp.net/infinitiesloop/ archive/2006/08/03/Truly-Understanding-Viewstate.aspx IPostBackDataHandler Interface h t t p : / / m s d n . m i c r o s o f t . c o m / e n us/library/system.web.ui.ipostbackdatahandler.aspx StateBag Class - http://msdn.microsoft.com/enus/library/system.web.ui.statebag.aspx

Vitor Tomaz estudante de Engenharia Informtica e Computadores no ISEL bem como Trabalhador Independente na rea de Tecnologias de Informao. Tem especial interesse por Programao Concorrente, Segurana Informtica e Aplicaes Web.

Vtor Tomaz
<7>

a programar

Lucene: programar um motor de busca

altamente ordenada de texto, ou de pedaos de texto (tokens), que torna a pesquisa muito mais eficiente. Porm, falha na capacidade de compresso de dados. Um ndice de 6 milhes de abstracts cientficos atinge facilmente os 1.7 GB, no caso de armazenar apenas tokens, ou os 6.6 GB caso guarde o texto. Esta diferena de tamanho vai, obviamente, afectar a performance. Da, uma vantagem para a pesquisa, ter o ndice fragmentado em vrios sub-ndices, de modo a cada um ter menos volume de informao. O modo como o texto tratado pelo Lucene, tambm alvo de ateno. Ao lermos texto para o lucene, ele ser primeiro submetido a um processo chamado analisador (analyzer), que pode ter vrias formas: Standard, Simple, Stop, regional, etc. Sem entrar em grandes explicaes, cada analisador trata o texto de maneira diferente. Uns ignoram a pontuao, outros so especficos para certas lnguas (como a nossa com o til e os acentos), outros ignoram palavras comuns, baseando-se numa lista de stop-words, etc. De seguida, tem que se criar um ndice, que pode ser, na maior parte das vezes, ou baseado no disco rgido (acesso mais lento), ou na memria RAM (temporrio). Uma estratgia para aumentar a velocidade de construo do ndice passa por criar o ndice na RAM e no fim, despej-lo para o disco rgido. Na pesquisa, o mesmo ndice pode voltar a ser lido para a RAM, potenciando (muito significativamente) a performance. Tendo o ndice criado, h que criar um escritor de ndices, de modo a popul-lo com os nossos textos. De entre as vrias opes a passar ao escritor, esto o analisador em causa e o ndice previamente criado. A insero de documentos no ndice faz-se por ltimo, adicionando documento a documento, criando os campos que forem precisos (por exemplo, a data de criao de um ficheiro, e o seu contedo, ou o ttulo de um livro, a sua editora, autor, ano de lanamento, e preo). Quantos mais campos, mais lento ficar o ndice, mas mais especfica poder ser a nossa pesquisa. Tomando o exemplo da livraria, podemos pesquisar apenas por editora, ou por ano de lanamento, ou mesmo por preo. A maneira de guardar a informao tambm varia. Podemos ter a necessidade de guardar alguns campos para mais tarde devolver ao utilizador que pesquise, mas outros campos podem ser fteis e so apenas guardados tokens dos mesmos. Estes tokens so fragmentos nicos do texto e no esto disponveis para futuras recuperaes. Exemplificando, um resumo de um artigo cientfico est dividido em ttulo e resumo. Podemos pesquisar sobre os resumos por uma determinada palavra, sendo devolvidos os ttulos que correpondem nossa pesquisa. No fim do ndice criado, pode-se, opcionalmente, mas sempre recomendado, passar por um processo de optimizao que vai aumentar a performance da pesquisa

O que o Lucene
O Lucene talvez dever-se-ia tratar por a Lucene, uma vez que se trata de uma biblioteca de recuperao de informao textual (do ingls information retrieval) de cdigo aberto e criada por Doug Cutting. Originalmente, foi escrita em Java, mas foi rapidamente adaptada a outras linguagens de programao, nomeadamente Python (Pylucene), Perl (Plucene), C# (Lucene.net), C++ (CLucene), e Ruby (Ferret). Contudo, estas adaptaes esto normalmente ligeiramente atrasadas no que toca verso original em Java, actualmente mantida e alojada pela Apache Sofware Foundation. Simples de aprender a usar, mas poderosa nas mos de um programador experiente, esta biblioteca suporta desde ndices estticos com um campo, at mltiplos ndices em paralelo, com centenas de campos e milhares de acessos simultneos. ideal para todo o tipo de projectos, desde o simples website com a search box at um grande motor de busca sobre, por exemplo, a coleco de PDFs que se tem no disco rgido.

Onde usado o Lucene


Provavelmente desconhecido para o leitor, o certo que j passou os dedos por esta til ferramenta. Ao fim de contas, quem nunca pesquisou no site Sourceforge, ou na CNET, ou mesmo at na Wikipedia? Para os utilizadores de Ubuntu, quem nunca tirou partido do software de indexao recentemente incorporado na distribuio: o Beagle. Este, no mais que suportado pela Lucene.Net, a implementao em C# desta biblioteca. Assim, a utilizao desta biblioteca por estas entidades (re)afirma por si s a qualidade e a utilidade da mesma.

Como funciona o Lucene


O modo de funcionamento do Lucene trivial de se perceber, mas mais complexo de se manusear na perfeio. Para comear, como j se indicou, h uma palavra chave em todo o processo: ndice. O ndice no passa de uma estrutura

<8>

a programar

no ndice recm criado. Este processo vai reduzir os segmentos do ndice a apenas um, facilitando assim a tarefa de abrir o ndice, em vez de mltiplos pequenos ficheiros. Explicaes sobre a formao destes segmentos esto para alm do mbito deste artigo, bastando por agora dizer apenas que so resultado da construo do ndice, podendo ser imaginados como sub-ndices que degradam significativamente a performance devido ao seu diminuto tamanho e contedo. Aps se ter um ndice, resta programar o pesquisador. O pesquisador vai usar um pesquisador de ndices (IndexSearcher), que vai precisar da directoria do ndice (tal como o IndexWriter), e de um parser da pesquisa (QueryParser), que vai depender do nome do campo onde pesquisar e de um analisador (igual ao usado na construo do ndice). Recuperam-se depois os resultados, que esto num iterador, e depois vai-se retirar de cada objectoresultado o campo pretendido (voltando ao exemplo do artigo cientfico, o ttulo do artigo). Os resultados esto ordenados por ordem de relevncia. O prprio Lucene tem um mecanismo de atribuio de relevncia, baseado no TFIDF, que d mais peso a documentos com maior frequncia do termo, e a termos pouco comuns no geral. Desta forma, simples construir um motor de busca, desde que se tenha maneira de ler os ficheiros (parser de PDFs para PDFs por exemplo). A documentao oficial do projecto bastante completa e simples de seguir, fornecendo um caminho perfeito para tirar as dvidas que possam surgir. Para alm disso, h bastantes mailing-lists que ajudam os novatos. A cereja no topo do bolo, a incluso de vrios scripts exemplo na distribuio do Lucene, e do PyLucene por exemplo. Estes exemplos so um ptimo ponto de partida para o Lucene.

Exemplos de cdigo
Tal como qualquer biblioteca em Python, chama-se o Lucene da seguinte forma:

import lucene Porm, isto no chega. Com a implementao JCC, trabalha-se dentro de uma mquina virtual de Java, sendo portanto necessrio cri-la, podendo definir-se os seus parmetros (maxheap - limite mximo de memoria RAM a ser usado, initialheap - memria RAM a ser usada inicialmente, etc):

lucene.initVM(lucene.CLASSPATH) lucene.initVM(lucene.CLASSPATH, maxheap=800m) lucene.initVM(lucene.CLASSPATH, maxheap=2g) lucene.initVM(lucene.CLASSPATH, initialheap=800m) lucene.initVM(lucene.CLASSPATH, initialheap=200m, maxheap=800m) O resultado que se deve obter, numa consola de Python, semelhante a:

>>> import lucene >>> lucene.initVM(lucene.CLASSPATH) <jcc.JCCEnv object at 0x8192240> >>> Visto como iniciar a mquina virtual, pode-se agora tirar partido de todo o potencial da biblioteca. Vamos comear por criar um indexador, ou seja, um script que crie um indce a partir de uma pasta contendo ficheiros de texto, no formato txt, por uma questo de simplicidade. de ter em ateno que, ao contrrio dos ficheiros txt, os ficheiros como por exemplo os PDF precisam de um parser para os ler, uma vez que ao Lucene alimentado o contedo do ficheiro, e no o ficheiro em si. A lgica por detrs do funcionamento do Lucene j foi explicada anteriormente.

PyLucene: usando o Lucene em Python


A biblioteca PyLucene est disponvel desde, pelo menos, 2004. Criada e mantida por uma nica pessoa, Andi Vadja, veio no s trazer aos utilizadores de Python o poder do Lucene, como tambm o fez de uma forma extremamente simplista e fiel biblioteca original. De incio, havia duas implementaes: GCJ e JCC. Porm, desde a verso 2.3.0 do Lucene, a implementao em GCJ foi deixada de parte. As principais diferenas entre as implementaes traduziam-se na velocidade de pesquisa, onde a GCJ liderava por larga margem, velocidade de indexao, onde era a JCC a levar a melhor, e noutras caractersticas como o tamanho dos ndices suportados (maior na JCC) e maior estabilidade (JCC). Contudo, o processo de instalao tornou-se mais complicado, da que apesar das fontes serem cedidas para compilao pelo utilizador, h quem disponibilize verses binrias para os mais novatos.

import lucene, os lucene.initVM(lucene.CLASSPATH) # Iniciar a mquina virtual

<9>

a programar
Indexador.py indexPath = "Texto/Index" # indicar o caminho da pasta com os ficheiros analyzer = lucene.StandardAnalyzer() # criar o analisador indexDir = lucene.FSDirectory.getDirectory(indexPa th) # criar o ndice indexWriter = lucene.IndexWriter(indexDir, analyzer) # criar o escritor do ndice for root, dirs, files in os.walk('Texto'): # percorremos os ficheiros da pasta for eachfile in files: fileinfo = eachfile. split('.') filename = ' '.join(fileinfo[:-1]) if fileinfo[-1] == 'txt': # Para assegurar que s lemos ficheiros de texto simples document = lucene.Document() # Criamos um documento pronto a ser inserido no ndice De seguida, podemos escrever em meia dzia de linhas um pesquisador para comprovarmos que o nosso ndice foi bem construido. No meu exemplo, indexei apenas 2 ficheiros, cada um com a seguinte frase: hello.txt Hello World? goodbye.txt Python is a wonderful language! Pesquisador.py import lucene lucene.initVM(lucene.CLASSPATH) directory = lucene.FSDirectory.getDirectory('Texto/ Index') # apontar para a directoria do indice searcher = lucene.IndexSearcher(directory) # criar o pesquisador analyzer = lucene.StandardAnalyzer() # criar o analisador term = raw_input('Escreva o termo a pesquisar: ') query = lucene.QueryParser("contents", analyzer).parse(term) # Passamos o termo a procurar para o QueryParser, de modo a ser analisado, apontando tambem que campo do indice deve ser procurado. hits = searcher.search(query) # Recuperamos os resultados if len(hits)>0: results = [hits[x] for x in range(len(hits))] # Criamos uma lista com os documentos dos resultados filenames = [doc. get("filename") for doc in results] # recuperamos o campo filename de cada resultado scores = [hits.score(x) for x in range(len(hits))] # recuperamos a pontuao que cada documento teve na pesquisa for i in range(len(filenames)): print "%s, %s" %(filenames[i], scores[i]) # Devolvemos os resultados else: print "Sem resultados!"

document.add(lucene.Field(("filename"), filename, lucene.Field.Store.YES, lucene.Field.Index.UN_TOKENIZED)) # Adicionamos o campo do nome do ficheiro, que vai ser posteriormente devolvido em pesquisas ao utilizador contents = open(os.path.join(root, eachfile), 'r').read()

document.add(lucene.Field(("contents"), contents, lucene.Field.Store.NO, lucene.Field.Index.TOKENIZED)) # Campo com o conteudo do ficheiro, tokenizado e no armazenado.

indexWriter.addDocument(document) # Adiciona o documento ao indice indexWriter.close() # Fechamos o escritor

<10>

a programar

O resultado deste script ser:

Concluso
A biblioteca Lucene permite ao programador criar rapidamente um motor de busca que pode ser usado como aplicao por si s, ou para ser incorporado noutra, ou num website. Apesar de drasticamente simples, pode tomar contornos bastante complexos medida que se vagueia pelas suas funcionalidades, permitindo uma personalizao e uma costumizao fenomenal, ideal para perfeccionistas que querem lidar com todos os pormenores, ou para aqueles que precisam de um sistema com um determinado conjunto de caractersticas. Para alm disso, grtis, de cdigo livre, de maneira a que para ser usada no precisamos de dispender nenhum tosto e podemos sempre dar uma olhadela ao cdigo por detrs do seu funcionamento para ganhar um maior conhecimento.

joao@jUbuntu:/Desktop$ python pesquisador.py Escreva o termo a pesquisar: python goodbye, 0.5 joao@jUbuntu:/Desktop$ python pesquisador.py Escreva o termo a pesquisar: hello hello, 0.625 joao@jUbuntu:/Desktop$ python pesquisador.py Escreva o termo a pesquisar: portugal Sem resultados!

Estranhamente, Joo Rodrigues no vem das hostes dos informticos tendo tido o primeiro contacto com a programao no 3 ano do curso. Um descontrado finalista da Licenciatura em Bioqumica em Coimbra, com particular interesse pelas reas da Bioinformtica e da Protemica, entrou para a Revista PROGRAMAR e com o objectivo de mostrar que h mais na informtica para alm de bits e bytes.

Joo Rodrigues

<11>

a programar

tericos e passemos para algo mais prtico. Por uma questo de hbito e facilidade de demonstrao, a linguagem usada ir ser Haskell.

Programas Circulares

RepMin
Comecemos pelo exemplo clssico repmin, o problema o seguinte. Imaginemos que temos uma rvore binria de folhas, queremos obter uma nova rvore morfologicamente idntica original, mas agora todas as suas folhas tero que ter o valor mnimo da rvore original. ( o valor mnimo que a rvore criada ter, tem como referncia aos valores das folhas iniciais). data Arvore = Folha Int -Uma folha ter um valor que ser um inteiro | Nodo Arvore Arvore -- Um nodo ter duas sub-rvores Agora para resolver o problema iremos criar a funo transforma que ir pegar numa rvore e devolver uma nova rvore. transforma :: Arvore -> Arvore transforma arv = replicaArv arv (minArv arv)

Introduo
Introduzido originalmente como demonstrao do poder da lazy evaluation nas linguagens funcionais nos anos 80, os programas circulares so considerados como uma tcnica poderosa, concisa, eficiente e elegante para resolver um particular tipo de problema. Se um algoritmo tiver de percorrer uma estrutura de dados vrias vezes, numa linguagem de avaliao atrasada, o mesmo poder ser expresso com uma nica travessia. Como o nome indica, programas circulares caracterizam-se por a sua definio ter uma aparncia circular, isto , um dos argumentos de uma funo depende de um dos argumentos que a mesma funo retorna x = f(x). Numa linguagem com strict evaluation nunca ir terminar, enquanto que numa linguagem lazy s vezes conseguir terminar. A avaliao atrasada ir sempre obter a ordem correcta de processamento, se essa ordem de facto existir. Assim, a funo f pela sua definio ser virtualmente circular, j que no momento da sua avaliao ir ser decomposta em no circular. No entanto, tambm sabido que os programas circulares so difceis de entender e escrever. Facilmente o programador define um programa realmente circular, ou seja, que nunca termine. Mas deixemos de conceitos

Como podemos constatar a funo transforma ir dar uso a duas funes. A funo minArv que ir calcular o valor mnimo de uma rvore:

<12>

a programar

minArv :: Arvore -> Int minArv (Folha x) = x minArv (Nodo e d) = min (minArv e) (minArv d) A funo replicaArv que ir replicar uma dada rvore com um valor mnimo.

Simples. Vejamos agora no caso de ser um nodo. repmin ((Nodo e d), m) = (replicaArv (Nodo e d) m, minArv (Nodo e d)) Mais uma vez, usamos as definies das funes replicaArv e minArv. repmin ((Nodo e d), m) = (Nodo (replicaArv e m) (replicaArv d m), min (minArv e) (minArv d)) Agora o passo seguinte poder no parecer to intuitivo. Mas visto que tanto a funo replicaArv como a funo minArv seguem o mesmo padro de recursividade, podemos usar a prpria definio de repmin para simplificar ainda mais o cdigo.

replicaArv :: Arvore -> Int -> Arvore replicaArv (Folha _) m = Folha m replicaArv (Nodo e d) m = Nodo (replicaArv e m) (replicaArv d m) Como podemos ver, a rvore ir ser percorrida duas vezes. Uma primeira vez para obter o valor mnimo da rvore e uma segunda vez para replicar a rvore com o valor mnimo.

Resoluo Circular (Uma travessia)


Vejamos agora como podemos transformar o cdigo de cima ficando um programa circular. A forma mais simples de efectuar essa transformao recorrendo fuso das duas funes atravs do uso de tuplos. Portanto comeamos a definir a funo repmin como o par das funes replicaArv e minArv. A nossa funo repmin ir receber uma rvore e um hipottico valor mnimo. repmin ((Nodo e d), m) = (Nodo e' d', min m1 m2) where (e', m1) = repmin (e, m) (d', m2) = repmin (d, m) Bem, se for um Nodo tambm no h muito mais a fazer. Recapitulemos como temos definido a nossa funo repmin: repmin :: (Arvore, Int) -> (Arvore, Int) repmin ((Folha x), m) = (Folha m, x) repmin ((Nodo e d), m) = (Nodo e' d', min m1 m2) where (e', m1) = repmin (e, m) (d', m2) = repmin (d, m) Bom, dado uma rvore e um hipottico valor mnimo, replica essa rvore com esse valor hipottico e ao mesmo tempo calcula o valor mnimo da rvore, tudo em apenas uma travessia. Ainda melhor era conseguirmos dizer que aquele valor hipottico era o valor mnimo calculado por ns. E aqui que entra a funo circular, redefinamos ento a funo transforma para nos permitir tal proeza. transforma :: Arvore -> Arvore transforma arv = arv' where (arv', m) = repmin (arv, m)

repmin :: (Arvore, Int) -> (Arvore, Int) repmin (a, m) = (replicaArv a m, minArv a) Vamos agora tentar fundir as duas funes, simplificando o cdigo. Ora uma rvore pode ser folhas ou nodos, portanto temos que ter os dois casos. Comecemos pelas folhas por ser mais simples. Ento caso seja uma folha, a linha de cima fica da seguinte forma: repmin ((Folha x), m) = (replicaArv (Folha x) m, minArv (Folha x)) Usando a definio de replicaArv e minArv obtemos um cdigo equivalente, simplificando-o ainda mais. repmin ((Folha x), m) = (Folha m, x)

<13>

a programar

E est feito. De salientar o uso do smbolo m nos dois lado da funo repmin, ou seja, ao mesmo tempo o argumento e o resultado da funo. No momento de execuo da funo transforma, o Haskell devido a ser lazy como que por magia ir transformar a rvore com um valor que s ter acesso no futuro, como se fosse possvel viajar no tempo.

J que estamos a trabalhar apenas com funes, para comear podemos dizer que a nossa Arrow a uma funo. Ento loop fica: loop :: ( (b, d) -> (c, d) ) -> (b -> c) Visto que o nosso input e output iro ser rvores, portanto o nosso b e c iro ser do tipo Arvore. O feedback ir ser o nosso hipottico valor minimo, ou seja, o d ser um Int. Fazendo estas substituies na assinatura do loop ficamos com:

Arrows
O exemplo foi feito de forma a demonstrar totalmente o processo de converter o cdigo para a verso circular. Na verdade, o ltimo passo desnecessrio. Haskell possui Arrows, um conceito similar s populares Monads mas mais generalista. Ora com arrows uma pessoa consegue com bastante facilidade descrever e conjugar computaes. E como j devem estar espera, existe uma arrow j pr-definida na biblioteca para o nosso caso. Essa arrow tem de nome loop e tem o seguinte esquema.

loop :: ( (Arvore, Int) -> (Arvore, Int) ) -> (Arvore -> Arvore) J est mais agradvel. A funo loop recebe como argumento uma funo e devolve outra funo. Se vermos com ateno, vimos que a assinatura desta funo (a de argumento) exactamente a mesma que a da nossa funo repmin. De facto, para pormos a funo repmin como circular basta passar para a funo loop como argumento. Visto isto, podemos redefinir a nossa funo transforma usando a biblioteca Control.Arrow.

transforma :: Arvore -> Arvore transforma = loop repmin A funo loop em si uma arrow que possui internamente uma outra arrow que dado um input ir devolver um ouput com um auxlio de um feedback. Como podem reparar este feedback ir ser a nossa referencia circular. Do ponto de vista do Haskell, a funo loop tem a seguinte assinatura.1) loop :: (Arrow a) => a (b, d) (c, d) > a b c Analisando a assinatura, podemos ver que a arrow interna tem de ser do tipo a (b, d) (c, d). Vamos ter o input do tipo b , o output do tipo c e o feedback ser do tipo d. No fim vamos ter como resultado a arrow a b c, ou seja, uma computao que dados aas devolve bbs. Vejamos como podemos usar isto no nosso caso.

Mdia
Agora que j demonstrmos um mtodo simples de transformar um programa com mltiplas travessias em apenas uma, vamos ver outro exemplo clssico, pois este mtodo simples est longe de ser perfeito, e nem sempre produz resultados ideais. Mas que se estivermos atentos facilmente contornamos o problema. Temos ento o seguinte problema. Dada uma lista de valores, queremos calcular a mdia da lista e incrementar cada valor da lista pela mdia obtida. Assim de imediato vemos que temos trs travessias na lista. Uma travessia para calcular o nmero de elementos na lista, uma segunda travessia para somar os elementos da lista e uma terceira travessia para incrementar cada valor da lista pela mdia. De salientar que a primeira travessia e a segunda travessia no dependem uma da outra e portanto muito simples fazer a sua fuso e apenas necessrio uma travessia. Mas no esse o ponto em questo, e para reforar a ideia, que para cada posio da lista temos que efectuar trs operaes.

1) No totalmente verdade, de facto o loop um ArrowLoop que uma extenso da classe Arrow, mas simplifica o processo de explicao.

<14>

a programar

Bem, no vou estar agora a fazer passo a passo, mas primeira tentativa o mais provvel era obtermos algo do gnero. transforma :: [Double] -> [Double] transforma = loop incrMedia incrMedia :: ([Double], (Double, Double)) -> ([Double], (Double, Double)) incrMedia ([], _) = ([], ( 0,0)) incrMedia ((x:xs), (soma, numElems)) = ( (x + media) : xs', (soma' + x, numElems' + 1)) where (xs', (soma', numElems')) = incrMedia (xs, (soma, numElems)) media = soma / numElems O problema deste cdigo que se formos executar com uma lista nunca ir terminar. O problema est no clculo da mdia em todo os passos. Podemos solucionar este problema separando o clculo da mdia da travessia da lista, isto , j termos o nosso feedback (a mdia) j calculada. A verso correcta seria ento: transforma :: [Double] -> [Double] transforma = loop incrMedia incrMedia :: ([Double], Double) -> ([Double], Double) incrMedia (lista, media) = (lista', soma / total) where (lista', (soma, total)) = incrMedia' (lista, media) incrMedia' :: ([Double], Double) -> ([Double], (Double, Double)) incrMedia' ([], _) = ([], ( 0, 0)) incrMedia' ((x:xs), media) = ((x + media) : xs', (soma + x, total + 1)) where (xs', (soma, total)) = incrMedia' (xs, media)

J que se est a usar Arrows pode-se sempre pr o cdigo ainda mais conciso, apesar de se tornar um pouco menos legvel. Fica ao gosto de cada um a forma que prefere.

transforma :: [Double] -> [Double] transforma = loop (incrMedia >>> id *** uncurry (/)) incrMedia :: ([Double], Double) -> ([Double], (Double, Double)) incrMedia ([], _) = ([], ( 0, 0)) incrMedia ((x:xs), media) = incrMedia >>> ((x + media):) *** ((+x) *** (+ 1)) $ (xs, media)

Concluso
Este artigo tinha como objectivo dar a conhecer o conceito de programas circulares e espero que tenha tido sucesso. Foi feita apenas uma pequena introduo do conceito, com o auxlio de um mtodo muito simples de transformao de programas. O mtodo aqui indicado tem vrias falhas. Nem sempre se obtm um programa circular vlido, que termine. As vrias travessias tem de seguir o mesmo padro recursivo. Devido ao ponto anterior, as travessias tem de ser sempre sobre a mesma estrutura de dados. O ltimo ponto bastante importante. Muitos casos tornam necessrio a formao de estrutura de dados intermdia entre as vrias travessias. Por exemplo, no caso do exemplo da mdia, se quisssemos que a lista obtida estivesse ordenada, ento o mais normal era usar como uma estrutura intermdia uma rvore binria e implementar algo tipo o quicksort ou mergesort. Este novo problema deita logo abaixo o nosso mtodo simples. Para quem tiver interessado recomendo que pesquise um pouco, esta uma rea com alguma investigao e existem vrios papers onde so abordados novos mtodos (mais complexos que no se enquadram neste artigo), mas que ultrapassam estes problemas referidos. De salientar, que apesar de ser uma rea um pouco obscura, j comea a ver-se alguns casos prticos de programas circulares. Sendo os mais usuais, o pretty-printing em que so necessrias vrias travessias por questes de formatao ou ento compiladores em que tambm

Como podemos verificar as duas solues so muito parecidas, mas na ltima verso inserimos uma funo extra no meio para separar o clculo da mdia da travessia da lista. necessrio, visto que se tivermos um valor hipottico de mdia, a assinatura da funo no encaixa, j que a cada passo o feedback ir ser o somatrio e a contagem dos elementos da lista. Da termos uma funo extra para servir de adaptador, para o nosso feedback ter o mesmo tipo, tanto entrada como sada.

<15>

a programar

necessrio vrias travessias para calcular por exemplo os endereos de jump.

Extras
Pgina do Haskell: http://haskell.org/ Introduo a Arrows: http://www.haskell.org/arrows/index.html Pequeno artigo sobre programas circulares que serviu de forte inspirao:

http://www.haskell.org/haskellwiki/Circular_programming The Monad Reader Issue 6 (Assembly: Circular Programming with Recursive do): http://www.haskell.org/sitewiki/images/1/14/TMRIssue6.pdf

Natural de Santa Maria da Feira, Miguel Bento encontra-se desde Novembro 2006 na Creativesystems, uma das principais lderes na rea de RFID na pennsula Ibrica. Tem como preferncia a nvel industrial a linguagem C# mas aproveita o seu tempo livre para aprofundar os seus conhecimentos na sua linguagem predilecta, Haskell.

Miguel Bento Miguel Bento


<16>

a programar

Serializao e desserializao de Objectos em C#


Introduo
Num projecto recente, desenvolvi um sistema multi-tier em que alguns dados eram provenientes de ficheiros XML, em que tambm era necessrio escrever dados para ficheiros em XML. Na definio dos objectos de negcio da aplicao, alm das propriedades estavam includos dois mtodos, ToXML() e FromXML(XmlNode), que convertiam os dados do objecto para XML ou recebiam os dados em XML e preenchiam o objecto com esses dados. Inicialmente, os mtodos de converso de XML para objecto e de objecto para XML estavam includos na classe que definia o objecto, com a personalizao necessria classe. Esta abordagem era evidentemente m, especialmente quando o nmero de classes era grande pois no permitia a reutilizao do cdigo. Com tempo foi possvel desenvolver uma classe generalizada, que permite a serializao e deserializao em XML dos objectos das diversas aplicaes que integram a classe, aumentando a eficincia de desenvolvimento. O artigo que segue, apresenta a estrutura tpica em que usado, a classe XmlCustomSerializer que efectua a serializao e desserializao do objecto automaticamente, e um exemplo de como utiliz-la.

que possam ser usados nas vrias camadas. Podem ser includas mais ou menos camadas, que o conceito mantemse - h a classe de suporte s propriedades, global s camadas, e um conjunto de classes gestoras, em cada camada. A DAL tem tipicamente o conjunto de mtodos CRUD de acesso base de dados ou repositrio de ficheiros. As classes da camada so gestores dos objectos no que diz respeito a acesso a dados. Por exemplo uma classe Pessoa, classe que um BO com as propriedades de uma pessoa da aplicao, tem na DAL uma classe PessoaDAL, com o conjunto de mtodos CRUD para gerir os dados de Pessoa na base de dados ou repositrio. A classe tem os mtodos Get(), GetList(), Insert(Pessoa), Update(Pessoa), Delete(Pessoa) e outro relevantes. A BLL composta tambm por classes gestoras dos objectos, mas com os mtodos relevantes camada de negcio validaes, autenticao, processamento de dados recebidos da aplicao ou da DAL, etc. Em alguns casos, os mtodos da BLL so simples chamadas do mtodo semelhante na DAL. A camada de apresentao tem o conjunto de mtodos relevantes apresentao da informao na aplicao e processamento das aces do utilizador. Esta estrutura permite tornar transparente a forma como funcionam as diversas camadas. Apenas passa o conjunto de dados gerado pelas camadas para a seguinte, e por exemplo a camada de apresentao nunca ter acesso directo camada de escrita de dados. Mais, possvel separar e distribuir as diversas camadas atravs de Remoting e/ou Web Services partilhando recursos entre aplicaes ou distribuindo o esforo por diversas mquinas.

Serializao no .NET
A serializao um mecanismo importante na framework do .NET, em que os objectos so transformados numa stream de dados, formato portvel, quer para utilizar remotamente, quer para persistir dados. No caso dos WebServices os dados das respostas so convertidos para XML, e o objecto a partir desses dados pode ser reconstrudo. A serializao e desserializao neste caso realizado automaticamente pela framework. Na framework h trs modos de serializao: Binria mais leve e que apresenta a melhor performance e usado no remoting. SOAP usado por Webservices para converter os objectos em XML. XML serializao costumizada para um formato desejado.

Enquadramento
As aplicaes que tenho desenvolvido, essencialmente na framework .NET (ASP.NET com C#), tm mantido a mesma estrutura multicamada. Aprendi este mtodo e adaptei-o s minhas necessidades aps a leitura de um conjunto de artigos do Imar Spaanjaars (http://imar.spaanjaars.com Building Layered Web Aplications With Microsoft ASP.NET 2.0). Resumidamente, o mtodo que ele descreve inclui uma camada de acesso a dados (DAL) uma camada de lgica de negcio (BLL) e a camada de apresentao. Comuns a estas 3 camadas esto os objectos de negcio (BO) que pouco mais so que contentores de objectos classes definidas apenas com propriedades e, nalguns casos, alguns mtodos

<17>

a programar

Quer a serializao binria quer a SOAP efectuam Deep Serialization no sentido que serializam o objecto na sua totalidade, incluindo outros objectos contidos nele. J o XML, porque apenas serializa os elementos pblicos do objecto, e feita da forma como ns indicamos, chamada de Shallow Serialization. O resto do artigo est ligado serializao costumizada em XML. bastante til para passar dados que esto em ficheiros XML directamente para um objecto ou vice versa. H aplicaes em que uma base de dados overkill, e meia dzia de ficheiros XML resolvem para suportar os dados. Escrever cdigo dedicado a cada objecto tambm muitas vezes desnecessrio (a menos que siga um formato muito prprio e os objectos em uso no admitam a converso directa). Para o demonstrar vou criar um pequeno exemplo. Este servir para apresentar o modo de implementao dos objectos como contentores, a classe genrica de serializao e a sua aplicao. Exemplo - lista de contactos Um bom exemplo uma lista de contactos. Os objectos de negcio que vou utilizar so:

ver no cdigo, a DAL tem o conjunto de mtodos que permite aceder fonte de dados e retornar os objectos. Apenas esta camada tem acesso aos dados, o que torna o processo de obteno de dados transparente para as camadas superiores. A BLL muitas vezes uma simples interface para os mtodos da DAL, podendo ter mais processamento, como validao e autenticao. A camada de apresentao constituda pelos vrios formulrios que a aplicao pode ter. Estes formulrios apenas conhecem os mtodos pblicos da BLL que por sua vez apenas conhece os mtodos pblicos da DAL. A separao implementada atravs de namespaces, e cada camada conhece apenas a camada seguinte. Este modo implementa uma clara separao da funcionalidade de cada camada.

A classe Pessoa contm os dados de uma pessoa (ID, nome e contactos) e utiliza ContactoList para associar vrios contactos ao mesmo registo de Pessoa. ContactoList no mais que uma lista genrica do tipo Contacto que contem os dados do contacto individual (tipo de contacto e o valor). PessoaList tambm uma lista genrica, mas do tipo Pessoa. A aplicao exemplo no utiliza as camadas BLL e DAL (a simplicidade no exige). No entanto declarei-os para apresentar um exemplo de como funciona. Como possvel

Relativo aplicao, a funcionalidade implementada o mnimo necessrio para demonstrar o serializador. Primeiro, tem um campo que permite criar uma instncia do objecto Pessoa atravs do nome. O ID atribudo automaticamente pelo processo de insero na lista PessoaList. ltima pessoa criada possvel associar uma lista de contactos adicionando um contacto de cada vez. A caixa de texto apresenta o XML gerado pelo serializador a partir da

<18>

a programar

instncia do objecto PessoaList que suporta os dados. Por fim, possvel converter os dados do XML em numa nova instncia de PessoaList. A classe Form1 do formulrio tem um membro declarado do tipo PessoaList para suportar a lista de pessoas:

Contacto c = new Contacto(textBox2.Text,textBox4.Text); if (aLista[aLista.Count 1].Contactos == null) aLista[aLista.Count 1].Contactos = new ContactoList(); aLista[aLista.Count 1].Contactos.Add(c); ShowXML();

public partial class Form1 : Form { PessoaList aLista = new PessoaList(); A adio de uma pessoa cria um objecto pessoa, com o nome preenchido e adiciona-o lista de pessoas:

private void button1_Click(object sender, EventArgs e) { Pessoa p = new Pessoa(textBox1.Text); aLista.Add(p); //o ID neste exemplo simples passa a ser a posio na lista aLista[aLista.Count- 1].ID = aLista.Count; //Com o construtor certo, as trs linhas de cima poderiam ser escritas numa s, do gnero: // aLista.Add(new Pessoa(aLista.Count, textBox1.Text)); //com ID inicial 0 //SaveList - aqui surgiria a chamada ao processo para armazenar os dados. ShowXML(); }

criado um novo contacto com o par valor / tipo no construtor. Se a lista de contactos da pessoa nulo, criado nova instncia da lista. Finalmente adicionado o contacto lista e armazenada a lista.

Serializador costumizado
Preparao dos objectos
Porque pretendemos serializar os objectos de forma automtica para um formato costumizado, temos que preparar os objectos para essa tarefa. O .Net tem um conjunto de atributos que devemos adicionar ao cdigo dos objectos para tornar a construo e desconstruo do objecto em XML possvel. Vamos primeiro analisar a classe Contacto:

public class Contacto { public Contacto() { } public Contacto(string contacto, string tdc) { this.Valor = contacto; this.Tipo = tdc; } private string _valor; [XmlElement] public string Valor { get { return _valor; } set { _valor = value; } } private string _tipo;

A criao do ID simulado neste caso o ID aps a insero na lista criado a partir do ndice do registo na lista. O processo de armazenar os dados tambm simulado, apenas mostrando o XML gerado na caixa de texto (o ShowXML ser descrito mais frente.) Para adicionar contactos temos:

private void button2_Click(object sender, EventArgs e) {

<19>

a programar

[XmlAttribute] public string Tipo { get { return _tipo; } set { _tipo = value; } } }

atributo XMLType com a propriedade TypeName sobre a classe permite alterar o nome com que serializado. O mesmo possivel com o XmlElement atravs do parametro ElementName. A classe Pessoa e PessoaList so: public class Pessoa { /// <summary> /// construtor vazio necessrio para a serializao /// </summary> public Pessoa() { } public Pessoa(string nome) { this.Nome = nome; } /// <summary> /// id nullo quando se adiciona o contacto, logo usemos um elemento nulvel /// </summary> private int? _id = null; [XmlElement(IsNullable= true)] public int? ID { get { if (_id.HasValue) return _id.Value; else return null ; } set { if (value.HasValue) _id = value.Value; else _id = null; } } private string _nome = String.Empty; [XmlElement] public string Nome { get { return _nome; } set { _nome = value; } } private ContactoList _contactos = null; [XmlArray(IsNullable= true)]

A classe tem dois construtores, um vazio (necessrio para o serializador) e outro parametrizado. Contm tambm as propriedades, com membros pblicos e privados. O atributo essencial para o processo de serializao o que est declarado imediatamente antes do membro pblico. [XmlElement] antes de Valor, indica que valor deve ser serializado como sendo um elemento XML; [XmlAttribute] antes de Tipo indica que Tipo ser um atributo do elemento Contacto. importante notar que os tipos nulveis (ainda) no so serializveis como XmlAttribute. O objecto serializado ter a seguinte estrutura:

<Contacto Tipo="telemovel"> <Valor>912345678</Valor> </Contacto> ContactoList, que declarado como:

[XmlType(TypeName="Contactos")] public class ContactoList : List<Contacto> { } Ser serializado com a forma:

<Contactos> <Contacto Tipo="telemovel"> <Valor>912345678</Valor> </Contacto> <Contacto Tipo="email"> <Valor>alho@miguelalho.com</Valor> </Contacto> (...) </Contactos> Por defeito, as listas, sem qualquer modificador no seu atributo, so serializadas como ArrayOfTipo (no caso de ContactoList seria ArrayOfContacto). A utlizao do

<20>

a programar

public ContactoList Contactos { get { return _contactos; } set { _contactos = value; } } } [XmlType(TypeName = "Pessoas")] public class PessoaList : List<Pessoa> {

<Pessoas xmlns:xsi="http://www.w3.org/2001/XMLSc hema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSc hema"> <Pessoa> <ID>1</ID> <Nome>Miguel Alho</Nome> <Contactos> <Contacto Tipo= "telemovel"> <Valor>912345678</Valor> </Contacto> <Contacto Tipo= "email"> <Valor>alho@migeulalho.com</Valor> </Contacto> </Contactos> </Pessoa> <Pessoa> <ID>2</ID> <Nome>outra pessoa</Nome> <Contactos> <Contacto Tipo= "email"> <Valor>outro@email</Valor> </Contacto> </Contactos> </Pessoa> </Pessoas>

Aqui, a primeira novidade o uso de [XmlArray] para indicar que Contactos (do tipo ContactoList) efectivamente uma lista e deve ser apresentado no XML como um array de Contacto. A segunda novidade o IsNullable no atributo de [XmlElemento] da propriedade ID e no [XmlArray] . Caso seja nulo, no XML gerado ser escrito na tag xsi:nil=true indicando explicitamente que nulo. Sem o IsNullable, no caso de o valor da propriedade ser nulo, o respectivo XML ignorado. Caso haja algum elemento pblico que no desejamos passar para o XML (como um mtodo que retorna um valor baseado nas propriedades) podemos usar o [XmlIgnore]. Usando o programa exemplo, se adicionar uma Pessoa (instanciar uma pessoa com o nome preenchido), o XML gerado :

Os objectos que so arrays so correctamente convertidos para listas de objectos, as propriedades so correctamente serializadas e apresentadas da forma que escolhi. Resta ver ento como fazer a serializao, propriamente.

XmlCustSerializer
<Pessoas xmlns:xsi="http://www.w3.org/2001/XMLSc hema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSc hema"> <Pessoa> <ID>1</ID> <Nome>Miguel Alho</Nome> <Contactos xsi:nil= true/> </Pessoa> </Pessoas> A classe XmlCustSerializer que efectua a converso de e para Xml. Est includa no namespace dos BO para poder ser usada nas diversas camadas da aplicao. escrita na forma de classe genrica de modo a suportar qualquer tipo que definimos.

A informao do namespace (xmlns:xsi) adicionada automaticamente pelo serializador e apenas no primeiro elemento. Se adicionarmos mais pessoas e contactos, temos:

public class XmlCustSerializer<T> { public static XmlElement ToXml(T obj) //XmlDocument xd) { { //cria stream na memria para suportar o Xml MemoryStream memoryStream = new MemoryStream();

<21>

a programar

try { //Instancia o serializador XmlSerializer xs = new XmlSerializer(obj.GetType()); //Instancia o XmlTextWriter XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8); //Serializa os dados da classe para o writer xs.Serialize(xmlTextWriter, obj); //Copia a stream do TextWriter para a memria memoryStream = (MemoryStream)xmlTextWriter.BaseStream; //Coloca o apontador para o incio da stream //(necessrio para evitar erros no carregamento dos XMlDoc) memoryStream.Position = 0; //Instancia o XmlDocument XmlDocument xd = new XmlDocument(); //carrega o Stream em XMl para o XmlDocument xd.Load(memoryStream); //Obtm o n raiz com os dados a retorna XmlElement node = xd.DocumentElement; //retorna o n raiz. return node; } catch { throw new InvalidCastException("Ocorreu um erro na serializao do objecto (1009002001)"); } //return registo; } O ToXml recebe um objecto do tipo T e converte-o em Xml, consoante os atributos da classe. O processo requer a serializao para uma stream de memria atravs de um XmlTextWriter. Posteriormente o stream lido para um XMLDocument e o elemento XML retornado. Como possvel verificar, o XmlSerializer efectua a serializao de

forma automtica, sem cdigo especifico a determinado objecto.

public static T FromXml(XmlNode O_Xml) { //Instancia uma representao de encoding UTF-8 UTF8Encoding encoding = new UTF8Encoding(); try { //Instancia uma Stream de memria, para onde passado o texto Xml do parmetro de entrada MemoryStream memoryStream = new MemoryStream(encoding.GetBytes(O_Xml.Ou terXml)); //retorna o apontador da stream para o incio memoryStream.Position = 0; //instancia a serializao para o tipo de dados XmlSerializer xs = new XmlSerializer(typeof(T)); T obj; obj = (T)xs.Deserialize(memoryStream); return obj; } catch { throw new InvalidOperationException ("Ocorreu um erro na desserializao do objecto (1009002002)"); } } }

O mtodo FromXML(XmlNode) efectua o processo inverso a partir de um n XML, com o encoding em UTF-8 (possivelmente o mtodo poder ser alterado para aceitar o encoding como parmetro), transfere-o para a stream de memria, desserializa-o para o o objecto do tipo T e retorna o objecto com os dados. Para o usar, basta usar a classe para o tipo desejado, por exemplo:

<22>

a programar

private void ShowXML() { textBox3.Text = XmlCustSerializer<PessoaList>.ToXml(aLi sta).OuterXml; }

Da mesma forma que podem haver ausncia de tags, pode existir tags e atributos redundantes:

onde aLista do tipo PessoaList, e o uso de .OuterXml permite obter uma string. Porque os mtodos so estticos, no necessrio criar uma instncia da classe XmlCustSerializer. No caso da desserializao, temos:

<Pessoas data="today" origem="a"> <Pessoa numero="1"> <Nome>Miguel Alho</Nome> <criado modo="automtico"/> </Pessoa> </Pessoas>

private void button3_Click(object sender, EventArgs e) { XmlDocument xDoc = new XmlDocument(); xDoc.LoadXml(textBox3.Text); dataGridView1.DataSource = XmlCustSerializer<PessoaList>. FromXml(x Doc.FirstChild); } Na aplicao, o XML contido na rea de texto transformado e XmlDocument e desserializado para a nova PessoaList, que serve de datasource ao dataGridView. Neste exemplo, a serializao e desserializao usada apenas para apresentar dados, mas podia ser usada para ler os dados de um ficheiro ou escrever para um ficheiro, por exemplo, tornando a converso automtica. O processo tambm bastante permissivo, no sentido que se retirar elementos do XML, posso construir o objecto na mesma (desde que a propriedade permita o nulo por defeito). Por exemplo:

Por exemplo os atributos data, origem, e numero, e o elemento criado no so relevantes para a nossa aplicao. No entanto, o objecto PessoaList construdo correctamente, ignorando o que est a mais. Podemos por exemplo guardar o ficheiro num repositrio para conservao, mas usar apenas os dados relevantes na aplicao.

Concluso
Penso que evidente XMLCustSerializer. a utilidade da classe

Implementa o processo de serializao e desserializao de objectos da aplicao para XML de forma automtica e customizada. Os mesmos mtodos aceitam objectos de tipos customizados, reutilizando cdigo de forma eficiente. A converso para XML permite implementar mtodos mais simples de armazenamento dos dados em ficheiros, e mtodos de leitura dos mesmos. O uso de XML til para interoperacionalidade da aplicao. O uso do XML tem custos, no entanto: O overhead das tags grande, e sentida em ficheiros com grande quantidade de dados (o XML pode ocupar 10x mais que um CSV equivalente). Uma forma de o contornar usar attributos onde possvel, e utilizar nomes curtos para os elementos. Em comparao aos outros modos de serializao, a binria mais rpida. Eu pessoalmente vou utilizando o formato XML, porque se necessrio, posso editar um ficheiro gerado mo, e a converso directa para objecto facilita a produo de cdigo de armazenamento e leitura dos ficheiros e facilita o

<Pessoas > <Pessoa> <Nome>Miguel Alho</Nome> </Pessoa> </Pessoas>

correctamente reconstrudo como objecto PessoaList, em que as propriedades ID e Contactos da nica Pessoa na lista so nulos. Esta caracteristica pode ser muito til na definio de um formato de ficheiro que uma aplicao deva receber, e que no necessite de ter os dados completos (diminuindo o tamanho do ficheiro). Depois, aps recepo, o objecto desserializado processado e os campos nulos podero ser validados ou preenchidos pela aplicao.

<23>

a programar

processo de declarao do formato de armazenamento.

Introducing Serialization in .NET , Joydip Kanjilal http://aspalliance.com Serialization in .NET , Nishith Pathak http://www.CodeProject.com XmlSerializer Class http://msdn2.microsoft.com System.Xml.XmlSerializer, Nitin Pande http://www.eggheadcafe.com

Bibliografia e Crditos
A classe XmlCustSerializer foi desenvolvido em conjunto com Marco Fernandes e Joaquim Rendeiro. Algumas fontes usadas para compor a parte terica do artigo: Building Layered Web Aplications With Microsoft ASP.NET 2.0 http://Imar.spaanjaars.com

Natural da Murtosa, Miguel Alho licenciado em Engenharia Electrnica e Telecomunicaes pela Universidade de Aveiro. Actualmente trabalha como programador freelancer, desenvolvendo aplicaes web e multimdia para entidades nacionais e internacionais, utilizando principalmente a tecnologia .NET da Microsoft.

Miguel Alho
<24>

a programar

Manipulao de Datas

Introduo
No mundo da programao, comum necessitarmos de algum utilitrio que efectue clculos com datas do calendrio gregoriano. Os ambientes de programao integrados normalmente possuem tais funes j definidas internamente, bastando ao programador apenas fazer uso das mesmas. A principal questo deste artigo responder questo: como podem esses clculos ser processados? Para solucionar este tipo de problemas, conveniente conhecer e utilizar algoritmos especficos. Existem vrias formas e solues, no entanto aconselhvel utilizar aquelas que j tenham sido testados como, por exemplo, algoritmos utilizados na rea da Observao Astronmica, que possibilitam calcular qualquer data a partir do ano 4712 a.C. Para entender melhor o processo do clculo de datas, tornase necessrio entender os conceitos de: Dia Juliano, Calendrio Juliano, Calendrio Gregoriano e Ano Bissexto.

o nome de Julho ao stimo ms do Calendrio Juliano, o qual possui at hoje um ciclo de 31 dias. A partir do ano 8 a.C., tempo do imperador Csar Augusto, houve a mudana do nome do oitavo ms para Agosto (em sua homenagem), e como o ms de Julho possua 31 dias, foi ento atribudo mais um dia ao ms de Agosto, passando este a ter um ciclo de 31 dias, tal como o ms de Julho e, para que no houvesse diferena entre as homenagens. Este dia a mais foi retirado do ms de Fevereiro, que passou a ter um ciclo de 28 ou 29 dias nos anos bissextos. Desde ento, ficaram institudas as regras para os meses com 31 dias (Janeiro, Maro, Maio, Julho, Agosto, Outubro e Dezembro), com 30 dias (Abril, Junho, Setembro e Novembro) e com 28 ou 29 dias (Fevereiro).

Calendrio Gregoriano
O calendrio Gregoriano foi institudo na reforma papal do pontificado do Papa Gregrio XIII. Um facto curioso que o calendrio Gregoriano foi iniciado em 05/10/1582, tendo uma diferena de 10 (dez) dias em relao ao trmino do calendrio Juliano. Observe como ficou o calendrio do ms de Outubro de 1582, quando ocorreu a juno dos calendrios Juliano e Gregoriano.

Outubro 1582 Dom Seg 1 17 24 18 25 Ter 2 19 26 Qua 3 20 27 Qui 4 21 28 Sex 15 22 29 Sb 16 23 30

Dia Juliano
O dia Juliano um valor sequencial positivo inteiro que representa uma contagem sucessiva de dias a partir do ano 4712 a.C., ou seja, do ano -4712. A data 01/01/2000 seria representada como dia Juliano com o valor 2.451.545. Assim sendo, possvel calcular a diferena entre datas distantes. Por exemplo, quantos dias existem entre as datas 01/01/2000 e 26/04/1965? Para obter o nmero de dias entre as datas, necessrio converter cada uma das datas para os respectivos valores sequenciais para ento efectuar o clculo da diferena de dias entre as datas desejadas. Desta forma, a data 26/04/1965 (2.438.877) subtrada da data 01/01/2000 (2.451.545) resulta no valor 12.688 dias.

A supresso de dez dias ocorreu devido a um erro no ciclo do nmero de dias de um ano, existente no calendrio Juliano, que prev um ano de 365,25 dias, quando este ciclo de 364,24219271 dias, sendo reduzido a uma razo de 0,005369 segundo por ano.

Calendrio Juliano
O calendrio Juliano foi institudo no ano 46 a.C. (poca do imperador romano Jlio Csar) e utilizado at 04/10/1582. Nesta ocasio foram considerados trs anos de 365 dias e um de 366, a cada quatrinio (ano bissexto). Nesse perodo, o ms de Fevereiro possua 29 dias, tendo 30 dias apenas nos anos bissextos. Em homenagem ao imperador foi dado

Ano Bissexto
Os clculos para determinar anos bissextos nos calendrios Juliano e Gregoriano so diferentes. No calendrio Juliano ano bissexto todo ano divisvel por 4 (quatro), porm no calendrio Gregoriano, devido s correces e para maior preciso astronmica, considera-se bissexto o ano divisvel

<25>

a programar

por 4 (quatro), excepto os anos terminados em 00 que para serem bissextos necessitam ser divisveis por 400 (quatrocentos). O ajuste nos anos terminados com 00 ocorre a cada 400 (anos), devido ao ciclo de um ano possuir 364,24219271 dias, sendo reduzido a uma razo de 0,005369 segundo por ano, ciclo denominado de ano trpico, quando ocorre o equincio (quando o Sol est exactamente sobre a linha do equador no incio da primavera ou no incio do ms de Outubro; nesta ocasio o dia e a noite tm a mesma durao temporal).

Converso de Dia Juliano em Data


Para converter um dia Juliano em data necessrio tambm seguir um algoritmo especfico de converso, que tem em considerao o facto de um ano ser ou no bissexto.
Leia JULIANO A <- JULIANO Se (A > 2.299.160) Ento B <- Inteiro((A - 1.867.216,25) / 36.524,25) C <- A + 1 + B - Inteiro(B / 4) Seno C <- A Fim_se D <- C + 1.524 E <- Inteiro((D - 122,1) / 365,25) F <- Inteiro(E * 365,25) G <- Inteiro((D - F) / 30,6001) H <- D - F - Inteiro(G * 30,6001) Se (G < 14) Ento I <- G - 1 Seno I <- G - 13 Fim_se Se (I > 2) Ento J <- E - 4.716 Seno J <- E - 4.715 Fim_se Se (J > 0) Ento K <- J Seno K <- Mdulo(J + 1) {Mdulo = valor positivo} Fim_se DIA <- H MS <- I ANO <- K Escreva DIA, MS, ANO

Algoritmos
A partir da exposio dos conceitos anteriores apresentado os algoritmos utilizados para converso de data em dia Juliano, converso de dia Juliano em data e verificao de ano bissexto. Converso de Data em Dia Juliano Para converter uma data do calendrio Juliano ou calendrio Gregoriano em dia Juliano deve-se fazer uso de um algoritmo especfico que transforma uma data num nmero sequencial, como o demonstrado:
Leia DIA, MS, ANO Se (MS < 3) Ento ANO <- ANO - 1 MS <- MS + 12 Fim_se Se (DATA >= 15/10/1582) Ento {Calendrio Gregoriano} A <- Inteiro(ANO / 100) B <- Inteiro(A / 4) C <- 2 - A + B Seno {Calendrio Juliano} C <- 0 Fim_se D <- Inteiro(365,25 * (ANO + 4.716)) E <- Inteiro(30,6001 * (MS + 1)) F <- D + E + DIA + 0,5 + C - 1.524,5 JULIANO <- Inteiro(F) Escreva JULIANO

O algoritmo de converso verifica primeiro se o MS menor que trs. Sendo a condio verdadeira, feito um ajuste nos valores de ANO e MS. Em seguida, verificado se a data fornecida pertence ao calendrio Gregoriano (datas a partir de 15/10/1582) ou calendrio Juliano (datas anteriores a 04/10/1852). Se a data pertencer parte do calendrio Gregoriano, a varivel C ajustada a partir das variveis A e B; caso contrrio, varivel C atribudo o valor de zero. Aps a verificao da condio e estando a varivel C ajustada, so realizados clculos para determinar o nmero de dias a partir de 4712 a.C.

O algoritmo em questo atribui a varivel A o valor de dias Juliano, e em seguida verifica se o valor de dias Juliano maior que 2299160 (no calendrio Gregoriano, equivale a 04/10/1582). Se esta condio for verdadeira, so executados os devidos ajustes de tempo para o valor da varivel C; caso contrrio (sendo a data pertencente ao calendrio Juliano), a varivel C implicada directamente pelo valor da varivel A (sem os ajustes). Seguidamente, executada uma srie de clculos para extrair os valores do DIA, MS e ANO do dia Juliano fornecido. Verificao de Ano Bissexto Para verificar se o ano de uma data ou no bissexto deve-se fazer uso do algoritmo apresentado em seguida.
Leia ANO Se (ANO mod 4 <> 0) Ento

<26>

a programar

Escreva ANO BISSEXTO Fim_se Fim_se

Seno

ANO NO BISSEXTO Se (ANO mod 100 = 0) Ento Se (ANO mod 400 = 0) Ento Escreva ANO BISSEXTO Seno Escreva ANO NO BISSEXTO Fim_se

um resultado sempre inteiro). Neste caso, existe a possibilidade de o ano ser bissexto. Dentro dessa possibilidade, utilizada uma segunda condio (para detectar os anos que terminam com 00), em que se verifica se o ano divisvel por cem. Se o ano for divisvel por cem, possvel ainda ser bissexto. Para verificar esta possibilidade utiliza-se a terceira condio quando o ano dividido por 400.

Referncia Bibliogrfica
MANZANO, J. A. N. G.; YAMATUMI, W. Y. Free Pascal: Programao de Computadores. So Paulo, Brasil: Editora rica, 2007. 390 p., ISBN 978-85-365-0136-9.

Com o algoritmo de ano bissexto possvel verificar primeiro se uma data divisvel por quatro. Pode ser divisvel quando o resto da diviso do ano por quatro for diferente de zero (considerando como quociente da diviso

Natural da Cidade de So Paulo, Augusto Manzano tem 23 anos de experincia em ensino e desenvolvimento de programao de software. professor da rede federal de ensino no Brasil, no Centro Federal de Educao Tecnolgica de So Paulo. tambm autor, possuindo na sua carreira mais de cinquenta obras publicadas..

Augusto Manzano
<27>

<28>

segurana

Internet Protocol Version 6 IPv6

IPv6, tambm conhecido por IPng, chamado por muitos de protocolo da prxima gerao. E visto que estamos cada vez mais prximos do upgrade da verso 4 para a 6 convm comearmos a familiarizar-nos com este protocolo e no que traz de novo. Grande parte das pessoas no sabe que estamos a chegar ao limite do IPv4. Na verdade, dos teoricamente 4.3 mil milhes de endereos que o IPv4 permite apenas temos disponveis cerca de 250 milhes endereos. E ainda existem muitas reas onde o IP pode e vai ser aplicado. Alm destas aplicaes que se pretendem fazer, tambm temos que levar em conta que apenas cerca de 10% da populao mundial est ligada Internet e que pases como por exemplo a China e ndia ainda agora comearam a ter acesso a ela. O IPv4 no consegue fazer face a todas estas necessidades, da a necessidade de haver uma mudana. Muito se tem feito para tentar atenuar a escassez de endereos com o IPv4, tem-se recorrido Variable Lenght Subnet Masks (VLSM) e ao Network Address Protocol (NAT) para tentar aproveitar ao mximo os endereos disponveis. Mas o IPv6 no se trata apenas de ter mais espao, no, este protocolo sofreu uma modificao radical tanto na sua estrutura como no seu funcionamento. Foi melhorado significativamente para oferecer mais capacidade, eficcia, flexibilidade e optimizao para ir ao encontro das necessidades actuais.

mil milhes de endereos disponveis, passamos a poder usar cerca de 340.282.366.920.938.463.463.374.607.431. 768.211.456 de endereos. Mas existem outras caractersticas que fazem com que uma mudana para o IPv6 seja benfica e que compense o tempo, o custo e o esforo da mudana. Muitas das coisas que existem hoje numa rede e em especial na Internet no foram pensadas quando se desenvolveu o IPv4 e por isso tem-se recorrido a muitos remendos para tentar colmatar essas falhas. Alm de que as tecnologias mais recentes comeam apresentar alguma dificuldade em trabalhar com o IPv4. Existem outros benefcios que vo surgir com a utilizao do IPv6: Auto-configurao; Segurana (IPsec); Melhor suporte para diferentes engenharias (diffserv ou RSVP); Multicast; Melhor suporte para redes ad hoc; E um dos melhores e grandes benefcios que o IPv6 vai trazer a eliminao do broadcast por completo.

Estrutura
Como foi referido anteriormente, o IPv6 apresenta mudanas profundas na sua estrutura, em especial no seu cabealho (header). Em primeiro lugar 5 campos do cabealho no IPv4 foram removidos, Header Length, Identification, Flags, Fragment Offset e Header Checksum. O Header Length foi removido porque o header j tem um tamanho fixo. Os campos Identification, Flags, e Fragment Offset esto relacionados com a fragmentao de pacotes em IPv4, mas foram removidos porque a fragmentao de pacotes em IPv6 funciona de maneira diferente. O campo Header Checksum tambm foi removido para aumentar a velocidade de processamento. Isto porque se os routers no precisarem de verificar e actualizar os checksums o processamento torna-se mais rpido.

Benefcios e Usos do IPv6


Talvez o que salte logo vista seja o facto de ao invs dos 4

Fonte: http://www.cisco.com/web/about/a c123/ac147/archived_issues/ipj_93/ipv6_internals.html

<29>

segurana

Endereos e expresses no IPv6


importante referir que os endereos no IPv6 vo ser muito maiores tendo em conta que passamos a usar 128 bits. Por isso em vez do habitual 192.168.10.10 passamos a ter algo como 2001:0db8:3c4d:0012:0000:0000:1234:56ab. A diferena que talvez mais se destaque seja o tamanho e o facto de usarmos 8 conjuntos de nmeros separados por um : e em hexadecimal. Tambm o endereo passa a ser dividido em 3 partes: Global Prefix 2001:0db8:3c4d Subnet 0012 Interface ID 0000:0000:1234:56ab De salientar que o endereo que estamos a usar como exemplo pode ser resumido at ficar assim 2001:db8:3c4d:12::1234:56ab, mas isso j envolve algumas regras que tem de ser seguidas, porque talvez tenham reparado que eliminamos alguns zeros, mas isso nem sempre possvel.

Como que o IPv6 funciona


Pode-se comear por explicar como um host recebe um endereo IPv6 e como consegue encontrar recursos e outros hosts numa rede. Tambm abordar o que a stateless autoconfiguration e stateful autoconfiguration.

Auto-configurao
Desde 1993 que se usa o DHCP em IPv4 de maneira a que os host obtenham no s o endereo como tambm o Gateway e o Sufixo DNS. No IPv6 existem, no entanto, duas maneiras de configurao de um endereo. Uma usando um DHCPv6 server, que basicamente funciona como o DHCP em IPv4 apesar de existir algumas diferenas nas mensagens usadas, o conceito o mesmo. A outra maneira chamada de stateless autoconfiguration. Com a auto-configurao um host pode dinamicamente obter um endereo usando para isso o endereo Link-Local Unicast. Para isto acontecer o host precisa de um prefixo /64 para configurar a interface. ento usado um protocolo do IPv6 chamado de Neighbor Discovery Protocol (NDP). Assim o host envia aos routers uma mensagem NDP chamada de RS (router solicitation) usando para isso uma mensagem IPv6 multicast. Esta mensagem pergunta qual o prefix IPv6 usado nesta subnet e qual o endereo(s) usado(s) pelo(s) default router na subnet.. O router por usa vez envia uma resposta com esse prefixo atravs de um RA (router advertisement) usando novamente o ICMP.

Endereos especiais
Assim como no IPv4 o IPv6 tambm endereos especiais e que esto reservados para diversas funes: 0:0:0:0:0:0:0:0 (::.) mesmo que 0.0.0.0 em Ipv4; 0:0:0:0:0:0:0:1 (::1) mesmo que o 127.0.0.1 em IPv4; Estes so apenas dois exemplos de endereos reservados mais conhecidos, porque muitos outros existem para se referir a tipos especficos de endereos, como global unicast, unique local unicast, linklocal unicast, multicast.

Tipos de Endereos
Novamente no IPv6, endereos tais como multicast, unicast que existem no IPv4 e que certamente conhecemos e estamos familiarizados, foram reaproveitados e usados tambm no IPv6. No entanto um endereo foi completamente eliminado, o broadcast. Lembram-se das broadcast storms? Pois , esse foi um dos muitos problemas que foi eliminado/resolvido com a eliminao do broadcast e que certamente no vai deixar saudades. Um endereo foi eliminado e um foi criado, estou-me a referir claro ao Anycast, mas j vamos l. S de salientar que os endereos Unicast, Global Unicast, Multicast, Link-Local e Unique Local funcionam basicamente como no IPv4 e sem grandes diferenas ou praticamente nenhumas no IPv6. Mas como dissemos surgiu um novo tipo de endereo, o Anycast. Este endereo identifica diversas interfaces, mas o pacote anycast apenas entregue a um endereo. Neste caso entregue ao primeiro endereo que ele encontre e que corresponda aos termos definidos pelo routing da rede. Este endereo usado em conjunto com o protocolo BGP.

O host pega ento o prefixo que recebeu e junta-o com o seu interface ID (MAC) e no meio desse valor junta um FFFE para compensar os bits que faltam. O processo mais complexo do que isto, porque usado certo tipo especfico de mensagens do ICMP assim como usado endereos Multicast. Alm de que existem diversas opes para a configurao do endereo.

Migrar para o IPv6


Apesar de todas as vantagens apresentadas certamente muitos se perguntem qual que vai ser o custo e o

<30>

segurana

trabalho que vai dar esta migrao. No podemos pensar que vai haver uma migrao em massa do IPv4 para IPv6, isto porque o nmero de dispositivos com IPv4 ascende aos milhes e nem todos esses dispositivos suportam IPv6 por isso bem provvel que se v demorar uns bons anos a fazer a transio. Alm de que a transio vai depender tambm da infra-estrutura que tenhamos, como bvio se tivermos routers ou switches j arcaicos o custo da migrao vai ser maior. Mas foram criadas algumas estratgias que permitem uma integrao gradual do IPv4 para a verso 6.

- NAT-PT
Em alguns casos teremos que usar uma terceira opo que permita que se converta um cabealho IPv6 em IPv4 e viceversa. Neste caso temos que usar o Network Address TranslationProtocol Translation (NAT-PT) apesar de no ser uma grande soluo. Para que se d esta converso necessrio que o router saiba quais os endereos IPv4 e IPv6 deve usar e assim como no NAT tradicional tambm temos static definition, dynamic NAT, e dynamic PAT.

- IPv4/IPv6 Dual Stacking


O termo Dual Stack significa que o host ou o router usa o IPv4 e o IPv6 ao mesmo tempo. Para os hosts significa que tem associado ao NIC tanto um endereo IPv4 como um IPv6 e que consegue enviar pacotes IPv4 para hosts com o IPv4 e o mesmo com o IPv6. Para os routers significa que alm dos endereos IPv4 e routing protocols tambm tem configurado endereos IPv6 assim como os respectivos routing protocols. Esta a estratgia mais usada porque a mais fcil de se usar isto porque permite o upgrade gradual tanto dos dispositivos como das aplicaes. 6to4 Tunneling Existem diversos tipos de tunneling, mas neste caso o que feito pegar num pacote IPv6 e encapsula-lo dentro de um pacote IPv4. Existem diversos tipos de tunneling que podemos usar: Manually configured tunnels (MCT); Dynamic 6to4 tunnels; Intra-site Automatic Tunnel Addressing Protocol (ISATAP) e; Teredo tunneling. Um aspecto a ter em ateno que se em algum ponto existir um NAT, este ir destruir esse tnel, mas existe uma maneira de dar a volta este problema e por usarmos um mtodo j citado Teredo.

Segurana
na segurana que o IPv6 tambm se destaca e pela positiva. Nesta rea viu-se a necessidade de redesenhar e incorporar algumas caractersticas bsicas em termos de segurana, de maneira a que o IPv6 possa, pelo menos, providenciar um nvel mnimo de segurana contra as muitas ameaas a que a Internet est sujeita. Por isso alguns aspectos bsicos foram levados em conta como a integridade a confidencialidade e a autenticao. Como j dissemos anteriormente, o IPv4 quando foi desenhado no levou em conta as ameaas que iriam surgir. Por isso surgiram algumas falhas de segurana, por exemplo com alguns protocolos usados. Protocolos esses que confiam a sua segurana da autenticao dos endereos IP e das portas. No entanto no sabemos se determinado pacote IP foi modificado ou lido o que leva a uma falha de segurana. Alm de que muitos protocolos que requerem autenticao enviam a password em puro texto que facilmente poder ser descodificado. Estes so alguns dos problemas que so colmatados atravs de Filtros para pacotes, Firewalls, SSL, PEM, PGP, etc. Como o IPv6 mais seguro? Graas Framework IPSec, que uma Framework de segurana para a camada onde trabalha o IP. Esta Framework consiste em seis elementos distintos: requerimentos de segurana na

<31>

segurana

camada network, encriptao (ESP), autenticao (AH), utilizao de algoritmos criptogrficos para encriptao e autenticao, definio de polticas de segurana e gesto da chave IPSec. Existem diversos usos que podemos dar IPSEC, confidencialidade nas transmisses, autenticao dos peer para os updates de routing, server lookups e autoconfigurao em DHCP e tambm a preveno de ataques Denial-of-Service. O IPSEC tambm exerce a sua influncia em outros servios e aplicaes das diversas camadas, mas nem todo um mar de rosas porque existem algumas reas onde ainda ocorrem alguns conflitos, como por exemplo em NAT, QoS e Tunneling. Mas tambm ainda existem falhas no IPv6 apesar de se considerar o IPSEC estvel, mas muito trabalho ainda se tem de fazer em diversas reas de maneira a poder usufruir ao mximo aquilo que o IPv6 tem para oferecer.

Concluso
Neste pequeno artigo foram abordados diversos aspectos relacionados com o IPv6, mas tudo isto que analismos apenas um pequeno resumo de toda a informao disponvel. Para poderem aprofundar melhor este assunto recomendo que leiam IPv6 Essentials O Reilly e o Chapter 13 - Internet Protocol Version 6 (IPv6) do Sybex CCNA Cisco Certified Network Associate Study Guide Exam 640-802 6th Edition. Podem tambm consultar o site http://www.pt.ipv6tf.org/ .

Residente em Lisboa, Ciro Cardoso um grande amante do vasto mundo que a informtica em especial a segurana. Est actualmente a trabalhar na prxima etapa do percurso Cisco com a certificao CCNP. Gosta bastante da rea de redes, configurao de protocolos assim como a implementao.

Ciro Cardoso
<32>

internet

USACO Training Pages


Site de treino das olimpadas de informtica dos EUA, recomendado a qualquer programador com interesse em testar/treinar as suas capacidades em algoritimia. Com background terico e novos problemas desbloqueveis medida que se avana, o site inclui ainda um grader que nos permite saber em que testes o programa submetido errou, entre outras informaes.

http://train.usaco.org/

Android
Site do projecto Android da Open Handset Alliance, uma plataforma opensource para telemveis em que o Google participa, onde poder encontrar o SDK e boa documentao sobre o Android.

http://code.google.com/android/

Free Software Foundation Licenses


Uma pgina com licenas reconhecidas pela FSF que permitem a distribuio de software e outro tipo de contedos de forma free as in speech. Muito til se planeia lanar software opensource e quer saber qual a que melhor se adequa a si e ao pblico-alvo do seu programa/biblioteca.

http://www.fsf.org/licensing/licenses/

PHP Classes Repository


Este site um dos maiores repositrios de cdigo PHP, nele pode encontrar milhares de classes que o vo ajudar no desenvolvimento das suas aplicaes.

http://www.phpclasses.org/

<33>

Queres participar na Revista PROGRAMAR? Queres integrar este projecto, escrever artigos e ajudar a tornar esta revista num marco da programao nacional? Vai a

www.revista-programar.info
para mais informaes em como participar, ou ento contacta-nos por

@portugal-a-programar.org
Precisamos do apoio de todos para tornar este projecto ainda maior... contamos com a tua ajuda!

revistaprogramar

Equipa PROGRAMAR
Um projecto Portugal-a-Programar.org

You might also like