/*********************************************************************
Validation javascript framework, version 4.0.0

Copyright (c) 1997-2006 Matthew A. Frank

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


This script now depends on Prototype, another javascript library.

	http://prototype.conio.net/

*********************************************************************/

/*
VALIDAÇÕES POSSÍVEIS:
	1  - REQUIRED	- Exige que o seja preenchido (Campo obrigatório)
	2  - INTEGER	- Exige que o campo seja um valor inteiro
	3  - FLOAT		- Exige que o campo seja um valor real 
	4  - DATE		- Exige que o campo seja uma data válida, é necessário colocar as "/" de separação, por default o ano deve possuir 4 dígitos e o formato
	                  padrão é "MM/DD/YYYY" o que pode ser alterado passando o novo formato - DATE="DD/MM/YYYY"
	5  - AMOUNT		- Exige que o campo seja um valor monetário com duas casas decimais e ponto de separação de milhar se necessário (12,45 ou 12.125,68)
	                  Alterado por Fabiano em 26/05/2006 (Exigir marcador de separação de milhar) 
	6  - MASK		- 
	7  - REGEXP		-
	8  - AND		- Conector lógico "e" que permite a combinção entre validações
	9  - OR			- Conector lógico "ou" que permite a combinação entre validações
	10 - NOSPACE	- Retira espaços em branco do início e final do campo
	11 - UPPERCASE 
	12 - LOWERCASE
	13 - NUMPROCESSO  - Permite validar os números de processo conforme padrão para a Justiça Federal em Alagoas. Aceita como parâmetro:
	                    numprocesso='jfc' - indica que o numero será validado como sendo um número da Justiça Federal Comum - AAAA.80.00.NNNNNN-N (Maceió)
						                                                                                                 ou - AAAA.80.01.NNNNNN-N (Arapiraca)
						numprocesso='jef' - indica que o numero será validado como sendo um número do Juizado Especial Federal - AAAA.80.13.NNNNNN-N
						                                                                                                 ou - AAAA.80.15.50NNNN-N (Arapiraca)						
						numprocesso='tur' - indica que o numero será validado como sendo um número da Turma Recursal - AAAA.80.14.NNNNNN-N
	                    
	                    Adicionado por Fabiano em 25/05/2006
	14 - CPF        - 	Permite validar se é um número de CPF válido. 
						Os CPF's 000.000.000-00 ... 999.999.999-99 são retornados como inválidos
						Aceita números formatados e sem formatação
						Aceita como parâmetro: cpf="formatar" - indica que o número de CPF, se válido, deverá ser formatado na saída: NNN.NNN.NNN-NN
						Adicionado por Fabiano em 09/06/2006
	15 - CNPJ       - 	Permite validar se é um número de CNPJ válido. 
						Os CNPJ's com números base 11.111.111 ... 99.999.999 são retornados como inválidos
						Aceita números formatados e sem formatação
						Aceita como parâmetro: cnpj="formatar" - indica que o número de CNPJ, se válido, deverá ser formatado na saída: NN.NNN.NNN/NNNN-NN
						Adicionado por Fabiano em 09/06/2006
	16 - CPFCNPJ    - 	Permite validar se é um número de CPF ou CNPJ válido. 
						Os CPF's 000.000.000-00 ... 999.999.999-99 são retornados como inválidos e os CNPJ's com números base 11.111.111 ... 99.999.999 também são retornados como inválidos
						Aceita números formatados e sem formatação
						Aceita como parâmetro: CPFCNPJ="formatar" - indica que o número de CPF ou CNPJ, se válido, deverá ser formatado na saída: NNN.NNN.NNN-NN (CPF) ou NN.NNN.NNN/NNNN-NN (CNPJ)
						Adicionado por Fabiano em 05/09/2006
						
	17 - CAPTCHA		-	Permite validar se o valor digitado pelo usuário é igual a sequência gerada aleatoriamente (captcha)
						Deve ser passado como parâmetro o valor gerado aleatoriamente: captcha="sequencia"
						Adicionado por Fabiano em 26/07/2006

	18 - EMAIL		-	Analisa se o e-mail está, de fino modo, errado.

Para se utilizar este script três inserções deverão ser feitas na página que contém os campos a serem validos:
1 - logo abaixo da tag <head> colocar as 18 linhas abaixo atentando para o path correto dos arquivos prototype.js e validation.js
	<style>
		body, table, input, button, select { font-family: verdana, arial, helvetica, sans-serif; font-size: small; }
		body { background-color: white; color: black; }
		input.required {border-right:3px solid red;}
		input[type="text"] {border: 1px dotted black; background-color: #eeeeee; padding-left: 1px; padding-right: 1px;}
		input[type="text"].required {border-right: 3px solid red;}
		input[type="text"]:focus {background-color: white; border: 1px solid black;}
		input[type="text"].required:focus {background-color: white; border-right: 3px solid red}
		input.invalid {background-color: #fcc; border: 1px solid red;}
		.validation-summary {color:black;background-color:#ffffcc;padding:10px;border-top:1px solid gold;border-bottom:1px solid gold;}
		TR TD:first-child { text-align: right; }
		a { color: blue }
	</style>
	<script type="text/javascript" src="prototype.js"></script>
	<script type="text/javascript" src="validation.js"></script>
	<script type="text/javascript">
		Validation.showPopup = false;       ----------- Esta configuração indica que será ou não mostrado um pop up com a msg de erro.
	</script>
	
2 - Logo abaixo da tag <body> colocar a linha abaixo (obs.: coloque o div dentro do formulário que será analisado)
	<div class="validation-summary" style="display:none"></div> ----- Vai mostrar o resumo de erros
	
3 - Em cada tag <input> do formulário em que se deseja validação colocar os parâmetros necessários:
   Ex.: <input ... required ... > <input ... amount="," ... > etc
   
*********************************************************************/
<!--
/*********************************************************************
 *********************************************************************/
// Funções auxiliares para validação e formatação de números de processo na Justiça Federal
// por Fabiano A. Costa 
// Em: 24/05/2006
//  // Editado em 02/10/2007: Douglas Dalbert Ferreira de Albuquerque
//--------------------------------------------------------------------------------
// //Formatação dos números com 15 digitos e 10 digitos da página inicial
function formata_numero_antigo(num){
	if(num.charAt(0) == '2'){
		numero = num.substr(0,4)+ '.' + num.charAt(4) + num.charAt(5) + '.'+ num.charAt(6) + num.charAt(7) +'.'+ num.charAt(8)+num.charAt(9)+num.charAt(10) + num.charAt(11) + num.charAt(12) + num.charAt(13)+ '-' + num.charAt(14);			
	}else{
		numero = num.substr(0,2)+'.'+ num.charAt(2)+ num.charAt(3)+num.charAt(4)+num.charAt(5)+num.charAt(6)+ num.charAt(7)+ num.charAt(8)+'-'+ num.charAt(9);
	}
	return numero;
}

// Formatação dos números no novo formato CJF (20 dígitos) - Fabiano 04/06/2010
function formata_numero(num){
	numero = num.substr(0,7)+ '-' + num.substr(7,2) + '.' + num.substr(9,4) + '.' + num.charAt(13) + '.' + num.substr(14,2) + '.' + num.substr(16,4);			
	return numero;
}

//--------------------------------------------------------------------------------
// Função que completa o numero do processo com zeros para que fique correto
function completa_zeros(numero){
	var num, i, zeros = '';	

	if(numero.charAt(0) == '2'){	
		for(i=1; i <= 15 - numero.length;i++){
			zeros = zeros + '0';
		}		
		numero = numero.substr(0,8) + zeros + numero.substr(8,numero.length );		
	} else {
		for(i=1; i <= 10 - numero.length;i++){
			zeros = zeros + '0';
		}		
		numero = numero.substr(0,2) + zeros + numero.substr(2,numero.length );					
	}
	
	return numero;
}

//--------------------------------------------------------------------------------
// Função que extrai todos os digitos de uma string
function extrai_digitos(str){
	var str_numeros = "";
	var i;
	for(i=0; i < str.length; i++){
		if((str.charAt(i) >= '0') && (str.charAt(i) <= '9'))
			str_numeros = str_numeros + str.charAt(i);
	}
	str_numeros = completa_zeros(str_numeros);
	return str_numeros;
}

