Tags: , | Posted by Rafael on 30/06/2011 01:45 | Comentários (2)

Olá pessoal!

Hoje gostaria de compartilhar com vocês, através de um rápido post, como definir qual versão do Microsoft Visual Studio será invocada através do atalho Menu Iniciar >> Executar >> devenv.

Muitos que desenvolvem utilizando o Microsoft Visual Studio, têm mais de uma versão da IDE instalada na máquina, por quaisquer motivos. E, a cada instalação do Microsoft Visual Studio, ao invocarmos o executável devenv através do prompt de comando do Windows, a última instalação do Microsoft Visual Studio efetuada é invocada.

Mas, afinal de contas, porque isso acontece? Não deveria invocar a versão mais atual? Não. Durante a instalação do Microsoft Visual Studio, o registro devenv.exe é atualizado com a versão da instalação. Ou seja, se você utiliza o Microsoft Visual Studio 2010 para desenvolver suas aplicação, e por algum motivo - necessidade de manutenção num projeto antigo, por exemplo, precisar instalar o Microsoft Visual Studio 2005, toda vez que você invocar o executável devenv.exe, o Microsoft Visual Studio 2005 será invocado, ao invés do Microsoft Visual Studio 2010.

Para alterar a versão padrão do Microsoft Visual Studio, acesse o Registro do Microsoft Windows - Menu Iniciar >> Executar >> regedit. Acesse o registro Computador >> HKEY_LOCAL_MACHINE >> SOFTWARE >> Microsoft >> Windows >> CurrentVersion >> App Paths >> devenv.exe, edite o registro "(Padrão)". Se você instalou o Microsoft Visual Studio 2008 por último, por exemplo, o registro deve estar da seguinte maneira:

 

  • C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE\devenv.exe

 

Para invocar o Microsoft Visual Studio 2010 ao invés do Microsoft Visual Studio 2008, altere a versão do Microsoft Visual Studio de 9.0 para 10.0. O registro ficará assim:

 

  • C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\devenv.exe

 

Clique em Ok, e encerre o Editor de Registros do Microsoft Windows.

Pronto!

Agora ao executar devenv através do prompt de comando do Microsoft Windows, o Visual Studio 2010 será invocado, ao invés do Microsoft Visual Studio 2008. O mesmo vale para o Microsoft Visual Studio 2005. Para que o Microsoft Visual Studio 2005 seja invocado, basta alterar a versão no registro para 8.0.

É isso! 

Até a próxima!

Tags: , , | Categories: Padrões de Projeto Posted by Rafael on 07/05/2011 17:06 | Comentários (0)

Olá pessoal!

Hoje vamos falar um pouco sobre um padrão muito utilizado e, de igual modo, simples: o padrão Singleton.

Esse padrão tem como objetivo "garantir que uma classe tenha somente uma instância e fornecer um ponto de acesso global para a mesma". [GAMMA, 2000].

Em algumas situações precisamos garantir que apenas uma instância de uma determinada classe seja criada no contexto do sistema. São os casos de fazermos uso de propriedades específicas de configuração comuns à toda aplicação, utilização de um Proxy qualquer existente na sua empresa, que seja utilizado para integração dos sistemas, por exemplo.

Por se tratar de um padrão muito simples, vamos direto para a representação da sua estrutura, e logo em seguida para uma implementação de exemplo.

A estrutura do padrão Singleton é a seguinte:

Estrutura Singleton

Para que exista uma instância única na aplicação, precisamos criar um construtor privado na classe Singleton, uma variável estática, e implementarmos a lógica para criação da instância e o seu retorno. O código abaixo exemplifica isso:

Aqui está o projeto completo: Singleton.zip (20,92 kb)

Ao executar o projeto, se você inserir um breakpoint no método obterInstancia da classe ProxyConnectionDB e ir passo-a-passo, notará que ele cria a instância apenas na primeira execução (variável con1), pois a classe nunca foi utilizada. Porém, na segunda chamada (variável con2) o objeto já existe, e sua instância é retornada, sem criar uma nova instância.

O exemplo acima implementa o padrão Singleton pois tem um contrutor privado, e um método que cria e/ou retorna a instância da classe, que será acessada por um único ponto na aplicação.

