terça-feira, 21 de dezembro de 2010

Lançada primeira versão do framework JFERA!

 Olá visitante,

 Nos últimos 8 meses estive desenvolvendo uma aplicação real utilizando Adobe Flex e o Google App Engine. Já postei aqui a aplicação, que se chama Revelação Virtual. Durante esse período foi intenso o aprendizado para integrar a tecnologia Flex, que permite fazer interfaces muito bonitas e responsivas, no Google App Engine, servidor fornecido pelo Google. Pensei que seria interessante repassar o conhecimento para outras pessoas.

 Dessa maneira, fui desenvolvendo em paralelo um framework para integrar as duas tecnologias, aproveitando para documentar muitas dores de cabeça experiências. O resultado foi o JFERA (Java/Flex Easy Remote Architecture). O objetivo foi criar uma arquitetura simples para efetuar chamadas remotas Flex no Google App Engine. A documentação pode ser conferida em http://jfera.nuccitec.com.br. A documentação se encontra em inglês (pelo qual já peço desculpas adiantadas, já que nunca estudei a língua...rs), mas já enviei um artigo para ser postado na revista MundoJ, e assim que eu souber em qual edição ele será incluído, se for incluído em alguma, venho aqui atualizar o blog.

 Diferente do JColtrane, onde contei com o Prof. Doutor Eduardo Guerra como mentor, esse framework eu desenvolvi sozinho. Não ter com quem tirar dúvidas realmente foi um grande desafio.

 A documentação não está 100% completa, mas já é possível fazer várias aplicações bacanas utilizando o projeto.

 Espero que gostem e me enviem sugestões.

 Até a próxima,
 Renzo Nuccitelli

terça-feira, 14 de dezembro de 2010

Revelação de Fotos pela internet

Recentemente o sistema de revelação de fotos da Nuccitec, o Revelação Virtual, ganhou sua versão web. Agora não é mais necessário instalar a aplicação, basta acessar o endereço fornecido pelo cliente. Em São José dos Campos, por exemplo, o laboratório Digital do Vale oferece o serviço através do endereço www.digitaldovale.com.br.

 A idéia do projeto é se espalhar pelo Brasil, viabilizando aos laboratórios de revelação fornecerem seus serviços pela internet, sem ter que se preocupar com tecnologia. Dessa forma, eles podem recuperar também os clientes que perderam para grandes players, uma vez que podem oferecer preços mais acessíveis e, principalmente, podem entregar as fotos mais rapidamente a seus cliente.

 Além disso, o caráter mais pessoal dos laboratórios locais trazem mais confiança a seus cliente, que possui um canal mais direto para resolução de problemas que possam ocorrer com a revelação, ou até mesmo para pedir que o laboratório retoque suas fotos usando Photoshop. Que grande player consegue fornecer um serviço mais humano dessa forma?

Esperamos que gostem do novo produto.

quinta-feira, 4 de novembro de 2010

CSS no Adobe Flex

 A documentação da Adobe aborda muito conteúdo sobre o CSS no Flex. Inclusive o Flash Builder contém muito boas ferramentas, como autocomplete no CSS e a possibilidade de vc editar o visual de um componente no modo design e depois exportar o CSS. Contudo, um amigo do trabalho me mandou dois links muito interessantes para trabalhar com CSS:

 No primeiro vc acessa a documentação completa das propriedades de CSS dos diferentes componentes. No segundo vc altera o visual dos componentes e confere as alterações "on the fly".

 Apesar de curto esse post, espero que ajude a muita gente.

 Até o próximo post.

quarta-feira, 20 de outubro de 2010