//--------------------------------------------------------------------------------
// Função que calcula o digito verificador do numero dado (com 10 digitos)
function calcula_digito1(numero){
	var digito = 0;
	var i;
	
	for(i=0; i< 9; i++){
		digito += parseInt(numero.charAt(i))*(i+1); 
	}
	digito = digito%11;
	if(digito > 9)
		digito = 0;
	return digito;
}
//--------------------------------------------------------------------------------
// Função que calcula o digito verificador do numero dado (com 15 digitos)
function calcula_digito2(numero){
	var digito = 0;
	var i;
	for(i=13; i > -1; i--){
		if(i >= 6) {
				digito += parseInt(numero.charAt(i))*(15-i); 
		}else {
			digito += parseInt(numero.charAt(i))*(7-i); 		
		}

	}
	digito = digito%11;
	if(digito > 9)
		digito = 0;
		
	return digito;
}
//---------------------------------------------------------------------------------
// Função que verifica o digito verificador do número de um processo dado no formato (99999999999)
function verifica_digito_processo_antigo(numero){
	var valido = true;
	var digito = -1;
	
	// Verifica o digito para um processo com 10 algarismos
	if(numero.length == 10){				
		digito = calcula_digito1(numero);						
		if(digito != parseInt(numero.charAt(9))){
			valido = false;
		}
	} 
	// Verifica o digito para um processo com 15algarismos	
	else if(numero.length == 15){
		digito = calcula_digito2(numero);										
		if(digito != parseInt(numero.charAt(14))){
			valido = false;
		}		
	} 
	// O número do processo não possui 10 nem 15 algarismos
	else {
		valido = false;
	}
	
	return valido;
}
//--------------------------------------------------------------------------------//
//Essa função só é utilizada se a opção for justiça comum
function retira_caracteres(str){
	var campo_final = "";
	var i;
	for(i=0; i < str.length; i++){
		if((str.charAt(i) != '/') && (str.charAt(i) != '%')&& (str.charAt(i) != '#')&& (str.charAt(i) != '$')&& (str.charAt(i) != '@')&& (str.charAt(i) != '-')&& (str.charAt(i) != '.')&& (str.charAt(i) != ' '))
			campo_final = campo_final + str.charAt(i);
	}
	
	return campo_final;	
}
//--------------------------------------------------------------------------------------
function ZerosAEsquerda(str, quantidade){
	var i, zeros = '';
	for (i=0; i <= (quantidade - str.length-1); i++){
		zeros = '0'+zeros;
	}
	str = zeros+str;
	return str;
}
//--------------------------------------------------------------------------------
//Função que completa o ano com os 4 digitos
function CompletaAno(Ano){

	var anoTotal, tamanho = Ano.length;
	
	if(tamanho == 2)
		if (Ano.substr(0,1) > 5)
			anoTotal = "19"+Ano;
		else
			anoTotal = "20"+Ano;
	else if(tamanho == 1)	
		anoTotal = "200"+Ano;
	else if(tamanho == 0)
		anoTotal = (new Date()).getYear();
	else
		anoTotal = Ano;
	
	return anoTotal;
}
//--------------------------------------------------------------------------------//
function ENumero(caractere){
	if((caractere >= '0') && (caractere <= '9')){
		return true;
	}else 
		return false;
}
//----------------------------------------------------------------------------------//
//Função que verifica se o ultimo caractere é '%' e o substitui pelo digito verificador
function CompletaDigito(Processo){
	var i, novoProcesso = '',digito = '';
	
	if(Processo.charAt(Processo.length-1) == '%'){
		if(Processo.length == 10){				
			digito = calcula_digito1(Processo);	
		}
		if(Processo.length == 15){
			digito = calcula_digito2(Processo);	
		}

		for(i=0;i<Processo.length-1;i++){
			novoProcesso = novoProcesso + Processo.charAt(i);
		}		
		novoProcesso = novoProcesso + digito;
	}else
		novoProcesso = Processo;
	return novoProcesso;
}
//--------------------------------------------------------------------------------//
//Função que monta o processo. Traduzido da função em ASP de consulta processual
function montar_processo_antigo(NumProc, opcao){

	var nParteAtual = 1
	var nParteAsterisco = 0
	var Parte1 = '';
	var Parte2 = ''; 
	var Parte3 = '';
	var Parte4 = '';
	var SecaoDef = '80';
	var LocalidadeDef;
	var Pos, caractere, Processo, Secao, Localidade;
	
	if(opcao == 'jfc')
		LocalidadeDef = '00';
	else if(opcao == 'jef')
		LocalidadeDef = '13';
		else if (opcao == 'tur')
		     LocalidadeDef = '14';
		
	var Tam = NumProc.length;
	for (Pos = 0; Pos <= Tam-1; Pos++){	
		caractere =  NumProc.substr(Tam-Pos-1,1);
		if ((ENumero(caractere)) || (caractere == '-')){
			if (ENumero(caractere)){
				if (nParteAtual == 1){
					Parte1 = caractere+Parte1;
				} else if(nParteAtual == 2){
					Parte2 = caractere+Parte2;
				} else if(nParteAtual == 3){
					Parte3 = caractere+Parte3;
				}else if(nParteAtual == 4){
					Parte4 = caractere+Parte4;
				}
			}
		} else if ((caractere == '.') || (caractere == '*')){
			if (caractere == '*'){
				if(Pos == 0){
					Parte1 = '%';
					nParteAtual = nParteAtual - 1;
				} else{
					nParteAtual = nParteAtual + 1;			
					nParteAsterisco = nParteAtual;
				}
			}
			nParteAtual = nParteAtual + 1;
		}
	}

	//NUMERO ANTIGO: no caso 95.987 é formato antigo.
	if ((nParteAsterisco == 0) && (nParteAtual == 2) && (Parte2.length == 2)){
//		alert("Teste do caso 97.66347");
		Processo = Parte2+ZerosAEsquerda(Parte1,8);
	}
	//NUMERO ANTIGO: no caso 95987 é formato antigo.
	else if ((nParteAsterisco == 0) && (nParteAtual == 1) && (Parte1.length <= 11)){
		Tam = Parte1.length;
//		alert("Teste do caso 9766347");
		Processo = Parte1.substr(0,2) + ZerosAEsquerda(Parte1.substr(2,Tam-2),8);
	//NUMERO NOVO
	} 
	else {
		//Excessao: no caso 03*987 o asterisco devia pular mais um, e 03 é o ano.
		if((nParteAsterisco == 2) && (nParteAtual == 3)){
			Parte4 = Parte3;
			Parte3 = '';
		}

		NumProcesso = Parte1;
		Localidade = Parte2;
		Secao = Parte3;
		Ano = Parte4;

		if ((NumProcesso.length > 0) && (nParteAsterisco == 0) && (nParteAtual == 1) && ((Secao.length + Localidade.length + Ano.length) == 0))
			Processo = NumProcesso;
		else {
			if (Secao.length == 0)
				Secao = SecaoDef;

			if (Localidade.length == 0)
				Localidade = LocalidadeDef;

		   	Processo =  CompletaAno(Ano) + ZerosAEsquerda(Secao,2) + ZerosAEsquerda(Localidade,2) + ZerosAEsquerda(NumProcesso,7);
		}
	}

	Processo = CompletaDigito(Processo);
	return Processo;
}

function montar_processo(NumProc, opcao){
	Processo = NumProc;
	return Processo;
}



