Temple Coding

  • Home
  • Open Source
  • About
    • Books I am reading
    • About
RSS

Mapeamentos condicionais usando o AutoMapper

Posted on 28/10/2010 by vintem
No Comments

Eu me deparei com um problema diferente usando o AutoMapper. Eu precisava mapear um atributo do tipo DateTime de um web service para uma classe de negócio.

Se você já fez isso, provavelmente sabe que quando tem um atributo do tipo DateTime, você terá na sua classe de proxy dois atributos. Um do tipo DateTime e um booleano que informa se o seu DateTime está preenchido ou não.

Assim, supondo que no seu web service exista um atributo do tipo DateTime chamado CriadoEm, então você terá em sua classe de proxy dois atributos assim:

?View Code CSHARP
1
2
public DateTime CriadoEm { get; set; }
public bool CriadoEmSpecified { get; set; }

Bom, nesse caso, eu queria que o AutoMapper mapeasse esse atributo apenas se CriadoEmSpecified fosse = true.

Eu resolvi isso dessa forma:

?View Code CSHARP
1
2
3
4
5
Mapper.CreateMap<ClasseOrigemWs, MinhaClasseNeg>()
  .ForMember(c => c.CriadoEm, opt => {
    opt.Condition(x => x.CriadoEmSpecified);
    opt.MapFrom(x => x.CriadoEm);
  });

É claro que isso vale para qualquer condição que você queira, então, agora é só aproveitar. Alegre

Tweet
government,politics news,politics news,politics
Categories: Development | Tags: automapper

Novidades no blog

Posted on 20/10/2010 by vintem
No Comments

O blog está com novo layout! Agora feito por uma profissional! Obrigado Michele.

E também agora os comentários são controlados pelo Disqus.

Críticas? Sugestões? Fazo uso do disqus e comente!

Tweet
government,politics news,politics news,politics
Categories: Blog | Tags: blog

Mapeando suas classes com o AutoMapper

Posted on 29/09/2010 by vintem
1 Comment

Um framework que eu tenho usado com frequência ultimamente é o AutoMapper, e pra quem não conhece ele, bom, ele faz.. mapeamento de objetos. Iupi!

Existem vários cenários onde isso é feito, no meu caso, principalmente, eu tenho usado para mapear estruturas de web services que eu consumo para objetos dentro da minha aplicação. Mas outro cenário comum é, quando usamos o padrão ViewModel, mapear objetos de negócio para a ViewModel.

A motivação para o uso do AutoMapper é manter as responsabilidades separadas, assim, temos um framework só para fazer isso e não precisamos colocar esse mapeamento no meio das nossas classes.

O uso do AutoMapper é bem simples, apenas um assembly que deve ser referenciado no projeto, depois disso devemos criar/definir os mapeamentos.

Vamos imaginar um cenário onde eu tenho um Web Service e quero mapear uma classe PedidoWs para a minha classe Pedido e para manter simples, digamos que as propriedades tem os mesmos nomes. Veja o diagrama abaixo:

Classes

Para fazer um mapeamento num cenário desses é bem simples, criamos o mapeamento assim:

?View Code CSHARP
1
Mapper.CreateMap<PedidoWs, Pedido>();

E depois para usarmos o mapeamento basta executar:

?View Code CSHARP
1
Mapper.Map<PedidoWs, Pedido>(meuObjetoDoTipoPedidoWs);

Esse é o padrão que vamos usar para mapear todos os objetos independentemente de como o mapeamento for criado.

Agora imagine que existam propriedades iguais, mas com nomes diferentes. Por exemplo, imagine que no PedidoWs existe uma propriedade chamada Cliente_ID ao invés de ClienteId, o mapeamento ficaria assim:

?View Code CSHARP
1
2
Mapper.CreateMap<PedidoWs, Pedido>()
     .ForMember(c => c.ClienteId, opt => opt.MapFrom(x => x.Cliente_ID));

Veja, todos os outros atributos serão mapeados normalmente, apenas o ClienteId que foi declarado de forma explícita de onde vem.

Um outro caso importante é quando temos que fazer alguma conversão. Por exemplo, digamos que no nosso caso a data vem do web service em formato de string e temos que converter para DateTime. Faríamos assim:

?View Code CSHARP
1
2
3
Mapper.CreateMap<PedidoWs, Pedido>()
     .ForMember(c => c.DataPedido, opt => opt.ResolveUsing<DateTimeResolver>()
         .FromMember(x => x.DataPedido);

Para usar o ResolveUsing precisamos definir a classe DateTimeResover e eu fiz dessa forma:

?View Code CSHARP
1
2
3
4
5
6
7
public class DateTimeResolver : ValueResolver<string, DateTime>
{
    protected override DateTime ResolveCore(string source)
    {
        return DateTime.Parse(source);
    }
}

Para finalizar, vale dizer que essa configuração dos mapeamentos pode ser demorada, então não é uma boa idéia executar as configurações toda a vez. O que eu faço, já que uso isso para a web a maior parte do tempo, é no meu Application_Start dentro do global.asax, executar essas configurações, assim elas são feitas apenas uma vez.

Existem várias outras opções de configuração para o AutoMapper e no site deles tem vários exemplos, vale a pena conferir. Aqui, foi só pra dar um gostinho.

Tweet
government,politics news,politics news,politics
Categories: Development | Tags: automapper

O Controle de Versão e o DeLorean

Posted on 21/09/2010 by vintem
No Comments

Um cenário que é comumente visto em equipes de desenvolvimento que usam ferramentas de controle de versão como Subversion, Source Safe, CVS, Git, etc, é aquele onde o desenvolvedor faz um checkout no código, altera o que tem que alterar e na sequência faz o commit (check-in se vc ainda é um infeliz usuário do VSS).

Qual o problema desse cenário? Você consegue dizer? O código está num repositório central disponível para todos os desenvolvedores da equipe, não está?

O problema, nesse caso, é que na grande maioria das vezes o que se faz é simplesmente esse procedimento de check-out e commit, não é efetivamente um Controle de Versão, existe apenas um repositório central de código.

Existem diversas razões as quais eu poderia dizer que você não quer fazer apenas um repositório central, desde a mais simples, que é o fato de você controlar o que é efetivamente disponibilizado a cada versão, até oDeLorean-DeVoltaparaoFuturo-1 que acho que é o maior benefício e que aqui vou chamar de a possibilidade de “viajar no tempo”.

Digamos que você disponibilizou a versão 1.0 do seu mais novo cliente do Twitter. Software no ar, milhares de downloads em poucas horas. Hora de preparar a inovadora versão 2.0 que vai ler as mensagens em voz alta e que você vai poder ditar as mensagens também. Ótimo para não perder nada do Twitter quando você está dirigindo.

Check-out feito, algumas alterações, novas funcionalidades e uns commits, afinal de contas, você é um praticante de Integração Contínua. De repente, seu telefone toca e aquela versão 1.0 tem um bug que trava o aplicativo e você precisa corrigir. O que você faz? Fala que não pode porque o código da versão 2.0 está no meio e ainda não foi testado? Desfaz o que foi feito?

Voltemos para o dia em que a versão 1.0 foi lançada, o código está no repositório e você decide iniciar a versão 2.0, que é um ponto no futuro onde você gostaria de chegar. É para isso que existe uma coisa chamada branch, ele é uma cópia separada da sua versão 1.0 onde você pode fazer alterações e ainda por cima manter a versão 1.0 disponível do jeito que você deixou. Quando esse bug chega, você altera o código do branch principal, o da versão em produção (no caso 1.0), e pode mandar essa versão, digamos, 1.0.1 com a correção sem se preocupar com o código da versão 2.

Parece simples, e realmente é, mas é um hábito muito pouco comum em equipes de desenvolvimento, esse de criar branches de versões.

Ferramentas de controle de versão são para isso, para dar esse poder a desenvolvedores, o poder de viajar entre as versões, as modificações, etc. Mas para isso é preciso, no mínimo, deixar um rastro do caminho a ser percorrido.

de-volta-para-o-futuro

Tweet
government,politics news,politics news,politics
Categories: Source Code Control | Tags: controle de versoes

Desenvolvedores felizes, código feliz!

Posted on 15/09/2010 by vintem
No Comments

Malcolm Gladwell em sem livro O Ponto da Virada, entre outras coisas, conta a história de como a cidade de Nova Iorque nos anos 90 praticamente refez as suas linhas de metrô, transformando-as de um local sujo onde o crime era uma constante para um dos mais modernos e organizados metrôs do mundo. Além disso nessa mesma época a cidade que tinha uma alta taxa de criminalidade viu o crime cair em grandes proporções.

Comparacao_metro

O segredo? Não deixar janelas quebradas!

Primeiro, como pode ser visto, os metrôs eram todos pixados, em um processo de grafitagem que levava três dias. Então eles resolveram que ao primeiro sinal de pixação o trêm seria limpo antes de ser colocado novamente nos trilhos. Resultado, ninguém queria ter que recomeçar o trabalho de pixar tudo do início novamente e os trens deixaram de ter essa imagem suja.

Na segunda etapa, como haviam muitos crimes no sistema metroviário, eles resolveram acabar com as viagens de graça (muita gente simplesmente não pagava o metrô porque algumas pessoas “travavam” a catraca), estima-se que em torno de 170 mil pessoas por dia usavam o metro sem pagar. Policiais à paisana pegavam os caloteiros, algemavam e deixavam à vista na plataforma para mostrar que aquilo estava mudando. Melhor que isso, 1 em cada 7 dessas pessoas tinha uma ordem de prisão anterior e 1 em cada 20 portava algum tipo de arma.

Claro, não foi somente isso que gerou toda essa mudança, mas isso iniciou o processo.

Enfim, qual o segredo? Atenção aos detalhes do ambiente. Ainda no ponto da virada, uma pesquisa é citada dizendo que muitas vezes nossas atitudes são influenciadas pelo ambiente em que estamos, ou seja, aquela máxima de “A ocasião faz o ladrão” é válida para outras coisas também, como, por exemplo, em ambientes agressivos pessoas se tornam mais agressivas.

“O Poder do Contexto estabelece que não precisamos resolver grandes problemas para encontrar a solução para a criminalidade. Podemos previnir a ocorrência de delitos apenas limpando a sujeira das paredes e prendendo os caloteiros.”

O ponto que eu quero chegar é se você quer exigir qualidade no software que você e sua equipe fazem,messy-office-03 garanta qualidade de ambiente de trabalho. Não espere que num ambiente que ninguém se importa com a imagem, com o conforto, com a limpeza, com o silêncio, etc, seus desenvolvedores farão o mesmo. Num local onde a máxima é algo como “um canto pra eles trabalharem” provavelmente vai gerar um software do tipo “só faz funcionar que tá valendo”.

Desenvolvedores realizam atividades criativas. Ponto! Você tem que pensar pra criar código e se quiser criar um código bem feito precisa pensar mais ainda.

Não insista! Não ache que criar software é igual levantar uma parede. Não! A analogia do construção civil também não se aplica para construção de software nesse caso.

Construir software está muito mais parecido com um profissional que constrói instrumentos musicais manualmente. Quanto melhor ele puder se dedicar a isso, tiver ferramentas, espaço e ambiente propício, melhor será o som do instrumento. Qual o resultado disso? Quanto melhor o instrumento, melhor o som.

2010-09-14_16-03-27_933_Piracicaba

Da mesma forma se você quer que seus desenvolvedores produzam bem e com qualidade, comece pelo ambiente de trabalho. Um ambiente onde ninguém consegue sentar devidamente porque suas pernas não cabem embaixo da mesa, ou onde não há espaço para apoiar os braços, ou cadeiras tão desconfortáveis que dão dores nas costas, na melhor das hipóteses diz “não nos importamos como, apenas faça o que tem que ser feito”. Além disso, como dois desenvolvedores poderão parear ou colaborar um com outro se não podem sentar um ao lado do outro?

Se queremos bons softwares, temos que trazer condições para os desenvolvedores criarem, para que possam se inspirar e isso começa com um bom ambiente.

Da convivência de anos com desenvolvedores e eu mesmo sendo um, posso deixar aqui algumas dicas:

  • Comece com uma boa cadeira, onde seja possível adaptá-la as necessidades fisicas individuais. Afinal de contas é sentado nela que o desenvolvedor passará a maior parte do tempo.
  • Uma mesa onde seja possível acomodar duas pessoas olhando para o mesmo computador ou que possam ter dois computadores lado a lado e ainda espaço para usar mouse, apoiar braços, deixar blocos de anotação entre outras coisas na mesa.
  • Desenvolvedores costumam gostar de coisas excêntricas, como bonecos, imagens, etc. Deixe um espaço para isso também e permita esse tipo de ambiente, isso exercita a criatividade.
  • Gaveteiros dificultam a movimentação, deixe um espaço um pouco afastado das mesas para isso.
  • Se possível permita que a disposição das mesas possa ser modificada conforme a necessidade do pessoal.
  • Um quadro branco é uma das melhores formas de comunicação, e você quer que todos saibam o que está acontecendo não é?

Por fim, se o ambiente dos seus desenvolvedores não está sob sua responsabilidade, ao menos reivindique que eles tenham um espaço saudável para trabalhar.

Não se esqueça: desenvolvedores felizes com certeza produzirão um software melhor, com menos bugs e portanto com menos dor de cabeça.

PS.: Segunda, 13 de setembro, foi o dia do programador, parabéns!

Tweet
government,politics news,politics news,politics
Categories: Development

Seja Ágil, não brigue de forma ágil

Posted on 13/09/2010 by vintem
No Comments

Durante o QConSP (que por sinal foi muito bom), uma discussão muito recorrente foi sobre as divergências entre as metodologias ágeis, tivemos inclusive uma palestra falando sobre a Guerra das Metodologias Ágeis 2.0.

tratamento-de-choque-poster02

Uma constante foram algumas críticas ao SCRUM, suas lacunas e falhas.

A primeira coisa que queria lembrar aqui é que o SCRUM é um framework de gerenciamento de projetos ágeis e não uma metodologia de desenvolvimento. E por isso, é óbvio que se você olhar para todo o processo de desenvolvimento o SCRUM não cobre diversos aspectos, e claramente ele não se propõe a fazer isso.

Errado está quem tenta usar o SCRUM para isso. Mas, como é ele que está em mais evidência hoje, obviamente foi o mais criticado.

Outra questão importante é que ser ágil não depende de nomes. SCRUM, XP, Kanban, Lean e afins, são formas de fazer isso, ou melhor, são ferramentas para auxílio no processo de ser ágil e não passam disso, ferramentas. O que não impede de se complementarem e/ou trabalharem juntos.

O que importa nesse caso, é o que se adapta melhor ao que você faz, ao modelo de negócios da sua empresa. Num exemplo bem simples, se você não trabalha com projetos e trabalha com atendimento sob demanda, talvez seja mais fácil usar apenas um quadro de kanban do que planejar iterações certo?

Por fim, fica a dica do Sérgio Monteiro (em conversa na QConSP), que é óbvia mas as pessoas tem esquecido. Olhe primeiro e principalmente para o Manifesto Ágil. Pare um minuto agora para ler aquelas 4 linhas, vai lá que eu espero.

Por acaso ali fala que uma iteração tem que ser de 2 semanas? Fala que você tem que colar post-its? Ou que você tem que fazer um Burndown chart?

Na próxima vez que você disser que é ágil ou que você pensar a respeito, reflita se você está levantando uma bandeira, ou se você realmente está olhando para o Manifesto.

Afinal de contas, ser ágil é focar mais em indivíduos e interações entre eles do que em processos e ferramentas.

Tweet
government,politics news,politics news,politics
Categories: Sem categoria | Tags: agilidade

Análise TDC2010

Posted on 29/08/2010 by vintem
No Comments

No último final de semana dos dias 21 e 22 de agosto, tive a oportunidade de participar do TDC2010. Estava inscrito nas trilhas de .NET e Arduino para sábado e domingo, respectivamente.

Estava inscrito, porém, ao chegar lá, logo na abertura fico sabendo do “Lado B”, que eram trilhas alternativas criadas de maneira espontânea e sem muita programação, ou seja, meu sábado foi inteiro B. :)