Alguns padrões podem ser implementados usando Singleton. É o caso dos padrões Prototype, AbstractyFactory e Builder. Já conhecemos o padrão AbstractyFactory, e veremos os padrões Prototype e Builder em breve.

É isso!

Até a próxima!

 

 

Referência Bibliográfica

GAMMA, Erich, Padrões de Projeto, Porto Alegre: Bookman, 2009.

Tags: , | Categories: C#, Linguagem de Programação Posted by Rafael on 12/04/2011 18:27 | Comentários (0)

Olá pessoal,

Vejam só que notícia bacana para aqueles que programam em C#: http://tirania.org/blog/archive/2011/Apr-06.html

Enjoy it, Cool

Até mais!

Tags: , , | Categories: C#, Linguagem de Programação Posted by Rafael on 11/01/2011 19:03 | Comentários (1)

Olá pessoal!

Falaremos hoje sobre operadores C#, em especial sobre os operadores shift, << e >> . A função desses operadores é deslocar bits para a esquerda ( << ) ou para a direita ( >> ), que podem ser utilizados apenas em operações com variáveis do tipo inteiro, pois, não existem números reais na base 2 (binários), apenas números inteiros.

Para entender melhor, vamos falar um pouco sobre números binários e inteiros.

Consideremos a seguinte tabela:

Essa é uma tabela para facilitar a representação de números inteiros em binários. Na linha superior (em azul) temos o expoente da base. Como a base que iremos trabalhar é binária, ou seja, base 2, a linha amarela representa o resultado da potenciação entre a base 2 e seus expoentes. Assim, temos 20 = 1, 21 = 2, 22 = 4, 23 = 8, ..., 210 = 1024, ..., e assim por diante (limitei até o expoente 10 apenas para facilitar a exemplificação).

Muito bem, agora, vamos representar o número inteiro 100 em binário. Na linha amarela, partimos sempre da esquerda para a direita, até encontrar o primeiro número menor ou igual ao número que queremos representar, que nosso caso é o inteiro 100.

Localizamos que o número 64 é o primeiro número menor ou igual a 100, da esquerda para a direita. Assim, “ligamos” o flag, ou seja, inserimos o número 1, da seguinte maneira:

Feito isso, partimos para o segundo bit. Devemos ter em mente o quanto resta para chegarmos a 100 inteiros. A conta é bem simples: se já “ligamos” o 64, a subtração entre 100 e 64 é igual a 36. A partir de agora, localizamos o primeiro número menor ou igual a 36, a partir da primeira célula à direita do flag que representa 64, que é 32.

Como 32 é menor ou igual a 36, ativamos também essa célula, ficando assim:

Legal, agora nos restam 4 inteiros (100 – 64 – 32 = 4). Dando seqüência, como 16 não é menor ou igual a 4, inserimos um 0, ou seja, “desligamos” o flag da célula 16, assim:

Da mesma maneira, fazemos com a célula 8, pois 8 não é menor ou igual a 4, ficando assim:

Como 4 é menor ou igual a 4, “ligamos” o flag, da seguinte maneira:

Como chegamos a 100 inteiros, completamos as células restantes à direita com 0, assim:

Temos agora o número inteiro 100 representado em binário como 1100100.

Muito bom! Agora que já sabemos como representar inteiros em binários de uma forma fácil, vamos entender como os operadores shift trabalham.

Basicamente, como dito anteriormente, o operador shift << desloca um bit à esquerda, inserindo um 0 (zero) na célula vazia, e o operador >> desloca um bit à direita, desconsiderando o bit que “sai” do range. Vamos exemplificar com um Console Application em C#, bem simples, junto com a nossa tabela de conversão.

Consideremos o seguinte Console Application:

namespace Blog.Operadores.Shift

{

    class Program

    {

        static void Main(string[] args)