Adobe Flex - Setando um item em ComboBox

 Olá a todos. Estou um tempo sem postar pq estou acabando a documentação preliminar do JFERA, framework de integração Java-Flex no Google App Engine.

 Apesar disso, sempre acompanho e respondo questões de Flex no GUJ, que apesar de ser um Fórum Java, é muito bom para qualquer linguagem de programação. Por algumas vezes respondi algumas questões sobre problemas para setar um item em um ComboBox.

 Já passei por esse problema uma vez, quando eu precisava mostrar um formulário de edição de endereço. Nele existiam dois combos, um para estado e outro para cidade. O combo da cidade era dependente do de estado, de forma que seu dataProvider era setado de acordo com o estado escolhido. Na hora de editar o endereço, eu pegava os dados de minha classe de domínio e setava meus campos visuais. Ao setar o estado, tudo funcionava perfeitamente, mas a cidade não.

 Depois de um tempo estudando percebi que da forma que eu fazia as coisas, ocorria o seguinte:

  1.  Eu setava o selecteIndex do combo
  2. Depois de escolhido o estado, eu setava o dataProvider com as respectivas cidades
Me ocorreu então que era provável que ao setar o dataProvider não devia haver uma lógica para conferir se o mesmo continha o objeto já indicado no selectedItem, e por isso que não era mostrado o item corretamente. Pensando nisso, criei um combo personalizado para essas horas:


package br.com.nuccitelli.component {
     import flash.events.Event;
     import mx.binding.utils.BindingUtils;
     import mx.utils.ObjectUtil;
     import spark.components.DropDownList;

     public class DropDowListWithMemory extends DropDownList {
         private var _selectedItemInMemory:Object=null;

         public function DropDowListWithMemory() {
              super();
              BindingUtils.bindSetter(dataProviderHandler,this,[ "dataProvider","length" ]);
         }

         private function dataProviderHandler(obj:Object=null):void {
              if(_selectedItemInMemory) {
                   for each(var item:Object in this.dataProvider) {
                        if(this.equals(item,_selectedItemInMemory)) {
                            this.selectedItem=item;
                            break;
                        }
                   }
              }
         }

         /**
          * The selectedItemInMemory sets selectedItem in 2 ocasions:
          * 1) When you set selectedItemInMemory and data provider has an equals object
          * 2) When dataProvider change and has an object equals to selectedItemInMemory
          **/
         public function get selectedItemInMemory():Object {
              return _selectedItemInMemory;
         }

         /**
          * The selectedItemInMemory sets selectedItem in 2 ocasions:
          * 1) When you set selectedItemInMemory and data provider has an equals object
          * 2) When dataProvider change and has an object equals to selectedItemInMemory
          **/
         public function set selectedItemInMemory(value:Object):void {
              _selectedItemInMemory=value;
              dataProviderHandler();
         }

         private function equals(item:Object,item2:Object):Boolean {
              return ObjectUtil.compare(item,item2)==0;
         }
     }
}


 Também fiz um código unitário, para exemplificar o uso:




package br.com.nuccitelli.component {
     import flexunit.framework.Assert;
     import mx.collections.ArrayCollection;

     public class DropDowListWithMemoryTest {

         [Test]
         public function testSelectedItemWithExistingDataProvider():void {
              var combo:DropDowListWithMemory=new DropDowListWithMemory();
              combo.dataProvider=new ArrayCollection([ "A" , "B" , "C" ]);
              Assert.assertUndefined(combo.selectedItem);
              combo.selectedItemInMemory="B";
              Assert.assertEquals("B" , combo.selectedItem);
         }

         [Test]
         public function testSelectedItemWithOutExistingDataProvider():void {
              var combo:DropDowListWithMemory=new DropDowListWithMemory();
              combo.dataProvider=new ArrayCollection([ "A" , "B" , "C" ]);
              Assert.assertUndefined(combo.selectedItem);
              combo.selectedItemInMemory="D";
              Assert.assertUndefined(combo.selectedItem);
              combo.dataProvider=new ArrayCollection([ "A" , "B" , "C" , "D" ]);
              Assert.assertEquals("D" , combo.selectedItem);
         }
     }
}