Passei a manhã numa conversa descontraída sobre empreendedorismo com gente que deu as caras a tapa e abriram suas empresas, gente como o Alexandre Gomes, o Felipe Rodrigues e o Vinicius Senger, além de outros participantes da conferência. Posso dizer com certeza que foram algumas poucas horas de muita informação e ainda muito divertimento. À tarde, pra completar o Felipe Rodrigues ainda falou sobre trabalhos como Freelancer no mundo Rails.

Enfim, foi um dia em que eu não vi muito de .NET, embora eu tenha conversado com gente que foi nas palestras de .NET e me disse que foram ótimas, mas foi um dia de grande crescimento.

No domingo eu participei o dia todo na trilha de Arduino (pra quem não sabe o que é o Arduino, deêm uma olhada nesse post), um dia de robótica, de automação para a casa, para o carro etc. O que eu posso dizer sobre o Arduino é que ele abre portas para uma área com grande potencial comercial a ser explorado, e no TDC2010 pude ver muitas idéias nessa área.

Concluindo, o TDC2010 foi uma conferência bem diferente das que eu já participei e talvez por isso tenha sido também bem especial. Uma coisa posso dizer, foi um tempo ótimo e muito bem organizado!

Tweet
government,politics news,politics news,politics
Categories: Sem categoria | Tags: eventos, tdc