        {

            try

            {

                Console.WriteLine("Insira um número inteiro:");

 

                int inteiro = 0;

                Int32.TryParse(Console.ReadLine(), out inteiro);

 

                Console.WriteLine("Número inteiro escolhido: " + inteiro.ToString());

 

                Console.WriteLine("");

 

                Console.WriteLine("Quantos bits você deseja deslocar?");

 

                int qtdeBits = 0;

                Int32.TryParse(Console.ReadLine(), out qtdeBits);

 

                Console.WriteLine("Bits a deslocar: " + qtdeBits.ToString());

 

                Console.WriteLine("");

 

                Console.WriteLine("À esquerda ou à direita? Digite << para à esquerda e >> para à direita:");

 

                string comando = Console.ReadLine();

 

                if (comando.Trim() != "<<" && comando.Trim() != ">>")

                {

                    throw new Exception("Comando inválido! Você deve escolher entre << e >>");

                }

 

                switch (comando.Trim())

                {

                    case "<<":

                        Console.WriteLine("Bit deslocado à esquerda");

                        inteiro = inteiro << qtdeBits; // forma simplificada: inteiro <<= qtdeBits;

                        break;

                    case ">>":

                        Console.WriteLine("Bit deslocado à direita");

                        inteiro = inteiro >> qtdeBits; // forma simplificada: inteiro >>= qtdeBits;

                        break;

                    default:

                        break;

                }

 

                Console.WriteLine("");

                Console.WriteLine("Resultado: " + inteiro.ToString());

            }

            catch (Exception ex)

            {

                Console.WriteLine("");

                Console.ForegroundColor = ConsoleColor.Red;

                Console.WriteLine("ERRO: " + ex.Message);

            }

            finally

            {

                Console.ResetColor();

                Console.ReadKey();

            }

        }

    }

}

Se preferir, faça o download do projeto aqui: Blog.Operadores.Shift.zip (19,21 kb)

Note os dois comentários // forma simplificada no código. Podemos escrever tanto assim x = x << y quanto x <<= y ou então x = x >> y quanto x >>= y. A segunda opção é a forma simplificada do comando. Muda apenas a sintaxe, o resultado é o mesmo.

Ao executarmos o aplicativo, temos a seguinte tela:

Para seguir o nosso exemplo, vamos inserir o número 100.

Vamos deslocar apenas 1 bit à esquerda.

Na tabela, podemos ver como pode ser feito manualmente:

Todos os bits são deslocados 1 (uma) casa para a esquerda, e a célula vaga é preenchida com 0 (zero).

Assim, temos o número inteiro 200 como resultado. Agora vamos executar novamente o aplicativo, porém, agora deslocando 1 bit à direita.

Na tabela:

Obtemos como resultado 50 inteiros.

Logo, podemos notar que, se deslocarmos 1 bit à esquerda, multiplicamos o número por 2, e se deslocar à direita, dividimos também por 2. Agora, porque por 2? A resposta é bem simples, como estamos trabalhando com binários, ou seja, base 2, o deslocamento de bits multiplica ou divide o valor pela base, que é 2.

Agora, se deslocarmos 3 bits à direita de 100, temos como resultado 12. Você pode me perguntar: porque não 12,5? A resposta também é simples: porque não existem números reais por representação de bits, ou seja, o resultado 12,5 é truncado, ficando apenas 12.

Vamos ver na tabela:

E na aplicação:

É isso aí.

Até a próxima!

Tags: , , , | Categories: Padrões de Projeto Posted by Rafael on 17/11/2010 00:30 | Comentários (1)

Pessoal, depois de um longo tempo impossibilitado de escrever, venho falar sobre o nosso primeiro dos cinco padrões de criação, o Abstract Factory, também conhecido como Kit.

A definição do padrão Abstract Factory, segundo o livro Padrões de Projeto - Soluções reutilizáveis de software orientado a objetos, escrito pelos integrantes da "Gang of Four" ou "GoF" é a seguinte: "Fornecer uma interface para a criação de famílias de objetos relacionados ou dependentes sem especificar suas classes concretas.". A definição é auto-explicativa. Utilizamos o padrão Abstract Factory quando queremos construir um conjunto de classes e fornecer apenas a interfaces de acessos às mesmas, não as implementações propriamente ditas, principalmente quando um sistema deve ser independente de como seus objetos são criados. Ou então, quando você precisar garantir que um conjunto de objetos deve ser utilizado em conjunto.

Existem diversas maneiras de implementarmos o padrão Abstract Factory. Demonstrarei apenas uma, bem simplificada, para facilitar o entendimento. A seguir está o diagrama de classes e o código gerado na linguagem C# pode ser baixado aqui: AbstractFactory.zip (30,20 kb)