function str_pad (input, pad_length, pad_string, pad_type) {
    // Returns input string padded on the left or right to specified length with pad_string  
    // 
    // version: 1004.2314
    // discuss at: http://phpjs.org/functions/str_pad    // +   original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // + namespaced by: Michael White (http://getsprink.com)
    // +      input by: Marco van Oort
    // +   bugfixed by: Brett Zamir (http://brett-zamir.me)
    // *     example 1: str_pad('Kevin van Zonneveld', 30, '-=', 'STR_PAD_LEFT');    // *     returns 1: '-=-=-=-=-=-Kevin van Zonneveld'
    // *     example 2: str_pad('Kevin van Zonneveld', 30, '-', 'STR_PAD_BOTH');
    // *     returns 2: '------Kevin van Zonneveld-----'
    var half = '', pad_to_go;
     var str_pad_repeater = function (s, len) {
        var collect = '', i;
 
        while (collect.length < len) {collect += s;}
        collect = collect.substr(0,len); 
        return collect;
    };
    input += '';    pad_string = pad_string !== undefined ? pad_string : ' ';
    
    if (pad_type != 'STR_PAD_LEFT' && pad_type != 'STR_PAD_RIGHT' && pad_type != 'STR_PAD_BOTH') { pad_type = 'STR_PAD_RIGHT'; }
/*    if ((pad_to_go = pad_length - input.length) > 0) {*/
        if (pad_type == 'STR_PAD_LEFT') { input = str_pad_repeater(pad_string, pad_to_go) + input; }        else if (pad_type == 'STR_PAD_RIGHT') { input = input + str_pad_repeater(pad_string, pad_to_go); }
        else if (pad_type == 'STR_PAD_BOTH') {
            half = str_pad_repeater(pad_string, Math.ceil(pad_to_go/2));
            input = half + input + half;
            input = input.substr(0, pad_length);        }
/*    }*/
 
    return input;
}

function calcula_digver(numproc){
	num_proc 	= numproc.substr(0,7);
	ano 		= numproc.substr(9,4);
	jtr			= 405;
	loc			= numproc.substr(16,4);
	numproc_semdigito	= num_proc + ano + jtr + loc + '00';
	modulo  	= 	numproc_semdigito % 97;
	subtracao	=	98 - modulo;
	digito		= 	str_pad(subtracao,2,'0','STR_PAD_LEFT');
	return digito;

}

// Função que verifica o digito verificador do número de um processo dado no formato (99999999999999999999)
function verifica_digito_processo(numero){
	var valido = true;
	var digito = -1;
	// Verifica o digito para um processo no novo formato CJF (20 digitos)
	if(numero.length == 20){				
		digito = calcula_digver(numero);
		if(digito != parseInt(numero.substr(7,2))){
			valido = false;
		}
	} 
	// O número do processo não possui 20 algarismos
	else {
		valido = false;
	}
	return valido;
}

/*
************************************************************************************************************************************************
                                             FINAL DAS FUNÇÕES PARA VALIDAÇÃO DE NÚMERO DE PROCESSO
************************************************************************************************************************************************
*/
/*
************************************************************************************************************************************************
// Funções auxiliares para validação e formatação de números de CPF e CNPJ
// por Fabiano A. Costa 
// Em: 09/06/2006
************************************************************************************************************************************************
*/
/**
 * PROTÓTIPOS:
 * método String.lpad(int pSize, char pCharPad)
 * método String.trim()
 *
 * String unformatNumber(String pNum)
 * String formatCpfCnpj(String pCpfCnpj, boolean pUseSepar, boolean pIsCnpj)
 * String dvCpfCnpj(String pEfetivo, boolean pIsCnpj)
 * boolean isCpf(String pCpf)
 * boolean isCnpj(String pCnpj)
 * boolean isCpfCnpj(String pCpfCnpj)
 */


var NUM_DIGITOS_CPF  = 11;
var NUM_DIGITOS_CNPJ = 14;
var NUM_DGT_CNPJ_BASE = 8;


/**
 * Adiciona método lpad() à classe String.
 * Preenche a String à esquerda com o caractere fornecido,
 * até que ela atinja o tamanho especificado.
 */
String.prototype.lpad = function(pSize, pCharPad)
{
	var str = this;
	var dif = pSize - str.length;
	var ch = String(pCharPad).charAt(0);
	for (; dif>0; dif--) str = ch + str;
	return (str);
} //String.lpad


/**
 * Adiciona método trim() à classe String.
 * Elimina brancos no início e fim da String.
 */
String.prototype.trim = function()
{
	return this.replace(/^\s*/, "").replace(/\s*$/, "");
} //String.trim


/**
 * Elimina caracteres de formatação e zeros à esquerda da string
 * de número fornecida.
 * @param String pNum
 *      String de número fornecida para ser desformatada.
 * @return String de número desformatada.
 */
function unformatNumber(pNum)
{
	return String(pNum).replace(/\D/g, "").replace(/^0+/, "");
} //unformatNumber


/**
 * Formata a string fornecida como CNPJ ou CPF, adicionando zeros
 * à esquerda se necessário e caracteres separadores, conforme solicitado.
 * @param String pCpfCnpj
 *      String fornecida para ser formatada.
 * @param boolean pUseSepar
 *      Indica se devem ser usados caracteres separadores (. - /).
 * @param boolean pIsCnpj
 *      Indica se a string fornecida é um CNPJ.
 *      Caso contrário, é CPF. Default = false (CPF).
 * @return String de CPF ou CNPJ devidamente formatada.
 */
function formatCpfCnpj(pCpfCnpj, pUseSepar, pIsCnpj)
{
	if (pIsCnpj==null) pIsCnpj = false;
	if (pUseSepar==null) pUseSepar = true;
	var maxDigitos = pIsCnpj? NUM_DIGITOS_CNPJ: NUM_DIGITOS_CPF;
	var numero = unformatNumber(pCpfCnpj);

	numero = numero.lpad(maxDigitos, '0');
	if (!pUseSepar) return numero;

	if (pIsCnpj)
	{
		reCnpj = /(\d{2})(\d{3})(\d{3})(\d{4})(\d{2})$/;
		numero = numero.replace(reCnpj, "$1.$2.$3/$4-$5");
	}
	else
	{
		reCpf  = /(\d{3})(\d{3})(\d{3})(\d{2})$/;
		numero = numero.replace(reCpf, "$1.$2.$3-$4");
	}
	return numero;
} //formatCpfCnpj


/**
 * Calcula os 2 dígitos verificadores para o número-efetivo pEfetivo de
 * CNPJ (12 dígitos) ou CPF (9 dígitos) fornecido. pIsCnpj é booleano e
 * informa se o número-efetivo fornecido é CNPJ (default = false).
 * @param String pEfetivo
 *      String do número-efetivo (SEM dígitos verificadores) de CNPJ ou CPF.
 * @param boolean pIsCnpj
 *      Indica se a string fornecida é de um CNPJ.
 *      Caso contrário, é CPF. Default = false (CPF).
 * @return String com os dois dígitos verificadores.
 */
function dvCpfCnpj(pEfetivo, pIsCnpj)
{
	if (pIsCnpj==null) pIsCnpj = false;
	var i, j, k, soma, dv;
	var cicloPeso = pIsCnpj? NUM_DGT_CNPJ_BASE: NUM_DIGITOS_CPF;
	var maxDigitos = pIsCnpj? NUM_DIGITOS_CNPJ: NUM_DIGITOS_CPF;
	var calculado = formatCpfCnpj(pEfetivo, false, pIsCnpj);
	calculado = calculado.substring(2, maxDigitos);
	var result = "";

	for (j = 1; j <= 2; j++)
	{
		k = 2;
		soma = 0;
		for (i = calculado.length-1; i >= 0; i--)
		{
			soma += (calculado.charAt(i) - '0') * k;
			k = (k-1) % cicloPeso + 2;
		}
		dv = 11 - soma % 11;
		if (dv > 9) dv = 0;
		calculado += dv;
		result += dv
	}

	return result;
} //dvCpfCnpj


/**
 * Testa se a String pCpf fornecida é um CPF válido.
 * Qualquer formatação que não seja algarismos é desconsiderada.
 * @param String pCpf
 *      String fornecida para ser testada.
 * @return <code>true</code> se a String fornecida for um CPF válido.
 */
function isCpf(pCpf)
{
	var numero = formatCpfCnpj(pCpf, false, false);
	var base = numero.substring(0, numero.length - 2);
	var digitos = dvCpfCnpj(base, false);
	var algUnico, i;

	// Valida dígitos verificadores
	if (numero != base + digitos) return false;

	/* Não serão considerados válidos os seguintes CPF:
	 * 000.000.000-00, 111.111.111-11, 222.222.222-22, 333.333.333-33, 444.444.444-44,
	 * 555.555.555-55, 666.666.666-66, 777.777.777-77, 888.888.888-88, 999.999.999-99.
	 */
	algUnico = true;
	for (i=1; i<NUM_DIGITOS_CPF; i++)
	{
		algUnico = algUnico && (numero.charAt(i-1) == numero.charAt(i));
	}
	if (algUnico)
	{
	  return false; 
	}
	else
	{
		return true;
	}
} //isCpf