O que é um bom código pra você?

Posted on 12/08/2010 by vintem
No Comments

Já ouvi e li muita gente dizer que um bom código é subjetivo, sujeito a interpretação e coisas do gênero. Eu acredito que alguns aspectos do código podem ser definidos de uma forma mais prática e não tão subjetiva.

É claro, os padrões de projeto que usamos, as linguagens, quantidade de linhas que tem um método, essas coisas são realmente subjetivas e devem ser analisadas de acordo com o projeto/cliente/equipe, etc.

Mas quando eu codifico eu tenho algumas regras, que acredito que sejam bem claras, que ajudam a definir um bom código, claro, não são as únicas, mas essas são as primeiras que eu tomo por padrão. Pra mim um bom código começa com:

1) Dar um bom nome

Um classe, método ou variável deve ter um nome que documente e principalmente determine o que faz. Se você tiver uma classe que chama Gerenciador e um método chamado Executar, você está abrindo o escopo do que a classe e método podem fazer. O nome não restringe e pior não indica nada que o código deve fazer. Classes e métodos devem ter um próposito único e o nome deve refletir esse propósito.

Da mesma forma uma váriavel que chama simples “data” ou “valor” não dizem muita coisa. Prefira um nome como dataNascimento ou valorFaturado.

2) Códigos devem ser de fácil manutenção/modificação