Usei o DropDownList, que o combo no Flex 4. Se vc estiver usando o Flex 3, basta trocar o DropDownList por Combo. Para utilizar, basta usar o selectedItemInMemory no lugar do selectedItem.

 Se vc gostou desse post, peço  a gentileza de divulgar o blog bem como os cursos da Nuccitec. Também deixe uma mensagem no blog :)

 Até o próximo post.

terça-feira, 21 de setembro de 2010

Palhaçada da Dell

Com a abertura do curso em São José dos Campos, estava procurando notes pela internet. Na empresa em que trabalho compraram vários Dell, e também por falar bem da Assistência Técnica, decidi por procurar seus computadores.
O Vostro e Inspiron possuem valores muito bons, mas quando vc vai fechar o negócio, percebe que o valor do frete é de R$ 140,00 por máquina.
Ligo então na Dell para ver se conseguiria algum desconto, ou que pelo menos os R$ 140,00 fossem cobrados apenas uma vez, em vez de ser cobrado de todos os 3 computadores que eu iria comprar. Eis que a atendente me faz uma comparação esdruxula: “Se vc tem doi filhos e paga uma van escolar, eles pagam pelo lugar que ocupam, não vão pagar uma vaga só, a mesma coisa ocorre com os computadores. Além disso, não posso dar mais desconto nem que você pague a vista pois o preço já é de promoção, praticamente preço de custo”. A única coisa que quem inventou um argumento desse não contava é que os consumidores não possuem um cérebro tão “evoluido” para assimilar tamanha inteligência.
Vamos a alguns fatos:
  1.  Todo processo de entrega é, na imensa maioria das vezes, subutilizado. Ou seja, sempre vai ter lugar sobrando no caminhão, kombi e etc. O que se faz é otimizar as entregas que se tem, de forma a cortar custos. Nem a UPS, que só trabalha com entregas, consegue otimizar ao máximo suas entregas. Compre livros na Amazon e vc vai ver que o frete não é proporcional por livro. Lógico que se vc pedir uma montanha deles, o frete sobe, mas o frete de um ou 10 simplesmente não varia.
  2. Colocar um preço com esse enorme frete (mais de 10%) é, na minha opinião, propaganda enganosa. Você entra num site como Buscapé para comparar preços e aparece o da Dell em primeiro, categorizado por menor preço. Aí quando vc vai comprar, o note que estava R$ 1.298 passa para R$ 1.438.  Já pensou se a moda pega? Você entra no Buscapé,  acha um note pela bagatela de R$ 500,00. Quando vai fechar o negócio, descobre que o frete é de R$ 900,00! Simplesmente o site perderia toda sua utilidade devido a “esperteza” das empresas.  Se fosse possível eu buscar o note direto na fábrica, até poderiam separar o preço do produto e do frete, mas como não é o caso, o preço ao consumidor é um só. O pior é eu ter que configurar todo o note para só ao final me aprensetarem o valor do frete. Porque já não pedem o endereço logo no começo do processo e me informam o valor do frete? Será que é medo de eu nem continuar a configuração? Por que me fazer perder tempo, já que um consumidor mais consciente não aceitaria um abuso desse, e no mínimo, buscaria por outros computadores, já computando o abusivo frete no preço dos computadores.
  3. Os cartões cobram cerca de 3% das empresas. Então se vc vai pagar pelo boleto, no mínimo 3% tem que ser dado de desconto. Além disso, se o preço a vista, em cash não tem desconto, compensa pagar parcelado e investir seu dinheiro, nem que seja na poupança. E essa história de promoção a quase preço de custo é uma história para boi dormir tão velha, que prefiro nem comentar.