/**
 * Testa se a String pCnpj fornecida é um CNPJ válido.
 * Qualquer formatação que não seja algarismos é desconsiderada.
 * @param String pCnpj
 *      String fornecida para ser testada.
 * @return <code>true</code> se a String fornecida for um CNPJ válido.
 */
function isCnpj(pCnpj)
{
	var numero = formatCpfCnpj(pCnpj, false, true);
	var base = numero.substring(0, NUM_DGT_CNPJ_BASE);
	var ordem = numero.substring(NUM_DGT_CNPJ_BASE, 12);
	var digitos = dvCpfCnpj(base + ordem, true);
	var algUnico;

	// Valida dígitos verificadores
	if (numero != base + ordem + digitos) return false;

	/* Não serão considerados válidos os CNPJ com os seguintes números BÁSICOS:
	 * 11.111.111, 22.222.222, 33.333.333, 44.444.444, 55.555.555,
	 * 66.666.666, 77.777.777, 88.888.888, 99.999.999.
	 */
	algUnico = numero.charAt(0) != '0';
	for (i=1; i<NUM_DGT_CNPJ_BASE; i++)
	{
		algUnico = algUnico && (numero.charAt(i-1) == numero.charAt(i));
	}
	if (algUnico) return false;

	/* Não será considerado válido CNPJ com número de ORDEM igual a 0000.
	 * Não será considerado válido CNPJ com número de ORDEM maior do que 0300
	 * e com as três primeiras posições do número BÁSICO com 000 (zeros).
	 * Esta crítica não será feita quando o no BÁSICO do CNPJ for igual a 00.000.000.
	 */
	if (ordem == "0000") return false;
	return (base == "00000000"
		|| parseInt(ordem, 10) <= 300 || base.substring(0, 3) != "000");
} //isCnpj


/**
 * Testa se a String pCpfCnpj fornecida é um CPF ou CNPJ válido.
 * Se a String tiver uma quantidade de dígitos igual ou inferior
 * a 11, valida como CPF. Se for maior que 11, valida como CNPJ.
 * Qualquer formatação que não seja algarismos é desconsiderada.
 * @param String pCpfCnpj
 *      String fornecida para ser testada.
 * @return <code>true</code> se a String fornecida for um CPF ou CNPJ válido.
 */
function isCpfCnpj(pCpfCnpj)
{
	var numero = pCpfCnpj.replace(/\D/g, "");
	if (numero.length > NUM_DIGITOS_CPF)
		return isCnpj(pCpfCnpj)
	else
		return isCpf(pCpfCnpj);
} //isCpfCnpj
/*
************************************************************************************************************************************************
                                             FINAL DAS FUNÇÕES PARA VALIDAÇÃO CPF E CNPJ
************************************************************************************************************************************************
*/

/*
************************************************************************************************************************************************
// Função auxiliar para formatação de números de CEP, DATAS, TELEFONE
// por Fabiano A. Costa 
// Em: 02/10/2006
************************************************************************************************************************************************
*/
/*
Configuração
Criar um Array que indique a quantidade de dígitos entre cada separador.
Por exemplo, 
1 - se quisermos uma dadta no formato dd/mm/aaaa:
var padrao = new Array(2,2,4)
2 - se quisermos a data no formato aaaa/mm/dd:
var padrao1 = new Array(4,2,2)
3 - Se quisermos um número telefônico no formato nn-nnn-nnnn-nnnn
var padrao2 = new Array(2,3,4,4)
4 - Se quisermos um número postal (CEP) no formato nnnnn-nnn
var padrão3 = new Array(5,3)
Se quisermos usar o mesmos script para campos com diferentes formatos, deve-se criar um Array para cada um e finalmente 
chamar o script em cada campo passando como parâmetros o próprio campo, o padrão (Array), o separador a ser utilizado e um 
valor booleano (true ou false) indicando se deve-se aceitar ou não somente números

mascara(this,array a utilizar, separador, true se somente números ou false se  qualquer caracter)

<input type="text" name = "data" onkeyup="mascara(this,'/',padrao,true)" maxlength="10" />
<input type="text" name = "telefone" onkeyup="mascara(this,'-',padrao2,true)" maxlength="16" /> 
<input type="text" name = "cep" onkeyup="mascara(this,'-',padrao3,true)" maxlength="9" /> 
*/
function mascara(d,sep,pat,nums){
if(d.valant != d.value){
	val = d.value
	largo = val.length
	val = val.split(sep)
	val2 = ''
	for(r=0;r<val.length;r++){
		val2 += val[r]	
	}
	if(nums){
		for(z=0;z<val2.length;z++){
			if(isNaN(val2.charAt(z))){
				letra = new RegExp(val2.charAt(z),"g")
				val2 = val2.replace(letra,"")
			}
		}
	}
	val = ''
	val3 = new Array()
	for(s=0; s<pat.length; s++){
		val3[s] = val2.substring(0,pat[s])
		val2 = val2.substr(pat[s])
	}
	for(q=0;q<val3.length; q++){
		if(q ==0){
			val = val3[q]
		}
		else{
			if(val3[q] != ""){
				val += sep + val3[q]
				}
		}
	}
	d.value = val
	d.valant = val
	}
}
/*
************************************************************************************************************************************************
                                             FINAL DA FUNÇÃO PARA FORMATAÇÃO DO CEP, DATAS, TELEFONE
************************************************************************************************************************************************
*/

Object.extend(Object, {
	isDefined: function(thing) {
		return typeof thing !== 'undefined';
	},
	hasValue: function(thing) {
		return Object.isDefined(thing) && thing !== null;
	},
	$get: function(thing, propertyName) {
		var returnValue;
		returnValue = thing[propertyName];
		if(!Object.isDefined(returnValue) && thing.getAttribute)
			returnValue=thing.getAttribute(propertyName);

		if($V(returnValue) && returnValue.isString && returnValue.startsWith('@'))
			returnValue = Function.create("return (" + returnValue.replace(/^@/, String.Empty) + ")").apply(thing, []);
		return returnValue;
	},
	$set: function(thing, propertyName, value) {
		thing[propertyName] = value;
	}
});
var $V = Object.hasValue;