Existe uma razão muito simples porque eu não concordo com a metáfora da construção civil para o desenvolvimento de software. Se você se sente quebrando uma parede quando está alterando ou adicionando uma melhoria para sua aplicação, com certeza você fez alguma coisa errada.

Existem diversos padrões de projetos e princípios que nos ajudam a fazer códigos que são mais fáceis de se manter. Comece sempre evitando repetições, se quando você tem que alterar uma funcionalidade, tem de mexer em mais de um local, provavelmente existe uma solução melhor pra isso.

Mas acima de tudo use o que a orientação a objeto tem de melhor para facilitar a alteração do sistema, afinal de contas, qual foi o projeto que você fez do início ao fim e que não teve nenhuma modificação?

3) Testes, testes e mais testes

Na verdade esse item poderia ser um complemento do anterior, testes ajudam a dar segurança e credibilidade na manutenção do código. Honestamente, eu não consigo mais me ver escrevendo um código novo sem teste unitário. O simples fato de fazer uma alteração e saber que nada quebrou porque tenho testes unitários já me convence de que eu preciso deles.

Conclusão

São 3 regras simples, somente elas não garantem um bom código, com certeza não. Mas para mim essas são as 3 regras que iniciam o desenvolvimento de um bom código, não consigo me ver escrevendo código sem pensar nessas regras e principalmente não acredito que um desenvolvedor que se considere sênior, seja realmente sênior se não tem essas 3 regras básicas.

E pra você, quais são as suas regras?

Tweet
government,politics news,politics news,politics
Categories: Sem categoria

Ser um especialista é saber o que você faz

Posted on 02/08/2010 by vintem
No Comments

House Arguing from Thiago Temple on Vimeo.

Eu sou um fã do seriado House M.D., não é de hoje, existem muitas coisas nesse seriado com as quais me identifico, mas uma das coisas que eu sempre curti, embora tenha que admitir, eu nunca entendo a parte técnica, são as discussões que eles fazem quando estão em um diagnóstico diferencial.

Veja só, na maioria das vezes, não só o House, como os outros médicos discutem e propõem idéias, sempre com base em seus conhecimentos e em exames médicos, a impressão que você tem ao assistir essas discussões é de que eles sabem do que estão falando. Claro, eu sei que é só uma ficção, mas por favor, não estrague o meu prazer de assistir o seriado :)

