ww
w.3
layer.
com
.br
Merlin
ww
w.3
layer.
com
.br
The First Runtime GUI Generator
Merlin - The First Runtime GUI Generator slide 2 de 44
ww
w.3
layer.
com
.br
Sumário
Cenário A proposta Comparações Características e Funcionalidades O presente e o futuro EOF
>> panorama geral
Merlin - The First Runtime GUI Generator slide 4 de 44
ww
w.3
layer.
com
.br
Panorama geral Quanto custa construir um sistema
Meyers, Brad – User Interface Software Tools (1994,2002)
Referências
Sistema completo
Interface do usuário
TC
TC elementares
100%
50%
30%
18%
Custo de construção
2
2
1
1
12Pesquisas próprias (2005,2006)
>> a construção da IU hoje
Merlin - The First Runtime GUI Generator slide 5 de 44
ww
w.3
layer.
com
.br
A construção da IU hoje
O cenário atual
1. ( WYSIWYG: /wɪziwɪg/ ) What You See Is What You Get, ou seja o que você vê (ou o que você desenha no editor) é o que você tem quando o sistema estiver em execução.
As diversas formas de construir interface de usuário e os problemas em comum
Abordagens Problemas recorrentes
Escrita de código-fonte Uso de ferramentas
WYSIWYG1
Uso de assistentes de criação
Geração baseada em modelos Templates MDA
Tempo elevado de construção Quanto custa criar um template?
Demora nas alterações Como refatorar classes já geradas? E se o código já foi alterado?
Falta de reuso Posso reusar o label “Nome do
cliente” em projetos diferentes?
Gerência de código Código template ou não? E a versão?
>> a ferramenta proposta
Merlin - The First Runtime GUI Generator slide 6 de 44
ww
w.3
layer.
com
.br
A ferramenta proposta
Abdicar totalmente da geração do código-fonte Gerar a TC durante a execução do sistema,
através de um processo de interpretação de meta-informações oriundas das próprias classes da aplicaçãoA idéia-chave
CAFE
class Cliente { String codigo; String nome;}
new JFrame.add(Merlin.createIU(Pessoa.class)
).setVisible(true);
>> motivação
1 2 3
Tempo de projeto Tempo de execução
4
Merlin - The First Runtime GUI Generator slide 7 de 44
ww
w.3
layer.
com
.br
Motivação TC são funções do modelo de dados
consistência,aparência,validação,
organização,customizações,
etc.
A dependência da TC em relação ao modelo de dados
Modelo de classes Tela de Cadastro
>> motivação
Merlin - The First Runtime GUI Generator slide 8 de 44
ww
w.3
layer.
com
.br
Motivação Regras clássicas
>> motivação
O mapeamento básico entre os elementos
Modelo de dados Tela de Cadastro
Classe Tela
Atributo Controle
Relacionamento Navegação
Merlin - The First Runtime GUI Generator slide 9 de 44
ww
w.3
layer.
com
.br
Motivação Regras clássicas
Implementando as regras clássicasClasse Tela
Atributo Controle
Relacionamento Navegação
public class Cliente { String nome; Cidade naturalidade; boolean ativo;}
>> motivação
Nome
Cadastro de Clientes
Ativo
Naturalidade
SalvarCancelar
O cadastro gerado
A classe de dados
1
1
Merlin - The First Runtime GUI Generator slide 10 de 44
ww
w.3
layer.
com
.br
Motivação Regras clássicas
Implementando as regras clássicasClasse Tela
Atributo Controle
Relacionamento Navegação
public class Cliente { String nome; Cidade naturalidade; boolean ativo;}
>> motivação
Nome
Cadastro de Clientes
Ativo
SalvarCancelar
O cadastro gerado
A classe de dados
2
2
Naturalidade
Merlin - The First Runtime GUI Generator slide 11 de 44
ww
w.3
layer.
com
.br
Motivação Regras clássicas
Implementando as regras clássicasClasse Tela
Atributo Controle
Relacionamento Navegação
public class Cliente { String nome; Cidade naturalidade; boolean ativo;}
>> o objetivo da ferramenta
Nome
Cadastro de Clientes
Ativo
Naturalidade
SalvarCancelar
O cadastro gerado
A classe de dados
3
3
Merlin - The First Runtime GUI Generator slide 12 de 44
ww
w.3
layer.
com
.br
O objetivo da ferramenta Gerar TCs elementares com o menor esforço
possívelUm exemplo de interface elementar a ser gerada
>> algumas definições
O código essencial
new JFrame().add(Merlin.createUI(Cliente.class)).setVisible(true);
Merlin - The First Runtime GUI Generator slide 13 de 44
ww
w.3
layer.
com
.br
Algunas definições importantes Contexto
É a relação entre o elemento e o ambiente em que ele ocorre
Algo é importante dependendo do local onde ele está
Empirismo É o conhecimento baseado na experiência
Eu sei porque eu já fiz isso É reativo
Heurística É o conhecimento baseado em aproximações
Eu acho que sei porque eu já fiz algo parecido É pró-ativa
Inferência Obtém-se novos conhecimentos a partir de informações
existentes Quanto mais contexto, melhor
>> o processo
Merlin - The First Runtime GUI Generator slide 14 de 44
ww
w.3
layer.
com
.br
O processo
1. Criar as classes de dados2. Opcionalmente, decorar elas com
anotações3. Dentro da aplicação, invocar
Merlin.createUI
>> comparação
Merlin - The First Runtime GUI Generator slide 15 de 44
ww
w.3
layer.
com
.br
Uma pequena comparação
A mesma entrada e as diferentes saídas...
Uma classe de dados para teste ...
public class Usuario { long codigo; String nome; String observacoes; String logradouro; int numero; Cidade cidade; String complemento;}
... ou em notação UML
>> comparação
Merlin - The First Runtime GUI Generator slide 16 de 44
ww
w.3
layer.
com
.br
Uma pequena comparação
A mesma entrada e as diferentes saídas...Interfaces geradas por ferramentas tradicionais (a) e pelo Merlin (b)
Um gerador tradicional (a) Merlin (b)
Nome
Cadastro de Usuário
DicasDicasO campo nome é obrigatório.O campo logradouro é obrigatórioO campo número é obrigatório
Logradouro Rua São Sepé
Número 256 Complemento
Cidade Porto Alegre
Endereço
Observações
SalvarCancelar
nome
usuario
logradouro Rua São Sepé
numero 256
complemento
cidade Porto Alegre
observacoes
SalvarCancelar
codigo
>> comparação
Merlin - The First Runtime GUI Generator slide 17 de 44
ww
w.3
layer.
com
.br
Uma pequena comparação
A mesma entrada e as diferentes saídas...
>> comparação
Interfaces geradas por ferramentas tradicionais (a) e pelo Merlin (b)
Um gerador tradicional (a) Merlin (b)
Nome
Cadastro de Usuário
DicasDicasO campo nome é obrigatório.O campo logradouro é obrigatórioO campo número é obrigatório
Logradouro Rua São Sepé
Número 256 Complemento
Cidade Porto Alegre
Endereço
Observações
SalvarCancelar
nome
usuario
logradouro Rua São Sepé
numero 256
complemento
cidade Porto Alegre
observacoes
SalvarCancelar
codigo
Porque Observações é uma caixa de texto de múltiplas
linhas?
Merlin - The First Runtime GUI Generator slide 18 de 44
ww
w.3
layer.
com
.br
Uma pequena comparação
A mesma entrada e as diferentes saídas...
Nome
Cadastro de Usuário
DicasDicasO campo nome é obrigatório.O campo logradouro é obrigatórioO campo número é obrigatório
Logradouro Rua São Sepé
Número 256 Complemento
Cidade
Endereço
Observações
SalvarCancelar
nome
usuario
logradouro Rua São Sepé
numero 256
complemento
cidade
observacoes
SalvarCancelar
codigo
Porque é Observações e não Observacoes?
>> comparação
Interfaces geradas por ferramentas tradicionais (a) e pelo Merlin (b)
Um gerador tradicional (a) Merlin (b)
Merlin - The First Runtime GUI Generator slide 19 de 44
ww
w.3
layer.
com
.br
Uma pequena comparação
A mesma entrada e as diferentes saídas...
>> características gerais
Interfaces geradas por ferramentas tradicionais (a) e pelo Merlin (b)
Um gerador tradicional (a) Merlin (b)
Nome
Cadastro de Usuário
DicasDicasO campo nome é obrigatório.O campo logradouro é obrigatórioO campo número é obrigatório
Logradouro Rua São Sepé
Número 256 Complemento
Cidade Porto Alegre
Endereço
Observações
SalvarCancelar
nome
usuario
logradouro Rua São Sepé
numero 256
complemento
cidade Porto Alegre
observacoes
SalvarCancelar
codigo
Qual é o campo da cidade exibido na caixa de
seleção?
Merlin - The First Runtime GUI Generator slide 20 de 44
ww
w.3
layer.
com
.br
Características gerais Essência
Não produzir código-fonte, mas sim renderizar a interface do sistema em tempo de execução
Ser independente de framework gráfico Protótipo em Swing Previsão para JSF e GWT Outras aplicações podem ser SWT, XUL
Baseada no modelo de objetos do sistema Ter uma API minimalista
Anotações Merlin.createUI()
Reusar (e apostar em novos) padrões do Java 220, 317 e 318 – EJB e JPA 299 – Web Beans (JBoss Seam) 295 – Java Beans Binding 227 – Binding/Data Acess for J2EE 273 – DesignTime Bean 303 – Bean Validation (Hibernate Validator) 094 – Java Rules Engine (JBoss Drools)
>> características gerais
Merlin - The First Runtime GUI Generator slide 21 de 44
ww
w.3
layer.
com
.br
Características gerais
Não utilizar metamodelo externo Tudo reside nas classes compiladas do sistema
Utilizar ao máximo conceitos como heurísiticas, empirismo, inferência baseada em contexto, etc.
Configuração por exceção Reuso de histórico
>> características gerais
Merlin - The First Runtime GUI Generator slide 22 de 44
ww
w.3
layer.
com
.br
Características gerais
Não utilizar metamodelo externo Tudo reside nas classes compiladas do sistema
Utilizar ao máximo conceitos como heurísiticas, empirismo, inferência baseada em contexto, etc.
Configuração por exceção Reuso de histórico
O custo dos geradores tradicionais
Tempo
CustoS1 S2 S3 Sn
>> características gerais
Merlin - The First Runtime GUI Generator slide 23 de 44
ww
w.3
layer.
com
.br
Características gerais
Não utilizar metamodelo externo Tudo reside nas classes compiladas do sistema
Utilizar ao máximo conceitos como heurísiticas, empirismo, inferência baseada em contexto, etc.
Configuração por exceção Reuso de histórico
O custo do Merlin
Tempo
CustoS1
S2S3 Sn
>> histórico
Merlin - The First Runtime GUI Generator slide 24 de 44
ww
w.3
layer.
com
.br
O histórico
A busca por informações históricas pode ser feita no próprio classpath do sistema Em servidores de aplicação, tudo pode ser
compartilhado Em aplicações simples (standalone), as classes
com anotações podem ser exportadas juntoClasses nos servidores de aplicação
>> histórico
Root LIBs classes
S1
S2
Sn
C1
C2
Cn
classes
classes
classes
Merlin - The First Runtime GUI Generator slide 25 de 44
ww
w.3
layer.
com
.br
O histórico
A busca por informações históricas pode ser feita no próprio classpath do sistema Em servidores de aplicação, tudo pode ser
compartilhado Em aplicações simples (standalone), as classes
com anotações podem ser exportadas juntoClasses nos servidores de aplicação
>> slistaks
Root LIBs
Histórico
classes
S1
S2
Sn
C1
C2
Cn
classes
classes
classes
Merlin - The First Runtime GUI Generator slide 26 de 44
ww
w.3
layer.
com
.br
Slistaks
Informações de contexto, heurísticas, empirismo e inferência são utilizados para: Gerar corretamente nomes para labels Mapear os tipos de controles em função do tipo
de dado Adicionar validadores, tamanho, etc. AgrupamentosUtilizando a ocorrência de termos para produzir o conteúdo em comboboxes
12
110nome
status
codigo 110
>> slistaks de graça
Merlin - The First Runtime GUI Generator slide 27 de 44
ww
w.3
layer.
com
.br
Slistaks de graça
Google como fonte de informações Relevância de campos pode ser obtida de
forma onlineO maior contexto gratuito do mundo: A internet
nome : 212 milhões
codigo : 148 milhões
O termo nome é mais significativo, logo ele é
usado na caixa de seleção
>> mais slistaks de graça
Merlin - The First Runtime GUI Generator slide 28 de 44
ww
w.3
layer.
com
.br
Mais slistaks de graça
Dicionários de sinônimos Para inferir mapeamentos de controles
observacao = informacaoComplementar = outrasInformacoes
Todos geram textAreasUtilizando um dicionário de sinônimos gratuito para inferir mapeamentos
>> ainda slistaks de graça
Se observacao é (ou já foi) um textArea, é provável que outrasInformacoes também
o seja
Merlin - The First Runtime GUI Generator slide 29 de 44
ww
w.3
layer.
com
.br
Ainda slistaks de graça
Algoritmos de similaridade Para detectar aproximações e inferir
correspondências observacao = observacoes
Muitos frameworks na webUtilizando um framework externo para identificar similaridades
System.out.print( StringMetrics.compare(“observacao”,”observacoes”));//imprime 0.8 (entre 0 e 1)
Por exemplo, se o valor for maior que 0.5 assumimos que os termos são iguais. Assim, se observacao é (ou já foi) um textArea, é provável que observacoes também o seja.
>> eu adoro slistaks
Merlin - The First Runtime GUI Generator slide 30 de 44
ww
w.3
layer.
com
.br
Eu adoro slistaks
Corretores ortográficos Para gerar labels
observacao = observação
Utilizando corretores ortográficos disponíveis no próprio ambiente
>> agrupamentos
Merlin - The First Runtime GUI Generator slide 31 de 44
ww
w.3
layer.
com
.br
Agrupamentos
Agrupando controles nas telas Requisito
Os campos Cidade, Rua e Número devem ser exibidos em conjuntoCriando um agrupamento simples
A classe de dadosA tela
@Group(caption=“Endereço”,fields=“cidade,rua,numero”)
class Cliente { String nome; Cidade cidade; String rua; String numero;}
Cadastro de Cliente
Dicas
Nome
SalvarCancelar
Cadastro de Cliente 1
2
3
4
5
6
7
8
>> dependências
Rua
Número
Cidade
Endereço
Merlin - The First Runtime GUI Generator slide 32 de 44
ww
w.3
layer.
com
.br
Dependências
Vinculando controles nas telas Requisito
Se o cliente possuir cheque especial, habilitar limite de crédito
Criando dependências simples
A classe de dadosA tela
class Cliente { String nome; @Dependence(“limite”) boolean possuiCheque; double limite;}
Cadastro de Cliente
Dicas
Nome
SalvarCancelar
Cadastro de Cliente
Limite
Possui cheque
1
2
3
4
5
6
>> agentes
Merlin - The First Runtime GUI Generator slide 33 de 44
ww
w.3
layer.
com
.br
Agentes
Derivados da linguagem Eiffel, agentes são elementos que podem ser plugados na IU e executar funções diversas, como: Tratamento de eventos Invocação de regras de negócio Definição de propriedades Execução de Scripts
O conceito de agentes
Eventos
Scripts
Regras de negócio
Propriedades
Controlede
tela
>> agentes
?
Merlin - The First Runtime GUI Generator slide 34 de 44
ww
w.3
layer.
com
.br
Agentes
Derivados da linguagem Eiffel, agentes são elementos que podem ser plugados na IU e executar funções diversas, como: Tratamento de eventos Invocação de regras de negócio Definição de propriedades Execução de Scripts
O conceito de agentes
Eventos
Scripts
Regras de negócio
Propriedades
Controlede
telaAgentes
>> agentes
Merlin - The First Runtime GUI Generator slide 35 de 44
ww
w.3
layer.
com
.br
Agentes Agentes na execução de regras de negócio
Requisito Ao preencher o salário do cliente, se ele não tiver
débitos deve ser habilitado um cartão de crédito para ele.
Conectando eventos e regras de negócio
A classe de dadosA tela
class Cliente { String nome; @Agent( event={“focusLost”}, action={“habilitarCartao”}) float salario; boolean cartaoCredito;}
Cadastro de Cliente
Dicas
Nome
SalvarCancelar
Cadastro de Cliente
Salário
Cartão de crédito
1
2
3
4
5
6
7
8
>> agentes
Merlin - The First Runtime GUI Generator slide 36 de 44
ww
w.3
layer.
com
.br
Agentes
Agentes na execução de regras de negócio Requisito (agora de forma assíncrona)
Ao preencher o salário do cliente, se ele não tiver débitos deve ser habilitado um cartão de crédito para ele.
Conectando eventos e regras de negócio de forma assíncrona
A classe de dadosA tela
class Cliente { String nome; @Async @Agent( event={“focusLost”}, action={“habilitarCartao”}) float salario; boolean cartaoCredito;}
Cadastro de Cliente
Dicas
Nome
SalvarCancelar
Cadastro de Cliente
Salário
Cartão de crédito
1
2
3
4
5
6
7
8
>> agentes
Merlin - The First Runtime GUI Generator slide 37 de 44
ww
w.3
layer.
com
.br
Agentes
Agentes na execução de regras de negócio Requisito
Ao preencher o salário do cliente, se ele não tiver débitos deve ser habilitado um cartão de crédito para ele.
Implementando a regra de negócio
public class AlgumasRegras { public void habilitarCartao() { @In JTextField salario; @In JCheckBox cartao;
boolean debitos = true; //processa regra de negócio... cartao.setEnabled(!debitos); }}
123456789
10
>> agentes
Merlin - The First Runtime GUI Generator slide 38 de 44
ww
w.3
layer.
com
.br
Agentes
Agentes na definição de propriedades de controles Requisito
Aplicar uma borda verde saliente sobre o nome do cliente.
Uma interface com controle customizado
A classe de dadosA tela
class Cliente {
@Agent( property={“border=BorderFactory.createLineBorder(Color.green,2)”})
String nome; float salario; boolean cartaoCredito;}
Cadastro de Cliente
Dicas
Nome
SalvarCancelar
Cadastro de Cliente
Salário
Cartão de crédito
1
2
3
4
5
6
7
8
>> agentes
Merlin - The First Runtime GUI Generator slide 39 de 44
ww
w.3
layer.
com
.br
Agentes
Agentes na execução de scripts (BeanShell, Groovy, etc.) Requisito
Criar uma regra externa configurável para calcular o limite de crédito do cliente em função do valor do salário.Utilizando agentes para externalizar comportamentos através de scripts
A classe de dadosA tela
class Cliente { String nome; @Agent(
script={“/scripts/calc.js”}) float salario; float limiteCredito;}
Cadastro de Cliente
Dicas
Nome
SalvarCancelar
Cadastro de Cliente
Salário
Limite de crédito
1
2
3
4
5
6
>> agentes
7
Merlin - The First Runtime GUI Generator slide 40 de 44
ww
w.3
layer.
com
.br
Agentes
Agentes na execução de scripts (BeanShell, Groovy, etc.) Requisito
Criar uma regra externa configurável para calcular o limite de crédito do cliente.
O script externo escrito em BeanShell
var salario = new Float(this.caller.getText());
var limite = Merlin.getControle(“cliente.limiteCredito”);
limite.setText(salario * 0.3);
1
2
3
4
5
6
/scripts/calc.js
>> layout
Merlin - The First Runtime GUI Generator slide 41 de 44
ww
w.3
layer.
com
.br
Layout O posicionamento de controles é totalmente
executado por algoritmos, os quais utilizam Gerenciadores de layout (TableLayout, JGoodies Forms,
MigLayout) Heurísiticas, UI patterns, regras de usabilidade Configurações via anotações
Customizações Simples
Uso de anotações Complexas
Implementação de novos algoritmos Malucas
Design manual
>> layout
Merlin - The First Runtime GUI Generator slide 42 de 44
ww
w.3
layer.
com
.br
Layout
Alterando o layout via anotações Modificando algumas coisas
Redefinindo a ordem de controles e a posição de labels na tela
A classe de dadosA tela
class Cliente { @Order(after=“observacoes”) String nome; float salario; @Caption(pos=Caption.TOP_LEFT) String observacoes;}
Cadastro de ClienteCadastro de Cliente
Salário
1
2
3
4
5
6Nome
Observações
7
2
5Observações
>> layout
Merlin - The First Runtime GUI Generator slide 43 de 44
ww
w.3
layer.
com
.br
Layout
Alterando o layout via anotações Modificando tudo de uma vez
Redefinindo a ordem de controles e a posição de todos os labels na tela
A classe de dadosA tela
@Caption(pos=Caption.TOP_LEFT)class Cliente { @Order(after=“observacoes”) String nome; float salario; String observacoes;}
Cadastro de ClienteCadastro de Cliente
Salário
1
2
3
4
5
6Nome
Observações
7
>> layout
Merlin - The First Runtime GUI Generator slide 44 de 44
ww
w.3
layer.
com
.br
Layout
Um layout maluco Eu quero do meu jeito
>> layout
A tela desejadaCadastro de ClienteCadastro de Cliente
Salário
Nome
Observações
Merlin - The First Runtime GUI Generator slide 45 de 44
ww
w.3
layer.
com
.br
Layout
Criando um layout maluco1. Cria-se uma classe IU com o layout desejado
TemplateMaluco extends JPanel { //... }
Cadastro de Cliente
>> layout
A tela desejada
Merlin - The First Runtime GUI Generator slide 46 de 44
ww
w.3
layer.
com
.br
Layout
Criando um layout maluco2. Define-se nomes de controles idênticos aos
que serão gerados
Cadastro de Cliente
lblSalario
txtSalario
lblNome
cliente.nome
txtaObservacoes
lblObservacoes
>> layout
A tela desejada
TemplateMaluco extends JPanel { //... }
Merlin - The First Runtime GUI Generator slide 47 de 44
ww
w.3
layer.
com
.br
Layout
Criando um layout maluco3. Executa-se a geração passando o template
como parâmetroMerlin.createIhc(Cliente.class,
TemplateMaluco.class);
>> extensões
O resultado finalCadastro de ClienteCadastro de Cliente
Salário
Nome
Observações
Merlin - The First Runtime GUI Generator slide 48 de 44
ww
w.3
layer.
com
.br
Extensões Modificando os controles de tela gerados
Uma interface padrão
A classe de dados A tela geradaCadastro de Cliente
Dicas
Nome
Naturalidade
SalvarCancelar
Cadastro de Clienteclass Cliente { String nome; Cidade naturalidade}
1
2
3
4
>> extensões
Merlin - The First Runtime GUI Generator slide 49 de 44
ww
w.3
layer.
com
.br
Extensões Modificando os controles de tela gerados
Uma interface com controle customizado
A classe de dados A tela gerada
class Cliente { String nome; @RenderAs(Lookup.class) Cidade naturalidade}
Cadastro de Cliente
Dicas
Nome
Naturalidade
SalvarCancelar
Cadastro de Cliente1
2
3
4
5
>> extensões
Merlin - The First Runtime GUI Generator slide 50 de 44
ww
w.3
layer.
com
.br
Extensões Modificando os controles de tela gerados
Criando o controle customizado
class Lookup extends JPanel //faz como quiser}
Uma interface com controle customizado
A classe de dados A tela gerada
class Cliente { String nome; @RenderAs(Lookup.class) Cidade naturalidade}
Cadastro de Cliente
Dicas
Nome
Naturalidade
SalvarCancelar
Cadastro de Cliente1
2
3
4
5
1
2
3
>> demos
Merlin - The First Runtime GUI Generator slide 51 de 44
ww
w.3
layer.
com
.br
Demos
Dois demos simples Criando uma tela simples
http://3layer.no-ip.info:6666/confluence/pages/viewpage.action?pageId=6979626
Usando renderizadores e binders cutomizados http
://3layer.no-ip.info:6666/confluence/display/MERLIN/Renderizadores+e+Binders
>> estágio atual e perspectivas
Merlin - The First Runtime GUI Generator slide 52 de 44
ww
w.3
layer.
com
.br
Estágio atual e perspectivas Divulgação Alfa release disponível
Controles básicos, agentes, layout e anotações essenciais Telas de cadastro simples
Parte teórica em desenvolvimento Binding, telas mestre-detalhte, integração com outros
frameworks Captação de recursos financeiros 2008/2
Beta release em Swing, Alpha release em JSF 2009 em diante
Desenvolvimento efetivo do projeto, gerência de realimentação
2010 produto para o mercado
>> EOF
Merlin - The First Runtime GUI Generator slide 53 de 44
ww
w.3
layer.
com
.br
Fim
ww
w.3
layer.
com
.br
Conteúdo http://merlin.dev.java.net http://merlin.3layer.com.br http://treelayer.dev.java.net http://treelayer-merlin.blogspot.com
Contato http://groups.google.com/group/treelayer-merli
n
Histórias http://telasdecadastro.blogspot.com