Consideremos que queremos criar uma aplicação que instancia objetos de acordo com o ambiente onde esteja rodando (web, stand-alone ou mobile). Para facilitar o nosso exemplo, essa informação estará no App.config do aplicativo, mas poderia estar em qualquer outro lugar ou ser consumida de qualquer outra forma.

Note que, na classe Cliente, não sabemos qual é o atual ambiente no qual a aplicação está rodando, apenas solicitamos a criação de um TextBox e de um Botão, através da instância retornada pela Factory. Desta maneira, não nos preocupamos com o "como" os objetos são implementados, apenas nos preocupamos em seguir o contrato estabelecido pela interface, mantendo implementação dos objetos restrita.

Se definirmos o valor da chave ambiente no App.config como web, temos a seguinte saída na aplicação Console:

Da mesma maneira, se alterarmos o valor da chave ambiente do App.config para standalone, temos a seguinte saída:

Não diferente, alterando para mobile, temos o seguinte:

Esse é um dos padrões de projeto mais utilizados por arquitetos e desenvolvedores. Seu conhecimento é essencial para quem almeja dominar o mundo dos Padrões de Projeto. O padrão Abstract Factory pode ser combinado com outros padrões, como o padrão Singleton ou Prototype. Abordarei a integração entre esses padrões assim que tivermos uma visão de geral de cada padrão, para facilitar o entendimento.

Padrões de Projeto, como citei anteriormente, não são implementados de uma única maneira. No nosso exemplo, utilizei interfaces no código C#, o que achei mais apropriado, pois não havia implementação, apenas queria estabelecer um contrato entre partes (classes). Porém, nada me impediria de, ao invés de utilizar interfaces, utilizar classes abstratas. Ao invés das classes concretas implementarem as interfaces, elas poderiam herdar o comportamento das classes abstratas. Usualmente, utilizamos interfaces quando não temos implementações padrão, e utilizamos classes abstratas quando temos pelo menos uma implementação padrão, que deve ser herdada pelas classes concretas. Essa abordagem é arquitetural, e foge do nosso foco que é aprender sobre padrões de projeto. O que eu quero deixar claro é que, não importa "o como" implementamos o padrão, desde que a implementação respeite o princípio do padrão, propriamente dito.

No próximo post sobre Padrões de Projeto, abordaremos o padrão Adapter, um padrão estrutural, também muito utilizado, mas não tanto quanto o padrão Abstract Factory.

Espero que esse exemplo simples tenha ajudado vocês de alguma forma.

Até a próxima!

Tags: , , , | Categories: Metodologia Posted by Rafael on 30/10/2010 05:43 | Comentários (2)

Pessoal, hoje venho com um post bem pequeno, porém interessante. Na verdade, é mais uma curiosidade sobre Terminologias de TI.

Já ouvi diversas vezes: "Utilizamos uma Medologia de Desenvolvimento baseado em RUP na empresa na qual eu trabalho", ou então, "Utilizamos um Processo de Desenvolvimento baseado em RUP na empresa na qual eu trabalho".

Mas, afinal de contas, Metodologia e Processo são a mesma coisa?

A resposta é não! 

A Metodologia define o Processo a ser executado. Assim sendo, o que usamos e/ou executamos durante o Desenvolvimento de um Software é um Processo baseado em uma Metodologia qualquer.

Pra quem não sabia a diferença, fica aí a dica.

Até mais!

Tags: , , | Categories: Padrões de Projeto Posted by Rafael on 19/10/2010 06:12 | Comentários (4)

Com esse post, inicio uma série sobre Padrões de Projeto (Design Patterns). Abordarei os 23 padrões de projeto de uma forma bem simples. A minha intenção é fazer uma breve descrição sobre cada padrão, seguindo de alguns exemplos, para ajudar àqueles que desenvolvem aplicativos Orientado a Objetos e não conhecem Padrões de Projeto.

Como citei em um post anterior, Padrões de Projeto devem ser utilizados com ponderação. Cada padrão foi criado para solucionar problemas específicos do dia-a-dia de desenvolvedores, porém, como todo e qualquer padrão, a grande maioria requer maior codificação. Por isso, a sua utilização em demasia, é prejudicial. Podemos chegar ao ponto de querer matar um simples e inofensível inseto com uma bazuca. Totalmente sem sentido.

Portanto, bom senso é muito bem-vindo na utilização de Padrões de Projeto.