Enfim, vou comprar notes em uma loja pequena mesmo, pois lá consigo negociar. Aliás, é esse poder de barganha e respeito ao cliente que torna o pequenos negócios mais competitivos. Pretendo renovar cerca de 10 notes a cada dois anos, e se isso não é nada para Dell, tenho certeza que para uma empresa menor é.
Por fim, transparência não parece ser um dos principais valores da Dell nessa questão de frete. Seria bom haver um pouco mais de respeito à inteligência do consumidor. Quando virem o preço de um computador Dell, já adicione R$ 140,00, no mínimo, ao preço
 Tive um Acer que nunca deu problema e a Assitência Técnica também foi muito boa com o Acer de um amigo. Segue uma loja onde os preços são bem em conta e onde se pode negociar: http://www.netserv19.com/ecommerce_site/index.php?&cdgc=jfjhae00/Uc&zt=1.
Abraços a todos.

sexta-feira, 17 de setembro de 2010

Validação de CPF e CNPJ em Flex

A classe Validator é feita para validar campos em Flex. Apesar de existir vários validadores por padrão, como de cartão de crédito e mail, não existem os de CPF e CNPJ. Fiz um validador para as duas, ambas com teste unitário:

 CNPJ:


package br.com.nuccitelli.validator {
     import mx.utils.ObjectUtil;
     import mx.validators.ValidationResult;
     import mx.validators.Validator;

     public class CNPJValidator extends Validator {
         static protected const FIRST_VERIFIER_DIGITS:Array=[ 5,4,3,2,9,8,7,6,5,4,3,2 ];
         static protected const SECOND_VERIFIER_DIGITS:Array=[ 6,5,4,3,2,9,8,7,6,5,4,3 ];

         override protected function doValidation(value:Object):Array {
              var results:Array=[];
              // Call base class doValidation().
              results=super.doValidation(value);
              // Return if there are errors.
              if(results.length>0)
                   return results;
              // Check first name field.
              var cnpj:String=value as String;
              if(cnpj==null||cnpj=="") {
                   return results;
              } else if(cnpj.length!=14) {
                   results.push(new ValidationResult(true,"","","O CNPJ deve conter 14 dígitos"));
                   return results;
              } else if(!verifyDigits(cnpj)) {
                   results.push(new ValidationResult(true,"","","CNPJ inválido"));
                   return results;
              }
              return results;
         }

         private function verifyDigits(cnpj:String):Boolean {
              var firstDigit:int=defineDigitValue(getDigitsPlusOperation(cnpj,FIRST_VERIFIER_DIGITS)%11);
              if(new Number(firstDigit)!=new Number(cnpj.charAt(12))) {
                   return false;
              }
              var secondDigit:int=defineDigitValue((getDigitsPlusOperation(cnpj,SECOND_VERIFIER_DIGITS)+firstDigit*2)%11);
              return new Number(secondDigit)==new Number(cnpj.charAt(13));
         }

         private function defineDigitValue(digit:int):int {
              return digit>1?11-digit:0;
         }

         private function getDigitsPlusOperation(cnpj:String,verifierDigitis:Array):int {
              var s:int=0;
              for(var i:int=0;i<12;++i) {
                   s+=new Number(cnpj.charAt(i))*verifierDigitis[i];
              }
              return s;
         }
     }
}

Teste do CNPJ:

package br.com.nuccitelli.validator {
     import flexunit.framework.Assert;
     import mx.validators.ValidationResult;

     public class CNPJValidatorTest {
         protected var cnpjValidator:CNPJValidator=new CNPJValidator();

         [Test]
         public function testValidCNPJ():void {
              Assert.assertNull(cnpjValidator.validate("11222333000181").results);
         }

         [Test]
         public function testUncompleteCNPJ():void {
              Assert.assertEquals("O CNPJ deve conter 14 dígitos",getValidationMessage(cnpjValidator.validate("1").results[0] as ValidationResult));
              Assert.assertEquals("O CNPJ deve conter 14 dígitos",getValidationMessage(cnpjValidator.validate("1212").results[0] as ValidationResult));
              Assert.assertEquals("O CNPJ deve conter 14 dígitos",getValidationMessage(cnpjValidator.validate("1122233300018").results[0] as ValidationResult));
         }

         [Test]
         public function testWrongFinalDigits():void {
              Assert.assertEquals("CNPJ inválido",getValidationMessage(cnpjValidator.validate("11222333000180").results[0] as ValidationResult));
              Assert.assertEquals("CNPJ inválido",getValidationMessage(cnpjValidator.validate("11222333000191").results[0] as ValidationResult));
              Assert.assertEquals("CNPJ inválido",getValidationMessage(cnpjValidator.validate("11222333000190").results[0] as ValidationResult));
         }

         private function getValidationMessage(result:ValidationResult):String {
              return result.errorMessage;
         }
     }
}