Function.Null = function() {};
Function.create = function(value) {
	if($V(value)) {
		if(value.isFunction)
			return value;
		else
			return new Function(value);
	} else {
		return Function.Null;
	}
};
Object.extend(Function.prototype, {
	then: function(that) {
		var me = this;
		return function() { me.apply(this, arguments); Function.create(that).apply(this, arguments); };
	},
	after: function(two) {
		var one = this;
		return Function.create(two).then(one);
	},
	forEach: function() {
		$A(arguments).forEach(this);
	},
	isFunction: true
});
Object.extend(String, {
	Empty: "",
	format: function() {
		var tokens = $A(arguments);
		var result = tokens.shift();
		tokens.each(function(token, index) {
			result = result.replace(new RegExp("\\{" + index + "\\}", "g"), token);
		});
		return result;
	}
});
Object.extend(String.prototype, {
	trim: function() {
		return this.replace(/^\s+|\s+$/g, String.Empty);
	},
	startsWith: function(prefix) {
		return new RegExp("^" + prefix).test(this);
	},
	endsWith: function(suffix) {
		return new RegExp(suffix + "$").test(this);
	},
	contains: function (substring$) {
		return this.indexOf(substring$) > -1;
	},
	containsIgnoreCase: function (substring$) {
		return this.toUpperCase().indexOf(substring$.toUpperCase()) > -1;
	},
	equalsIgnoreCase: function(that) {
		if ($V(that) && that.isString)
			return this.toLowerCase() == that.toLowerCase();
		return false;
	},
	format: function() {
		return String.format.apply({}, [this].concat($A(arguments)));
	},
	isString: true
});
RegExp.prototype.isRegExp = true;
Object.extend(Number.prototype, {
	isEven: function() { return Math.abs(this % 2) === 0; },
	isOdd: function() { return Math.abs(this % 2) === 1; }
});
Number.format = function(i) {
	//TODO validation constants
	if (!$V(i))
		return null;
	var end = (/\./.test(i = i.toString()))?"\\.":'$';
	var re = new RegExp("(\\d)(\\d{3})(,|" + end + ")");
	if (re.test(i))
		i = Number.format(i.replace(re, "$1,$2$3"));
	return i;
};
// the following methods are part of the 1.5 spec
if(![].forEach)
Array.prototype.forEach = function (callback, thisObject) {
	for (var i = 0; i < this.length; i++)
		callback.apply(thisObject || {}, [this[i]]);
};
if(![].map)
Array.prototype.map = function (callback, thisObject) {
	var result = [];
	this.forEach(function(i) {
		result.push(callback.apply(thisObject || {}, [i]));
	});
	return result;
};
if(![].filter)
Array.prototype.filter = function (callback, thisObject) {
	var result = [];
	this.forEach( function(i) {
		if (callback.apply(thisObject || {}, [i]))
			result.push(i);
	});
	return result;
};
if (![].some)
Array.prototype.some = function(callback, thisObject) {
	for (var i = 0; i < this.length; i++)
		if (!!callback.apply(thisObject || {}, [this[i]]))
			return true;
	return false;
};
if (![].every)
Array.prototype.every = function(callback, thisObject) {
	for (var i = 0; i < this.length; i++)
		if (!callback.apply(thisObject || {}, [this[i]]))
			return false;
	return true;
};
Object.extend(Array.prototype, {
	equals: function (otherArray) {
		otherArray = $A(otherArray);
		if (this.length === otherArray.length) {
			for(var i = 0; i < this.length; i++) {
				//doesn't handle embedded arrays
				if (this[i] != otherArray[i])
					return false;
			}
			return true;
		}
		return false;
	},
	choose: function () {
		for (var i = 0; i < this.length; i++)
			if ($V(this[i])) return this[i];
		return null;
	},
	notEmpty: function() {
		return this.first() !== null;
	},
	poke: function(property, value) {
		this.forEach(function(item){ item[property] = value; });
	},
	contains: function (item) {
		return this.some(function(each) { return each == item; });
	},
	excludes: function (item) {
		return !this.contains(item);
	},
	lastIndexOf: function(object) {
		for(var i=this.length-1; i>=0; i--)
			if (object == this[i]) return i;
		return -1;
	},
	distinct: function() {
		var result = [];
		for(var i=0; i<this.length; i++)
			if (result.excludes(this[i])) result.push(this[i]);
		return result;
	},
	union: function(other) {
		return this.concat(other).distinct();
	},
	intersection: function(other) {
		return this.filter(other.contains, other).distinct();
	},
	minus: function(other) {
		return this.filter(other.excludes, other).distinct();
	},
	symmetricDifference: function(other) {
		return this.union(other).minus(this.intersection(other));
	}
});
Object.extend(Element, {
	getElementsByTagNames: function(element) {
		var result = [];
		var tagNames = $A(arguments).slice(1);
		
		var elements;
		for (var i = 0; i < tagNames.length; i++) {
			elements = element.getElementsByTagName(tagNames[i]);
			for (var j = 0; j < elements.length; j++)
				result.push(elements[j]);
		}
		return result;
	},
	getContainerByTagName: function(element, tagName) {
		for(var parent = $(element).parentNode; parent && !tagName.equalsIgnoreCase(parent.tagName); parent = parent.parentNode){}
		return parent;
	},
	getProperty: function(element, propertyName){
		var result = Object.$get($(element), propertyName);
		if ($V(result) && result.isFunction)
			result = result.apply(element, [element]);
		return result;
	},
	getHandler: function(element, handlerName) {
		return Function.create(Object.$get($(element), handlerName));
	},
	propertyOn: function(/* attribute list */){
		var isOn, attribute, length = arguments.length;
		for(var i=0;i<length;i++){
			attribute = arguments[i];
			if(typeof attribute=='string')
				attribute = attribute.toLowerCase();
			isOn = $V(attribute) &&
				   attribute!='false' &&
				   attribute!='off' &&
				   attribute!='no' &&
			       attribute!=false &&
			       attribute!=String.Empty;
			if(isOn) break;
		}
		return !!isOn;
	},
	_identityCounter: 0,
	idFor: function (element) {
		if (!element.id)
			element.id = 'v_ctl' + this._identityCounter++;
		return element.id;
	}
});
var $P = Element.getProperty;

Object.extend(Form, {
	restore: function(form, reset){
		form = $(form);
		form.isValid = true;
		Validation.clearMessages(form);
		for(var i = 0;i < form.elements.length; i++){
			Form.Element.restore(form.elements[i]);
			if(reset)form.elements[i].onreset();
		}
	},
	isValid: function(form,event){
		var i,iElements,orderBy,position;
		var element,elementList = $A(form.elements);
		Form.restore(form);
		if(form.onbeforevalidate()==false)
			return false;
		//TODO validation constants
		orderBy = $P(form, 'ORDERED-VALIDATION');
		if($ON(orderBy)){
			orderBy = /^tabindex$/i.test(orderBy)?'tabIndex':'VALIDATION-ORDER';
			elementList = [];
			for(i=0,iElements=form.elements.length;i<iElements;i++){
				element=form.elements[i];
				position = parseInt($P(element, orderBy));
				if($ON(position) && !isNaN(position))
					elementList=elementList.slice(0,position).concat(element,elementList.slice(position));
				else
					elementList[elementList.length]=element;
			}
		}
		for(i=0,iElements=elementList.length;i<iElements;i++)
			if (!Form.Element.validate(elementList[i], event))
				form.isValid = false;
		if(form.onaftervalidate()==false)
			return false;
		return form.isValid;
	},
	markRequired: function(form){
		$A(form.elements).forEach(Form.Element.markRequired);
	},
	validate: function(form, oEvent){
		form.isValid = Form.isValid(form, oEvent);
		Validation.displayMessages(form);
		return form.isValid;
	},
	validateAndSubmit: function(form) {
		form = $(form);
		//TODO pass event for mozilla
		if(form.onsubmit()!==false)
			form.submit();
	},
	resetValidation: function(form){
		Form.restore(form, true);
		Validation.renderSummary(form);
	}
});