Quando usamos padrões, agregamos qualidade ao nosso desenvolvimento. Consequentemente, diminuímos a produtividade. É impossível aumentar a qualidade e a produtividade ao mesmo tempo, de qualquer que seja o produto (no nosso caso, software). O que devemos fazer, é encontrar um ponto ótimo entre qualidade e produtividade, mas isso é assunto pra um outro post, só sobre Qualidade x Produtividade, o que não é o nosso foco agora.

Muitas vezes utilizamos técnicas para resolver problemas e criar soluções no nosso dia-a-dia, e nem sabemos que essas técnicas são padrões de projeto. Isso já aconteceu comigo, principalmente quando comecei a estudar padrões de projeto. Portanto, não se espante se ao longo do nosso estudo, se deparar com um padrão que você já utiliza, mas não sabia que é um padrão de projeto.

Os Padrões de Projeto são classificados em 3 grupos, de acordo com suas finalidades: Padrões de Criação, Padrões Estruturais e Padrões Comportamentais. São eles:

Padrões de Criação:

Padrões Estruturais:

  • Adapter
  • Bridge
  • Composite
  • Decorator
  • Façade
  • Flyweight
  • Proxy

Padrões Comportamentais:

  • Chain of Responsability
  • Command
  • Interpreter
  • Iterator
  • Mediator
  • Memento
  • Observer
  • State
  • Strategy
  • Template Method
  • Visitor

Iniciarei pelos seguintes padrões, que são os mais simples e comuns:

Logo após, darei sequência aos demais padrões.

Espero que gostem.

Aguardem!

Tags: , , , | Categories: ASP.NET, JavaScript Posted by Rafael on 14/10/2010 08:32 | Comentários (4)

Meses atrás eu me deparei com um pequeno problema. Eu precisava fazer com que um botão de uma página ASP.NET fosse desabilitado no clique, e o evento Click do mesmo fosse disparado.

Existem diversas maneiras de implementar essa solução, inclusive com padrões de projeto e melhores práticas. Porém, todo padrão deve ser utilizado com bom senso (falarei mais sobre isso em posts futuros), ou então, poderemos criar uma bazuca para matarmos uma mosca. Não faz o menor sentido.

Sou um grande adepto da utilização de padrões de projeto, porém, busco sempre um meio termo, um "ponto ótimo" ou "ponto de equilíbrio".

Assim sendo, nas circunstâncias que eu me encontrava, implementei da maneira mais rápida e prática possível, resolvendo muito bem o problema, e no tempo que eu precisava.

Até a chamada do evento Click ao clicar, nada demais. Com as facilidades do Microsoft Visual Studio, bastam dois cliques no botão, que o método Click é criado e associado ao botão, juntamente com o evento. Tudo muito rápido e fácil.

Aqui está o código gerado na página ASP.NET, seguido do código gerado no CodeBehind da mesma:

<asp:Button ID="botao" runat="server" Text="Clique" onclick="botao_Click"/>



protected void botao_Click(object sender, EventArgs e)

{

            

}

 

Legal, o evento clique já foi associado a um método pelo atributo onclick.

Existe um atributo chamado OnClientClick que é utilizado para invocar scripts no lado do cliente (client side), ou seja, é utilizado para invocar scripts da própria página. Assim que o evento Click é disparado, o script contido ou referenciado no atributo OnClientClick é invocado, e, se o retorno do script for true, o método associado ao atributo onclick é invocado.

O script em JavaScript e o código do botão da página ASP.NET ficaram assim:

<script type="text/javascript">

    function desabilitarBotao() {

        document.getElementById("botao").disabled = true;

    }

<script>



<asp:Button ID="botao" runat="server" Text="Clique" onclick="botao_Click" 

          OnClientClick="javascript:return desabilitarBotao();"/>

 

Tudo parece estar correto. Porém, quando executamos a página, o botão é desabilitado como desejado, porém, o método botao_Click não é invocado.

Isso ocorre porque o IE desabilita toda e qualquer ação do botão quando o mesmo é desabilitado, o que faz sentido. Se estamos desabilitando um objeto, não queremos que alguma ação relacionada a ele seja disparada.