Existem duas analogias que quero fazer em relação a isso.

Primeiro os exames médicos. Para que eles possam evoluir no diagnóstico que estão fazendo eles fazem exames, eles não saem abrindo o paciente (pelo menos não na maioria das vezes). O que quero dizer com isso é, não é só usando o debugger que resolvemos problemas, isso, geralmente é um sinal de um software mal feito. Veja, podemos escrever logs, podemos rodar testes unitários, podemos fazer uma análise de DUMP de memória. Debugar, principalmente quando falamos de um sistema que roda na web deveria ser a última opção. Quando for escrever seu próximo sistema, pense que você deve gerar logs com o máximo de informação relevante para resolver algum problema futuro.

Em segundo lugar, eles sabem do que estão falando, tem conhecimento sobre o assunto, nesse caso obviamente percebemos principalmente com o House, mas os outros médicos sabem do que estão falando também. E o que quero dizer aqui pode parecer óbvio, mas não é o que vejo em muitos casos. Quando for resolver um problema ou desenvolver uma nova solução ou simplesmente dar continuidade em um projeto, tente entender porque aquilo funciona daquele jeito, conheça porque aquela tecnologia funciona e não somente “tá funcionando, não põe a mão”.

Como programadores muitas vezes buscamos uma solução para um problema na internet, copiamos um código, colamos no projeto e pronto. Funcionou? Sim, então tá bom. Não! Não está bom, saiba porque aquilo funciona, porque se tiver algum problema é você que terá que corrigir.

Finalmente, quero concluir dizendo que você não é um especialista em uma tecnologia (digamos Java ou .NET), porque você não conhece outra, você é um especialista em uma tecnologia quando você conhece profundamente aquela tecnologia. Dizer que você é um especialista em .NET porque você nunca programou em Java, não faz você saber como funciona o gerenciamento de memória do .NET Framework.

Tweet
government,politics news,politics news,politics
Categories: Sem categoria

Localização de mensagem de erro no ASP.NET MVC

Posted on 22/07/2010 by vintem
No Comments

Sabe quando você preenche uma data inválida em uma página usando o ASP.NET MVC e o erro vem em inglês assim:

ErroIngles

Isso acontece porque o DefaultModelBinder do MVC não conseguiu converter essa data, no caso acima, é óbvio porque não existe um mês 15. A questão é, como traduzir essa mensagem?

Um jeito que achei foi adicionando uma pasta App_GlobalResources e dentro dessa pasta adicionar um arquivo de resources, que no caso, chamei de CustomMvcResources.resx.

ArquivoResources

Nesse arquivo de resources adicione a seguinte linha:

ItemResource

No global.asax altere o método Application_Start para que fique assim:

?View Code CSHARP
1
2
3
4
5
6
protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();
    DefaultModelBinder.ResourceClassKey = "CustomMvcResources";
    RegisterRoutes(RouteTable.Routes);
}

O importante é que o valor informado à propriedade ResourceClassKey tenha o nome do arquivo de resource criado.

Agora o erro será apresentado do jeito que foi configurado no arquivo de resources.

ErroTraduzido

Tweet
government,politics news,politics news,politics
Categories: ASPNET MVC | Tags: asp.net mvc
Previous Entries
Next Entries
  • Categories

    • .NET (1)
    • ASP.NET (1)
    • ASPNET MVC (15)
    • Blog (1)
    • Source Code Control (2)
    • Development (10)
    • Java (1)
    • JavaScript (2)
    • jQuery (1)
    • Reading (5)
    • Ruby (2)
    • Ruby on Rails (1)
    • Sem categoria (23)
    • Testing (4)
  • Language

    • English
    • Português
  • Tags

    agilidade asp.net asp.net mvc asp.net vc automapper blog code templates controle de versoes css dataaccess dependency injection ebook encoding eventos excecoes firebug git globalizacao hibernate iis ironruby jasypt java javascript jquery json leitura less mvccontrib qcon rails ruby selenium simpledata snippet stored procedures structuremap tdc templates testes testes integrados visualstudio vraptor windsor
© Temple Coding. Proudly Powered by WordPress | Nest Theme by YChong