Object.extend(Form.Element, {
	markInvalid: function(element){
		Element.addClassName($(element), Validation.invalidClassName);
	},
	restore: function(element){
		element = $(element);
		element.__validated = false;
		element.isValid = true;
		Validation.unregisterMessage(element);
		Element.removeClassName(element, Validation.invalidClassName);
	},
	markRequired: function(element){
		if($ON($P(element, 'REQUIRED')))
			Element.addClassName(element, 'required');
		else
			Element.removeClassName(element, 'required');
	},
	validateFocus: function(element) {
		element = $(element);
		Element.getHandler(element, 'onvalidatefocus')();
		if (element.focus) element.focus();
		if (element.select) element.select();
	},
	isValid: function(element, event){
		// Do not validate label or fieldset elements
		if(!Object.isDefined(element.type)||element.__validated||$ON($P(element, 'disabled'))||$ON($P(element, 'readOnly')))
			return true;
		if(['button','submit','reset'].contains(element.type))
			return true;
		element.__validated = true;
		if(element.onbeforevalidate()==false)
			return false;
		var iLength,vAnd,or,oRegexp,iMin,iMax,format,sMask,date,minDate,maxDate,bFirst;
		iMin = $P(element, 'MIN');
		iMax = $P(element, 'MAX');
		var pass=true;
		if(element.value && !/file|select/.test(element.type))
			element.value = element.value.trim();
		var sValue = $F(element);
		var bSigned = $P(element, 'SIGNED');
		var sSeparador = $P(element, 'SEPARADOR'); /* Adicionado por Fabiano A. Costa em 02/10/2006 quando usado em  conjunto com validações de DATA,
		                                              PHONE, ZIP em que estas validações estejam com o parâmetro 'formatar', pode-se indicar através deste
													  o separador que será usado */
		// REQUIRED
		if(Validation.isRequired(element) && !(sValue && sValue.first ? sValue.first() : sValue)){
			Validation.fail(element, "Por favor digite um valor campo obrigatório", 'REQUIRED', event);
			return false;
		}
		// FLOAT, NUMBER
		if(((bFirst=$ON($P(element, 'FLOAT')))||$ON($P(element, 'NUMBER'))) && sValue){
			if(!Validation.isFloat(sValue, bSigned))
				pass=false;
			else if(iMin==parseFloat(iMin) && parseFloat(sValue.replace(/,/g, String.Empty)) < parseFloat(iMin))
				pass=false;
			else if(iMax==parseFloat(iMax) && parseFloat(sValue.replace(/,/g, String.Empty)) > parseFloat(iMax))
				pass=false;
			if(!pass){
				Validation.fail(element, "Por favor digite um numero {0}{1}".format(
					bSigned ? String.Empty : "positivo", 
					Validation.minMaxRange(Number.format(iMin), Number.format(iMax)))
					,bFirst?'FLOAT':'NUMBER',event);
				return false;
			}
		}
		// NUMPROCESSOANTIGO - **************************************** ADICIONADO POR FABIANO EM 28/08/2006
		else if($ON(sNumProcessoType=$P(element, 'NUMPROCESSOANTIGO'))&&sValue)
		{
			var num = montar_processo_antigo(retira_caracteres(sValue),sNumProcessoType);
			//Verifica se o número do processo é válido de acordo com o dígito verificador	
			var valido = verifica_digito_processo_antigo(num);
			//Se o número do processo for válido, formata o número
			if (valido) 
			{
				element.value = formata_numero_antigo(num);
			} else
			{
			Validation.fail(element, "Por favor digite um número de processo válido",'PROCESSO',event);
			return false;
			}
		}
		
		// NUMPROCESSO - **************************************** ADICIONADO POR FABIANO EM 04/06/2010
		else if($ON(sNumProcessoType=$P(element, 'NUMPROCESSO'))&&sValue)
		{
			var num = retira_caracteres(sValue);
			//Verifica se o número do processo é válido de acordo com o dígito verificador	
			var valido = verifica_digito_processo(num);
			//Se o número do processo for válido, formata o número
			if (valido) 
			{
				element.value = formata_numero(num);
			} else
			{
			Validation.fail(element, "Por favor digite um número de processo válido",'PROCESSO',event);
			return false;
			}
		}

		// CPF - *********************************************** ADICIONADO POR FABIANO EM 28/08/2006
		else if($ON(bCPFformat=$P(element, 'CPF'))&&sValue)
		{
			// Atribui um valor default para bCPFformat
			bCPFformat=(bCPFformat=="formatar")?true:false;
			if (isCpf(sValue))
			{
				element.value = formatCpfCnpj(sValue, bCPFformat, false);
			}
			else
			{
				Validation.fail(element, "Por favor digite um número de CPF válido",'CPF',event);
				return false;
			}
		}
		// CNPJ - ********************************************** ADICIONADO POR FABIANO EM 28/08/2006
		else if($ON(bCNPJformat=$P(element, 'CNPJ'))&&sValue)
		{
			// Atribui um valor default para bCNPJformat
			bCNPJformat=(bCNPJformat=="formatar")?true:false;
			if (isCnpj(sValue))
			{
				element.value = formatCpfCnpj(sValue, bCNPJformat, true);
			}
			else
			{
				Validation.fail(element, "Por favor digite um número de CNPJ válido",'CNPJ',event);
				return false;
			}
		}
		// CPF/CNPJ - ********************************************** ADICIONADO POR FABIANO EM 05/09/2006
		else if($ON(bCPFCNPJformat=$P(element, 'CPFCNPJ'))&&sValue)
		{
			// Atribui um valor default para bCPFCNPJformat
			bCPFCNPJformat=(bCPFCNPJformat=="formatar")?true:false;
			if (isCnpj(sValue))
			{
				element.value = formatCpfCnpj(sValue, bCPFCNPJformat, true);
			}
			else if(isCpf(sValue))
			{
				element.value = formatCpfCnpj(sValue, bCPFCNPJformat, false);
			}
			else
			{
				Validation.fail(element, "Por favor digite um número de CPF ou CNPJ válido",'CPFCNPJ',event);
				return false;
			}
		}
		// EQUAL - ******************************************* ADICIONADO POR FABIANO EM 31/08/2006
		else if($ON(sEQUALsequencia=$P(element, 'EQUAL'))&&sValue)
		{
			if ((sValue)!=sEQUALsequencia)
			{
				Validation.fail(element, "Este é um campo de confirmação. Seu conteúdo deve ser idêntico ao do campo solicitado",'EQUAL',event);
				return false;
			}
		}
		// AMOUNT, CURRENCY
		else if (((bFirst=$ON($P(element, 'AMOUNT')))||$ON($P(element, 'CURRENCY'))) && sValue){ 
			if(!Validation.isCurrency(sValue, bSigned))
				pass=false;
			else if(iMin==parseFloat(iMin) && parseFloat(sValue.replace(/[\$,]/g,String.Empty).replace(/^\(\$(.*)\)$/,"-$1"))<parseFloat(iMin))
				pass=false;
			else if(iMax==parseFloat(iMax) && parseFloat(sValue.replace(/[\$,]/g,String.Empty).replace(/^\(\$(.*)\)$/,"-$1"))>parseFloat(iMax))
				pass=false;
			if(!pass){
				Validation.fail(element, "Por favor digite um "+(bSigned?String.Empty:"positivo ")+"valor em reais"+Validation.minMaxRange(Number.format(iMin),Number.format(iMax)),bFirst?'AMOUNT':'CURRENCY',event);
				return false;
			}
		}
		// INTEGER
		else if ($ON($P(element, 'INTEGER')) && sValue){
			if (!Validation.isInteger(sValue, bSigned))
				pass=false;
			else if(iMin==parseInt(iMin) && parseInt(sValue.replace(/,/g,String.Empty))<parseInt(iMin))
				pass=false;
			else if(iMax==parseInt(iMax) && parseInt(sValue.replace(/,/g,String.Empty))>parseInt(iMax))
				pass=false;
			if(!pass){
				Validation.fail(element, "Por favor digite um "+(bSigned?"n ":"positivo ")+"inteiro"+Validation.minMaxRange(Number.format(iMin),Number.format(iMax)),'INTEGER',event);
				return false;
			}
		}
		// DATE, DATETIME
		else if(((bFirst=$ON((format=$P(element, 'DATE'))))||$ON((format=$P(element, 'DATETIME'))))&&sValue){
			// Set default date format
			if(format == String.Empty || typeof format != 'string')
				format = this.defaultDateFormat;
			minDate = Validation.toDateString(iMin, format);
			maxDate = Validation.toDateString(iMax, format);
			date = Validation.toDateString(sValue, format);
			if(!Object.isDefined(date))
				pass = false;
			else if($ON(iMin) && Object.isDefined(minDate) && date < minDate)
				pass = false;
			else if($ON(iMax) && Object.isDefined(maxDate) && date > maxDate)
				pass = false;
			if(!pass){
				Validation.fail(element,"Por favor digite um valor "+Validation.dateOrTime(format)+" "+Validation.minMaxRange(iMin,iMax)+" no formato adequado: "+format.replace(/ap/i,'AM/PM').toUpperCase(),bFirst?'DATE':'DATETIME',event);
				return false;
			}
		}
		// PHONE 
		else if($ON(bPhoneformat=$P(element, 'PHONE'))&&sValue){
			// Atribui um valor default para bPhoneformat
			bPhoneformat=(bPhoneformat=="formatar")?true:false;
//			var sPhone=sValue.replace(/\D/g,String.Empty); // Substitui todo caracter não numérico por "" - vazio
			var sPhone=sValue;
			var iDigits=sPhone.length;
//			if((iDigits==8||iDigits==9&&/^1/.test(sPhone))){
			if (/^\d{4}(-?\d{4})$/.test(sPhone)){
				if (bPhoneformat)
				{ 
					 sValue = sValue.replace(/\D/g,String.Empty);
					 element.value = sValue.substr(0,4)+'-'+sValue.substr(4,4);
				}
			}
			else{
				Validation.fail(element,"Por favor digite um número telefônico válido",'PHONE',event);
				return false;
			}
		}
		// EMAIL
		else if($ON($P(element, 'EMAIL'))&&sValue){
			if(!/^[\w_-]+(\.[\w_-]+)*@[\w_-]+(\.[\w_-]+)*\.[a-z]{2,4}$/i.test(sValue)){
				Validation.fail(element,"Por favor digite um endereço de correio eletrônico válido", 'EMAIL', event);
				return false;
			}
		}
		// ZIP Code
		else if ($ON(bZipformat=$P(element, 'ZIP')) && sValue){
			// Atribui um valor default para bZipformat
			bZipformat=(bZipformat=="formatar")?true:false;
			if (/^\d{5}(-?\d{3})$/.test(sValue)){
				if (bZipformat)
				{ 
					// Atribui um valor default para sSeparador
					sSeparador=(sSeparador==null)?'-':sSeparador;
					var padrao = new Array(5,3);
					mascara(element,sSeparador,padrao,true)
				}
			}
			else{
				Validation.fail(element, "Por favor digite um código postal válido (CEP)", 'ZIP', event);
				return false;
			}
		}
		// UpperCase
		else if ($ON($P(element, 'UPPERCASE')) && sValue){
			element.value = element.value.toUpperCase();
		}
		// LowerCase
		else if ($ON($P(element, 'LOWERCASE')) && sValue){
			element.value = element.value.toLowerCase();
		}
		// Captcha
		if ($ON(bCaptchaformat=$P(element, 'CAPTCHA')) && sValue){
			// Atribui um valor default para bZipformat
			element.value = element.value.toUpperCase();
			if (element.value != bCaptchaformat){
				Validation.fail(element, "Por favor digite o código verificador correto.", 'ZIP', event);
				return false;
			}
		}
		// REGEXP
		if ($ON(oRegexp=$P(element, 'REGEXP')) && sValue){
			if (!oRegexp.isRegExp)
				oRegexp = new RegExp(oRegexp, 'i');
			if (!oRegexp.test(sValue)){
				Validation.fail(element, "Por favor digite um valor válido", 'REGEXP', event);
				return false;
			}
		}
		// MAXLENGTH
		if (sValue&&(iLength=$P(element, 'maxLength'))&&!/\D/.test(iLength)&&sValue.length>iLength){
			Validation.fail(element,"Por favor digite no máximo " + Number.format(iLength) + " caracteres", 'MAXLENGTH',event);
			return false;
		}
		for(var i=0;Validation._validationFunctions[i];i++){
			if(Validation._validationFunctions[i](element, sValue)==false)
				return false;
		}
		// AND
		if ($ON(vAnd = $P(element, 'AND')) && !sValue){
			if(typeof vAnd == 'string') vAnd = vAnd.toString().split(/,/);
			for(var oNewElement,i=0,iFields=vAnd.length; i<iFields; i++){
				if((oNewElement=(typeof vAnd[i].form=='object')?vAnd[i]:element.form.elements[vAnd[i].trim()])){
					if(!!$F(oNewElement)){
						Validation.fail(element, "Por favor digite um valor", 'AND',event);
						return false;
					}
				}
			}
		}
		// OR
		if ((or = $P(element, 'OR')) && !sValue){
			var fields,message;
			if(or.constructor==Array||or.constructor==String)
				fields = or;
			else
				fields = or['fields'];
			if(!!fields){
				if(fields.constructor!=Array)
					fields=fields.toString().split(/,/);
				for(var oNewElement,i=0,iFields=fields.length,bValue; !bValue&&i<iFields; i++){
					oNewElement=(fields[i].form)?fields[i]:element.form.elements[fields[i].trim()];
					if(oNewElement) bValue = !!$F(oNewElement);
				}
				if(!bValue){
					Validation.fail(element, message ? message : "Por favor digite um valor", 'OR', event);
					return false;
				}
			}
		}
		if(element.onvalidate()==false)
			return false;
		if(element.onaftervalidate()==false)
			return false;

		return true;
	},
	validate: function(element, oEvent){
		element = $(element);
		element.isValid = Form.Element.isValid(element, oEvent);
		return element.isValid;
	}

});