CPF:

package br.com.nuccitelli.validator {
     import mx.utils.ObjectUtil;
     import mx.validators.ValidationResult;
     import mx.validators.Validator;

     public class CPFValidator extends Validator {
         override protected function doValidation(value:Object):Array {
              var results:Array=[];
              // Call base class doValidation().
              results=super.doValidation(value);
              // Return if there are errors.
              if(results.length>0)
                   return results;
              // Check first name field.
              var cpf:String=value as String;
              if(cpf==null||cpf=="") {
                   return results;
              } else if(cpf.length!=11) {
                   results.push(new ValidationResult(true,"","","O CPF deve conter 11 dígitos"));
                   return results;
              } else if(!verifyDigits(cpf)) {
                   results.push(new ValidationResult(true,"","","CPF inválido"));
                   return results;
              }
              return results;
         }

         private function verifyDigits(cpf:String):Boolean {
              var firstDigit:int=defineDigitValue(getDigitsPlusOperation(cpf,10)%11);
              if(new Number(firstDigit)!=new Number(cpf.charAt(9))) {
                   return false;
              }
              var secondDigit:int=defineDigitValue((getDigitsPlusOperation(cpf,11)+firstDigit*2)%11);
              return new Number(secondDigit)==new Number(cpf.charAt(10));
         }

         private function defineDigitValue(digit:int):int {
              return digit>1?11-digit:0;
         }

         private function getDigitsPlusOperation(cpf:String,initialFactor:int):int {
              var s:int=0;
              for(var i:int=0;i<9;++i,--initialFactor) {
                   s+=new Number(cpf.charAt(i))*initialFactor;
              }
              return s;
         }
     }
}


Teste do CPF:

package br.com.nuccitelli.validator {
     import flexunit.framework.Assert;
     import mx.validators.ValidationResult;

     public class CPFValidatorTest {
         protected var cpfValidator:CPFValidator=new CPFValidator();

         [Test]
         public function testValidCPF():void {
              Assert.assertNull(cpfValidator.validate("12345678909").results);
         }

         [Test]
         public function testUncompleteCPF():void {
              Assert.assertEquals("O CPF deve conter 11 dígitos",getValidationMessage(cpfValidator.validate("1").results[0] as ValidationResult));
              Assert.assertEquals("O CPF deve conter 11 dígitos",getValidationMessage(cpfValidator.validate("1212").results[0] as ValidationResult));
              Assert.assertEquals("O CPF deve conter 11 dígitos",getValidationMessage(cpfValidator.validate("1234567890").results[0] as ValidationResult));
         }

         [Test]
         public function testWrongFinalDigits():void {
              Assert.assertEquals("CPF inválido",getValidationMessage(cpfValidator.validate("12345678919").results[0] as ValidationResult));
              Assert.assertEquals("CPF inválido",getValidationMessage(cpfValidator.validate("12345678908").results[0] as ValidationResult));
              Assert.assertEquals("CPF inválido",getValidationMessage(cpfValidator.validate("12345678918").results[0] as ValidationResult));
         }

         private function getValidationMessage(result:ValidationResult):String {
              return result.errorMessage;
         }
     }
}



Espero que economize tempo do pessoal :)