• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Revista programar 26
 

Revista programar 26

on

  • 1,304 views

 

Statistics

Views

Total Views
1,304
Views on SlideShare
1,304
Embed Views
0

Actions

Likes
0
Downloads
17
Comments
0

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Revista programar 26 Revista programar 26 Document Transcript

    • EditorialEDITORIAL EQUIPA PROGRAMAR Sempre em movimento… Coordenadores Porque sabemos que parar é morrer, nesta edição da Revista António Silva PROGRAMAR introduzimos várias alterações que achamos importantes Fernando Martins para continuidade deste projecto. Das várias alterações introduzidas, a salta imediatamente à vista, mesmo ao leitor que ainda está somente a ler a Editor página do editorial, é a mudança de design . Em qualquer tipo de António Silva publicação o design influencia o modo como vemos como lemos. Aqui temos que agradecer a todos quantos ajudaram a adaptar este novo design, Design mas especialmente ao Sérgio Alves por toda a parte da idealização e Sérgio Alves (@scorpion_blood) desenho do novo design. Outra alteração, que todavia não será tão notada pelos leitores é a Redacção alteração do software de paginação. Chegamos à conclusão que o Scribus André Lage, Augusto Manzano, Diogo já evoluiu bastante desde a última vez que foi utilizado para paginar a Constantino, Fernando Martins, João Mares, Revista PROGRAMAR e está à altura das nossas necessidades. Assim João Matos, Jorge Paulino, Paulo Morgado, decidimos que não havia necessidade de continuarmos a utilizar um Pedro Aniceto, Ricardo Rodrigues, Ricardo software pago e que trazia vários problemas de leitura a alguns utilizadores Trindade, Sara Silva (dos quais chegamos a receber comentários). Também fizemos várias parcerias com algumas comunidades Contacto portuguesas que estão de algum modo relacionadas com programação, de revistaprogramar@portugal-a-programar.info modo a obter mais e melhores artigos para si. Todavia não estamos fechados a mais parcerias, continuamos abertos a futuros contactos para o Website nosso endereço de correio electrónico, que serão posteriormente analisados http://www.revista-programar.info por toda a equipa. Trazemos também até si, colunas de opinião e colunas direccionadas a ISSN um tema específico. Assim poderá contar que surgirão artigos desse 1 647-071 0 assunto com uma periodicidade específica na sua Revista favorita. Por fim, achamos que estamos prontos para voltar a trazer a Revista PROGRAMAR até si de 2 em 2 meses , e por isso a próxima edição deverá INDICE sair em Fevereiro ao invés de Março como estava programado.4 Tema de Capa - LINQ Tudo isto para si, que está ler. Esperámos que as alterações sejam bem11 BYACC recebidas por todos, mas também esperámos opiniões sobre todas estas18 Introdução ao Entity Framework alterações, mesmo porque as novidades poderão não ficar por aqui,23 Programação Funcional Perl (Parte I ) contámos ter mais novidades na próxima edição. Por isso não tenha medo26 BackgroundWorkers em WPF de nos contactar para revistaprogramar@portugal-a-programar.org a dizer o31 jQuery - O quê, como e porquê? que acha de todas estas alterações. Porque você é importante para nós,35 Tutorial de Lua (Parte 6) quer as suas opiniões, quer o seu trabalho a divulgar o nosso projecto aos41 E se amanhã a Apple dominar? seus amigos e colegas, e mais importante a sua preferência que nos43 SQL em Oracle permite crescer para lhe oferecer algo maior e melhor.47 Aspectos low-level de 3D54 Quando se é ! Produtivo A equipa da Revista PROGRAMAR56 Client Object Model para SilverlightA revista PROGRAMAR é um projecto voluntário, sem fins lucrativos. Todos os artigos são da responsabilidade dos autores, não podendo a revista ou acomunidade ser responsabilizada por alguma imprecisão ou erro. Para qualquer dúvida ou esclarecimento poderá sempre contactar-nos. 2
    • Noticias NOTICIAS U p l o a d Li s b o a e U p l o a d Li s b o a Se m i n á ri o Po c ke tPT s o b re Pro 2 0 1 0 te c n o l o gi a s Wi n d o ws Ph o n eO Upload Lisboa é um evento que por si só nomeia a era Encontram-se abertas as inscrições para o 6º Seminárioem que estamos. A era da nova comunicação, da troca de PocketPT sobre tecnologias móveis Windows Phone. Esteinformação no momento, de forma prática e natural, e da ano o seminário será dedicado à nova plataforma móvel dapartilha de conhecimentos em rede. O Upload Lisboa Microsoft, e irá incluir várias sessões que irão dar apretende, mais uma vez, passar a esfera da rede interior e conhecer as funcionalidades do mesmo.global para a esfera da partilha conjunta, física. Será ainda uma excelente oportunidade para osEste evento nasce da necessidade crescente de debate e participantes testarem e verem em primeira mão os novospartilha de conhecimentos sobre a web 2.0, numa altura em equipamentos.que as novas plataformas de comunicação e informação Como tem vindo a acontecer nos anos anteriores aassumem um lugar cada vez mais central na vida de inscrição este ano é gratuita e irá ter lugar no auditório dapessoas e empresas. Hoje, mais que nunca, a partilha Microsoft Portugal no TagusPark em Porto Salvo noatravés das plataformas sociais na web ocupam um lugar próximo dia 1 8 de Dezembro pelas 1 0h.de destaque na influência na opinião pública e na formação Mais informações e inscrições:de critérios de análise ao que se passa no país e no http://www.mtechseminar.com/201 0/index.htmmundo.São dois dias, 11 e 1 5 de Dezembro, que certamente nãoirá perder!Mais informações: http://uploadlisboa.com/ SAPO C o d e B i ts 2 0 1 0 1 6 a R e u n i ã o Pre s e n c i a l d a C o m u n i d a d e N e tPo n toDe 11 a 1 3 de Novembro de 201 0 decorreu o Sapo No dia 11 /1 2/201 0 será realizada a 1 6ª reunião presencialCodebits 201 0. A comunidade Portugal-a-Programar esteve da comunidade NetPonto, em Lisboa. Nesta sessão,presente, tendo alguns membros efectuado alguns poderá ver duas apresentações presenciais sobre Domainprojectos. Este ano, com oferta da comunidade, todos os Driven Design e WP7 & XNA – Let’s play?que participaram e solicitaram, tiveram direito a uma t-shirt Para participar, basta efectuar a inscrição através do sitepara usar durante o evento. http://netponto-lisboa-dezembro-201 0.eventbrite.com/ AEsta foi a foto de grupo de alguns dos elementos que entrada é gratuita e são realizadas reuniões todos osestiveram presentes (infelizmente não foi possível juntar meses.todos): Para mais informações, consulta de próximas sessões e inscrição: http://netponto.org/ 3
    • TEMA DE CAPALI N Q: I m p l e m e n ta ç ã o d o s o p e ra d o re s Ta ke La st,Ta ke La stWh i l e , Ski p La st e S ki p La stWh i l eHá algum tempo necessitei de obter os últimos original uma vez e mais três vezes sobre ositens de uma sequência que satisfaziam um itens que satisfazem o critério. Se a sequênciadeterminado critério e, olhando para os original for grande, isto pode consumir muitaoperadores disponíveis na classe Enumerable, memória e tempo.apercebi-me de que tal operador não existia. Existe ainda um problema adicional quando seA única forma de obter o resultado pretendido usa a variante que usa o índice de item naera inverter a ordem dos itens na sequência, sequência original na avaliação do critério deobter os itens que satisfaziam o critério e inverter selecção (>). Quando se inverte a ordem dosos itens da sequência resultante. itens, os índices destes serão invertidos e o predicado de avaliação do critério de selecçãoAlgo como isto: terá de ter isso em consideração, o que poderá não ser possível se não se souber o número de Sequence itens na sequência original. .Reverse() .TakeWhile(criteria) Tinha de haver uma solução melhor, e é por isso .Reverse(); que eu implementei os Operadores Take Last: TakeLast<TSource>(IEnumerable<TSource>)Parece simples, certo? Primeiro chamamos ométodo Reverse para produzir uma nova Retorna o número especificado de elementossequência com os mesmos itens mas na ordem contínuos no fim da sequência.inversa da sequência original, depois chamamos int[] grades = { 59, 82, 70, 56, 92, 98, 85o método TakeWhile para obter os primeiros };itens que satisfazem o critério e, finalmente,chamamos novamente o método Reverse para var topThreeGrades = gradesrecuperar a ordem original dos itens. .OrderBy(grade => grade) .TakeLast(3);O problema desta aproximação é que o métodorev memoriza toda a sequência antes de iterar Console.WriteLine("As notas mais altassobre os seus itens na ordem inversa – e o são:");código acima usa-o duas vezes. Isto significaiterar sobre todos os itens da sequência original foreach (int grade in topThreeGrades)e memoriza-los, iterar sobre os primeiros itens {que satisfazem o critério e memoriza-los e, Console.WriteLine(grade);finalmente, iterar sobre estes itens para produzir }a sequência final.Se estiveram a contar, chegaram à conclusão deque se iterou sobre todos os itens da sequência 4
    • TEMA DE CAPA LI N Q: I m p l e m e n ta ç ã o d o s o p e ra d o re s Ta ke La st, Ta ke La stWh i l e , Ski p La st e Ski p La stWh i l e /* string[] fruits = Este código produz o seguinte resultado: { "maçã", "maracujá","banana", "manga", As notas mais altas são: "laranja", "mirtilo", "uva", "morango" }; 98 var query = fruits 92 .TakeLastWhile((fruit, index) => 85 fruit.Length >= index); */ foreach (string fruit in query)TakeLastWhile<TSource>(IEnumerable<TSou {rce>, Func<TSource, Boolean>) Console.WriteLine(fruit); }Retorna os elementos do fim da sequência paraos quais a condição especificada é verdadeira. /* Este código produz o seguinte resultado: string[] fruits = morango { "maçã", "maracujá","banana", "manga", */ "laranja", "mirtilo", "uva", "morango" }; Tendo introduzido os operadores TakeLast, faz var query = fruits todo o sentido introduzido os seus duais: os .TakeLastWhile(fruit => operadores SkipLast: string.Compare("laranja", fruit, true) != 0); SkipLast<TSource>(IEnumerable<TSource>) foreach (string fruit in query) Retorna todos os elementos da sequência à { excepção do número especificado de elementos Console.WriteLine(fruit); contínuos no fim da sequência. } int[] grades = /* { 59, 82, 70, 56, 92, 98, 85 }; Este código produz o seguinte resultado: var lowerGrades = grades maracujá .OrderBy(g => g) uva .SkipLast(3); morango */ Console.WriteLine("Todas as notas excepto as top 3:");TakeLastWhile<TSource>(IEnumerable<TSou foreach (int grade in lowerGrades)rce>, Func<TSource, Int32, Boolean>) { Console.WriteLine(grade);Retorna os elementos do fim da sequência para }os quais a condição especificada é verdadeira. 5
    • TEMA DE CAPALI N Q: I m p l e m e n ta ç ã o d o s o p e ra d o re s Ta ke La st, Ta ke La stWh i l e , Ski p La st e Ski p La stWh i l e /* SkipLastWhile<TSource>(IEnumerable<TSour Este código produz o seguinte resultado: ce>, Func<TSource, Int32, Boolean>) As notas mais altas, excepto: 56 Retorna todos os elementos da sequência à 59 excepção dos elementos do fim da sequência 70 para os quais a condição especificada é 82 verdadeira. */ int[] amounts = {SkipLastWhile<TSource>(IEnumerable<TSour 5000, 2500, 9000, 8000,ce>, Func<TSource, Boolean>) 6500, 4000, 1500, 5500 };Retorna todos os elementos da sequência àexcepção dos elementos do fim da sequência var query = amountspara os quais a condição especificada é .SkipWhile((amount, index) => amount >verdadeira. index * 1000); int[] grades = foreach (int amount in query) { 59, 82, 70, 56, 92, 98, 85 }; { var lowerGrades = grades Console.WriteLine(amount); .OrderBy(grade => grade) } .SkipLastWhile(grade => grade >= 80); /* Este código produz o seguinte resultado: Console.WriteLine("Todas as notas menores que 5000 80:"); 2500 */ foreach (int grade in lowerGrades) { Console.WriteLine(grade); } IMPLEMENTADO OS OPERADORES TAKELAST /* I mplementando O Operador TakeLast Este código produz o seguinte resultado: Todas as notas menores que 80: O operador TakeLast retorna o número 56 especificado de elementos contínuos do fim de 59 uma sequência e é implementado como o 70 método de extensão TakeLast. */ Para implementar este operador, primeiro começamos por memorizar, pelo menos, o número requerido (count) de itens da sequência 6
    • TEMA DE CAPA LI N Q: I m p l e m e n ta ç ã o d o s o p e ra d o re s Ta ke La st, Ta ke La stWh i l e , Ski p La st e Ski p La stWh i l efonte (source) num array que funciona como for (; numOfItems > 0; idx = (idx + 1) %uma memória intermédia (buffer) circular: count, numOfItems--) var sourceEnumerator = { source.GetEnumerator(); yield return buffer[idx]; var buffer = new TSource[count]; } var numOfItems = 0; int idx; Há duas optimizações que ainda podemos fazer. for (idx = 0; (idx < count) && sourceEnumerator.MoveNext(); idx++, A primeira é óbvia, se o número de itens numOfItems++) requerido for 0 (zero), retornamos uma { sequência vazia: buffer[idx] = sourceEnumerator.Current; if (count <= 0) {Se o número de itens memorizados return(numOfItems) for inferior ao número requerido System.Linq.Enumerable.Empty<TSource>();(count), produzimos os itens memorizados: } if (numOfItems < count) A segunda é se a sequência fonte (source) { implementar a interface IList<T>. Os objectos for (idx = 0; idx < numOfItems; idx++) que implementam esta interface têm uma { propriedade Count e acesso indexado aos seus yield return buffer[idx]; itens que nos permite optimizar a produção da } sequência final. yield break; } A produção da sequência final passa por produzir o número de itens requeridos do fim daEm seguida, iteramos pelos restantes itens e lista (ou todos se a lista contiver menos que osvamos os armazenando, de forma circular, na itens requeridos):memória intermédia: int listCount = list.Count; for (idx = 0; sourceEnumerator.MoveNext(); for (int idx = listCount - ((count < idx = (idx + 1) % count) listCount) ? count : listCount); idx < { listCount; idx++) buffer[idx] = { sourceEnumerator.Current; yield return list[idx]; } } Implementando os OperadoresE finalmente, iteramos sobre os itens TakeLastWhilememorizados para produzir a sequência final: O operador TakeLastWhile retorna os últimos 7
    • TEMA DE CAPALI N Q: I m p l e m e n ta ç ã o d o s o p e ra d o re s Ta ke La st, Ta ke La stWh i l e , Ski p La st e Ski p La stWh i l eelementos contíguos que satisfazem o critério buffer.Add(item);especificado e é implementado como os }métodos de extensão TakeLastWhile. elsePara implementar este operador, primeiro {começamos com uma memória intermédia buffer.Clear();(buffer) vazia e, para cada item que satisfaça o }critério implementado pelo predicado (predicate), }memorizamos esse item. Sempre que ocorrerum item que não satisfaça o critério de selecção, foreach (var item in buffer)a memória intermédia é limpa: { var buffer = new List<TSource>(); yield return item; foreach (var item in source) } { if (predicate(item)) { IMPLEMENTANDO OS OPERADORES buffer.Add(item); SKIPLAST } else Implementando o Operador SkipLast { buffer.Clear(); O operador SkipLast retorna o número } especificado de elementos contínuos do fim de } uma sequência e é implementado como o método de extensão SkipLast.Depois de percorrer toda a sequência fonte Para implementar este operador, começamos(source), produzimos todos os itens, se por memorizar, pelo menos, o número requeridoexistirem, da memória intermédia: (count) de itens da sequência fonte (source) num array que funciona como uma memória foreach (var item in buffer) intermédia (buffer) circular: { yield return item; var sourceEnumerator = } source.GetEnumerator(); var buffer = new TSource[count];A diferença para o método que tem em conta o int idx;índice do item no predicado (predicate) deselecção é apenas na invocação deste: for (idx = 0; (idx < count) && sourceEnumerator.MoveNext(); idx++) var buffer = new List<TSource>(); { var idx = 0; buffer[idx] = sourceEnumerator.Current; } foreach (var item in source) { Em seguida, iteramos pelos restantes itens da if (predicate(item, idx++)) sequência fonte (source) memorizando { 8
    • TEMA DE CAPA LI N Q: I m p l e m e n ta ç ã o d o s o p e ra d o re s Ta ke La st, Ta ke La stWh i l e , Ski p La st e Ski p La stWh i l ecircularmente cada item e produzindo o item var list = source as IList<TSource>;armazenado anteriormente na mesma posição: if (list != null) idx = 0; { if (count >= list.Count) while (sourceEnumerator.MoveNext()) { { return var item = buffer[idx]; System.Linq.Enumerable.Empty<TSource>(); buffer[idx] = sourceEnumerator.Current; } idx = (idx + 1) % count; // ... } yield return item; } Se o número de itens da sequência fonte (source) for superior ao número de itens aSe o número de itens a excluir for igual ou excluir, produzir a sequência final consiste emsuperior ao número de itens existentes na produzir todos os itens da sequência fontesequência fonte (source), o método (source) excepto os últimos count itens:sourceEnumerator.MoveNext() retornará false naprimeira iteração do ciclo while e será produzida int returnCount = list.Count - count;uma sequência vazia. for (int idx = 0; idx < returnCount; idx++)Tal como acontecia com o operador TakeLast, {podem-se fazer algumas optimizações. yield return list[idx]; }A primeira é óbvia, se o número de itensrequeridos for 0 (zero) ou inferior, retornamos Implementando os Operadoresuma sequência equivalente à fonte (source): SkipLastWhile if (count <= 0) O operador SkipLastWhile retorna os últimos { elementos contíguos que satisfazem o critério return source.Select(i => i); especificado e é implementado como os } métodos de extensão SkipLastWhile. Para implementar este operador, primeiroA segunda é se a sequência fonte (source) começamos com uma memória intermédiaimplementar a interface IList<T>. Os objectos (buffer) vazia e, para cada item que satisfaça oque implementam esta interface têm uma critério implementado pelo predicado (predicate),propriedade Count e acesso indexado aos seus memorizamos esse item.itens que nos permite optimizar a produção dasequência final. Sempre que ocorrer um item que não satisfaça o critério de selecção, a memória intermédia éSe o número de itens a excluir for igual ou limpa e o item que não satisfaz o critério ésuperior ao número de itens da sequência fonte produzido:(source), retornamos uma sequência vazia: 9
    • TEMA DE CAPALI N Q: I m p l e m e n ta ç ã o d o s o p e ra d o re s Ta ke La st, Ta ke La stWh i l e , Ski p La st e Ski p La stWh i l e var buffer = new List<TSource>(); else foreach (var item in source) { { if (buffer.Count > 0) if (predicate(item)) { { foreach (var bufferedItem in buffer) buffer.Add(item); { } yield return bufferedItem; else } { buffer.Clear(); if (buffer.Count > 0) } { yield return item; foreach (var bufferedItem in buffer) } { } yield return bufferedItem; } buffer.Clear(); Conclusão } Como podem ver, implementar este tipo de yield return item; operadores é muito fácil, pelo que, não se deve } evitar a sua implementação sempre que se } justifique. Implementar um específico para a nossa aplicação pode significar uma melhorA diferença para o método que tem em conta o legibilidade do código e até um aumento deíndice do item no predicado (predicate) de performance.selecção é apenas na invocação deste: Podem encontrar a implementação completa destes operadores (e outros) no meu projecto de var buffer = new List<TSource>(); utilitários e operadores para LINQ no CodePlex: var idx = 0; PauloMorgado.Linq. foreach (var item in source) Recursos { O meu website: http://PauloMorgado.NET/ if (predicate(item, idx++)) Livro “LINQ Com C#” { PauloMorgado.Linq buffer.Add(item); Classe Enumerable } Métodos de extensão AUTOR Escrito por Paulo Morgado É licenciado em Engenharia Electrónica e Telecomunicações (Sistemas Digitais) pelo Instituto Superior de Engenharia de Lisboa e Licenciado em Engenharia Informática pela Faculdade de Ciências e Tecnologia da Universidade Nova de Lisboa. Pelo seu contributo para a comunidade de desenvolvimento em .NET em língua Portuguesa, a Microsoft premeia-o com o prémio MVP (C#) desde 2003. É ainda co-autor do livro “LINQ Com C#” da FCA. 10
    • A PROGRAMARBYAC CNo artigo anterior adquirimos algumas noções eles seguem a gramática que ele define. Se osobre flex e vimos como implementar um objectivo do parser for só verificar que um certoscanner simples. Relembrando, o flex é um ficheiro, por exemplo um ficheiro xml, segue agerador de analisadores lexicais ou scanners, e especificação da linguagem, podemos não tero byacc é um gerador de parsers. Usados em interesse nenhum em saber o valor de qualquerconjunto permitem escrever aplicações bastante token. A nossa calculadora no entanto, precisasofisticadas, mas no nosso artigo limitamo-nos a de produzir resultados, portanto necessita deconsiderar uma calculadora simples, servindo saber o valor de cada token NUMBER quecomo exemplo introdutório. Agora que temos o recebe. O parser define os tokens e o tipo descanner para a nossa calculadora escrito valores que lhes podem estar associados napodemos começar a considerar o parser. zona das definições, sempre que precisa de um token novo ele chama o scanner com o resto doUm ficheiro byacc tem a mesma estrutura que o input que falta analisar. Vejamos a definição dosflex, já que o analisador lexical em que o flex se tokens para a nossa calculadora:baseia, o lex, copiou a sua estrutura do yacc, ogerador de parsers em que o byacc se baseia. %union {Como tal o nosso ficheiro byacc vai ser algo double d;deste género: }; definições %token<d> NUMBER %token NL %% %left + - gramática %left * / %right ^ %% %nonassoc UMINUS int main() { %% yyparse(); } ... %%Comecemos por considerar como é que o parsere o scanner funcionam em conjunto. Um parser int main()recebe tokens e verifica se esses tokens estão a {seguir uma gramática. O que nós estávamos a yyparse();retornar no scanner, o NUMBER e o NL são }esses tokens. Os tokens podem ter um valorassociado ou não. O que o parser faz é ver se 11
    • A PROGRAMARBYAC CA primeira coisa que encontramos é uma%union, seguida da declaração de dois tokens, %%NUMBER e NL. A %union serve para indicar expr_list : expr NL { std::couttipos que queiramos associar a tokens e << $1 << std::endl; }eventualmente a elementos da gramática. Ao | expr_list expr NL {escrevermos %token<d> NUMBER estamos a std::cout << $2 << std::endl; }indicar que para além de NUMBER ser um ;token, tem um valor associado do tipo d, nestecaso double. Isto vai ser importante quando expr : NUMBER { $$ = $1; }passarmos para a gramática e é por esta razão | - expr %prec UMINUS { $$ =que no scanner passávamos o número que -$2; }tínhamos lido ao yylval.d antes de retornarmos o | expr + expr { $$ =token. A informação da union e dos tokens que $1+$3; }escrevermos nesta secção vai servir para o | expr - expr { $$ = $1-byacc gerar o header ao qual o nosso scanner $3; }fez #include e que permite ao scanner e ao | expr * expr { $$ =parser comunicarem entre si. O +, -, *, /, ^ e $1*$3; }UMINUS também são tokens mas aqui para | expr / expr { $$ =além de indicarmos que são tokens estamos a $1/$3; }indicar a associatividade dos operadores, um | expr ^ expr { $$ =conceito que o leitor deverá conhecer, mas que pow($1, $3); }abordaremos com maior profundidade na | ( expr ) { $$ = $2;gramática. } ; %{ #include <iostream> #include <cmath> %% %} int main() { %union { yyparse(); double d; } }; Esta versão do parser introduz a gramática, mas %token<d> NUMBER comecemos por observar as diferenças na %token NL secção das definições. Podemos ver primeiro que a introdução de código C/C++ se processa %left + - da mesma forma que no scanner. Em seguida %left * / temos a instrução, %type<d> expr, expr não é %right ^ um token, é outro símbolo da gramática mas %nonassoc UMINUS ainda assim tem um tipo, portanto temos que o indicar. %type<d> expr Uma gramática, tal como a gramática da língua 12
    • A PROGRAMAR BYAC Cportuguesa, serve para nos indicar a estrutura faz sentido criar várias produções para um stmt,da linguagem, quais as composições de já que um stmt pode ser várias coisas. Nesteelementos que são válidas ou não de acordo caso, um while, um if, um bloco, e continuandocom a linguagem. É fácil de ver como isto é útil teríamos um for, um switch, um do while, etc.para um compilador. A nossa calculadora tem Sendo usual a existência de várias produçõesuma gramática muito simples, mas ainda assim com a mesma cabeça, o byacc permite usar atem-la, portanto temos que compreender alguns seguinte sintaxe, com significado equivalente,princípios sobre gramáticas. As gramáticas são para aumentar a legibilidade:um conjunto de regras, às quais chamamos stmt : WHILE expression stmtproduções, constituídas por uma cabeça e um | IF expression stmtcorpo. Por exemplo, | IF expression stmt ELSE stmt | block stmt : WHILE expression stmt; ... ;é uma produção, com cabeça stmt e corpoWHILE expression stmt. A cabeça indica-nos Se quiséssemos escrever um parser para umauma construção da gramática e o corpo como linguagem de programação, tínhamos de terela é composta. Os elementos duma gramática uma forma de relacionar as várias regras, pordividem-se em símbolos terminais e não outras palavras uma gramática necessita determinais, sendo os terminais, para efeitos deste uma estrutura. A forma de criar essa estrutura éartigo, os tokens que o scanner envia e os não- criando um símbolo não terminal inicial ao qualterminais as cabeças de produções, ou seja todos os outros estão subordinados. Pode ajudarsímbolos que podem ser produzidos através pensar na estrutura da gramática como umadoutros símbolos. árvore na qual o símbolo não terminal inicial é a raiz, os outros não terminais são nós e osPor clareza, usamos maiúsculas para terminais são as folhas.representar terminais e minúsculas para nãoterminais, logo, no exemplo acima, stmt e %%expression são símbolos não terminais enquantoque o WHILE é terminal. Um símbolo terminal program : listnão pode ser obtido através da junção de outros ;símbolos, portanto só pode aparecer em corposde produções. Um não terminal por outro lado list : statementpode ser derivado de terminais e outros não | list statementterminais, logo pode aparecer tanto na cabeça ;como no corpo duma produção. Um símbolo nãoterminal pode, e habitualmente, tem várias statement : declarationdefinições. Pegando no exemplo anterior e | functionexpandindo, obtemos, ; stmt : WHILE expression stmt; declaration : type identifier stmt : IF expression stmt; | type identifier = stmt : IF expression stmt ELSE stmt; expression stmt : block; ; ... 13
    • A PROGRAMARBYAC C s : x | y type : INT ; | DOUBLE x : A B C ; | CHAR y : A B C ; ; Este caso é óbvio, temos duas produções function : type identifier ( arg_list ) diferentes com o mesmo corpo, o parser não block sabe qual deve usar quando recebe os três ; tokens. O mesmo se passa nos casos seguintes. block : { stmt_list } s : x ; | y ; stmt_list : stmt x : A B C ; | stmt_list stmt y : A z C ; ; z : B ; ... %% s : x | yAcima temos um esqueleto de uma linguagem ;muito simplificada, ainda com vários não x : A B C ;terminais sem produções associadas, mas basta y : z C ;para termos uma noção da estrutura duma z : A B ;gramática. Qualquer que seja o programa escritopara esta linguagem, se ele estiver O byacc só tem um token de lookahead, ou seja,sintacticamente correcto deve ser possível partir no caso abaixo ele não consegue decidir se ode program e derivar todos os elementos que o que recebeu foi o x ou o y porque no momentocompõem. Neste caso program é o símbolo de escolher a produção ele só sabe que o seinicial da gramática, e indicamos isso ao byacc segue é o token C. Como existem dois casoscolocando-o como a primeira produção do com o token C, ele não sabe o que fazer. Istoficheiro. não é um problema com a gramática, é umaJá vimos nos exemplos anteriores que as limitação do byacc.produções podem ser recursivas, o corpo dumaprodução pode conter o mesmo não terminal s : x C Dque é a cabeça. A recursividade é necessária e | y C Falgo que o byacc processa muito eficientemente, ;mas usada sem cuidado é uma das coisas que x : A B;introduz conflictos na gramática. Um conflicto y : A B;surge quando o parser não sabe que regra usarpara uma determinada sequência de tokens. Um O mesmo não ocorre no caso seguinte. Nestaexemplo segue-se: situação ele consegue saber que produção usar vendo se o lookahead é D ou F. 14
    • A PROGRAMAR BYAC C s : x D %nonassoc IFX | y F %token ELSE ; x : A B; ... y : A B; %%A existência de conflictos na gramática nãoimpede o parser de ser gerado, já que o byacc ...tem comportamentos default quando não sabeque produção usar, mas claro que o stmt : IF expression stmt %prec IFXcomportamento default pode não ser o que o | IF expression stmt ELSE stmtprogramador tinha em mente quando escreveu a ;gramática portanto convém eliminar os conflictosantes de gerar o parser. ... %%Os conflictos são introduzidos na escrita dagramática e podem sempre ser eliminadosreescrevendo-a, mas por vezes é preferível Introduzimos o token IFX - o token ELSE já temeliminá-los usando precedências. Tomemos o de estar definido, tal como o IF se o estamos aseguinte exemplo clássico, o “dangling else”: usar na gramática - que não é retornado pelo scanner. O IFX só existe dentro do parser e stmt : IF expression stmt serve apenas para indicar o nível de | IF expression stmt ELSE stmt precedência de uma produção. Indicamos ao ; byacc o nível de precedência dos tokens pela ordem em que os declaramos, tendo os últimosPara o seguinte input: maior precedência que os primeiros. A precedência de um token determina a if(a) precedência da produção em que ele se if(b) c = a + b; else c = a; encontra, numa situação em que duas produções são viáveis como no exemplo anteriorO problema que nos surge é que o parser não a produção com maior precedência é usada. Sesabe se o que ele tem é um IF expression stmt quisermos modificar a precedência de umacom expression igual a (a) e o stmt igual a if(b) c produção sem afectar a precedência de nenhum= a + b; else c = a; ou se em vez disso tem um dos seus tokens, podemos, como mencionadoIF expression stmt ELSE stmt com expression previamente, criar um token “falso” como o IFX etambém igual a (a), o primeiro stmt igual a if(b) c escrever %prec IFX no fim da produção para o= a + b; e o segundo stmt igual a c = a;. O que conseguir. Usando o token IFX no primeiro IFqueremos que o parser faça? Associe o else ao estamos a dizer que aquele tipo de if tem menosprimeiro if ou ao segundo? O comportamento precedência que o segundo IF,já que o token IFXque esperamos é que associe ao segundo, é declarado antes do token ELSE, portantoportanto para o conseguir vamos usar quando existem as duas hipóteses o parserprecedências. escolhe sempre a segunda, o que é o comportamento que desejávamos. 15
    • A PROGRAMARBYAC C expr : expr * expr | expr ^ expr | NUMBER | ( expr ) ; ;Neste caso para o input NUMBER * NUMBER * Dizemos que os operadores binários + e - sãoNUMBER por exemplo, o parser não sabe se há- associativos à esquerda e têm a mesmade fazer (NUMBER * NUMBER) * NUMBER ou precedência. Os operadores * e / funcionam deNUMBER * (NUMBER * NUMBER). Para forma idêntica mas têm maior precedência. Oresolver este problema precisamos de indicar a operador de potência ^ é associativo à direita eassociatividade do operador binário * ao byacc. tem a maior precedência de todos os operadoresUm operador com associatividade à esquerda binários. O UMINUS indica que uma expressãopara o input NUMBER * NUMBER * NUMBER * negada tem a maior precedência e que não seNUMBER faz ((NUMBER * NUMBER) * pode negar uma negação. Os parênteses forçamNUMBER) * NUMBER, um operador com a avaliação de qualquer que seja a expressãoassociatividade à direita faz NUMBER * que estiver dentro deles, contornando as(NUMBER * (NUMBER * NUMBER)) para o precedências caso seja necessário. Para o input,mesmo input. A forma de indicar a -1 ^2 + 5 + 3 - 2 * 3 ^ 4 ^ 5 / -6 / 2 - 5 a nossaassociatividade de um token ao byacc é gramática vai fazer (((((-1 )^2) + 5) + 3) - (((2 * (3escrever %left ou %right em vez de %token ^ (4 ^ 5))) / (-6)) / 2)) - 5 como seria de esperar.quando o declaramos. Para declarar umoperador unário não associativo (ou seja um Podemos associar acções a cada produção,operador que não se pode encadear) para serem executadas quando o parser acabaescrevemos %nonassoc em vez de %token. de processar o corpo de uma produção e o substitui pela cabeça. As acções indicam-se daEntendendo associatividade e precedências mesma forma que no scanner, e é possível usarpodemos começar a compreender a gramática elementos da produção dentro delas desde queda nossa calculadora. eles tenham valores associados. Para indicar o valor da cabeça usamos $$, para os membros %token NUMBER do corpo usamos $1 , $2, … $n de acordo com a ordem em que eles aparecem. Um não terminal %left + - tem por default associado um int. Se quisermos %left * / associar um tipo diferente declaramos %right ^ %type<tipo-do-valor-associado> nome-do- %nonassoc UMINUS símbolo-não-terminal na primeira secção do ficheiro. Vejamos então o ficheiro inteiro: %% %% expr : NUMBER %{ | - expr %prec UMINUS #include <iostream> | expr + expr #include <cmath> | expr - expr %} | expr * expr | expr / expr 16
    • A PROGRAMAR BYAC C tipos associados, %union { associatividade e double d; precedência. Concluímos a }; primeira secção com a declaração que o símbolo não %token<d> NUMBER terminal expr tem um valor %token NL associado do tipo double. Isto %left + - é essencial porque as nossas %left * / operações não estão a %right ^ receber tokens NUMBER %nonassoc UMINUS como argumentos mas sim %type<d> expr não terminais expr. O símbolo inicial da nossa gramática é %% expr_list e está definido como expr_list : expr NL { std::cout << $1 << std::endl; } uma sequência de um ou mais | expr_list expr NL { std::cout << $2 << std::endl; } não terminais expr, separados ; por mudanças de linha. Associamos a cada produção expr : NUMBER { $$ = $1; } de expr_list a acção da | - expr %prec UMINUS { $$ = -$2; } impressão do valor de expr. | expr + expr { $$ = $1+$3; } As produções com cabeça | expr - expr { $$ = $1-$3; } expr tem associadas as | expr * expr { $$ = $1*$3; } acções que realizam os | expr / expr { $$ = $1/$3; } cálculos, guardando os | expr ^ expr { $$ = pow($1, $3); } valores na cabeça. Na terceira | ( expr ) { $$ = $2; } secção temos um main que ; chama o yyparse(). %% int main() Neste momento temos um { parser e um scanner para a yyparse(); nossa calculadora, no próximo } artigo veremos como ligá-los eO ficheiro começa com os #includes de C++ que como modificar o scanner e oprecisamos, seguidos da %union com o único parser em conjunto de forma a adicionar maistipo que a nossa calculadora necessita, um funcionalidades à calculadora.double. Lemos a declaração dos tokens, com os AUTOR Escrito por João Mares Estando actualmente no terceiro ano de LEIC no IST, interssa-se preferencialmente por arquitectura de computadores e computação gráfica. 17
    • VISUAL (NOT) BASICI n tro d u ç ã o a o E n ti ty Fra m e wo rkO ADO.NET Entity Framework permite criar tenham como nome “Jorge” e que tenham comoaplicações em que o acesso a dados é feito com morada a “Moita”.base em um modelo conceitual e não utilizandocomandos directos à base de dados. Isto Imaginemos que o programador ou o DBApermite que o programador se abstraia (database administrator) altera o campo “nome”totalmente da base de dados (criação de para “nomecompleto”, pois quer que se registe oligações de acesso, comandos, parâmetros, etc.) nome completo do utilizador e, desta forma, oe utilize apenas objectos durante o nome do campo fica mais coerente. Sedesenvolvimento. aplicação for compilada não é detectado qualquer problema e só no momento deA versão 4.0 do Entity Framework (actual), que execução irá ocorrer um erro. Situações comoestá disponível na .NET Framework 4.0, tem um estas são muito frequentes e podemconjunto de novas funcionalidades e melhorias, representam vários erros na aplicação.como é o caso de suporte a POCO - Plain OldCLR Objects (permite criar classes que não Este é apenas um exemplo de como se podeherdam, nem implementam nenhuma outra beneficiar, e muito, da utilização do Entityclasses ou interface), abordagem Model-First Framework, mas existem muito mais vantagens(permite criar primeiro o modelo conceptual e, como a utilização de LINQ to Entities,com base nele, criar a base de dados), suporte intellisense no momento em que se está apara o uso de funções em LINQ-to-Entities, escrever o código, código mais fácil de manter eComplex Types (criação de tipos de dados actualizar, etc, etc.complexos), Deferred Loading ou Lazy Loading(capacidade de carregar as propriedades de Neste artigo, que será uma breve introdução aoassociação das entidades no momento em são Entity Framework, irá apenas mostrar comochamadas, se forem chamadas), etc. Não é construir um modelo relacional de uma base deespecifica apenas para o SQL Server, pois dados SQL, uma abordagem database-first, eexistem providers que permitem usar outras como executar algumas operações CRUD.bases de dados, como Oracle, MySql,PostgreSQL, DB2, SQL Anywhere, Ingres, CRIAÇÃO DO MODELO RELACIONALProgress, Firebird, Synergy, etc. (database-first)Existem várias vantagens na utilização de um Para criação de um modelo relacional iremosORM (Object-relational mapping), que tornam a usar a seguinte base de dados SQL:sua adopção quase inevitável, mas vejamos oseguinte exemplo:“SELECT * FROM utilizadores WHERE nome =‘Jorge’ AND morada = ‘Moita’”Este exemplo irá listar todos os utilizadores que 18
    • VISUAL (NOT) BASIC I n tro d u ç ã o a o E n ti ty Fra m e wo rk Para o nome da ligação, e para este exemplo,Como é possível ver nesta imagem, existem utilize “vendasEntities“.apenas 3 tabelas, com as respectivas chavesprimárias/estrangeiras: produtos, clientes e uma A última opção deste Wizard é onde sãoterceira tabela onde se registam os movimentos. seleccionados os objectos a utilizar no modelo. Neste exemplo são escolhidas as três tabelas jáO primeiro passo é adicionar um novo item ao referidas.projecto (menu Project – Add New Item), eseleccionar no grupo de templates “Data” o item“ADO.NET Entity Data Model”. Isto irá iniciar umWizard que permitirá criar o modelo final.De seguida seleccionar “Generate fromdatabase” e carregar em “Next”. Após este processo está criado o ficheiro EDMX,A próxima opção permite fazer a ligação à base que não é mais do que um conjunto de classes ede dados, escolhendo uma já existente ou métodos que nos permitirá aceder à base decriando uma nova ligação. dados de uma forma simples, como iremos ver de seguida. OPERAÇÕES CRUD As operações CRUD (acrónimo de Create, Read, Update e Delete em Inglês) são quatro operações básicas e fundamentais para a manipulação de bases de dados. São por isso 19
    • VISUAL (NOT) BASICI n tro d u ç ã o a o E n ti ty Fra m e wo rkbastante importantes e requerem, sem autilização de um ORM como o Entity Framework, context.clientes.AddObject(cliente)algum trabalho que é normalmente complexo. context.SaveChanges()Com o Entity Framework este trabalho está Podemos verificar logo o númerobastante simplificado para o programador, (ID) do registo inseridonecessitando apenas de algumas linhas de Debug.WriteLine("Número de registo: " &código, com recurso a IntelliSense, para as cliente.id.ToString())executar. End UsingO funcionamento para todas as operações ésemelhante: é criada uma nova instância danossa entidade (neste exemplo “vendasEntities”) Apagar registosque herda de uma classe da EntityFrameworkchamada ObjectContext, que a classe primária e Para apagar um registo é necessário seleccionarresponsável de gerir a informação como o registo correcto, neste caso usando umaobjectos e a ligação dos objectos aos dados. Lambda Expression, e caso o resultado seja válido, executamos o método DeleteObject(),Inserir registos indicando o registo a apagar.Para inserir novos registos, neste caso um novo Finalmente gravamos as alterações na base decliente, criamos uma nova instância da dados.respectiva classe, definindo as suaspropriedades, que correspondem aosrespectivos campos. Depois adicionamos oobjecto através do método AddObject() e, Using context As New vendasEntitiesfinalmente, executamos o métodoSaveChanges() que irá efectuar as respectivas Procura o registo com o número dealterações, neste caso inserir um registo, na cliente (ID) igual a 1base de dados. Dim cliente = context.clientes.Where( Function(c) c.id = 1). FirstOrDefault() Using context As New vendasEntities If cliente IsNot Nothing Then context.clientes.DeleteObject(cliente) Cria um novo cliente context.SaveChanges() Dim cliente As New clientes With Else { MessageBox.Show( .nome = "Rui Paulo", "Número de cliente inválido") .morada = "Lisboa", End If .datanascimento = New DateTime(1980, 10, 31) End Using } 20
    • VISUAL (NOT) BASIC I n tro d u ç ã o a o E n ti ty Fra m e wo rkModificar Registos Using context As New vendasEntitiesPara modificar um registo, e à semelhança da Dim listaClientes =operação anterior, é necessário seleccionar o From c In context.clientesregisto. Neste exemplo utilizamos LINQ to Where c.morada.Contains("Lisboa") AndEntities para fazer essa selecção. Depois, c.datanascimento <modificamos o que for para modificar e New DateTime(1985, 1, 1)finalmente gravamos as alterações. Select c Using context As New vendasEntities For Each c As clientes In listaClientes Debug.WriteLine(c.nome) Dim cliente = Next (From c In context.clientes Where c.id = 1 End Using Select c).FirstOrDefault() Entre entidades existir normalmente If cliente IsNot Nothing Then associações, e essas associações (também With cliente representadas na última imagem), têm algo que .nome = "Rui Paulo" se designa por Navigation Properties. As .morada = "Setúbal" Navigation Properties permitem uma navegação .datanascimento = bidireccional entre entidades, de acordo com as New DateTime(1979, 10, 31) suas associações. Isto é algo bastante prático End With pois permite-nos criar queries entre várias context.SaveChanges() entidades usando LINQ to Entities. Else MessageBox.Show( O seguinte exemplo mostra esta abordagem, "Número de cliente inválido") definindo depois o resultado como DataSource End If num controlo DataGridView. End Using NOTA: Se utilizar uma base de dados anexa ao Using context As New vendasEntitiesListar Registos Dim listaClientes = From c In context.clientesA listagem de registo é também muito Join m In context.movimentossemelhante às operações anteriores. Neste On m.clienteid Equals c.idexemplo, usando LINQ to Entities, vamos Join p In context.produtosseleccionar todos os registo com base num On m.produtoid Equals p.idcritério, para uma variável do tipo IQueryable(Of Select m.datavenda,T), e depois efectuamos um ciclo para mostraros resultados obtidos. 21
    • VISUAL (NOT) BASICI n tro d u ç ã o a o E n ti ty Fra m e wo rk Select m.datavenda, especiais), etc c.nome, p.produto, Estas são apenas algumas, das muitas m.preco vantagens, que nos devem fazer de uma vez por todas, deixar de usar SqlCommands, Me.DataGridView1.DataSource = listaClientes SqlConnections, DataSets, etc. End Usingprojecto (AttachDb), a base de dados é copiadapara as pastas Debug/Release. Pode Alguns recursos interessantes:seleccionar no menu Project a opção Show AllFiles e verificar as alterações nessa localização. Data Developer Center http://msdn.microsoft.com/en-us/data/ef.aspxCONCLUSÃO Data Access Hands-on Labs http://msdn.microsoft.com/en-Como foi possível ver ao longo do artigo, que us/data/gg427655.aspxabordou de uma forma muito superficial algumasdas funcionalidades deste ORM, o Entity ADO.NET team blogFramework é uma excelente opção para se http://blogs.msdn.com/b/adonet/trabalhar com bases de dados. Julie Lermans BlogÉ simples de utilizar, permite-nos trabalhar http://thedatafarm.com/blog/apenas com objectos e com intellisense, resolveinúmeros problemas que são habituais quandotrabalhamos directamente com a base de dados(formatos de datas, números, caracteres AUTOR Escrito por Jorge Paulino Exerce funções de analista-programador numa multinacional sediada em Portugal. É formador e ministra cursos de formação em tecnologias Microsoft .NET e VBA. É Microsoft Most Valuable Professional (MVP), em Visual Basic, pela sua participação nas comunidades técnicas . É administrador da Comunidade Portugal-a-Programar e membro de várias comunidades (PontoNetPT, NetPonto, MSDN, Experts- Exchange, CodeProject, etc). É autor do blog http://vbtuga.blogspot.com - twitter @vbtuga 22
    • A PROGRAMARPro gra m a ç ã o Fu n c i o n a l c o m Pe rl ( p a rte I )Começo com este artigo uma série de artigos sobre PF por exemplo). Como já há váriosrelacionados com a Programação Funcional em artigos sobre PF em diversas linguagens, comoPerl. Python, Scheme, Haskell (recomendo que os leiam), deixo aqui a sugestão a alguém, paraNesta série de artigos pretendo demonstrar redigir um artigo teórico e agnóstico (em relaçãoalgumas das capacidades do Perl para utilização a linguagens de programação) sobrecom o paradigma de Programação Funcional. Programação Funcional.Não pretendo ensinar nem as bases da Umas das principaisProgramação Funcional, nem do Perl. Vou abrir características do Perlexcepções quando se tratarem de aspectos maisavançados e/ou muito relacionados com a (...) é não obrigar oprópria Programação Funcional. A compreensão programador a utilizar (...)elementar do Perl e da Programação Funcional mas sim permitir aoé um requisito para a compreensão destesartigos contudo tudo será explicado de forma a programador utilizar o quepermitir que um principiante possa compreender quiser quando quisertudo e quem tiver dúvidas poderá contactar-mepara as esclarecer. Algumas das funcionalidades elementares das linguagens funcionais são as funções anónimasUmas das principais características do Perl, em e as closures. O Perl tem ambas as features.seguimento do mantra da sua comunidade(«Theres more than one way to do it»), é não Uma das alterações que o Perl 5.1 2 trouxe foiobrigar o programador a utilizar, ou escolher um uma função chamada say. O say é basicamenteparadigma de programação, mas sim permitir ao um print que adiciona um newline à string queprogramador utilizar o que quiser quando quiser, queremos imprimir (poupa-nos pelo menos 4ficando ao cuidado dele ter os cuidados caracteres).necessários para que o código seja útil e sigaboas práticas de programação. Há quem Qualquer uma das seguintes linhas de códigoconcorde com esta filosofia, há quem não vai imprimir isolado numa linha a string: «Helloconcorde, mas a filosofia do Perl e da sua world!»:comunidade não é o âmbito deste artigo. print "Hello world!n";Um dos muitos paradigmas de programação que print "Hello world!"."n";são possíveis utilizar em Perl é a Programação print "Hello world!", "n";Funcional (PF). Contudo não cabe a este artigo say "Hello world!";explicar a PF. Por isso sugiro que antes deprosseguirem na leitura deste artigo leiam pelomenos uma curta explicação do que é PF (osprimeiros parágrafos do artigo da Wikipedia 23
    • A PROGRAMARPro gra m a ç ã o Fu n c i o n a l c o m Pe rl ( p a rte I )Para demonstrar a utilização de funções utilização nas "dispach tables":anónimas decidi criar uma implementação dafunção say que permite definir antes da sua my %lingua = ( #dispach tableutilização como queremos que a string seja "pt" => sub { return "Olá mundo!" },formatada: "es" => sub { return "Hola mundo!" }, "en" => sub { return "Hello world!" }, sub say { #definição da função say "fr" => sub { return "Bonjour monde!" }, my ($string, $format) = @_; ); my $str = $format->($string); print $str; sub dispach { } my $l = shift; my $format = sub { #função anónima de if(defined $lingua{$l} && exists formatação da string $lingua{$l}) { my $str = shift; my $str = $lingua{$l}->(); return $str."n"; print $str."n"; }; } say("Hello world!", $format); else { print "Erro: lingua desconhecida!n"; }Explicação do código do exemplo anterior: } dispach("fr");Primeiro começamos por definir a função say,como definiríamos qualquer outra função emPerl. Depois definimos a função anónima deformatação, e atribuímos essa função a umavariável (que guarda uma referência para Explicação do código do exemplo anterior:código) para que possa ser passada de formavisualmente mais limpa à função say Começou por ser definido uma hash table que,(poderíamos também ter definido a função como chaves contém, as opções válidas deanónima, na invocação de say mas faria com línguas que queremos utilizar na impressão deque o código fosse muito menos legível). uma saudação e como valores, tem funções anónimas que imprimem uma saudação na língua representada pela sua chave na hashQual a utilidade das funções anónimas? table.As utilidades são diversas. E vão desde a Isto poderia ter sido feito definindoutilização das funções anónimas para poder individualmente funções "regulares", criandomodificar o comportamento de uma função que variáveis que eram referências para cada umatenha sido criada para poder permitir essa dessas funções e utilizando essas variáveisalteração. Há quem utilize isto para poder por como valores a utilizar na hash table.exemplo poder voltar a correr código que tinhasido serializado. E passam pela utilização em Mas isso traria imediatamente dois problemas:"dispach tables". Uma outra utilidade é a aumentaria a quantidade de código necessário e este artigo tem um limite de caracteres; não 24
    • A PROGRAMAR Pro gra m a ç ã o Fu n c i o n a l c o m Pe rl ( p a rte I )utilizaria funções anónimas, que é o objectivo solução escale para mais opções de línguas,deste exemplo ;). sem qualquer alteração e atinge melhor vários dos objectivos da utilização de funções naPara além de isso, o que é pretendido neste programação: conter/isolar os problemas deexemplo, é algo tremendamente simples que forma a simplificar a sua resolução, facilitar apode perfeitamente ser feito utilizando funções compreensão do código.anónimas, sem se aumentar a dificuldaderelevante da sua compreensão como um todo eem parte. No próximo, artigo vou falar da segunda das principais capacidades do Perl para a Programação Funcional de que falei antes, asA opção por esta solução, em vez de a utilização closures.de um encadeamento maior de if-elsif, ou de umswitch-case (também maior) permite que a (...) permite que a solução escale para mais opções de línguas, sem qualquer alteração e atinge melhor vários dos objectivos da utilização de funções na programação (...) AUTOR Escrito por Diogo Constantino é Consultor na área as tecnologias licenciadas como Software Livre, com aproximadamente vários anos de experiência profissional, especializado em desenvolvimento com Perl. Larga experiência na área de sistemas, engenharia e de operações de redes de telecoms, tendo desenvolvido, mantido e utilizado ferramentas para diversas telecoms nestas áreas. Conhecimentos em tecnologias como Perl, Python, PHP, MySQL, GNU/Linux, C, HTML, CSS, Javascript, GNU/Linux. Tendo tido ainda contacto profissional com tecnologias como Switchs, equipamentos de routing, firewalling e switching de diversos fabricantes, diversos sistemas *nix e diversas outras ferramentas e tecnologias comuns em sistemas *nix e/ou utilizadas em empresas de telecomunicações, redes e web. Relativamente conhecido advogado da causa do Software Livre em diversas comunidades. Sócio da Associação Nacional para o Software Livre e da Associação Portuguesa de Programadores de Perl. 25
    • COMUNIDADE NETPONTOB a c kgro u n d Wo rke rs - I m p l e m e n ta ç ã o p rá ti c a e mWi n d o ws Pre s e n ta ti o n Fo u n d a ti o n ( WPF)Neste artigo pretendo mostrar o que é o System.ComponentModel. Esta classe permite-BackgroundWorker e vou exemplificar como se nos ajudar a gerir uma tarefa numa threaddeve proceder à sua implementação usando a separada da thread principal sem termos de nostecnologia WPF na versão .Net Framework 4. preocupar com a inicialização e gestão da thread onde vamos executar a tarefa.Suponhamos: As propriedades a ter em conta são:“Tenho um algoritmo complexo de Optimização Combinatória que irá ter como parâmetro de CancellationPending entrada um objecto do tipo World. Classe que Permite obter se a tarefa foi cancelada. define toda a estrutura de dados da minha aplicação e no final retorna o objecto World com WorkerReportsProgress as alterações realizadas pelo algoritmo.” Permite obter e definir se o BackgroundWorker vai reportar o seu progresso da tarefa.Esta geração vai implicar que tenhamos pelomenos três passos: WorkerSupportsCancellation1 . A partir do objecto World vamos criar a Permitir obter e definir se o BackgroundWorkerestrutura de dados do algoritmo; vai permitir cancelar a tarefa.2. Gera-se o algoritmo a partir dos dadosrecebidos; Os métodos a ter em conta são:3. Depois de gerar o algoritmo é precisoconverter o resultado de forma a reflectir no RunWorkerAsyncWorld o resultado do algoritmo; Permite iniciar a tarefa. Existem duas assinaturas deste método. UmaEnquanto estes três passos estão a decorrer, eu delas não tem argumento, a outra que o temquero ser informada sobre o progresso da utiliza-o na execução da tarefa.geração do algoritmo e pretendo ter acapacidade de a cancelar. CancelAsync Permite cancelar a tarefa e consequentemente oEste cenário é um dos muitos cenários onde o BackgroundWorker irá terminar.BackgroundWorker pode ser implementado. Para que seja possível cancelar a tarefa éOutros exemplos reais são a leitura de ficheiros necessário que a propriedadeextensos, aceder a base de dados para efectuar WorkerSupportsCancellation tenha o valor deo carregamento de dados, fazer o load de verdade true.imagens e gerar relatórios. ReportProgressAntes de passarmos à implementação vou dar Permite reportar o progresso da tarefa em dadouma breve apresentação teórica: momento. Para que o progresso seja reportado éUm BackgroundWorker é uma classe contida no necessário que o WorkerReportsProgress tenha 26
    • COMUNIDADE NETPONTO B a c kgro u n d Wo rke rs - I m p l e m e n ta ç ã o p rá ti c a e m Wi n d o ws Pre s e n ta ti o n Fo u n d a ti o n ( WPF)o valor de verdade true. três propriedades relevantes.Este método apresenta duas assinaturas, São a propriedade Cancelled - que nos informaReportProgress(int percentProgress) e se a tarefa foi cancelada, a propriedade Error -ReportProgress(int percentProgress, object que nos reporta a excepção que fez terminar auserState). Ambas permitem reportar a tarefa e a propriedade Result - que representa opercentagem da tarefa que já foi realizada. Na resultado da execução da tarefa.última assinatura é possível enviar maisinformação sobre o estado da tarefa. Vamos agora passar à implementação prática, para isso vou usar um projecto doOs eventos a ter em conta: tipo WPF Application.DoWork Na interface da janela vamos ter:Ocorre quando o método RunWorkerAsync é - Um Button para executar a tarefa;chamado. - Um Button para cancelar a tarefa;Ao subscrever este evento é definido um handler - Um Progressbar para mostrar o progresso;que recebe dois parâmetros: - Uma Listbox que indica mais detalhes- Um parâmetro do tipo object que representa o do progresso.objecto que subscreveu o evento.- Um parâmetro do tipo DoWorkEventArgs quecontém informação respeitante ao parâmetro deentrada e permite devolver o resultado da tarefa.De referir ainda que este parâmetro possui duaspropriedades relevantes. Sendo elas, apropriedade Argument - que representa oobjecto que é enviado como parâmetro dométodo RunWorkerAsync e a propriedade Result- que representa o resultado do DoWork. Toda a interface é definida no ficheiro .xaml. Em Code Behind iremos proceder àProgressChanged implementação de toda a funcionalidade paraOcorre quando o método ReportProgress é resolver o problema em causa.chamado.Um dos parâmetros do handler deste evento é 1. Comecemos então por definir uma variávelum objecto do tipo ProgressChangedEventArgs, global:que contém duas propriedades relevantes, quesão o ProgressPercentage e UserState, cujos private BackgroundWorker _backgroundWorker;valores foram enviados pelo métodoReportProgress;RunWorkerCompleted 2. De seguida vamos criar um método ondeOcorre quando a tarefa é terminada, cancelada vamos fazer a inicialização desta variável eou é lançada uma excepção. definir as suas propriedades e subscrever osUm dos parâmetros do handler deste evento é eventos:um objecto do tipoRunWorkerCompletedEventArgs, que contêm 27
    • COMUNIDADE NETPONTOB a c kgro u n d Wo rke rs - I m p l e m e n ta ç ã o p rá ti c a e m Wi n d o ws Pre s e n ta ti o n Fo u n d a ti o n ( WPF) private void InitializeBackgroundWorker() private void RunBackground_Click( { object sender, _backgroundWorker = RoutedEventArgs e) new BackgroundWorker(); { ClearProgress(); _backgroundWorker.DoWork += new DoWorkEventHandler(DoWork); _backgroundWorker.RunWorkerAsync( (object)_world); _backgroundWorker.ProgressChanged += btnCancel.IsEnabled = true; new ProgressChangedEventHandler( btnRunBackground.IsEnabled=false; ProgressChanged); } _backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler( RunWorkerCompleted); Caso não pretendêssemos enviar parâmetros _backgroundWorker.WorkerReportsProgress = true; usávamos a assinatura do RunWorkerAsync _backgroundWorker.WorkerSupportsCancellation sem parâmetros. = true; } 5. No handler do evento do Click do btnCancel vamos mandar cancelar a tarefa, chamando o método CancelAsync.De notar que já estou a definir que o meuobjecto _backgroundWorker vai permitir que a private void btnCancel_Click(tarefa seja cancelada a meio e que o progresso object sender, RoutedEventArgs e) {da tarefa possa ser reportado. _backgroundWorker.CancelAsync(); btnCancel.IsEnabled = false; btnRunBackground.IsEnabled = true;3. Agora vamos definir os handler dos }eventos: 6. Neste momento estamos prontos para private void DoWork definir a tarefa (handler): (object sender, DoWorkEventArgs e) {} private void DoWork(object sender, private void ProgressChanged (object sender, ProgressChangedEventArgs DoWorkEventArgs e){} args) {} É executado quando o método RunWorkerAsync private void RunWorkerCompleted é chamado. Consideremos a seguinte porção de (object sender, código: RunWorkerCompletedEventArgs e) {} private void DoWork(object sender, DoWorkEventArgs e) {4. No handler do evento do Click do Algorithm algorithm = new Algorithm(); World world = (World)e.Argument;btnRunBackground vamos mandar executara tarefa e como parâmetro vamos enviar o object stepValue = world;objecto _world. foreach (IAlgorithmStep step in algorithm.Steps) {stepValue = step.DoWork(stepValue);} e.Result = stepValue; } 28
    • COMUNIDADE NETPONTO B a c kgro u n d Wo rke rs - I m p l e m e n ta ç ã o p rá ti c a e m Wi n d o ws Pre s e n ta ti o n Fo u n d a ti o n ( WPF)Note-se que vou obter o objecto do tipo World object stepValue = world;que foi enviado por parâmetro e em seguida vouiterar pelos vários passos do algoritmo. foreach (IAlgorithmStep step in algorithm.Steps) { ifPor fim vou devolver o resultado da tarefa. (_backgroundWorker.CancellationPending) { _backgroundWorker.ReportProgress(10,Aparentemente posso pensar que já defini a string.Format( "{0} is canceled.", step.Name));minha tarefa, no entanto, ainda não estou a ter e.Cancel = true;em conta que poderei cancelar a execução do return; }algoritmo nem estou a reportar o progresso. else { _backgroundWorker.ReportProgress(10, private void DoWork( object sender, string.Format( DoWorkEventArgs e) "{0} is starting.", step.Name)); { Algorithm algorithm = new Algorithm(); stepValue = World world = (World)e.Argument; step.DoWork(stepValue); object stepValue = world; _backgroundWorker.ReportProgress(20, string.Format( foreach "{0} is finished.", step.Name)); (IAlgorithmStep step in algorithm.Steps) } { } if (_backgroundWorker.CancellationPending) e.Result = stepValue; { e.Cancel = true; _backgroundWorker.ReportProgress(5, return; "Finished."); } else } { stepValue = step.DoWork(stepValue); Neste momento já temos a nossa tarefa definida } } tendo em conta as operações que pretendíamos. e.Result = stepValue; } 7. Para que o progresso seja apresentado na interface com o utilizador é preciso definir oA cada passo do algoritmo vou verificar se a seguinte handler:tarefa foi cancelada através da propriedadeCancellationPending e consoante o valor de private void ProgressChanged(object sender,verdade desta propriedade a tarefa continua ou ProgressChangedEventArgs args){}não. Que é executado quando o métodoPor fim temos que reportar o progresso de cada ReportProgress é chamado.passo e para isso vamos recorrer ao métodoReportProgress. private void ProgressChanged( object sender, ProgressChangedEventArgs args) private void DoWork( object sender, DoWorkEventArgs e) { { progressBar.Value += Algorithm algorithm = new Algorithm(); args.ProgressPercentage; lbxProgress.Items.Add( World world = (World)e.Argument; args.UserState.ToString()); } _backgroundWorker.ReportProgress( 5, "Is starting..."); 29
    • A PROGRAMARB a c kgro u n d Wo rke rs - I m p l e m e n ta ç ã o p rá ti c a e m Wi n d o ws Pre s e n ta ti o n Fo u n d a ti o n ( WPF)Desta forma actualizamos o progresso na tarefa. Caso tenha ocorrido um erro, este seráinterface com o utilizador. apresentado ao utilizador.8. Para terminar, vejamos o handler: Em conclusão, a implementação de um BackgroundWorker permite-nos correr umaprivate void RunWorkerCompleted(object tarefa numa thread separada sem que estasender, RunWorkerCompletedEventArgs e){} interfira com a interface com o utilizador. Permite-nos ainda ter a capacidade de:Que é executado depois do DoWork ter - Cancelar a tarefa;terminado, ter ocorrido uma excepção ou a - Reportar o progresso da tarefa;tarefa ter sido cancelada. - Actualizar os controlos de WPF enquanto a tarefa decorre. private void RunWorkerCompleted( object sender, RunWorkerCompletedEventArgs e) { if (!e.Cancelled) { try { _world = (World)e.Result; A comunidade NetPonto é uma iniciativa } independente e sem fins lucrativos, que tem catch { como simples e único objectivo a partilha de lbxProgress.Items.Add( conhecimento na área de arquitectura e e.Error.Message); lbxProgress.Items.Add( desenvolvimento de software na plataforma "Aborted."); progressBar.Value = .NET, na tentativa de disseminar o conhecimento progressBar.Maximum; diferenciado de cada um de seus membros. } } else Cada um de nós tem diferentes talentos, e com { lbxProgress.Items.Add("Finished."); as dezenas de tecnologias que são lançadas progressBar.Value = todos os dias, é muito difícil (para não dizer progressBar.Maximum; } impossível) estar por dentro de tudo, e essa é btnRunBackground.IsEnabled = true; uma das principais vantagens em fazer parte de btnCancel.IsEnabled = false; uma comunidade de pessoas ligadas à nossa } área. Podemos aprender mais, e mais rápido, com as experiências de cada um.Vou verificar se a tarefa foi cancelada ou não. Visite-nos em http://netponto.orgEm caso de sucesso posso obter o resultado da AUTOR Escrito por Sara Silva É licenciada em Matemática – Especialidade em Computação, pela Universidade de Coimbra, actualmente é Software Developer no Porto. O entusiasmo pela área resultou na obtenção dos títulos de Microsoft Certified Profissional Developer – Windows 3.5, Microsoft Certified Tecnology Specialist – WPF 3.5, WPF 4 e Windows Forms. Faz parte de várias comunidades, tendo uma participação activa na Comunidade NetPonto e no P@P. 30
    • A PROGRAMAR31
    • A PROGRAMARj Qu e ry - O q u ê , c o m o e p o rq u ê ?O objectivo deste artigo é dar a conhecer as dispositivos móveis, pois o seu grande trunfo éprincipais funcionalidades do jQuery, um pouco ser cross-browser entre as várias plataformasda sua história e motivações e fornecer móveis e além disso as próprias themes seremexemplos da sua utilização. adaptadas ao aspecto do dispositivo em uso, fazendo com que o aspecto e usabilidade (lookO jQuery, existente desde 26 de Agosto de 2006, & feel) das aplicações desenvolvidas com estecriado por John Resig, é uma cross-browser plugin não se distingam das aplicações nativasJavaScript library (embora considerado uma do dispositivo, o que é um avanço enorme noverdadeira framework), licenciado ao abrigo do desenvolvimento de aplicações web paraMIT e GNU, fazendo dele software livre, e é o dispositivos móveis.mais usado mundialmente face aos seusconcorrentes (Dojo, MooTools, Prototype). Pode-se acrescentar que tanto o jQuery como o jQuery UI têm um mecanismo de extensibilidadeOs seus objectivos são simplificar a interacção que permite aos programadores criarem pluginscom o DOM (Document Object Model), handling completamente integrados na API, fazendo comde eventos, criação de animações, interacção que actualmente existam cerca de 4000 pluginsAJAX (Asynchronous JavaScript and XML), e, na página oficial de plugins do jQuery.last but not least, ser cross-browser, que foi o De seguida irei apresentar um tutorial muitofactor decisivo para John Resig o criar. básico de como desenvolver com jQuery que irei aprofundar em futuras edições.O jQuery tem uma sub-library de nome jQueryUI, que é um subset do jQuery específico para Para iniciar o desenvolvimento, deve-seanimações e interface visual, fornecendo muitas adicionar uma referência ao ficheiro js quefuncionalidades out-of-the-box, como vários contém o jQuery (minificado) na head do nossocontrolos, um motor de estilos visuais para estes html document: (img.1 )(theme roller), várias funcionalidades utilizadasem interfaces ricos como drag & drop, dialogs, <html>tabs, sliders, entre muitos outros. <head> <script type="text/javascript"O projecto jQuery gerou um spin-off de nome src="jquery-1.4.3.min.js"></script>Sizzle, que é um motor de selectores CSS em <script type="text/javascript">JavaScript, sendo naturalmente utilizado nojQuery, a partir do qual foi gerado. </script> </head>Actualmente a versão do jQuery é a 1 .4.3 e do <body>jQuery UI 1 .8.5. <a href="http://www.portugal-a-Para o futuro, a grande novidade é o jQuery programar.org/">PaP</a>Mobile (do qual já foi feita uma release 1 .0 alpha </body>1 em 1 6 de Outubro de 201 0), que irá </html>revolucionar o desenvolvimento a nível de 32
    • A PROGRAMAR j Qu e ry - O q u ê , c o m o e p o rq u ê ? $(document).ready(function() { $(“a”).bind(“click”, function(event) { alert("Aceder ao site da comunidade Portugal a Programar”); }); }); img.1Para código assim que o nosso documento Existem mais 2 modos de assignar um handlerestiver no estado ready (on document ready), ao evento ready do nosso document:antes do jQuery, o natural seria ter algumcódigo: $(document).bind(“ready”, function() {}); window.onload = function() { alert("on doc ready"); } e o modo mais abreviado e mais utilizado:O problema de executar código neste evento éque este só é executado quando o DOM está $(function() {completamente carregado e todas as referências });externas já foram descarregadas do servidor(imagens, js, css), o que não é nada agradável Neste momento podemos gravar o nossopara o programador. ficheiro HTML com todo o código e testar: Ao testarmos clicar no link, a popup aparece, e Por este motivo, o jQuery tem um evento que é de seguida entramos na página Portugal adespoletado logo que o DOM está carregado, Programar.não esperando pelos recursos externos: <html> $(document).ready(function() { <head> //código aqui <script type="text/javascript" }); src="jquery­1.4.3.min.js"> </script>Podemos adicionar código para ao clicarmos no <script type="text/javascript">link, mostrar um alert: $(document).ready(function() { $(“a”).bind(“click”, function(event) { </html> alert("Aceder ao site da comunidade Portugal a Programar”); }); img.2 33
    • A PROGRAMARj Qu e ry - O q u ê , c o m o e p o rq u ê ? }); </script> $(document).ready(function() { </head> $(“a”).bind(“click”, <body> function(event) { <ahref="http://www.portugal­a­ alert("Deste modo, já não somos programar.org/">PaP</a> direccionados para o site Portugal </body> a Programar”); </html> event.preventDefault(); });Se quisermos prevenir o comportamento por })omissão (default) do nosso clique sobre aâncora, podemos fazê-lo, chamando a funçãopreventDefault do objecto event, que é recebido Para carregarmos o jQuery, a melhor opção éno handler de qualquer evento: utilizar um CDN (Content Delivery Network, queimg. 4 fornece conteúdos na área geográfica do utilizador, de alta disponibilidade e a alta velocidade) da Microsoft ou da Google. Quanto ao script incluído inline, o ideal é ser colocado num ficheiro externo, de modo a não poluir o html. Como pude demonstrar neste pequeno tutorial básico, de iniciação ao jQuery, ele é uma framework tão acessível quanto poderosa e com um potencial cada vez maior e com cada vez img.2 mais funcionalidade, por isso, irei continuar em artigos subsequentes, a aprofundar cada vez mais as suas funcionalidades, truques e dicas, assim como partilhar boas prácticas de desenvolvimento, por isso não percam os próximos artigos! Actualmente existem cerca de 4000 plugins img.3 na página oficial ! 34
    • A PROGRAMAR j Qu e ry - O q u ê , c o m o e p o rq u ê ? Uma framework tão acessível quanto poderosa e com um potencial cada vez maior img.4AUTOR Escrito por Ricardo Rodrigues É técnico Nível III em Informática/Gestão pela Fundação Escola Profissional de Setúbal, tendo ingressado após na FCT da Universidade Nova de Lisboa. Posteriormente frequentou vários cursos da Microsoft em diversas áreas como Windows Forms,ASP.NET, Securing .NET Applications, WCF, WWF, Web Services e COM+ tendo obtido as certificações MCP .NET 2.0, MCAD .NET 1 .1 , MCSD .NET 1 .1 , MCPD Windows, Web e Distributed Applications e MCPD - Enterprise Applications Developer. (MCP Profile) Contribui activamente em comunidades como StackOverflow e também possui um blog/twitter como temática relacionada: Blog / @ricmrodrigues 35
    • A PROGRAMARLu a – Li n gu a ge m d e Pro gra m a ç ã o ( Pa rte 6 )No artigo anterior (quinto artigo desta série) fora usada em conjunto com outras linguagens comoapresentado o tema relacionado ao uso e se fosse um satélite natural para essas outrascriação de funções. Como prometido este artigo linguagens.tratará do tema relacionado ao uso de arquivos.Além deste será tratado também alguns Fica aqui esta questão para ser pensada.aspectos ainda não mencionado sobre oambiente interactivo da linguagem e a obtenção Ambiente Interactivode tamanho de strings. A linguagem de programação Lua possui umUm pouco mais sobre Lua ambiente de trabalho que pode ser usado na forma interactiva.Na primeira parte desta série de artigos foi Neste modo de operação pode-se realizarcomentado um breve histórico sobre o algumas tarefas operacionais. Para tanto, nasurgimento da linguagem Lua. Cabe ainda linha de comando prompt (modo terminal) doacrescentar mais alguns detalhes. sistema operacional em uso faça a chamada doAntes do surgimento da linguagem Lua o programa lua e accione <Enter>. Neste sentidodepartamento de informática da PUC-Rio fazia será apresentada uma mensagem deuso interno das linguagens DEL (Data-Entry identificação semelhante a:Language) e SOL (Simple Object Language) Lua 5.1.4 Copyright (C) 1994-2008 … RioCada uma das linguagens fora desenvolvida >entre 1 992 e 1 993 no sentido de adicionar maiorflexibilidade de interactividade a dois projectos Para sair do prompt do ambiente Lua e retornarde aplicação em computação gráfica para o ao terminal do sistema operacional bastadepartamento de engenharia da empresa executar o comando os.exit() e em seguidaPETROBRAS. Apesar da ideia arrojada, ambas accionar a tecla <Enter> ou <Return> ou aindaas linguagens apresentavam problemas muito usar as teclas de atalho <Ctrl> + <c> ou entãocomuns e foi a partir desses problemas que as teclas de atalho <Ctrl> + <z> + <Enter>ocorreu a junção das linguagens DEL e SOL, dependendo do sistema operacional em uso.dando vez a linguagem Lua. Dentro do ambiente interactivo é possível passarSegundo reza a lenda o nome Lua foi sugerido comandos com o sentido de obter respostas. Pordevido ao uso da linguagem SOL. Mas cabe exemplo, desejando-se obter o resultado daaqui um pouco de devaneio, pois me parece o soma do valor 7.5 com o valor 4.8, bastanome Lua bem mais sugestivo que que uma executar a linha de comando:ocorrência a partir da linguagem SOL. Lua é osatélite natural do planeta Terra. print(7.5 + 4.8)A linguagem Lua é uma linguagem que apesarde sua independência operacional pode ser 36
    • A PROGRAMAR Lu a – Li n gu a ge m d e Pro gra m a ç ã o ( Pa rte 6 )Após accionar a tecla <Enter> ou accionar a Serão apresentados como resultados os valorestecla <Return> obter-se-á o resultado 1 2.3. 6, 0.66666666666667, 5 e -1 . Os cálculos efectivados poderá trabalhar comVeja a seguir uma série de operações com outros formatos numéricos, como notaçãocálculos matemáticos que podem ser cientifica. Por exemplo, desejando-se obter oefectivadas junto ao ambiente interactivo. resultado decimal do valor 9.5e2, sendo: print(-2 + -3) =9.5e2 print(2 * 3) print(10 / 4) Que mostrará como resultado o valor 950, pois print(10 % 4) calcula-se o valor 9.5 multiplicando-se por 1 0 e print(2 ^ 3) elevando-se a potência 2, ou seja, 9.5 x 1 02. print(2 + 5 * 3) Experimente =9.5e-2 para obtenção do resultado print(2 + (5 * 3)) 0.095. print((2 + 5) * 3) Outra possibilidade de operações são os usos de valores hexadecimais convertidos em valoresOs exemplos apresentados anteriormente decimais. Por exemplo, observe os seguintesresultam respectivamente nos valores: -5, 6, 2.5, comandos.2, 8, 1 7, 1 7 e 21 . =0xaO ambiente interactivo retorna mensagens de =0xAerro quando alguma coisa não é escrita dentro =0Xadas regras sintácticas do ambiente. Por =0XAexemplo, execute o código. Ao serem executados os comandos anteriores print(2 + + 3) todos resultam na apresentação do valor 1 0 (A hexadecimal igual a 1 0 decimal). Note que não importa como é definido o valor, seja em formatoOcorrerá a apresentação da mensagem de erro de carácter maiúsculo ou formato de carácterstdin:1: unexpected symbol near + informando minúsculo o resultado será sempre apresentado.que um dos símbolos “+” é desconhecido. O ambiente interactivo permite a definição e usoPara a obtenção de resultados de cálculos de variáveis. Por exemplo, informe as linhas dematemáticos pode-se substituir o comando código seguintes accionando a tecla <Enter> ouprint() pelo símbolo “=” igual a. Desta forma, <Return> para cada linha informada.podem ser definidos os seguintes cálculos. =2*3 A = 2 =2/3 B = 3 =2+3 print(A + B) =2-3 37
    • A PROGRAMARLu a – Li n gu a ge m d e Pro gra m a ç ã o ( Pa rte 6 )Observe o surgimento do valor 5 como resultado Vagarosamente a cada artigo estão sendoda operação. apresentados diversos recursos operacionais que podem ser utilizados junto a linguagem deUm cuidado que se deve tomar na definição de programação Lua. Entre os recursos explanadosvariáveis é com relação ao nome atribuído. Por cabe neste instante abordar o operador “#” deexemplo as seguintes variáveis não são as obtenção de tamanho de um string.mesmas variáveis, pois a linguagem Lua é do Observe a seguir as linhas de código que podemtipo case sensitive. ser executados no ambiente interactivo. COR = 1 print(#" ") COr = 2 print(#"Linguagem Lua") Cor = 3 cor = 4 Cor = 5 Após executar as linhas de código anteriores cOr = 6 serão apresentados os valores 1 e 1 3 que são CoR = 7 respectivamente o tamanho das mensagens um coR = 8 espaço e Linguagem Lua. print(COR) print(COr) Arquivos print(Cor) print(cor) Um dos recursos mais úteis e importantes a ser print(Cor) oferecido por uma linguagem de programação print(cOr) de computadores á a capacidade desta print(CoR) linguagem permitir a manipulação de arquivos. print(coR) A linguagem Lua oferta para o programador uma biblioteca de entrada e de saída para o controloOutro detalhe no uso e definição de variáveis é a das operações de arquivos. A abordagem destepossibilidade de se efectivar a criação de artigo se restringirá em aplicações básicas.múltiplas variáveis. Por exemplo, observe o O programa seguinte apresenta um exemplo decódigo seguinte: programa que cria um arquivo contendo valores numéricos pares situados na faixa de valores CODIGO, NOME = 123, "Paulo" entre 1 um) e 200 (duzentos). print(CODIGO) print(NOME) -- inicio do programa ARQ01 ARQ = io.open("pares.txt","w")Observe que serão apresentados os valores 1 23e Paulo. O símbolo “=” separa os conteúdos das for N = 1, 200 dovariáveis (1 23 e Paulo) das variáveis (CODIGO R = N % 2e NOME). if (R == 0) then ARQ:write(N.."n")Detecção de Tamanho de String end end 38
    • A PROGRAMAR Lu a – Li n gu a ge m d e Pro gra m a ç ã o ( Pa rte 6 ) Este valor poderá ser 1 (se o valor for ímpar) ou ARQ:close() 0 (se o valor for par). -- fim do programa ARQ01 A instrução if (R == 0) then verifica se o valor do resto da divisão é zero, sendo executa a instrução ARQ:write() que escreve no arquivo oEm seguida escreva o código de programa em valor par obtido. O indicativo “n” está sendoum editor de texto, gravando-o com o nome usado para armazenar no arquivo um valorarq01 .lua e execute-o com a linha de comando numérico por linha. Sem este recurso os valoreslua 5.1 arq01 .lua. numéricos seriam armazenados um ao lado do outro.O programa estabelece para a variável ARQestá sendo atribuída pela função io.open() que Ao final a instrução ARQ:close() efectua otem por finalidade abrir um arquivo para escrita, fechamento do arquivo.leitura ou adição. Caso o arquivo não exista omesmo é automaticamente criado. A função Se quiser ver o conteúdo do arquivo basta pedirio.open() utiliza entre aspas inglesas dois para listar seu conteúdo directamente na linhaargumentos para sua operação: de comando do sistema.● nome (primeiro argumento); O programa seguinte efectua a leitura do arquivo● modo (segundo argumento). pares.txt e faz o somatório do valores e mostra seu resultado.O argumento nome caracteriza-se por ser onome do arquivo a ser aberto ou criado, neste -- inicio do programa ARQ02caso pares.txt e o argumento modo indica aforma de operação sobre o arquivo, podendo ARQ = io.open("pares.txt","r")ser: SOMA = 0● r – modo leitura (forma padrão); for VALOR in ARQ:lines() do● w – modo escrita; SOMA = SOMA + tonumber(VALOR)● a – modo adição (inserção); end● r+ – modo actualização, todos os registosexistentes são preservados; ARQ:close()● w+ – modo actualização, todos os registosexistentes são apagados; print(SOMA)● a+ – modo actualização de adição, todos osregistos existentes são preservados e as novas -- fim do programa ARQ02inserções ocorrem após o final do arquivo;● b – modo de operação para manipulação de Em seguida escreva o código de programa emarquivos binários, usado ao lado direito da um editor de texto, gravando-o com o nomedefinição dos modo “r”, “w” e “a”. arq02.lua e execute-o com a linha de comando lua 5.1 arq02.lua.A linha de instrução R = N % 2 obtém o valor doresto da divisão do valor da variável N por 2. 39
    • A PROGRAMARLu a – Li n gu a ge m d e Pro gra m a ç ã o ( Pa rte 6 )O programa anterior faz uso do argumento de ARQ:write(REGISTO.."n")modo r (para leitura) quando da abertura do io.write("[+]registo? S/N ")arquivo pares.txt por parte da instrução RESP = string.upper(io.read())io.open() . endQuando da explanação do uso de laços a ARQ:close()instrução for foi apresentada na sua forma maissimples. Note que neste exemplo a instrução for -- fim do programa ARQ03faz uso do comando in definida como for VALORin ARQ:lines() do. Esta forma de uso dainstrução for denomina-se uso genérico. Em seguida escreva o código de programa em um editor de texto, gravando-o com o nomeNeste caso, a instrução for faz com que a arq03.lua e execute-o com a linha de comandovariável VALOR seja atribuída com o conteúdo lua 5.1 arq03.lua.(in) existente no arquivo pares.txt representadopela variável ARQ. Note o uso da função lines() O programa usa na função io.open() o modo deanexa a variável ARQ que permite avançar no acção a+ para permitir a inserção de novosarquivo uma linha a frente posicionando-se registos ao arquivo.sobre cada um dos registos. Um novidade neste programa é a funçãoA função tonumber() faz com que cada valor string.upper() que transforma em maiúsculo asnumérico armazenado no arquivo na forma de entradas efectuadas junto as variáveis NOME estring quando capturado seja convertido para RESP.sua forma numérica. Apesar da linguagem Luafazer este tipo de conversão automaticamente é O programa seguinte efectua a leitura dos dadosfortemente recomendado que se defina este tipo do arquivo agenda.txt.de operação de forma explicita como feira noprograma arq02.lua. -- inicio do programa ARQ04O próximo programa tem por objectivo fazer a ARQ = io.open("agenda.txt","r")entrada de dados com nome e telefone earmazenar os dados em uma agenda. for REGISTO in io.lines("agenda.txt") do -- inicio do programa ARQ03 io.write(REGISTO.."n") end ARQ = io.open("agenda.txt","a+") ARQ:close() RESP = "S" while (RESP == "S") do -- fim do programa ARQ04 io.write("Nome .......: ") NOME = string.upper(io.read()) io.write("Telefone ...: ") Em seguida escreva o código de programa em TELE = io.read(); um editor de texto, gravando-o com o nome REGISTO = NOME.." "..TELE arq04.lua e execute-o com a linha de comando lua 5.1 arq04.lua. 40
    • A PROGRAMAR Lu a – Li n gu a ge m d e Pro gra m a ç ã o ( Pa rte 6 )O programa usa a função lines() um pouco ARQ:close()diferente do que fora utilizada no programaarq02.lua. Neste versão usa-se a função como -- fim do programa ARQ04io.lines() com o nome do arquivo agenda.txtcomo argumento.Quando se utiliza arquivos na linguagem Lua Em seguida escreva o código de programa empode-se fazer uso de duas abordagens de um editor de texto, gravando-o com o nomeacesso aos seus descritores, que pode ser arq05.lua e execute-o com a linha de comandoimplícito ou explicito. l ua 5.1 arq05.lua. Observe junto ao programa as definições das tags XHTML para criação daQuando se faz uso de descritores implícitos, página com o nome teste.html.todas as operações de acesso ocorrem com ouso dos recursos da tabela io. Quando se faz Conclusãouso de descritores explícitos, todas asoperações são providas como métodos do Neste artigo foi dado atenção as acções de usodescritor de arquivo. de arquivos em modo texto na linguagem Lua. Foi também fornecido informações sobre o usoÉ possível com a linguagem Lua criar um do ambiente em modo interactivo.programa que efectue a criação automática de No próximo artigo será tratado o uso de funçõespáginas HTML/XHTML. para acesso em tabelas, escopos de variáveis, descrição de dados, meta-tabelas e orientação aO programa a seguir cria uma página em código objectos em Lua.XHTML. Errata -- inicio do programa ARQ04 No primeiro artigo desta série foi informado ARQ = io.open("agenda.txt","r") equivocadamente que o resto de divisão entre dois valores poderia ser obtido a partir da função for REGISTO in mod(). De fato, pode-se fazer uso desta função io.lines("agenda.txt") do para se obter o valor do resto de uma divisão io.write(REGISTO.."n") desde que esta função esteja associada a sua end biblioteca, neste caso, a biblioteca math, por meio da sintaxe math.mod() ou então pode-se fazer uso do operador % mostrado neste artigo. AUTOR Escrito por Augusto Manzano Natural da Cidade de São Paulo, tem experiência em ensino e desenvolvimento de programação de software desde 1 986. É professor da rede federal de ensino no Brasil, no Instituto Federal de Educação, Ciência e Tecnologia. É também autor, possuindo na sua carreira várias obras publicadas na área da computação. 41
    • MAC ADDRESSE s e a m a n h ã a Ap p l e d o m i n a r?Já tenho idade e experiência suficiente para conceitos...poder ter uma perspectiva sólida sobre aevolução de plataformas computacionais de Ipod, iPhone, iPad são apenas os três últimosdesenvolvimento. Já percorri parte da "travessia exemplos do que acabei de tentar demonstrar.do deserto" que a Apple efectuou no início dosanos noventa, altura em que mesmo os maiscépticos se questionavam sobre o futuro daCompanhia. Se é verdade que a imprensa a Apple fez de umanunciou várias vezes a "morte" da marca de mercado que não existiaCupertino (notícias que felizmente se veio a (...) um império colossalconcluir serem manifestamente exageradas),não é menos verdade que embora uma que rende milhões deplataforma nicho, esteve sempre muito à frente dólares(e por vezes demasiado na vanguarda), dainovação e na capacidade de se recompor decada desaire. O caso do iPod é paradigmático na minha linha de pensamento: Não é a criação do hardware, Sejamos francos, hoje a marca Apple é "trendy", não é a criação do software (que, recordo, foi"fashionable" e mais umas dúzias de palavrões Mac only durante um ano e alguns meses...) que do jargão IT. Arrasta multidões (e você pode fazem (ou fizeram) a revolução. É a experiência muito bem ser um deles...) como uma lâmpada do utilizador. Pela primeira vez, um ecossistema acesa atrai mosquitos. Nem sempre foi assim. permitia ao cliente não "power user", uma Reduzidos a uma franja residual de utilizadores, experiência de uso integrada, pacífica e autênticos gauleses irredutíveis na sua aldeia, a totalmente tranquila. Esse é um dos grandesApple sobreviveu graças à capacidade de visão capitais da Apple. Colocar no mercado produtos dos que presidiram aos seus destinos (Steve pensados (verdadeiramente pensados) para o Jobs, anyone?), mas também graças a uma utilizador comum, que de uma forma tranquila se capacidade inigualável de R&D (que também vai rendendo aos encantos desse esforço. Sim, teve as suas nódoas negras no caminho), e a a Apple fez de um mercado que não existia um desempenho industrial quase irrepreensível. (Napster. Anyone?), um império colossal que rende milhões de dólares. Artistas, compositores Se uma nuvem de "copycats" me irritou no e músicos querem hoje cortar o "middleman" e passado, hoje isso quase que se tornou banal. estar de forma directa na Store. Meia dúzia deTodos os trimestres se perfilam no mercado anos passados, quem se lembra de como eram"Killers" de isto e daquilo. A maioria deles as coisas anteriormente? pretende ser "killer" de um produto Apple, mas não é menos verdade que há cemitérios inteiros Replicar a experiência noutras plataformas foi cheios de produtos que se arrogam a ser a apenas uma questão de poucos anos. Não próxima grande descoberta. O verdadeiro "killer" passa nenhuma semana no meu calendário que está ainda, penso eu, nos estiradores dos não tenha contactos de programadores 42
    • MAC ADDRESS E s e a m a n h ã a Ap p l e d o m i n a r? .experientes ou simples iniciantes que mecontactam em busca desse Santo Graal que é a Sim, disse apenasiniciação ao desenvolvimento para iPhone. Sim,disse apenas iPhone; foi com este produto que iPhone; foi com estetudo realmente começou. E ao longo dos últimos produto que tudo começoutrês anos, no início dos quais se contavam pelosdedos de ambas as mãos de um lançador defoguetes destreinado, a quantidade de genteportuguesa envolvida no desenvolvimento,passámos a contá-los por centenas eposteriormente já na casa do milhar.É divertido. Divertido e reconfortante assistir aesta corrida ao ouro. Numa Store que todosinvejam e tentam copiar (por vezes demasiadomal), há espaço para todos e todos são tratadospor igual. É o mercado a funcionar. Destacam-seos bons dos medianos e maus, ninguém ficaverdadeiramente prejudicado pois a escolha(compra) do cliente final é que éverdadeiramente decisória. Vingam as boasideias. E essas, reconhecidamente temo-las emPortugal com programadores portugueses.Alguns deles já reconhecidos internacionalmentecom prémios do próprio fabricante.Quem sabe, se uma das suas ideias não chegaao top da AppStore? AUTOR Escrito por Pedro Aniceto Pedro Aniceto, é Gestor de Produto Apple desde 1 998 e utilizador da marca desde bem mais cedo. Não acredita em monstros, mas espreita de quando em vez para debaixo da secretária. 43
    • A PROGRAMARS QL e m O ra c l eIntrodução cérebro da base de dados). Alguns desses dados variam ao longo do tempo. Por isso, ou oQuando desenvolvemos uma aplicação assente optimizador é inteligente ao ponto de escolhernuma base de dados, um dos processos que sempre o melhor caminho, ou teremos de sernormalmente nos passa ao lado é a optimização nós – programadores - a ensiná-lo.de queries.Preocupamo-nos com a interacção da aplicação a lentidão de umacom o utilizador ou com questões de segurança,não dando importância a pormenores de SQL aplicação com acessos àque podem, muitas vezes, condicionar a base de dados resulta deperformance da aplicação. O tempo de espera SQL mal construído ou dena execução de uma query pode arruinar umaaplicação e, em última instância, uma base de estruturas de dadosdados inteira. desadequadas O tempo de espera na As bases de dados recentes, e em especial aexecução de uma query Oracle, já têm algoritmos bastante poderosos que cobrem a maioria das situações. No entanto,pode arruinar uma há ainda alguma margem de “invenção” para oaplicação e, em última programador poder influenciar o desempenho doinstância, uma base de SQL.dados inteira Estrutura ultra simplificada de umaA solução passa, muitas vezes, por melhorar o BD Oraclehardware, culpando-o da baixa performance dasnossas queries. Mas, nem sempre o problemareside no hardware. Aliás, muitas vezes, alentidão de uma aplicação com acessos à basede dados resulta de SQL mal construído ou deestruturas de dados desadequadas ao nossoprojecto. Para sabermos o que optimizar e como optimizar, há que conhecer a estrutura interna deNão existe uma fórmula para optimizar SQL. uma base de dados Oracle.Cada caso é um caso. A estrutura de dados, aquantidade ou a qualidade dos dados são Como este artigo não pretende ser exaustivo,factores que influenciam o optimizador (o mostra-se apenas uma visão muito simplista do 44
    • A PROGRAMAR SQL e m O ra c l emodo de funcionamento de uma base de dadosOracle, o suficiente para perceber os conceitos select nome, morada, telefone from t_clientesaqui referidos: where nif = 12345; 1. O cliente envia a instrução SQL para o servidor. 2. O server process procura na shared pool uma instrução igual à solicitada. Se não encontrar, compila a nova instrução (parsing) e armazena-a na shared pool. 3. O server process procura na buffer cache os blocos de dados que necessita. Se nãoCliente – a “nossa” aplicação que comunica com encontrar, faz uma consulta aos data files. 4.a base de dados. Os dados são enviados para o cliente.Oracle Server Process – processo que recebe Se repetirmos a mesma query, de seguida, oas instruções do cliente e as executa. processo será o seguinte: 1.Datafiles – ficheiros onde é armazenada aestrutura e os dados de uma BD. O cliente envia a instrução SQL para o servidor. 2.SGA – zona de memória utilizada para guardardados partilhados pelos vários O server process procura na shared poolutilizadores/aplicações da BD. Armazena dados uma instrução igual à solicitada. Encontra-a e jáno Buffer Cache e instruções SQL na Shared sabe como encontrar os dados.Pool. 3. O server process procura na buffer cacheAs instruções SQL e os dados solicitados os blocos de dados que necessita. Acabaram deatravés de queries são guardados na SGA, ser requisitados na query anterior. Ainda lá estão. Não é necessário recorrer aos datafiles,poupando tempos de processamento e acessos pois os dados encontram-se todos em memória.ao disco, em futuras chamadas da mesmaquery. 4. Os dados são enviados da SGA para o cliente.Como o Oracle processa um comando Por onde começar?Tomemos como exemplo o seguinte query: Verificámos que o Oracle guarda as queries pedidas em memória com a informação do 45
    • A PROGRAMARSQL e m O ra c l emelhor percurso para obter os dados. Uma funcionalidade do Oracle e que permiteImaginemos uma aplicação que executa, optimizar a utilização repetida de queries iguaissistematicamente, esta query com diferentes são as bind variables . Estas variáveis permitemcondições: executar a instrução da seguinte forma: select nome, morada, telefone from t_clientes where nif = 12345; variable nif_n number; exec :nif_n := 12345; select nome, morada, telefone from t_clientes query -> select nome, morada, where nif = 12346; telefone from t_clientes where nif = :nif_n; select nome, morada, telefone from t_clientes exec :nif_n := 12346; where nif = 23245; query -> select nome, morada, (...) telefone from t_clientes where nif = :nif_n;As queries são todas diferentes. Logo, o Oraclevai armazenar cada uma delas na shared pool. Agora, sim, a query é sempre igual, aos olhos doMas, na prática, o processo de obtenção dos optimizador Oracle e, em vez de guardardados é sempre o mesmo. inúmeras queries iguais em memória, guarda apenas uma:Na verdade, as queries são todas iguais,excepto o critério da condição where. Ooptimizador não é suficientemente esperto ao select nome, morada, telefone fromponto de perceber que o processo é sempre o t_clientes where nif = :nif_n;mesmo.Poderíamos, facilmente, encontrar estas queriesem memória, na SGA, executando a seguinte Estas situações tomam especial importância emconsulta: bases de dados onde a mesma query é repetida milhares de vezes ficando a memória entupida com instruções iguais. select hash_value,sql_text, parse_calls, A repetição da mesma query milhares de vezes loads, executions pode rapidamente ocupar toda a memória from v$sqlarea disponível. Ao utilizarmos bind variables, where sql_text like select nome, morada, estamos a poupar CPU no parsing e RAM na telefone from t_clientes where nif =%; shared pool. Como caso prático da utilização de bind variables podemos referir um website de vendaVerificaríamos inúmeras queries similares, com de automóveis usados.variância no parâmetro nif. 46
    • A PROGRAMAR SQL e m O ra c l eSe o campo de pesquisa for a marca, modelo e quando tem apenas uma parse_calls e muitasano, estaremos a executar uma query que executions.procura numa tabela os automóveis com amarca X, modelo Y e ano Z, que podem ser Naturalmente que, em queries pouco frequentes,seleccionados recorrendo a bind variables , não é necessário preocuparmo-nos com estaevitando assim milhares de queries similares. optimização e nem devemos generalizar a optimização somente às bind variables . Existem muitas maneiras de tornar o código SQLConclusão mais eficiente e esta é apenas uma delas e de fácil implementação.A utilização de bind variables é uma prática quedeve ser adoptada sempre que possível. Se a Uma análise mais aprofundada da estrutura denossa aplicação já está em produção, uma uma base de dados Oracle permite umanálise à vista dinâmica v$sqlarea permite conhecimento mais vasto sobre o modo como odetectar as instruções SQL similares que podem Oracle processa os pedidos de informação.ser reduzidas a uma só. Na prática, os conceitos aqui referidos são bem mais complexos. No entanto, a nível do A utilização de bind programador que estrutura o SQL e que,variables é uma prática eventualmente, cria a estrutura de dados, estes conceitos são suficientes para este tipo deque deve ser adoptada optimização.sempre que possível O detalhe vai interessar mais ao DBA que também poderá fazer “maravilhas” no tunning da base de dados.Para isso, podemos olhar para as colunasparse_calls e executions.Uma query muito frequente está optimizada AUTOR Escrito por Ricardo Trindade É actualmente o responsável pela área informática dos Serviços Sociais da Câmara Municipal de Lisboa onde efectua, desde administração de sistemas, até programação em .NET. Está também ligado ao projecto N-Ideias na área da consultoria, webdesign e software, trabalhando essencialmente com BDs Oracle, PostgreSQL e SQL Server. 47
    • A PROGRAMARAs p e c to s l o w- l e ve l d e 3 DIntroduçao ao 3D (normalmente implementada nos drivers) e a placa gráfica?Este artigo explica alguma da teoria relacionadacom o funcionamento de baixo nível de gráficos3D, desde a placa gráfica, às bibliotecas que seusam para as programar, e alguma da magia(matemática) necessária para que tudo funcione.Recomenda-se alguma experiência básica comconceitos 3D.Quem não se lembra de jogos como Quake eDuke Nukem 3D? Estes jogos (pelo menos asversões originais), eram "renderizados" Pensem na pipeline 3D como uma linha de(transformados numa imagem para mostrar no execução de uma fábrica. Os materiais sãoecrã) completamente por software, ou seja, sem introduzidos, processados em várias fases, erecurso a aceleração por hardware. obtemos o produto final. Convém também ficar claro que existem vários métodos diferentesSó anos depois, com a popularidade dos jogos para fazer render de gráficos 3D. O que asna plataforma PC, é que as placas gráficas placas gráficas actuais usam (e os primeiroscomeçaram a ser vendidas e distribuídas com os jogos 3D que funcionavam apenas por software)computadores. As placas gráficas (GPU) são é chamado de rasterisation. Existem outrosutilizadas para acelerar os cálculos necessários métodos como ray tracing, mas não vão serpara representar realisticamente os objectos em explicados.3D. As primeiras gerações de placas gráficas apenasAs placas são constituídas por processadores executavam a fase Rasterizer, sendo que a faseespecializados, e com grande capacidade de de Geometry era totalmente processada peloparalelização, em contraste com um CPU. Devido à crescente complexidade dasprocessador normal (CPU), que está preparado aplicações 3D, o CPU não conseguia processarpara executar os mais variados tipos de toda a informação em tempo útil, e a faseaplicações. Geometry passou a ser implementada no GPU. Esta capacidade é normalmente referida nasCom o aparecimento das primeiras placas funcionalidades das placas gráficas porgráficas surge a necessidade de criar APIs para hardware T&L (Transform & Lighting).tirar proveito das capacidades deprocessamento do hardware. As bibliotecas mais Esta pipeline está de acordo com um modeloconhecidas são o OpenGL e o Direct3D, embora conhecido por Fixed-function pipeline. As placasalguns talvez ainda se lembrem do Glide, que gráficas modernas são muito mais flexíveis ehoje em dia não passa de um artefacto histórico. dispõem de uma pipeline programável, utilizandoComo funcionam e qual a relação entre a API shaders. Ainda é possível programar com este 48
    • A PROGRAMAR As p e c to s l o w- l e ve l d e 3 D modelo não-programável nas placas gráficas Por questões de optimização todos os cálculos mais recentes, mas o seu funcionamento é internos são feitos em triângulos, por ser uma"emulado" pela API gráfica. representação simples. Consequentemente, todas as outras formas de representação sãoA esmagadora maioria dos chipsets gráficos convertidas para triângulos, usando umproduzidos hoje em dia são programáveis, processo chamado tessellation (ou Polygonsendo a excepção mais notável a consola Wii da triangulation).Nintendo. Os dispositivos móveis tambémdemoraram um pouco a adoptar este novo Realizada esta conversão os dados sãomodelo, mas as novas versões do iPhone e enviados pelo bus (AGP ou PCI-Express) para adispositivos Android também já suportam placa gráfica.shaders (através do OpenGL ES 2). A webtambém está a caminhar para este modelo, com Geometry stagea adopção do WebGL por vários browsers. Esta fase recebe os vérticesApplication stage 3D enviados para a placa gráfica pela fase anterior, eTal como o nome implica, a primeira fase ocorre executa uma série dena aplicação desenvolvida pelo programador, e é transformações necessáriasprocessada apenas no CPU. Nesta etapa, são para adaptar estes dadosnormalmente processadas tarefas como num formato adequado paradetecção de colisão (Collision detection), o processamento daanimação, simulação de física, algoritmos de próxima fase. Esta é a parteaceleração (Space partitioning, Culling), entre mais importante da pipeline,outros, dependendo do tipo de aplicação. e onde são efectuados a maior parte dos cálculos.A aplicação é também responsável por enviar osdados dos objectos 3D para a API. Os objectos Antes de analisarmos emem 3D são geralmente representados por mais detalhe cada uma das transformaçõespolígonos: triângulos e quadriláteros. Existem desta etapa, vamos ver o que são espaços deoutras formas de representação, como coordenadas e como são representados oscurvas/superfícies NURBS (Non-uniform vértices.Rational B-splines), mas apesar de permitirem amodelação de alguns tipos de objectos de forma Em 3D é comum utilizarmos vários espaços demais precisa (através de modelos matemáticos) coordenadas pois faz sentido falar de diferentesprecisam de ser convertidas noutras coordenadas dependendo do objecto ourepresentações. referência que estejamos a considerar. Os espaços fundamentais são denominados por Model/Object Space, World Space e Camera/Eye Space, pela ordem que são processados na pipeline. Inicialmente um objecto em 3D reside num espaço chamado Model Space, que significa que 49
    • A PROGRAMARAs p e c to s l o w- l e ve l d e 3 Do objecto ainda não foi transformado e seencontra no seu próprio espaço de coordenadas.É importante que cada objecto defina o seupróprio espaço, pois podemos associar váriastransformações a um objecto inicial, obtendovárias cópias no objecto no mundo comlocalizações, orientações e tamanhos diferentes,sem ser necessário enviar todos estes objectosdiferentes para a placa gráfica (esta técnica éconhecida por Instancing). Neste caso osobjectos estão normalmente posicionados naorigem para fácil manipulação. World Space é um espaço de coordenadas“especial” pois todos os outros espaços vão ser referenciados em relação a este. Em outras As matrizes vão corresponder a transformações palavras este é o “maior” espaço de de um espaço de coordenadas para outro coordenadas no mundo. diferente. Exemplos de transformações representáveis com matrizes são translações,É mais fácil perceber a relação entre estes rotações, escalamentos ou redimensionamentos,diferentes espaços utilizando um exemplo. reflexões, projecções, entre outros.Todos nós temos o nosso próprio espaço decoordenadas. Se eu vos disser para darem um Existem várias formas de representar matrizespasso em frente (Object Space), não faço ideia na memória: row-major order e column-majorse vão para Norte, Sul, Este ou Oeste (World order. É fundamental que não se misturem osSpace). dois tipos de representações, pois a ordem da multiplicação para a concatenação deAntes de estudarmos os diferentes tipos de transformações é diferente.transformações que os objectos sofrem, énecessário um modelo que possa ser facilmente Com o uso de matrizes também se tornatrabalhado. Os pioneiros em computação gráfica possível a concatenação de diferentes tipos deescolheram vectores como a forma de transformações (representadas em diferentesrepresentação dos vértices. Esta representação matrizes) numa únicapermite reutilizar todo o conhecimento da área matriz. Isto é bastantematemática conhecida por álgebra linear. Esta útil, pois apenasárea estuda as propriedades dos vectores e dos temos de multiplicarconceitos associados (espaços vectoriais). os vértices por essa matriz composta eEsta representação vai permitir o uso de obtemos logo omatrizes (que podem ser visualizadas como um resultado equivalenteconjunto de vectores) para a manipulação dos a multiplicar o vértice por cada transformaçãovértices. em separado. 50
    • A PROGRAMAR As p e c to s l o w- l e ve l d e 3 DExistem bastantes mais detalhes sobre matrizes Agora que já vimos o modelo usado paraque convém estudar para se conseguir perceber trabalhar os vértices, e como eles sãodetalhadamente como a teoria (e a prática!) representados no computador, vamos analisarfunciona. Mais concretamente, é fortemente as transformações principais que acontecemrecomendada a leitura sobre coordenadas internamente na pipeline (não se preocupem sehomogéneas, transformações lineares e não perceberem os diferentes espaços detransformações afins. coordenadas, vão ser explicados mais à frente):É bom que estudem também como as diferentes 1. Model transform, transformação detransformações funcionam em termos de Model Space para World Space.operações matriciais. Como exemplo, vejam 2. View transform, transformação de Worlduma matriz de translação (apresentada na Space para Camera Space.figura) e tentem multiplicar um vector pela 3. Projection transform, transformação dematriz. Camera Space para Clip Space.As diferentes APIs gráficas usam diferentes Usando notação matemática, podemosconvenções para a representação de matrizes e representar estas transformações pela seguintevectores em memória. Vamos ver as diferenças: multiplicação de matrizes: Model & View Transform A primeira transformação que ocorre é a transformação designada por Model. Esta transformação é usada para colocar os objectos na sua posição do mundo. Como já vimos, os objectos começam com o seu próprio espaço de coordenadas, e normalmente estão centrados na origem. Se quisermos colocar dois cubos no mundo 3D (definidos num ficheiro externo e centrados na origem), vamos ter duas matrizes de model diferentes, que os colocam emConvém também perceber as convenções de posições diferentes, e que também permitemeixos usadas nas principais APIs gráficas podem que eles tenham tamanhos diferentes ou queser vistas de diferentes formas. É preciso ter não estejam orientados da mesma forma.cuidado se temos um sistema de coordenadasleft-handed ou um sistema de coordenadas right- A transformação View vai colocar os objectoshanded. centrados no espaço da câmara. Ou seja, objectos mesmo à frente da lente da câmara vãoEm relação à correspondência dos eixos, a estar na origem desse novo espaço. Ao inícioconvenção usada é que o Y corresponde a pode parecer confuso, pois ao contrário do quecima/baixo, o X a esquerda/direita e o Z a estamos habituado no mundo real (onde osfrente/trás (ver imagens), embora isto possa ser objectos não mudam de sítio), em 3D são osalterado. vértices dos objectos que são multiplicados por 51
    • A PROGRAMARAs p e c to s l o w- l e ve l d e 3 Duma matriz, e é normal que sejam os objectosque mudam de sitio para serem vistos dediferentes posições.ProjectionDepois de os objectos estarem posicionados noespaço da câmara, é necessário que eles sejamprojectados. A projecção consiste nomapeamento dos vértices (em 3D) para um certoplano com representação bi-dimensional (2D).Podemos considerar dois tipos de projecções: No final da projecção, o resultado de multiplicar• Ortogonais (ortographic projection) todos os vértices pelas matrizes de• Perspectivas (perspective projection). transformação e projecção vai ser diferente, dependendo do tipo de projecção escolhido. No caso da projecção ortográfica, o resultado vai ser um paralelepípedo, enquanto no caso da projecção perspectiva vai ser uma pirâmide invertida com o topo truncado, a que se dá o nome de frustum (exemplo na figura). No final da projecção, o resultado de multiplicar todos os vértices pelas matrizes de transformação e projecção vai ser diferente, dependendo do tipo de projecção escolhido. NoTal como representado na figura, podemos ver caso da projecção ortográfica, o resultado vaiuma projecção perspectiva na esquerda. As ser um paralelepípedo, enquanto no caso dalinhas, quando vistas no horizonte, focam-se projecção perspectiva vai ser uma pirâmidenum ponto (vanishing point). A este efeito invertida com o topo truncado, a que se dá ochama-se foreshortening. Tem a característica nome de frustum (exemplo na figura).que objectos mais longe parecem maispequenos. Este é o tipo de projecção a queestamos habituados a ver no dia-a-dia.Outro tipo de projecção, apresentado na direita,é a projecção ortográfica. Esta projecção tem acaracterística que linhas paralelas continuamparalelas depois da projecção. Por exemplo,estamos habituados a ver este tipo de projecção As APIs gráficas normalizam o resultado deem plantas de edifícios. todos os tipos de projecção num cubo centrado na origem com dimensões que variam de (-1 ,1 ) no eixo X, Y e Z. Isto permite que os restantes 52
    • A PROGRAMAR As p e c to s l o w- l e ve l d e 3 Dpassos da pipeline sejam executados de forma Rasterizer stageuniforme. O espaço resultante é chamado de clipspace pois nesta mesma fase todos os vértices Esta fase utiliza as primitivas geradas na faseque estejam fora do espaço definido pelo cubo, anterior para determinar os píxeis finais que vãosão ignorados (também conhecido por clipping). ser escritos no framebuffer. O primeiro passo a ser processado é conhecido por ScanÉ de notar que o funcionamento apresentado conversion. Este passo transforma os triângulospode ser ligeiramente diferente entre o OpenGL 2D (mais a sua profundidade) em fragmentos.e o Direct3D, mas a teoria é equivalente entre os Fragmentos são potenciais píxeis que vão serdois. Normalmente só alguns pormenores escritos no framebuffer. Têm associadosvariam, sendo recomendada a consulta da informação como localização, cor, coordenadasdocumentação oficial de cada API para saber de texturação e profundidade.mais concretamente de como são executadostodos estes passos. Alguns pequenos A informação que está associada aospormenores também foram omitidos pois fragmentos é usada para determinar a sua cor. Arequerem conhecimento mais avançado sobre a cor de um fragmento pode depender de váriosrepresentação de coordenadas homogéneas em factores, por exemplo, se existem luzes quematrizes (perspective divide e normalized device afectam o fragmento, ou se o fragmento faz usocoordinates). de texturas. Esta fase é chamada de shading e existem vários algoritmos de diferentesViewport Mapping complexidades que dão resultados melhores ou piores de acordo com o seu custo deAs APIs gráficas normalmente permitem a processamento.definição de uma sub-região da janela onde ooutput final é mostrado. Imaginem por exemplo Nos primeiros jogos as fórmulas utilizadasum jogo de carros, com suporte para 2 simplificavam bastante as equações necessáriasjogadores no mesmo ecrã (o que os jogos pois ainda não existia poder de processamentonormalmente chamam de split-screen). suficiente para utilizar técnicas mais avançadas.Normalmente o ecrã é dividido ao meio e é A informação era normalmente processada paramostrada a área de jogo de cada jogador em cada vértice (per-vertex shading) e depoiscada uma dessas regiões. Nas APIs gráficas, interpolada em cada fragmento (Gouraudcada uma dessas regiões é conhecida por shading). Hoje em dia já temos poder deviewport. processamento suficiente para calcular a informação da cor por cada fragmento (per-pixelDepois de obter as coordenadas normalizadas shading) com técnicas como o Phong shading.no cubo, é feito o mapeamento para o espaço de Esta fase é normalmente implementada nascoordenadas da janela, ou Window Space. Este placas modernas com shaders, que permitemprocesso é conhecido por Viewport Mapping, total controlo e flexibilidade sobre o algoritmopois tem em conta as definições do viewport utilizado já que são escritos pelo utilizador.actual, para permitir que diferentes imagenssejam mostradas na mesma janela. Depois de calculada a cor de cada fragmento, essa cor pode ser misturada com a já existente 53
    • A PROGRAMARAs p e c to s l o w- l e ve l d e 3 Dno framebuffer (de fragmentos anteriores que mostrar, o OpenGL podia ordenar os objectos eocupam a mesma posição). Esta técnica é desenhar os que estão mais longe primeiro (ochamada de chamado Painters algorithm), mas isso causablending e o problemas com objectos que se intersectam (verOpenGL por figura). A solução utilizada pelo OpenGL eexemplo permite o Direct3D é ordenar os objectos ao nível do pixel,controlo das utilizando uma zona de memória que armazenaequações a profundidade de cada pixel (chamado deutilizadas para depth- ou Z-buffer).efectuar a mistura.É possível assim Depois de conhecida então a cor do fragmento,obter efeitos como quando um fragmento está para ser escrito notransparências parciais ou totais. framebuffer, a sua profundidade é comparada com a do fragmento que está no buffer (depthO que vemos na figura é um exemplo de buffer test). Só se o fragmento novo estiver maisblending por adição. Os fragmentos do quadrado perto (se o seu valor for menor) é que o novoverde são misturados com os já existentes do valor de cor é escrito no framebuffer.quadrado vermelho, dando origem ao amarelo. No fim do processamento de todos osUtilizando a mesma figura, outro conceito fragmentos, a aplicação mostra o conteúdo doimportante a perceber é o controlo da framebuffer no ecrã (normalmente numa janela)profundidade dos objectos. Por exemplo, se ou grava o conteúdo para uma imagem.tiverem um quadrado à frente de outro, sóquerem que o quadrado mais próximo da Chegamos ao fim do artigo! Embora este artigo câmara seja já dê uma pequena ideia sobre o mundo que é o mostrado, pois está a 3D, foi apenas uma pequena introdução sobre o tapar o quadrado de tema. Espero que tenham gostado e aprendido trás. A profundidade é com o artigo, e se quiserem aprender mais, controlada com o podem consultar os seguintes recursos. valor de profundidade do vértice quando Real-Time Rendering projectado no espaço Essential Math for Game Developers de coordenadas da GameDev.net câmara (eixo dos Z).Para controlar e saber quais os objectos a AUTOR Escrito por João Matos Também conhecido por triton, frequenta o segundo ano do curso de Engenharia Informática e Computadores no IST. Tem como principais interesses as áreas de Sistemas Operativos, Computação Gráfica e Arquitectura de Computadores. 54
    • CORE DUMPQu a n d o s e é ! Pro d u ti voQuem ganha a vida a bater código está acusadas cai por terra. Muitas das vezes até éhabituado a ver a sua produtividade medida. Por possível mostrar que a verdadeira razão da faltavezes essa medição não é efectuada de forma de produtividade vem da equipa de gestão.correcta e, pior, muitas vezes não é sequerefectuada de forma justa. O resultado é, muitas Mas então, como encontrar e medir essasvezes, uma enorme irritação para com a gestão ineficiências? É aqui que entra o poder depor esta se refugiar em frases, quase observação e o cérebro.infindáveis, como “Estás quase sempre atrasadonos prazos de entrega”, ou “O desenvolvimento O primeiro passo é identificar todas as causasnunca entrega as coisas a tempo e horas”. que nos levam ao desespero quando fazemos desenvolvimento. Já me deparei com coisas tãoAs desculpas, ou justificações, por quem faz variadas como intromissões de anti-vírus, faltadesenvolvimento são também elas inúmeras, de permissões no sistema de desenvolvimento,vão do simples “O servidor é muito lento” ao ou uso de máquinas virtuais.“Estão sempre a mudar as especificações doproduto”. Para exemplificar, no caso do anti-vírus o mesmo não podia ser configurado pelo utilizadorEsta parece uma luta desigual, entre o para não verificar os directórios referentes aodesenvolvimento e a gestão, mas na verdade código fonte, ao código compilado, às bibliotecasapenas o é porque tipicamente o usadas, etc.; enquanto que o clássico caso dedesenvolvimento não faz uso daquilo que melhor falta de permissões, faz com que qualquertem ao seu alcance: o seu cérebro e o poder de alteração necessite de uma longa interacçãoobservação. entre efectuar um pedido para a alteração e o mesmo ser satisfeito; já o caso da máquinaSe a produtividade pode ser medida, a virtual, há quem tenha de desenvolver usandoineficiência também. E quando se mede a uma máquina virtual que sub-aproveita osineficiência então há factos que sustentam a recursos da máquina física e, devido àfalta de produtividade e que, por sua vez, trazem quantidade de camadas intermédias envolvidas,luz à verdadeira causa dessas ineficiências. torna toda a interacção com o sistema muito mais lenta. Se a produtividade O segundo passo é encontrar uma forma depode ser medida, a medir os problemas identificados e convertê-losineficiência também numa medida que a gestão compreenda. Neste caso o tempo é uma das escolhasQuando fazemos este exercício de medir a naturais. Por exemplo, no caso do anti-vírus, oineficiência, posso assegurar-vos que a larga tempo de compilação da aplicação sofreu ummaioria das vezes a tal falta de produtividade de aumento significativo, que somado ao longo deque as equipas de desenvolvimento são uma semana resultava em, aproximadamente, 55
    • CORE DUMPQu a n d o s e é ! Pro d u ti voduas horas de inactividade, ou seja um dia por tem oitenta pessoas em regime de outsourcing amês de inactividade só devido ao facto do anti- quem se pagam 4 semanas de trabalho paravírus estar incorrectamente configurado. trabalharem pouco mais de 3 semanas, o resultado financeiro é desastroso.Esta situação levou-me a questionar a gestão seeu podia configurar o anti-vírus correctamente etirar um dia de folga a mais por mês, afinal o Após efectuar estaresultado seria exactamente o mesmo. medição, a extrapolaçãoNo caso das máquinas virtuais voltei a medir o dos valores obtidostempo, mas desta vez as coisas foram mais mostrou 33 horas dedrásticas. E não era só pelo facto da mesmamáquina física ter de correr dois sistemas inactividade mensaloperativos com dois anti-vírus e desperdiçar500MB de RAM porque a máquina virtualapenas conseguia alocar 1 .5GB de RAM... Tudo pode ser medido, pelo que o desafio está em encontrar uma forma inteligente de medir oEra um conjunto de situações que somado que está mal e apresentar esses resultados.resultava num aumento de quatro vezes o tempode espera na operação de compilação e deploy Certamente que não é o desenvolvimento queda aplicação. não é produtivo quando um bug ocorreu devido a um requisito mal especificado, ou quandoSim, a produtividade caiu para valores críticos. existe um processo moroso para satisfazer uma solicitação, ou quando ocorre uma alteração naApós efectuar esta medição, a extrapolação dos especificação do sistema.valores obtidos mostrou 33 horas de inactividademensal. Trinta e três horas por mês num mês Da próxima vez, não se queixem, identifiquem aque tem quarenta horas de trabalho semanal ineficiência, meçam a ineficiência e apresentemresulta quase numa semana de inactividade. essa ineficiência à vossa gestão.O caso tomou proporções interessantes uma vezque esta situação se passou num cliente quetinha mais de oitenta pessoas externas a fazerdesenvolvimento nestas condições. Quando se AUTOR Escrito por Fernando Martins Faz parte da geração que se iniciou nos ZX Spectrum 48K. Tem um Mestrado em Informática e mais de uma década de experiência profissional nas áreas de Tecnologias e Sistemas de Informação. Criou a sua própria consultora sendo a sua especialidade a migração de dados. 56
    • COMUNIDADE SHAREPOINTPTC l i e n t O b j e c t M o d e l p a ra S i l ve rl i gh tCom o lançamento da nova versão do crescido a nível de serviço e a nível deSharePoint, mais propiamente SharePoint 201 0 importância nas instituições empresariais,no início deste ano, e o seu sucesso a nível tornando uma aposta mais que decisiva damundial da sua adopção como uma das Microsoft, com a sua implementação eferramenta empressariais de Portais e integração de todos os seus produtos nestaColaboração, este artigo tem como prespectiva a plataforma, tornando-se o sistema operativo dassua demostração como ferramenta de empresas.desenvolvimento para Soluções empresariais. Uma das suas vantagens é a capacidade deNeste artigo irei ainda dar atenção a um dos integração entre as diversas tecnologiasnovos serviços disponibilizados pelo SharePoint Microsoft e a capacidade de integrações de201 0 que é o Client Object Model para plataformas externas, como SAP, Oracle entreSilverlight, com a criação de um projecto e outras, de forma a torna um ponto de partilhachamada de métodos para demostrar a sua única da Informação da empresa, sendocapacidade de acesso a conteudos existente construido numa plataforma Web o que tornanos sites em SharePoint. bastante acessível o seu acesso.A plataforma SharePoint é um conjunto integrado No próximo quadro encontram-se os serviçosde recursos que pode ajudar a melhorar a que estão disponíveis para o SharePoint 201 0.eficácia organizacional fornecendo uma gestãode conteúdo abrangente e pesquisa empresarial,acelerando os processos comerciaiscompartilhados e facilitando a partilha deinformações para uma melhor visão dosnegócios.Os serviços disponibilizados vão desde Gestãode Conteúdos, Gestão Documental, BusinessIntelligence, Comunidades, Integração dePlataforma externas a Microsoft através dosBCS(Business Connectivity Services),Workflows, Office Web app (Integração das Com o lançamento do SharePoint 201 0 foramferramentas Microsoft Office em formato Web), disponibilizados múltiplos novos serviços comoSharePoint Designer 201 0, Gestão de Projectos, LINQ, novas API’s para acesso a dadosServiços de Pesquisa de Portal e Conteúdos (utilizando o Client Object Model), utilização deExterno, com diversos tipos de autenticação REST - ADO.NET Data Services e utilização deutilização de federações entre outros serviços. Ajax em webParts com processos AsynchronousEnfim uma plataforma bastante completa. (sem utilização de postback nas páginas) entre outros novos serviços.Durante os últimos anos a plataforma tem O SharePoint 201 0 apresenta 3 novas Client 57
    • COMUNIDADE SHAREPOINTPTC l i e n t O b j e c t M o d e l p a ra S i l ve rl i gh tAPI’s para interagir com conteúdos dos sites de no Visual Studio 201 0, com uma aplicação emSharePoint: Silverlight 4, utilizando a API do SharePoint e• A partir de aplicações .Net “nunca inferiores a integrando do SharePoint 201 0.Framework 3.5”;• A partir de aplicações Silverlight “nunca Para suporte da nossa solução em SharePointinferiores a Silverlight 2.0” eu criei uma Lista chamada “ Geral” com um• A partis de ECMAScript ou seja de Javascript, conjunto de dados para teste.Jscript Criar um novo Projecto com o Visual Studio Arquitectura do Client Object Model 201 0 no Template “Silverlight” e seleccionar a opção para associar a um novo Web site com a versão do Silverlight 4:Estas novas API em Client Object Modelfornecem um sistema orientado a objectos parainteragir com os dados do SharePointremotamente, sendo bastante fáceis de utilizarporque a sua nomenclatura é bastante parecidado Server Object Model do SharePoint.Para demostrar a forma de acesso aos Objectosda API na próxima tabela mostra a diferentesAPI’s para as diversas plataformas e a formaidêntica da utilização do Object Model.Neste exemplo, irei criar um pequeno Projecto 58
    • COMUNIDADE SHAREPOINTPT C l i e n t O b j e c t M o d e l p a ra Si l ve rl i gh tPara realizar as chamadas ao conteúdo do Método 1 :SharePoint, através da API em Silverlight, será Retorna o nome das Listas existentes no site denecessário adicionar como referencias as DLL’s SharePoint utilizando o Client Object Mode. Foique se encontram na pasta da instalação do utilizado uma expressão Lambda para retornarSharePoint 201 0 as listas e o Titulo associado.(Microsoft.SharePoint.Client.Silverlight eMicrosoft.SharePoint.Client.Silverlight.Runtime), private void LoadLists()tipicamente em C:Program FilesCommon {FilesMicrosoft SharedWeb Server ClientContext clientContext =Extensions1 4TEMPLATELAYOUTSClientBin. new ClientContext("http://[Site]"); oWebsite = clientContext.Web; collList = oWebsite.Lists; clientContext.Load(oWebsite, website => website.Title); //Lambda expression para retornar as Listas listInfo = clientContext.LoadQuery(Futuramente, a Microsoft irá disponibilizar um collList.Include(package com as DLLs em SharePoint .NET list => list.Title,Client Object Model, onde se poderá realizar o list => list.Fields.Include(download e a sua distribuição ao cliente. field => field.Title).Where( field => field.Required == trueCom a utilização do Visual Studio 201 0 existe a && field.Hidden != true)));possibilidade de integrar o Microsoft ExpressionBlend 4 com as nossas aplicações clientContext.ExecuteQueryAsync(onQuerySucceedesenvolvidas em Silverlight. ded, onQueryFailed); } private void onQuerySucceeded(object sender, ClientRequestSucceededEventArgs args) { UpdateUIMethod updateUI = DisplayInfo;Depois de termos realizado a nossa this.Dispatcher.BeginInvoke(updateUI);customização podemos voltar à nossa solução }em Visual Studio 201 0 e começar a criar osnosso métodos para retornar conteúdo do Site. private void onQueryFailed(object sender,Para isso criei 2 métodos, um para retornar a ClientRequestFailedEventArgs args)listas do nosso site em SharePoint e outro para {retornar o conteúdo de uma Lista numa MessageBox.Show("Request failed. " +Datagrid. args.Message + "n" + args.StackTrace); 59
    • COMUNIDADE SHAREPOINTPTC l i e n t O b j e c t M o d e l p a ra S i l ve rl i gh t } _projectItems = private void DisplayInfo() projects.GetItems(camlQuery); { context.Load(_projectItems); collList = oWebsite.Lists; listBox1.ItemsSource = listInfo; context.ExecuteQueryAsync(OnRequestSucceeded, listBox1.DisplayMemberPath = "Title"; null); } } private delegate void UpdateUIMethod(); #region Methods private void OnRequestSucceeded(ObjectExemplo: sender, ClientRequestSucceededEventArgs args)http://msdn.microsoft.com/en- {us/library/ee538971 .aspx Dispatcher.BeginInvoke(BindData);Método 2: }Retorna dados da Lista “Geral” para uma private void BindData()DataGrid utilizando CAML para realizar os filtros {dos conteúdos a retornar: //Utilizando o conteúdo numa lista de Objecto do tipo Geral como a Lista private void LoadGrid() var list = new List<Geral>(); { foreach (var li in _projectItems) //Contexto do site em SharePoint a chamar { var context = new list.Add(new Geral ClientContext("http://[Site]"); { context.Load(context.Web); Title = li["Title"].ToString(), Nome = li["Nome"].ToString(), //retornar o objecto List com o nome Activo = “Geral” Convert.ToBoolean(li["Activo"].ToString()) List projects = }); context.Web.Lists.GetByTitle("Geral"); } context.Load(projects); //adicionar os Dados da Lista na Datagrid //CAML Query para Filtar os valores da dataGrid1.ItemsSource = list; nossa Lista } CamlQuery camlQuery = new CamlQuery(); camlQuery.ViewXml = No seguinte exemplo foi criado um pequeno "<View><Query><Where><Geq><FieldRef formulário no Silverlight para a lista “Anuncios”. Name=ID/>" + Esta lista tem um conjunto de artigos de "<Value referência ao Site e este método mostra como Type=Number>0</Value></Geq></Where></Query> se consegue criar um formulário de uma forma <RowLimit>100</RowLimit></View>"; simples, sem ter a necessidade de realizar 60
    • COMUNIDADE SHAREPOINTPT C l i e n t O b j e c t M o d e l p a ra Si l ve rl i gh tcustomização de páginas em aspx. oListItem["Title"] = TxtTitle.Text; oListItem["Body"] = TxtBody.Text; oListItem.Update(); clientContext.Load(oList, list => list.Title);Foram adicionadas na Tab “formulário” doSilverlight, 3 campos de preenchimento do clientContext.ExecuteQueryAsync(onQueryInsertnosso Artigo, como o Url do site onde se destina, Succeeded, onQueryInsertFailed);Titulo e corpo. } else { MessageBox.Show("Vazio!!"); }Método 3:Este método ira criar uma nova entrada na Listade SharePoint de um novo anúncio. if (!TxtTitle.Text.Equals("")) { ClientContext clientContext = Com a criação deste 2 pequenos exemplos new ClientContext(TxtUrl.Text); podemos criar a nossa solução Web oWebsite = “AccessData.XAP”. clientContext.Web; ListCollection collList = oWebsite.Lists; SharePoint Silverlight Web Part oList = SharePoint disponibiliza ferramentas para clientContext.Web.Lists.GetByTitle("Anuncios" integrar o projecto desenvolvido em Silverlight e ); adicionar nos nossos sites em SharePoint de uma forma bastante simples. ListItem oListItem = O primeiro passo será adicionar o nosso projecto oList.AddItem(new em Silverlight, neste caso “AccessData.XAP” e ListItemCreationInformation()); adicionar no nosso site em SharePoint, podendo ser uma Folder, uma Document Library ou até na 61
    • COMUNIDADE SHAREPOINTPTC l i e n t O b j e c t M o d e l p a ra S i l ve rl i gh tdirectoria ou pasta “Hive” onde se encontra Quando nos encontramos a trabalhar eminstalado o SharePoint no servidor. Neste caso ambiente Web a aplicação Fiddler é umacriei uma Folder dentro do site em SharePoint. ferramenta essencial para captura e validaçãoEstas pastas não são visíveis aos utilizadores do nosso tráfego na Web. Estando ela emfinais, garantido que o ficheiro não é apagado funcionamento podemos encontrar asacidentalmente. transacções realizadas, através da Client OM, e encontramos uma chamada ao WCF Web Service “client.svc” e um Web Service XML para comunicação e transacção das operações.Depois de adicionado a nossa solução emSilverlight, acedemos ao nosso site emSharePoint e adicionamos uma Web Part que seencontra por defeito no SharePoint “SilverlightWeb Part”. Um dos parâmetros que é requisitado Existem outra forma de poder interagir com osé o caminho de onde se encontra a nossa dados em SharePoint, com o Silverlight atravéssolução em Silverlight. dos “REST” em WCF e com todas as suas potencialidades.Assim que esteja tudo correctamenteadicionado, irá ser disponibilizado na nossapágina de internet a nossa solução de Silverlight,dentro do SharePoint, numa WebPart podendotrabalhar e interagir com o conteúdo do Siteonde se encontra. Conclusão Este foi um pequeno exemplo de como o Client 62
    • COMUNIDADE SHAREPOINTPT C l i e n t O b j e c t M o d e l p a ra Si l ve rl i gh tObject Model e como o SharePoint 201 0 Create a Silverlight 4 Web Part for SharePointconsegue fornecer informação e integração com 201 0Silverlight. http://msdn.microsoft.com/en-Teria muita mais que falar, isto é um tema para us/magazine/ff956224.aspxdiversos subtópicos e com múltiplas formas de Página Oficial do SharePoint 201 0tratar, apenas quero demostra as portas que http://sharepoint.microsoft.com/pt-podem ser abertas e como o SharePoint 201 0 é pt/Pages/default.aspxuma ferramenta de integração com todas asdiversas Tecnologias Microsoft. Este e outros artigos relacionados com aAlguns links úteis: Tecnologia Microsoft SharePoint estãoUsing the Silverlight Object Model disponibilizados pelo site da Comunidadehttp://msdn.microsoft.com/en- Portuguesa de SharePoint. Podem tornar-seus/library/ee538971 .aspx membros activos, criando artigos e aUsing the SharePoint Foundation 201 0 Managed participando em eventos mensais daClient Object Model Comunidade sobre a tecnologia SharePoint.http://msdn.microsoft.com/en-us/library/ee857094.aspx Comunidade Portuguesa de SharePointUsing the SharePoint Foundation 201 0 Managed http://www.sharepointpt.org/Client Object Model with the Open XML SDK 2.0http://msdn.microsoft.com/en-us/library/ee956524.aspxSharePoint 201 0 Reference: SoftwareDevelopment Kithttp://www.microsoft.com/downloads/en/details.aspx?FamilyID=f0c9daf3-4c54-45ed-9bde-7b4d83a8f26f&displaylang=en AUTOR Escrito por André Lage Microsoft SharePoint MVP, trabalhando na Suiça em empresa Farmaceutica e Banca. Apoiando as diversas Comunidades em SharePoint pelo mundo com participaçoes em eventos como speaker e efectuando artigos com focus nas tecnologias SharePoint. Um dos administradores da Comunidade Portuguesa de SharePoint, Co-fundada por Rodrigo Pinto, www.Sharepointpt.org. Blog pessoal http://aaclage.blogspot.com/ 63