var Validation = {
	markRequiredInterval: 100,
	summaryIntroduction: 'Por favor corrija os erros listados abaixo:',
	summaryClassName: 'validation-summary',
	showPopup: false,
	showSummary: true,
	validateOnChange: true,
	currencySymbol: '$',
	decimalCharacter: '.',
	thousandsSeparator: ',',
	defaultDateFormat: 'D/M/YYYY',
	invalidClassName: 'invalid',

	_validationFunctions: [],
	isInitialFocusSet: false,
	
	pad: function(value, width){
		width = width || 2;
		var returnValue=value.toString();
		for(var i=width-returnValue.length;i>0;i--)
			returnValue='0'+returnValue;
		return returnValue;
	},
	minMaxRange: function(min,max){
		if ($ON(min)) min = String.Empty + min;
		if ($ON(max)) max = String.Empty + max;
		if (!!min && !!max) return " entre " + min + " e " + max;
		else if (!!min) return " maior que ou igual a " + min;
		else if (!!max) return " menor que ou igual a " + max;
		else return String.Empty;
	},
	dateOrTime: function(format){
		var date = false, time = false;
		date = format.search(/mm?/i)>-1 || format.search(/dd?/i)>-1 || format.search(/yyyy/i)>-1;
		time = format.search(/hh?/i)>-1 || format.search(/nn/i)>-1 || format.search(/ss/i)>-1 || format.search(/ap/i)>-1;
		return (date?"data":String.Empty)+(time?"hora":String.Empty);
	},
	toDateString: function(date, dateFormat){
		var i, regex, index=[];
		var day, month, year, hour, minute, second, ampm;
		// Determine order of datetime tokens
		with(dateFormat){
			index[search(/dd?/i)]='dia';
			index[search(/mm?/i)]='mês';
			index[search(/yyyy/i)]='ano';
			index[search(/hh?/i)]='hora';
			index[search(/nn/i)]='minuto';
			index[search(/ss/i)]='segundo';
			index[search(/ap/i)]='ampm';

			// timing of replaces is quite important!
			regex=dateFormat.replace(/(\$|\^|\*|\(|\)|\+|\.|\?|\\|\{|\}|\||\[|\])/g,"\\$1");
			// only allow one pass for day and month
			if(search(/dd/i)>-1)
				regex=regex.replace(/dd/i,"(0[1-9]|[1-2]\\d|3[0-1])");
			else
				regex=regex.replace(/d/i,"(0?[1-9]|[1-2]\\d|3[0-1])");
			if(search(/mm/i)>-1)
				regex=regex.replace(/mm/i,"(0[1-9]|1[0-2])");
			else
				regex=regex.replace(/m/i,"(0?[1-9]|1[0-2])");
			regex=regex.replace(/nn/i,"([0-5]\\d)")
				.replace(/ss/i,"([0-5]\\d)")
				.replace(/yyyy/i,"(\\d{4})")
				.replace(/\s+/g,"\\s*");
			if(search(/hh24/i)>-1)
				regex=regex.replace(/hh24/i,"([0-1]\\d|2[0-3])");
			else if(search(/h24/i)>-1)
				regex=regex.replace(/h24/i,"([0-1]?\\d|2[0-3])");
			else if(search(/hh/i)>-1)
				regex=regex.replace(/hh/i,"(0\\d|1[0-2])").replace(/ap/i,"([ap]m?)");
			else
				regex=regex.replace(/h/i,"(0?\\d|1[0-2])").replace(/ap/i,"([ap]m?)");
		}
		if(!new RegExp("^"+regex+"$",'i').test(date))
			return;
		year=month=day=hour=minute=second=0,ampm=String.Empty;
		for(var key=0,i=0;key<index.length;key++)
			if(index[key]) eval(index[key]+"=RegExp.$"+(++i));
		if(hour<12&&/^pm?$/i.test(ampm))
			hour = parseInt(hour)+12;
		else if(hour==12&&/^am?$/i.test(ampm))
			hour=0;
		if(year==0) year=1;
		if(month==0) month=1;
		if(day==0) day=1;
		if(month==2 && day>((year%4==0&&year%100!=0||year%400==0)?29:28) || day>((month-1)%7+1)%2+30)
			return;
		return String.Empty+this.pad(year,4)+this.pad(month)+this.pad(day)+this.pad(hour)+this.pad(minute)+this.pad(second);
	},
	isRequired: function(element){
		return $ON($P(element, 'REQUIRED'));
	},
	isFloat: function(value, signed){
		return new RegExp("^"+($ON(signed)?"-?":String.Empty)+"(\\d*(,?\\d{3})*\\,?\\d+|\\d+(,?\\d{3})*\\,?\\d*)$").test(value);
	},
	isInteger: function(value, signed){
		//TODO validation constants
		return new RegExp("^"+($ON(signed)?"-?":String.Empty)+"(\\d{1,3})(,?\\d{3})*$").test(value);
	},
	isCurrency: function(value, signed){
//		var reMain = "((\\d{1,3})(.?\\d{3})*(\\,\\d{2})?|((\\d{1,3})(.?\\d{3})*)?\\,\\d{2})"; 
		var reMain = "((\\d{1,3})(\\.\\d{3})*(\\,\\d{2}){1})";      // Alterado por Fabiano A. Costa (01/09/2006) - Exigir ponto de milhar e virgula dos decimais
		return new RegExp("^("+"("+ ($ON(signed)?"(\\$?\\-?|\\-?\\$?)":"\\$?")+reMain +")"+($ON(signed)?"|(\\(\\$?"+reMain+"\\))":String.Empty)+")$").test(value)	
	},
	add: function(code) {
		//evaluate the function in private scope to Validation; enables use of private functions
		eval("code="+code.toString());
		this._validationFunctions.push(Function.create(code));
	},
	setup: function(){
		for(var i=0,form; i < document.forms.length; i++){
			form=document.forms[i];
			if(!form._setup){
				form.isValid = true;
				form._onsubmit_ = Element.getHandler(form, 'onsubmit');
				form._onreset_ = Element.getHandler(form, 'onreset');
				form.onbeforevalidate = Element.getHandler(form, 'onbeforevalidate');
				form.onaftervalidate = Element.getHandler(form, 'onaftervalidate');
				form.onautosubmit = Element.getHandler(form, 'onautosubmit');
				form.onsubmit = function(oEvent){ //NN passed event
					if(!Form.validate(this, oEvent || window.event)) return false;
					if (this._onsubmit_(oEvent)==false)
						return false;
					return true;
				};
				Event.observe(form, 'reset', Form.resetValidation.bind({}, form));
				form._setup = true;
			}
			for(var j=0,element; j < form.elements.length; j++){
				element = form.elements[j];
				if(!element._setup){
					var initialFocus;
					if(!this.isInitialFocusSet && $ON((initialFocus=$P(element, 'INITIAL-FOCUS')))){
						element.focus();
						if(/^select$/i.test(initialFocus)) element.select();
						this.isInitialFocusSet = true;
					}
					element._onkeypress_ = Element.getHandler(element, 'onkeypress');
					element._onchange_ = Element.getHandler(element, 'onchange');
					element.isValid = true;
					element.onbeforevalidate = Element.getHandler(element, 'onbeforevalidate');
					element.onvalidate = Element.getHandler(element, 'onvalidate');
					element.onaftervalidate = Element.getHandler(element, 'onaftervalidate');
					element.onautosubmit = Element.getHandler(element, 'onautosubmit');
					element.onreset = Element.getHandler(element, 'onreset');
					if(Object.isDefined(element.type)){
						element.onkeypress = function(oEvent){ //NN passes event object
var keyEnter = 13, keyNewLine = 10, keyTab = 9, keyBackspace = 8, keyNull = 0, keyDelete = 0, keyEscape = 27;
							if(this._onkeypress_(oEvent)==false) return false;
							var filter = $P(this, 'FILTER');
							if ($ON(filter)){
								if (!filter.isRegExp)
									filter = new RegExp(filter);
								oEvent = oEvent || window.event;
								
								var keyCode = keyNull;
								if ($V(oEvent.charCode))
									keyCode = oEvent.charCode;
								else
									keyCode = oEvent.keyCode;

								if(![keyNull, keyTab, keyEnter, keyNewLine, keyBackspace, keyDelete, keyEscape].contains(keyCode)
										&& !filter.test(String.fromCharCode(keyCode)))
									return false;
							}
							return true;
						};
					}
					if(!['radio','checkbox'].contains(element.type)){
						element.onchange = function(oEvent){
							oEvent = oEvent || window.event;
							Form.Element.restore(this);
							if(Validation.validateOnChange)
								if(!Form.Element.validate(this, oEvent)) {
									return;
								}
							if(this._onchange_(oEvent)===false)
								return false;
							var autoSubmit = $P(this, 'AUTO-SUBMIT');
							if($ON(autoSubmit) && this.onautosubmit()!==false && this.form.onautosubmit()!==false)
								this.form.submit();
						};
					}
					element._setup = true;
				}
			}
			Form.markRequired(form);
			setInterval(Form.markRequired.bind({},form), Validation.markRequiredInterval);
		}
	},
	fail: function(element, message, stem, event){
		if(event == null || typeof event != 'object')
			event = { type: 'sham' };
		if(event.type != 'change'){
	 		var displayName = $P(element, 'DISPLAY-NAME');
			message = [
				(stem ? $P(element, stem.toUpperCase()+'-MESSAGE') : null),
				$P(element, 'MESSAGE'),
				message].choose();
			var extendedMessage = message.replace(/\.$/, String.Empty)
				+ (!!displayName ? " no campo {0}.".format(displayName) : ".");
			this._registerMessage(element, extendedMessage);
		}
		Form.Element.markInvalid(element, message);
	},
	displayMessages: function (form) {
		if (Validation.showPopup)
			this._displayPopup(form);
		if (Validation.showSummary)
			this.renderSummary(form);
	},
	_displayPopup: function (form) {
		if (!this._hasMessages(form)) return;
		var message = this.summaryIntroduction;
		var map = this._getIndexMap(form);
		var fieldMessages = this._getMessageMap(form);
		for(var i = 0; i < map.length; i++)
			message += "\n  - " + fieldMessages[map[i]];
		window.alert(message);
	},
	renderSummary: function (form) {
		var summary = this._getValidationSummary(form);
		if (!summary) return;
		Element.hide(summary);
		var elementId, list, listItem, link;
		var map = this._getIndexMap(form);
		var fieldMessages;
		if (this._hasMessages(form)) {
			fieldMessages = this._getMessageMap(form);
			Element.update(summary, String.Empty);
			summary.appendChild(document.createTextNode(this.summaryIntroduction));
			list = document.createElement('UL');
			summary.appendChild(list);
			for(var i = 0; i < map.length; i++) {
				elementId = map[i];
				listItem = document.createElement('LI');
				link = document.createElement('A');
				link.setAttribute('href', "javascript:Form.Element.validateFocus('{0}');".format(elementId));
				link.appendChild(document.createTextNode(fieldMessages[elementId]));
				listItem.appendChild(link);
				list.appendChild(listItem);
			}
			Element.show(summary);
			Element.scrollTo(summary);
		}
	},
	_hasMessages: function (form) {
		return this._getIndexMap(form).length > 0;
	},
	_messageMap: [],
	_indexMap: [],
	_getMessageMap: function (form) {
		var id = Element.idFor(form);
		if (!this._messageMap[id])
			this._messageMap[id] = [];
		return this._messageMap[id];
	},
	_getIndexMap: function (form) {
		var id = Element.idFor(form);
		if (!this._indexMap[id])
			this._indexMap[id] = [];
		return this._indexMap[id]
	},
	_registerMessage: function (element, message) {
		var id = Element.idFor(element);
		this._getMessageMap(element.form)[id] = message;
		this._getIndexMap(element.form).push(id);
	},
	_getValidationSummary: function (form) {
		var divs = form.getElementsByTagName('DIV');
		for (var i = 0; i < divs.length; i++) {
			if (Element.hasClassName(divs[i], this.summaryClassName))
				return divs[i];
		}
		return null;
	},
	unregisterMessage: function (element) {
		var elementId = Element.idFor(element);
		delete this._getMessageMap(element.form)[elementId];
		delete this._getIndexMap(element.form)[elementId];
		this._indexMap = this._indexMap.compact();
	},
	clearMessages: function (form) {
		var id = Element.idFor(form);
		this._messageMap[id] = [];
		this._indexMap[id] = [];
	}
};
var $ON = Element.propertyOn;

if(!!window.RegExp 
	&& !!String.Empty.replace 
	&& "ab".replace(/a/, String.Empty)=="b" 
	&& !!document.forms 
	&& !( navigator.appVersion.contains('Mac') && navigator.appVersion.contains('MSIE') )
) {
	Event.observe(window, 'load', Validation.setup);
}