Agora é que entra a função setTimeout do JavaScript. Vejamos os parâmetros dessa função: setTimeout(code, delay), onde code é o código que queremos adiar sua execução, e delay é o tempo que queremos adiar o código, expresso em milisegundos.

Vamos modificar o script, adicionando a função setTimeout:

<script type="text/javascript">

    function desabilitarBotao() {

        window.setTimeout('document.getElementById("botao").disabled = true;', 50);

        return true;

    }

<script>

 

Definimos um delay de 50 milisegundos.

Para testarmos se o botão é desabilitado e o método do CodeBehind realmente é chamado, inseri um breakpoint dentro do método, e executei a aplicação ASP.NET:

Botão da página desabilitado:

É isso. Espero ter ajudado de alguma forma.

Até a próxima!

Tags: , , | Categories: C#, Linguagem de Programação Posted by Rafael on 12/10/2010 23:19 | Comentários (0)

Quando declaramos variáveis de tipos nativos em C#, sempre um valor default é associado às mesmas. Veja o código abaixo.

As variáveis foram declaradas, e note na coluna Value que cada uma recebeu um valor padrão. Isso, em determinadas situações, pode ser um problema. Imagine que você deseja persistir um objeto em uma tabela do banco de dados, e que, alguns campos dessa tabela permitem a inserção de valores nulos. Na compilação não teremos problemas, porém, uma exception será disparada em tempo de execução, se tentarmos atribuir um valor nulo à alguma propriedade do nosso objeto.

Para resolvermos esse problema, utilizamos os nullable types. Muito simples e fácil, basta inserirmos o símbolo ? à direita do tipo da variável, assim:

Notem na coluna Value que o valor atribuído a cada variável é null, ao invés do valor padrão de cada tipo. Assim, podemos atribuir valores nulos ao nosso objeto, e persisti-lo sem problemas.

Simples assim.

Até a próxima!

Tags: , , | Categories: C#, Linguagem de Programação Posted by Rafael on 12/10/2010 21:37 | Comentários (0)

Dando seqüência à série Operadores C#, vamos falar sobre os operadores de incremento (++) e decremento (--) de variáveis.

Operadores de incremento e decremento de variáveis

O conceito de operadores de incremento e decremento é muito simples. Basicamente, utilizamos o operador de incremento para simplificar a expressão “variável = variável + 1”, ou então o operador de decremento para simplificar a expressão “variável = variável - 1”. O trecho de código abaixo ilustra a sintaxe dos operadores:

    int x = 0;



    // incrementando a variável x

    x = x + 1;



    // incrementando a variável x, utilizando o operador de incremento

    x++;



    // decrementando a variável x

    x = x - 1;



    // decrementando a variável x, utilizando o operador de decremento

    x--;

 

Muito simples e fácil de entender. Agora, consideremos o seguinte trecho de código:

    class Program

    {

        static void Main(string[] args)

        {

            int x = 0;

            int y = 0;

            Console.WriteLine("1º loop:");

            for (int i = 0; i < 5; i++)

            {

                if (x++ == 2)

                {

                    Console.WriteLine("Entrou no if da variável x++");

                }

                if (++y == 2)

                {

                    Console.WriteLine("Entrou no if da variável ++y");

                }

            }

            Console.WriteLine();

            x = 5;

            y = 5;

            Console.WriteLine("2º loop:");

            for (int i = 0; i < 5; i++)

            {

                if (x-- == 2)

                {

                    Console.WriteLine("Entrou no if da variável x--");

                }

                if (--y == 2)

                {

                    Console.WriteLine("Entrou no if da variável --y");

                }

            }

            Console.ReadKey();

        }

    }

 

Vemos que no primeiro loop, as variáveis x e y são incrementadas, porém de maneiras diferentes. A variável x é incrementada após a execução da instrução if (x++ == 2), e a variável y é incrementa antes da execução da instrução if (++y == 2). O mesmo acontece no segundo loop, só que, ao invés das variáveis serem incrementadas, elas são decrementadas. No código acima, utilizamos as mesmas condições dos ifs para demonstrar que as variáveis com operador à esquerda são incrementadas ou decrementadas antes da execução da instrução, e as variáveis com operador à direita são incrementadas ou decrementadas após a execução da instrução. Ao executarmos o código, temos a seguinte saída:

Muito simples e fácil. Espero ter ajudado!

Até a próxima!