/* SpryValidationTextField.js - Revision: Spry Preview Release 1.4 */

// Copyright (c) 2006. Adobe Systems Incorporated.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//   * Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//   * Neither the name of Adobe Systems Incorporated nor the names of its
//     contributors may be used to endorse or promote products derived from this
//     software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

var Spry;
if (!Spry) Spry = {};
if (!Spry.Widget) Spry.Widget = {};

Spry.Widget.BrowserSniff = function() {
	var b = navigator.appName.toString();
	var up = navigator.platform.toString();
	var ua = navigator.userAgent.toString();

	this.mozilla = this.ie = this.opera = r = false;
	var re_opera = /Opera.([0-9\.]*)/i;
	var re_msie = /MSIE.([0-9\.]*)/i;
	var re_gecko = /gecko/i;
	var re_safari = /safari\/([\d\.]*)/i;
	
	if (ua.match(re_opera)) {
		r = ua.match(re_opera);
		this.opera = true;
		this.version = parseFloat(r[1]);
	} else if (ua.match(re_msie)) {
		r = ua.match(re_msie);
		this.ie = true;
		this.version = parseFloat(r[1]);
	} else if (ua.match(re_safari)) {
		this.safari = true;
		this.version = 1.4;
	} else if (ua.match(re_gecko)) {
		var re_gecko_version = /rv:\s*([0-9\.]+)/i;
		r = ua.match(re_gecko_version);
		this.mozilla = true;
		this.version = parseFloat(r[1]);
	}
	this.windows = this.mac = this.linux = false;

	this.Platform = ua.match(/windows/i) ? "windows" :
					(ua.match(/linux/i) ? "linux" :
					(ua.match(/mac/i) ? "mac" :
					ua.match(/unix/i)? "unix" : "unknown"));
	this[this.Platform] = true;
	this.v = this.version;

	if (this.safari && this.mac && this.mozilla) {
		this.mozilla = false;
	}
};

Spry.is = new Spry.Widget.BrowserSniff();

Spry.Widget.ValidationTextField = function(element, type, options)
{
	type = Spry.Widget.Utils.firstValid(type, "none");
	if (typeof type != 'string') {
		return;
	}
	if (typeof Spry.Widget.ValidationTextField.ValidationDescriptors[type] == 'undefined') {
		return;
	}
	options = Spry.Widget.Utils.firstValid(options, {});
	this.type = type;
	if (!this.isBrowserSupported()) {
		//disable character masking and pattern behaviors for low level browsers
		options.useCharacterMasking = false;
	}
	this.init(element, options);

	//make sure we validate at least on submit
	var validateOn = ['submit'].concat(Spry.Widget.Utils.firstValid(this.options.validateOn, []));
	validateOn = validateOn.join(",");

	this.validateOn = 0;
	this.validateOn = this.validateOn | (validateOn.indexOf('submit') != -1 ? Spry.Widget.ValidationTextField.ONSUBMIT : 0);
	this.validateOn = this.validateOn | (validateOn.indexOf('blur') != -1 ? Spry.Widget.ValidationTextField.ONBLUR : 0);
	this.validateOn = this.validateOn | (validateOn.indexOf('change') != -1 ? Spry.Widget.ValidationTextField.ONCHANGE : 0);

	if (Spry.Widget.ValidationTextField.onloadDidFire)
		this.attachBehaviors();
	else
		Spry.Widget.ValidationTextField.loadQueue.push(this);
};

Spry.Widget.ValidationTextField.ONCHANGE = 1;
Spry.Widget.ValidationTextField.ONBLUR = 2;
Spry.Widget.ValidationTextField.ONSUBMIT = 4;

Spry.Widget.ValidationTextField.ERROR_REQUIRED = 1;
Spry.Widget.ValidationTextField.ERROR_FORMAT = 2;
Spry.Widget.ValidationTextField.ERROR_RANGE_MIN = 4;
Spry.Widget.ValidationTextField.ERROR_RANGE_MAX = 8;
Spry.Widget.ValidationTextField.ERROR_CHARS_MIN = 16;
Spry.Widget.ValidationTextField.ERROR_CHARS_MAX = 32;

/* validation parameters:
 *  - characterMasking : prevent typing of characters not matching an regular expression
 *  - regExpFilter : additional regular expression to disalow typing of characters 
 *		(like the "-" sign in the middle of the value); use for partial matching of the currently typed value;
 * 		the typed value must match regExpFilter at any moment
 *  - pattern : enforce character on each position inside a pattern (AX0?)
 *  - validation : function performing logic validation; return false if failed and the typedValue value on success
 *  - minValue, maxValue : range validation; check if typedValue inside the specified range
 *  - minChars, maxChars : value length validation; at least/at most number of characters
 * */
Spry.Widget.ValidationTextField.ValidationDescriptors = {
	'none': {
	},
	'custom': {
	},
	'integer': {
		characterMasking: /[\-\+\d]/,
		regExpFilter: /^[\-\+]?\d*$/,
		validation: function(value, options) {
			if (value == '' || value == '-' || value == '+') {
				return false;
			}
			var regExp = /^[\-\+]?\d*$/;
			if (!regExp.test(value)) {
				return false;
			}
			options = options || {allowNegative:false};
			var ret = parseInt(value, 10);
			if (!isNaN(ret)) {
				var allowNegative = true;
				if (typeof options.allowNegative != 'undefined' && options.allowNegative == false) {
					allowNegative = false;
				}
				if (!allowNegative && value < 0) {
					ret = false;
				}
			} else {
				ret = false;
			}
			return ret;
		}
	},
	'real': {
		characterMasking: /[\d\.,\-\+e]/i,
		regExpFilter: /^[\-\+]?\d(?:|\.,\d{0,2})|(?:|e{0,1}[\-\+]?\d{0,})$/i,
		validation: function (value, options) {
			var regExp = /^[\+\-]?[0-9]+([\.,][0-9]+)?([eE]{0,1}[\-\+]?[0-9]+)?$/;
			if (!regExp.test(value)) {
				return false;
			}
			var ret = parseFloat(value);
			if (isNaN(ret)) {
				ret = false;
			}
			return ret;
		}
	},
	'currency': {
		formats: {
			'dot_comma': {
				characterMasking: /[\d\.\,\-\+\$]/,
				regExpFilter: /^[\-\+]?(?:[\d\.]*)+(|\,\d{0,2})$/,
				validation: function(value, options) {
					var ret = false;
					//2 or no digits after the comma
					if (/^(\-|\+)?\d{1,3}(?:\.\d{3})*(?:\,\d{2}|)$/.test(value) || /^(\-|\+)?\d+(?:\,\d{2}|)$/.test(value)) {
						value = value.toString().replace(/\./gi, '').replace(/\,/, '.');
						ret = parseFloat(value);
					}
					return ret;
				}
			},
			'comma_dot': {
				characterMasking: /[\d\.\,\-\+\$]/,
				regExpFilter: /^[\-\+]?(?:[\d\,]*)+(|\.\d{0,2})$/,
				validation: function(value, options) {
					var ret = false;
					//2 or no digits after the comma
					if (/^(\-|\+)?\d{1,3}(?:\,\d{3})*(?:\.\d{2}|)$/.test(value) || /^(\-|\+)?\d+(?:\.\d{2}|)$/.test(value)) {
						value = value.toString().replace(/\,/gi, '');
						ret = parseFloat(value);
					}
					return ret;
				}
			}
		}
	},
	'email': {
		characterMasking: /[^\s]/,
		validation: function(value, options) {
			var rx = /^[\w\.-]+@[\w\.-]+\.\w+$/i;
			return rx.test(value);
		}
	},
	'date': {
		validation: function(value, options) {
			var formatRegExp = /^([mdy]+)[\.\-\/\\\s]+([mdy]+)[\.\-\/\\\s]+([mdy]+)$/i;
			var valueRegExp = this.dateValidationPattern;
			var formatGroups = options.format.match(formatRegExp);
			var valueGroups = value.match(valueRegExp);
			if (formatGroups !== null && valueGroups !== null) {
				var dayIndex = -1;
				var monthIndex = -1;
				var yearIndex = -1;
				for (var i=1; i<formatGroups.length; i++) {
					switch (formatGroups[i].toLowerCase()) {
						case "dd":
							dayIndex = i;
							break;
						cas1$O,b($Q]PF?cV6)I".TyCx1U6A5S#9QSNDlDCp-?Om9s՞0jn>T,sGI-m#,Z`J`*ڈ`_B5`T$?צE  WYJx%#Hh@m_ P\MO
guRɏܰdEX~(Sґ"dQ%UoH. ԌR?AuUjCQE`Ou3-Dc1f  {?gHaǮ'zUx!Jv)GLą~l y Qk^Wʟϩ9fT:sW	Vh gZ'
JH*ZSDoځ^X)V60L@)NU4j<!?u}x?vO_Dstݕ״,մdi5"~=F J\tv?TȘ%#3CCz^8?kO{Pxw F7oV[+O5-,UԉIN9b_AVCPf*ҝ :) co~[JxLg 	?H#x``Ȫ{(d1?:g p 7CA4窆:zRO<rƦ~YRe<G:THtPg	&XOKND"USO #QOvybK S'y|.Bc|Dҽm4"/3V[ERO^d`:NWS&8 tẖt(=BqJD
 7z'ձXoӽ笖:Vǀ%Hd
tgFH_xbyG_΅GW6z /I/{cNMdXJ¯OB8G;;M4 Rǈg&i'O:z+QL*
,Ig>J?@K*3}iG=>#ҧ^}}qQ-tp?@[oRϢT>ޤauI_TSC!2@ r?jڙfҟ-`O,bJ [#?_۰2c<zEY^?:~ތw_3$IjQ?U0S<S		^mlpBY۹??Gc(DKQ*-m~剎`J>ZOJ~X?%mt2LC>:2JM!L41/ԅNǲYMC:сZjRTBc:q
[$( :tHƣˣ]Jzh5hK	4-a릝#6ys)ph$hLe]

nmǴD-I:ݦfd('Q%%Z5N^q0f+z5adntM3*,jI4iD,[`~* #3]>tϗUk2Y
X$8ꙡT=E2n'L3~_ܧx|sq W#'U-OQEF5\%@4tSSEPJfg׽\GۼDqIUdM?>? 34{v))[ ՠ:ϰ~x~~N<:zتq-d38u3o}#y	΢%5R1qRe*#iSQJ}rΟoVD8ٳy(V6Oxa o-Jҍ
3qY/D&B8^$?|z>_+gqIC,*!a+P6?EҖè1LGSGaUQ,TuYmTxOS~I 1|t{ck? cEqqHw?)y'CMYֶI?@nR-Z?m
B:
yv":6ʹs5_A?i5G/>2J?tb(%2H@~=>&aǳG+\GT#?@'wdi`E[X~UKcEAs8tV-4m"|m嚠"cϴczuzs<e'/m.j<r!!)/Q3ia{cQB'#8t H'Wt죑ӼӨCOK%=Bh镞B/[\ğxІ7S5Al-32yrf@n>#p=$RLXq\?bʴ$2fI.}d`|OBoTA?iLSE8dUP&V8? e> /AXc-8)Avh*+OS t㤚if"N:\*MXhf	cOiSIcHƈ/Sv/ԕ'V?gO"3!ii)5/!$*Yg%eg}.Z{cz\(JhY&OR$1XZ-],1bE?:5:[r?QDʪj)0xipQGHNď/z_: Sc?{jR)JEL+Mʭ?oaNqbg|`ݜ[|pۑa6-x*gO!)%^F^Z4OEF|LP=I3*ȺB$f'{m6-,ޕ8GNȦM:TXf \3 ?:I#jjp~ZDE#Lv\<̛a 8]%>?ꂪ'}d?8y^d䂀_os41}0SYˬP)+Z]2B4DOO}]::QP8ΦU6Zh:(.Ir;j£kHF´
ӿhr<AПˏF<`5ϖznId9bII(Rܣ6[ǻ[c9 P,5q ObAR%jNR4r椒 Sp:5+тy)+	H^eYUbYdX_dIExtJj!OK4oY5@bӤ?V_CXKI(P/ U:h	zYVtX4f(pid*oeqjȀq# V:.p 3NB
Y9fAıE,|OЇQߛbB&1OA=g)ӈh5[5TPSn@ ؞(4 Ѓv!㧅hjCO[χ?ä1dR1=MK
/<vh`iZsZ/j?4z t8R*]#cv<p̃H̦6I %[X:^O$BKB.hHGб=8
1Ffw2ѓ$X@U\ԍ??Z]U$~N41wUmA*Ra z\?/^UTWk I&] iK{v G ֙K_BEmF\}kGWy7f㛟1@ؚ|e\ePTE 'ʝx5X=`z]A%<U3.{yGiOM7~tdigit = parseInt(value.charAt(i), 10) * 2;
					digits[digits.length] = digit.toString().charAt(0);
					if (digit.toString().length == 2) {
						digits[digits.length] = digit.toString().charAt(1);
					}
				} else {
					digit = value.charAt(i);
					digits[digits.length] = digit;
				}
				j++;
			}
			var sum = 0;
			for(i=0; i < digits.length; i++ ) {
				sum += parseInt(digits[i], 10);
			}
			if ((sum%10) == 0) {
				return true;
			}
			return false;
		}
	},
	'zip_code': {
		formats: {
			'zip_us9': {
				pattern:'00000-0000'
			},
			'zip_us5': {
				pattern:'00000'
			},
			'zip_uk': {
				characterMasking: /[\dA-Z\s]/,
				validation: function(value, options) {
					//check one of the following masks
					// AN NAA, ANA NAA, ANN NAA, AAN NAA, AANA NAA, AANN NAA
					return /^[A-Z]{1,2}\d[\dA-Z]?\s?\d[A-Z]{2}$/.test(value);
				}
			},
			'zip_canada': {
				characterMasking: /[\dA-Z\s]/,
				pattern: 'A0A 0A0'
			},
			'zip_custom': {}
		}
	},
	'phone_number': {
		formats: {
			//US phone number; 10 digits
			'phone_us': {
				pattern:'(000) 000-0000'
			},
			'phone_custom': {}
		}
	},
	'social_security_number': {
		pattern:'000-00-0000'
	},
	'ip': {
		characterMaskingFormats: {
			'ipv4': /[\d\.]/i,
			'ipv6_ipv4': /[\d\.\:A-F\/]/i,
			'ipv6': /[\d\.\:A-F\/]/i
		},
		validation: function (value, options) {
			return Spry.Widget.ValidationTextField.validateIP(value, options.format);
		}
	},

	'url': {
		characterMasking: /[^\s]/,
		validation: function(value, options) {
			//fix for ?ID=223429 and ?ID=223387
			/* the following regexp matches components of an URI as specified in http://tools.ietf.org/html/rfc3986#page-51 page 51, Appendix B.
				scheme    = $2
				authority = $4
				path      = $5
				query     = $7
				fragment  = $9
			*/
			var URI_spliter = /^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/;
			var parts = value.match(URI_spliter);
			if (parts && parts[4]) {
				//encode each component of the domain name using Punycode encoding scheme: http://tools.ietf.org/html/rfc3492
				var host  = parts[4].split(".");
				var punyencoded = '';
				for (var i=0; i<host.length; i++) {
					punyencoded = Spry.Widget.Utils.punycode_encode(host[i], 64);
					if (!punyencoded) {
						return false;
					} else {
						if (punyencoded != (host[i] + "-")) {
							host[i] = 'xn--' + punyencoded;
						}
					}
				}
				host = host .join(".");
				//the encoded domain name is replaced into the original URL to be validated again later as URL
				value = value.replace(URI_spliter, "$1//" + host + "$5$6$8");
			}

			//fix for ?ID=223358 and ?ID=223594
			//the following validates an URL using ABNF rules as defined in http://tools.ietf.org/html/rfc3986 , Appendix A., page 49
			//except host which is extracted by match[1] and validated separately
			/*
			 * userinfo=	(?:(?:[a-z0-9\-\._~\!\$\&\'\(\)\*\+\,\;\=:]|%[0-9a-f]{2,2})*\@)?
			 * host=			(?:((?:(?:[a-z0-9][a-z0-9\-]*[a-z0-9]|[a-z0-9])\.)*(?:[a-z][a-z0-9\-]*[a-z0-9]|[a-z])|(?:\[[^\]]*\]))
			 * pathname=	(?:\/(?:[a-z0-9\-\._~\!\$\&\'\(\)\*\+\,\;\=\:\@]|%[0-9a-f]{2,2})*)*
			 * query=			(?:\?(?:[a-z0-9\-\._~\!\$\&\'\(\)\*\+\,\;\=\:\@\/\?]|%[0-9a-f]{2,2})*)?
			 * anchor=		(?:\#(?:[a-z0-9\-\._~\!\$\&\'\(\)\*\+\,\;\=\:\@\/\?]|%[0-9a-f]{2,2})*)?
			 */
			var regExp = /^(?:https?|ftp)\:\/\/(?:(?:[a-z0-9\-\._~\!\$\&\'\(\)\*\+\,\;\=:]|%[0-9a-f]{2,2})*\@)?(?:((?:(?:[a-z0-9][a-z0-9\-]*[a-z0-9]|[a-z0-9])\.)*(?:[a-z][a-z0-9\-]*[a-z0-9]|[a-z])|(?:\[[^\]]*\]))(?:\:[0-9]*)?)(?:\/(?:[a-z0-9\-\._~\!\$\&\'\(\)\*\+\,\;\=\:\@]|%[0-9a-f]{2,2})*)*(?:\?(?:[a-z0-9\-\._~\!\$\&\'\(\)\*\+\,\;\=\:\@\/\?]|%[0-9a-f]{2,2})*)?(?:\#(?:[a-z0-9\-\._~\!\$\&\'\(\)\*\+\,\;\=\:\@\/\?]|%[0-9a-f]{2,2})*)?$/i;

			var valid = value.match(regExp);
			if (valid) {
				//extract the  address from URL
				var address = valid[1];

				if (address) {
					if (address == '[]') {
						return false;
					}
					var first = address.charAt(0);
					var last = address.charAt(address.length - 1);
					if (first == '[' && last != ']' || first != '[' && last == ']') {
						return false;
					} else if (first == '[' && last == ']') {
						//IPv6 address or IPv4 enclosed in square brackets
						address = address.replace(/^\[|\]$/gi, '');
						return Spry.Widget.ValidationTextField.validateIP(address, 'ipv6_ipv4');
					} else {
						if (/[^0-9\.]/.test(address)) {
							return true;
						} else {
							//check if hostname is all digits and dots and then check for IPv4
							return Spry.Widget.ValidationTextField.validateIP(address, 'ipv4');
						}
					}
				} else {
					return true;
				}
			} else {
				return false;
			}
		}
	}
};

/*
2.2.1. Preferred
x:x:x:x:x:x:x:x, where the 'x's are the hexadecimal values of the eight 16-bit pieces of the address.
Examples:
	FEDC:BA98:7654:3210:FEDC:BA98:7654:3210
	1080:0:0:0:8:800:200C:417A
Note that it is not necessary to write the leading zeros in an
individual field, but there must be at least one numeral in every
field (except for the case described in 2.2.2.).

2.2.2. Compressed
The use of "::" indicates multiple groups of 16-bits of zeros.
The "::" can only appear once in an address.  The "::" can also be
used to compress the leading and/or trailing zeros in an address.
	1080:0:0:0:8:800:200C:417A --> 1080::8:800:200C:417A
	FF01:0:0:0:0:0:0:101 --> FF01::101
	0:0:0:0:0:0:0:1 --> ::1
	0:0:0:0:0:0:0:0 --> ::

2.5.4 IPv6 Addresses with Embedded IPv4 Addresses
	IPv4-compatible IPv6 address (tunnel IPv6 packets over IPv4 routing infrastructures)
	::0:129.144.52.38
	IPv4-mapped IPv6 address (represent the addresses of IPv4-only nodes as IPv6 addresses)
	::ffff:129.144.52.38

The text representation of IPv6 addresses and prefixes in Augmented BNF (Backus-Naur Form) [ABNF] for reference purposes.
[ABNF http://tools.ietf.org/html/rfc2234]
      IPv6address = hexpart [ ":" IPv4address ]
      IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT

      IPv6prefix  = hexpart "/" 1*2DIGIT

      hexpart = hexseq | hexseq "::" [ hexseq ] | "::" [ hexseq ]
      hexseq  = hex4 *( ":" hex4)
      hex4    = 1*4HEXDIG
*/
Spry.Widget.ValidationTextField.validateIP = function (value, format)
{
	var validIPv6Addresses = [
		//preferred
		/^(?:[a-f0-9]{1,4}:){7}[a-f0-9]{1,4}(?:\/\d{1,3})?$/i,

		//various compressed
		/^[a-f0-9]{0,4}::(?:\/\d{1,3})?$/i,
		/^:(?::[a-f0-9]{1,4}){1,6}(?:\/\d{1,3})?$/i,
		/^(?:[a-f0-9]{1,4}:){1,6}:(?:\/\d{1,3})?$/i,
		/^(?:[a-f0-9]{1,4}:)(?::[a-f0-9]{1,4}){1,6}(?:\/\d{1,3})?$/i,
		/^(?:[a-f0-9]{1,4}:){2}(?::[a-f0-9]{1,4}){1,5}(?:\/\d{1,3})?$/i,
		/^(?:[a-f0-9]{1,4}:){3}(?::[a-f0-9]{1,4}){1,4}(?:\/\d{1,3})?$/i,
		/^(?:[a-f0-9]{1,4}:){4}(?::[a-f0-9]{1,4}){1,3}(?:\/\d{1,3})?$/i,
		/^(?:[a-f0-9]{1,4}:){5}(?::[a-f0-9]{1,4}){1,2}(?:\/\d{1,3})?$/i,
		/^(?:[a-f0-9]{1,4}:){6}(?::[a-f0-9]{1,4})(?:\/\d{1,3})?$/i,


		//IPv6 mixes with IPv4
		/^(?:[a-f0-9]{1,4}:){6}(?:\d{1,3}\.){3}\d{1,3}(?:\/\d{1,3})?$/i,
		/^:(?::[a-f0-9]{1,4}){0,4}:(?:\d{1,3}\.){3}\d{1,3}(?:\/\d{1,3})?$/i,
		/^(?:[a-f0-9]{1,4}:){1,5}:(?:\d{1,3}\.){3}\d{1,3}(?:\/\d{1,3})?$/i,
		/^(?:[a-f0-9]{1,4}:)(?::[a-f0-9]{1,4}){1,4}:(?:\d{1,3}\.){3}\d{1,3}(?:\/\d{1,3})?$/i,
		/^(?:[a-f0-9]{1,4}:){2}(?::[a-f0-9]{1,4}){1,3}:(?:\d{1,3}\.){3}\d{1,3}(?:\/\d{1,3})?$/i,	
		/^(?:[a-f0-9]{1,4}:){3}(?::[a-f0-9]{1,4}){1,2}:(?:\d{1,3}\.){3}\d{1,3}(?:\/\d{1,3})?$/i,
		/^(?:[a-f0-9]{1,4}:){4}(?::[a-f0-9]{1,4}):(?:\d{1,3}\.){3}\d{1,3}(?:\/\d{1,3})?$/i
	];
	var validIPv4Addresses = [
		//IPv4
		/^(\d{1,3}\.){3}\d{1,3}$/i
	];
	var validAddresses = [];
	if (format == 'ipv6' || format == 'ipv6_ipv4') {
		validAddresses = validAddresses.concat(validIPv6Addresses);
	}
	if (format == 'ipv4' || format == 'ipv6_ipv4') {
		validAddresses = validAddresses.concat(validIPv4Addresses);
	}

	var ret = false;
	for (var i=0; i<validAddresses.length; i++) {
		if (validAddresses[i].test(value)) {
			ret = true;
			break;
		}
	}

	if (ret && value.indexOf(".") != -1) {
		//if address contains IPv4 fragment, it must be valid; all 4 groups must be less than 256
		var ipv4 = value.match(/:?(?:\d{1,3}\.){3}\d{1,3}/i);
		if(!ipv4) {
			return false;
		}
		ipv4 = ipv4[0].replace(/^:/, '');
		var pieces = ipv4.split('.');
		if (pieb1H봄Dn^t2>t䰲\bj)RHRVƥSpeV 7MGZCtڹeMD*VNtZD#\y4g|? ٯBgn,ε,~S	)UK]E8P# N<j`T]H"'QԪĒ $R0~UW{%(ץAN?,t.br,ʎ59g31xWٯ*2~ْ_Oڼ..W?	KUIS$k,"ҺA*7:hH~ϤGD<S!HԿwmKT  ԁг@ WIyᣮEMXU4W/G@H,[~=q+Bs_Ot[<LULMy
DIּ?*?˦Fr%%TR*kCB,j[* }P@ODC%GJTIvY
X::ydWpO}>]<DWʟ>z
mNC1oB3iY Td@Wקc<KYi䪯(S
D'>3 6϶qO
 2EJݩONWS#ETdiԒ 2*U^N~2Y  @Gk!hᆒ

Q*&y}?0o?ڻ:O1յuIS!2$MQQ"Gie%tp4OfX,M+F/?{􁟱_MTMDO=zNAPSXgR;OV" U uv$t?ΣCCJ6T1K#TSr*4J8
|itm!LkZmJBjhR9i0ӣ2OP:HͿJyghFӖ2QTB)sY	>#IDqӇ?ԟf-
ڕ:?tef,S;U㪇VqĆTJ	'OVoh,.5ۧ u6%v?>_cPeL<	d^~rnO{gj!o HO7xWcNDe_HjgF_!-Ƿ--pN]>9A:B6Jʕ2*x<n%TԮ~jK3Oe[&?e:# OOYY%dMO5d^sY	ZjO呴(.!oפ148|tVƴqRVIcvhx8kRJc#BG@DUF*5ӕu5$R<妖YQRDTBfGVSVӁ{(xd /~DʫE-LgƋ#MY5C<u6G?v$u>_#H9]V 3RYXFJ(+`EO$jy?ΡOpICi2bSԫL*],*jx$f[oVm2t`g`Ҡ !>]+(vaJܘe&DҺ-Ck _e 	0[:Ptp#$QLՃY 6߻c*gIF5R_#2J:	%3Iul@oŬ}JK*3q Uzsg^rϝ%	^	0DI]O5:${A}+Ci1
Cx U:gXifi3 &:ZZO6+[ilosdGy?㣩j%I~U2VF*K>ڎ:-4ҏ|^41촯TGOxyj!,2TqqGi	y?ԅ`'$C?zi*I$o$iJ ĺ|?cϭ;2jstT55pUK7:vI@Thv(rEC?9ǴS٬ ?J~Υ6:mYTTXU,⬂H%@5+@"~#/ ?I'@?è5|ږ?<Hm<$c3 !urq̝U]<Xzh(;M# W}݇D)uGJ|6ЂdfPӥijꌒG9* ر_j\s._8%1O-L3if>p%a4V{+ n:*<*QOKC<,KT#+k?>j+oO@]q˜P4S,bt`!K oxVˣOՅ$n#PieSJԆ65uBB?8siO.a V}z7WMM<iĎ8j[ lDS/#׊O+5Y{b:iԄf9#STcT O¸?gN2f!d/MRbfyby"?ytzjM__)Ɛz_Igj==,7'ۇ~jsn!-T M#<ZZJqij?,MngaOfr4RᏳj٥A#~ ?~}MsUMUOMT/PjhĆPfſ2F^OkRN*4u\UB9uB,Ҭt7I?~2_qzB~xXm,4ˍHetS6AUg$t
@{[>M:,:  tW+}@+cARB-H0D	SGy	n[iJʣJc`$/RwS4TTEчn~MxuG )秎OHo/Be~Ll+p@l|@/Ӭ4Q	H,5:G^ڍ#@"yS_Ϧ-^SciDQU/݉E ԔNd:-Z=?ү W!
	G|t(ԉ$p"T%S)S%2 ok^0:K:t/bݗԵCM
H+FBzXcD1GWJBtIi2(Y<t)Di㞇<]II>)$0}8)n?:G$=8SçLU}Q$fo-;$Tj^"պDG  pX xi(D㚕H$i|7,G-JdFaԓ*UjBY&xU.YIw-+6δ|_=p(yT1NQXXSĺai"?]u:tL П}8яE'ݼMS'J)YX~t{RhoҪ*ϮY,2i"zxXEr8·a3U WJtO%8	:jSΥt<!&iXVۈ]VQъ.>S,xqXXicaNȺ>Sw_}]y3Í8e*T:j֥bd("Is&O,n3tCQlD1Sc}q T7, Ihe^˥-VSAfYE+!dctۢGWZ tH5( WRVB)9GK-!r=qKd{#Ӱ5,tI4O\J_,s0XI,4+y {2*4$6Z>^F<^)JC$_ySDg5 ڷ+{\<?s+otor.pattern);
	options.validation = Spry.Widget.Utils.firstValid(options.validation, validationDescriptor.validation);
	if (typeof options.validation == 'string') {
		options.validation = eval(options.validation);
	}

	options.minValue = Spry.Widget.Utils.firstValid(options.minValue, validationDescriptor.minValue);
	options.maxValue = Spry.Widget.Utils.firstValid(options.maxValue, validationDescriptor.maxValue);

	options.minChars = Spry.Widget.Utils.firstValid(options.minChars, validationDescriptor.minChars);
	options.maxChars = Spry.Widget.Utils.firstValid(options.maxChars, validationDescriptor.maxChars);

	Spry.Widget.Utils.setOptions(this, options);
	Spry.Widget.Utils.setOptions(this.options, options);
};

Spry.Widget.ValidationTextField.prototype.destroy = function() {
	for (var i=0; i<this.event_handlers.length; i++) {
		Spry.Widget.Utils.removeEventListener(this.event_handlers[i][0], this.event_handlers[i][1], this.event_handlers[i][2], false);
	}
	try { delete this.element; } catch(err) {}
	try { delete this.input; } catch(err) {}
	try { delete this.form; } catch(err) {}
	try { delete this.event_handlers; } catch(err) {}
	try { this.selection.destroy(); } catch(err) {}
	try { delete this.selection; } catch(err) {}

	var q = Spry.Widget.Form.onSubmitWidgetQueue;
	var qlen = q.length;
	for (var i = 0; i < qlen; i++) {
		if (q[i] == this) {
			q.splice(i, 1);
			break;
		}
	}
};

Spry.Widget.ValidationTextField.prototype.attachBehaviors = function()
{
	if (this.element) {
		if (this.element.nodeName == "INPUT") {
			this.input = this.element;
		} else {
			this.input = Spry.Widget.Utils.getFirstChildWithNodeNameAtAnyLevel(this.element, "INPUT");
		}
	}

	if (this.input) {
		if (this.maxChars) {
			this.input.removeAttribute("maxLength");
		}
		this.putHint();
		this.compilePattern();
		if (this.type == 'date') {
			this.compileDatePattern();
		}
		this.input.setAttribute("AutoComplete", "off");
		this.selection = new Spry.Widget.SelectionDescriptor(this.input);
		this.oldValue = this.input.value;

		var self = this;
		this.event_handlers = [];

		this.event_handlers.push([this.input, "keydown", function(e) { if (self.isDisabled()) return true; return self.onKeyDown(e || event); }]);
		this.event_handlers.push([this.input, "keypress", function(e) { if (self.isDisabled()) return true; return self.onKeyPress(e || event); }]);
		if (Spry.is.opera) {
			this.event_handlers.push([this.input, "keyup", function(e) { if (self.isDisabled()) return true; return self.onKeyUp(e || event); }]);
		}

		this.event_handlers.push([this.input, "focus", function(e) { if (self.isDisabled()) return true; return self.onFocus(e || event); }]);
		this.event_handlers.push([this.input, "blur", function(e) { if (self.isDisabled()) return true; return self.onBlur(e || event); }]);

		this.event_handlers.push([this.input, "mousedown", function(e) { if (self.isDisabled()) return true; return self.onMouseDown(e || event); }]);

		var changeEvent = 
			Spry.is.mozilla || Spry.is.opera || Spry.is.safari?"input":
			Spry.is.ie?"propertychange":
			"change";
		this.event_handlers.push([this.input, changeEvent, function(e) { if (self.isDisabled()) return true; return self.onChange(e || event); }]);

		if (Spry.is.mozilla || Spry.is.safari) {
			//oninput event on mozilla does not fire ondragdrop
			this.event_handlers.push([this.input, "dragdrop", function(e) { if (self.isDisabled()) return true; self.removeHint();return self.onChange(e || event); }]);
		} else if (Spry.is.ie){
			//ondrop&onpropertychange crash on IE 
			this.event_handlers.push([this.input, "drop", function(e) { if (self.isDisabled()) return true; return self.onDrop(e || event); }]);
		}

		for (var i=0; i<this.event_handlers.length; i++) {
			Spry.Widget.Utils.addEventListener(this.event_handlers[i][0], this.event_handlers[i][1], this.event_handlers[i][2], false);
		}

		// submit
		this.form = Spry.Widget.Utils.getFirstParentWithNodeName(this.input, "FORM");
		if (this.form) {
			// if no "onSubmit" handler has been attached to the current form, attach one
			if (!this.form.attache^%[/X{E8$(ϡȳ0m-JeoJO? 'U$֟.=@Z kJ׋D<n?N[NMiƍEME5I(s˷^
zfCqʳ_<!;:6LwݲgE?:qGD[(Zyđ;o%'os*5?/)41%n|?YDJpd4m&hdɣ8 a7i  :3)aTHږ;㧑JDуgH<:'74fAO_WRBSOYb85 r}݄QCuXr?oOCc^/?-EH@$Ѥ}7nI&&?oJzZ+49)gBaHT.Ԥ>Ĝ7ӭ'Rd)>ݞ(YsIO]dO\I*7UGVՂx3_*ԓBU?gEsnLMˤ#Iar]Wل['O\A A%Mr%BKiIuD"B?Pc=:,Tq64;TךYI$v
(~"cwMKTYCccS&FqQVKM`?لPxu.#i˧%:x|jhѽe3<qE1S _wTP r?ئN0㦪(Ԩm^T$pU $_l:HztD dtE\55^)[#4-9銢
"4XFDG9ҏУ<~_=t U)gJLj)pOvXjV:nsʝLi)RC;T Uiq0
?9`jGRE=%c|r3?ϴ#I5Oş?Q*y5bZs?ӥW*jjDzi1*VSW:raSYh&UN.sRJ}<a Ҫy, U3J ,?=}_֎%D*o$HZOFGmHV]XJq du0*2U2OAkTnu2 @[_* U:.<SG4Ls?qۑbG	gڲ/OK4i<q꧑=D uo>1>~ޘxo^ċKI*q0M,OTV4d,Z?> 2Jt qM,kEp%#KbGϑOǴ8^Mg:045E"X@GM%4шύ !0OaP
=$K'fwI0֣Qi)@?:?5 )pI5@}Bi24VEK3TS4Li)$Xt@]0y ֟iM*5pKH(F<â6:<# #ERgF>*.*3*31:!$khX"(g'ү7?h{j3rQN= <bY&R.&?Q~XҜ:jIA`U1_M/qnѥA٪
ph2'ڛv*_OF|:c|dٲ=u(Ӆ5MdS~tcy%ao?H>|!ҧZiH#)VnF.dh[Oӱ9:z(`7-kFC%-FW'}'@ V2mYN> ANO֪2+JjZ:*9 !|q2jWڥ<M*[Y%F.elqTOIOR&H թ"O~-j:CHF(ir襤 :aKO#3LzT֧fWyשR#`)zxҵ++N`~##{GevOA@iN)*^%&֐52Y+ ŏGhcS=n	$55M,Uk-pUP&2$o*ؿG#[ ʃjE>]WY=c'rYwZWZ/Z|P*[ƲkW{~ʞ6}:Y$Ip}?.RMYEFլtyRi K,lڹʷ$/  ~>L\ϡ
:ɲ8#$Ԥq@5(ICJܒ4̶q}jQL	)?ӥMjCA1jQI*jZ6X4ҕ_V֦"iJ!J_tT;O=%e%M
iVGS5MM1X_>۲$Zn=}=	(1Yi!YJiKL+WoŽqQ@vq]sB#O'Լ51GII3 d<u?t@\}D5oY" WzXckM:sEMEE|Gr;i߆ɮ/.)O'I-}
$m	YOK0G%E<JP?Ss?~m#Hc2+L}7YJ)xL.M^SX*p1Vv`"$YcpDtE*ݨe*ݡgH<5.oe?ckN, xg:qq:)VDUpY @r2ɬ;_:+5 yJphcO[W/'}sNM/Nd`SSCCU*9T 970U5%u~oIKU	 ':aE4PeCQ~yoFUlZoӥoWpr)JKTSs0$A,wQx qOD.5s_ˠz`LFEw}OTSP* P{X=H Gų Q U:hRcYS5~<Jq&㩭?Y omF2Ƒ /JtEZ0j[ kI)sN`>.3>CD*,dR5FV%cSLh-6/<?Ν(*)>SoJJEIJM-M[
2R,Piqn<^"=$MCN^c=E,,aOef20%&ݝVPGN?m:q;*c&v` >o[o,=tg. lnJy*4u0LQ&Tos~u 'E7V`|)JtL$Ԗo0x~z& oڻJڛ+EUq zGesDKD5,ڛSkHS tQ㿗΃/4Y<3TBM{KӢ7]}rqg@T<uSm":zgA<Rj$e$R0>JU]. :ZROHDH9 62ҽ-UWK owbԼkN՚to<YZ},ES4thO6 ~ T_^7נDH s9D	9J5e?UydHeG5WVGtu%L z GB
NQOTrԢ=BMM(+7F2C&?>jJxF<ϧJ\~G Rb(g	5X459)"F%[يUtը4c)^ 
ծV1T,V(testValue.charAt(i))) {
				errors = errors | Spry.Widget.ValidationTextField.ERROR_FORMAT;
				fixedValue = revertValue;
				mustRevert = true;
				break;
			}
		}
	}

	//regExpFilter - character mask positioning (additional mask to restrict some characters only in some position)
	if (!mustRevert && this.useCharacterMasking && this.regExpFilter) {
		if (!this.regExpFilter.test(fixedValue)) {
			errors = errors | Spry.Widget.ValidationTextField.ERROR_FORMAT;
			mustRevert = true;
		}
	}

	//pattern - testValue matches the pattern so far
	if (!mustRevert && this.pattern) {
		var currentRegExp = this.patternToRegExp(testValue.length);
		if (!currentRegExp.test(testValue)) {
			errors = errors | Spry.Widget.ValidationTextField.ERROR_FORMAT;
			mustRevert = true;
		} else if (this.patternLength != testValue.length) {
			//testValue matches pattern so far, but it's not ok if it does not have the proper length
			//do not revert, but should show the error
			errors = errors | Spry.Widget.ValidationTextField.ERROR_FORMAT;
		}
	}

	if (fixedValue == '') {
		errors = errors | Spry.Widget.ValidationTextField.ERROR_REQUIRED;
	}

	if (!mustRevert && this.pattern && this.useCharacterMasking) {
		var n = this.getAutoComplete(testValue.length);
		if (n) {
			fixedValue += n;
		}
	}

	if(!mustRevert && this.minChars !== null  && continueValidations) {
		if (testValue.length < this.minChars) {
			errors = errors | Spry.Widget.ValidationTextField.ERROR_CHARS_MIN;
			continueValidations = false;
		}
	}

	if(!mustRevert && this.maxChars !== null && continueValidations) {
		if (testValue.length > this.maxChars) {
			errors = errors | Spry.Widget.ValidationTextField.ERROR_CHARS_MAX;
			continueValidations = false;
		}
	}

	//validation - testValue passes widget validation function
	if (!mustRevert && this.validation && continueValidations) {
		var value = this.validation(fixedValue, this.options);
		if (false === value) {
			errors = errors | Spry.Widget.ValidationTextField.ERROR_FORMAT;
			continueValidations = false;
		} else {
			this.typedValue = value;
		}
	}

	if(!mustRevert && this.validation && this.minValue !== null && continueValidations) {
		var minValue = this.validation(this.minValue, this.options);
		if (minValue !== false) {
			if (this.typedValue < minValue) {
				errors = errors | Spry.Widget.ValidationTextField.ERROR_RANGE_MIN;
				continueValidations = false;
			}
		}
	}

	if(!mustRevert && this.validation && this.maxValue !== null && continueValidations) {
		var maxValue = this.validation(this.maxValue, this.options);
		if (maxValue !== false) {
			if( this.typedValue > maxValue) {
				errors = errors | Spry.Widget.ValidationTextField.ERROR_RANGE_MAX;
				continueValidations = false;
			}
		}
	}

	//an invalid value was tested; must make sure it does not get inside the input
	if (this.useCharacterMasking && mustRevert) {
		this.revertState(revertValue);
	}

	this.errors = errors;
	this.fixedValue = fixedValue;

	this.flags.locked = false;

	return mustRevert;
};

Spry.Widget.ValidationTextField.prototype.onChange = function(e)
{
	if (Spry.is.opera && this.flags.operaRevertOnKeyUp) {
		return true;
	}
	if (Spry.is.ie && e && e.propertyName != 'value') {
		return true;
	}

	if (this.flags.drop) {
		//delay this if it's a drop operation
		var self = this;
		setTimeout(function() {
			self.flags.drop = false;
			self.onChange(null);
		}, 0);
		return;
	}

	if (this.flags.hintOn) {
		return true;
	}

	if (this.keyCode == 8 || this.keyCode == 46 ) {
		var mustRevert = this.doValidations(this.input.value, this.input.value);
		this.oldValue = this.input.value;
		if ((mustRevert || this.errors) && this.validateOn & Spry.Widget.ValidationTextField.ONCHANGE) {
			var self = this;
			setTimeout(function() {self.validate();}, 0);
			return true;
		}
	}

	var mustRevert = this.doValidations(this.input.value, this.oldValue);
	if ((!mustRevert || this.errors) && this.validateOn & Spry.Widget.ValidationTextField.ONCHANGE) {
		var self = this;
		setTimeout(function() {self.validate();}, 0);
	}
	return true;
};

Spry.Widget.ValidationTextFiI#k8 9FR)gӥ]Vz3e}/a f(1A #%>c	cdXK@mj4'MEΐ4)ibE.O*6<
Z /V5Pqh*jYRuUғI6 }}&$*g1btkQQRk41.8J5|SӳF
<#H okc*<zc =rfNcfY
F EŨr?zPՎ3G$o	@!q ~U?:ڝ$\ /X4)(d <Q.-{ok zֽOB3䂞0ʷ5/.+-;:H}$׺VƔzJ;;HWo6U
i˂}h^(R9?/7!ZO
Ժ
W>2VLQiS?qPSeF+V5$u_'XO1f3K䐔+d wR> W^HJ >w	R~|3{@Ƨ!{8ܓEfH׎u!(׎O+Vqݸu $WUc',Z@+}:N ꨧwI!ANHHbtKH%k~#$ gBˡyQ@ƚ0y[dky9*=}TʱRO \GhIFhKTȊ? "5N+YR_*AY	,(K CI)Nz(E+
2<3I9r5eܓx$d~tRQo1F 0! :ewkx~"v).(@?妉Z1R=ed#QS/I{}Too	#]@T*#- ,6}~8 ^=էW1T)bj-`5Ζ<O2  Ӫۂ U?񾹥% jA*$ 0"Ho{vIϧ	%iO-i=: M^׻νRz?׼h]YX|C_5%E PO{
 /ca3ìkڨt21z}@jS]:QCzdY=d:k_ 6l[y{yuP?:$IZ8%RuG'W'۱R_ꪴ+Z 	J/CS!#$@I[ b˪jP+WujF 6iR M Oz@т}hRX#
ĉ(ke6@I,ߕϭN>]y"]Kk/F1ƲqǶd%P鰅XîgX7M$+(EX Z5h8$||jxEY+C%F#_f^-pGe5ky p.$2(嵓ϒGA pJ8VV3
@2!yDha{Z _w`)eM+^;S[VOv28= 5=H OV¾_?|YLQfh[}*P<R,P|i)?g\d̅DN1(FhY8>#_z˩F4sgYY m*YYf?klAX騐,`*ydgePt؋{N[e*(oϧkN<u&7Vp<rC:Ǔʥ܍ϯ:ee Ɖ+2 	2IE [X٭oVWt:%Hj$@^T.&Oɽ 1
_MX{CNTj,\q]?_uge??`:R c/&EA& B+im&gN.?' -p=fVXP9bg  G?Ճ.:J :i2!i[*荙DRE~aiҀC>`bmyL)+Fcī>	nx> |~O:Y=C[nH]HeϤ)XiIYǖI&A般A ARp=k^iݼ W '\DG#Js71 2?N#еG?ZR$I5g_]+2LO Q$q݀LPyTzZiXSQ^
 v*[VdMWUFU>FbnJ&AbYCTq`55Z7DR!.$LzY?{i&26XT2C& >M4A/ XkߔӧPJ빟#(G/J INϯ^RϮ2>CtH(/)aZElHjc:C
׆}:M*51Χ̋iㄙԖD@O]-ozzuTi˩Ȕ9P!¨` ,ִ WVE(?$w6?/  W@.s`$:E@yWV])}LOtǘSXJ-8 ~G'@*qְMzF:y&P	e ?@4 ӫ1?\w.	b!T[Wj8̕vּ=^0B fyYkjfkKA'Yqݜ_O:i $$O@u^^Aڳ4UyP%Ճ<fh52ǩA vSPi|5&+qԙ_"gT}QcϽJ9B xdW WX)e)F2K{ouCdj.#3FGh&/?oھ3ՄX Xf1Hf+,؝%~oզ jץv]BH0#ΝPSX<Rlޣyhe@0& BK#`MIzS1 DIcR07BG'ٙJC]^6ԊӬfEO,q++ʪߤ0V*(R2)_.&˭:/VD4.:Q5ߛpGLphki(STh'9"'S3J"~k=EF~>(8yuI%etX#R}x,W:R:b|}:~8ʮ}xg[$vM$fc)`?u4BOHmCGhԙ!6nqytJAד#XFp$R4׫`}6$ WzҀePxH%$-~P- 5kW&A0?G(Ԇ _\OOA'P`mk3v&(hb'SŚjW\
0PHhVQIQ0yU: i=
(}ZZ)b[Nyb *+=Sp{ptN}?hn^4n$ajUF"zT/h%A N1^KI^)N
ID+Kck[H*~}lN&_AtPhU$phY݌g0iߔ0uNatjT|u5]g6LVک5nSqG&{ä$Q̪4T%h\c'BIk~tЫϭ+ʾY)Y+5%aS1
ʱ$opnW4^f4w[m>QIWQt2f1GQQIg:, H:@_-4t%Lu<zNSq9	+ghY1i'Ioo4f`*j+O!^?:ׇˠ0[V c#I?NuY>LtJ:\Sb:͏\{])p	xP +{tU"J:ԪU]ԔL] HkX{rʬqZZWGzЊǟAHXC5<1V+X4mpC+2HzU-RE\҇fz^l&喛ga:d^=<ITd2!ȷ$ZUZ .VP)OTSYmSݸ8L3Q2$Iuybb_![?,@SqO,
g?HuVi.W`窫bCV_\}m6*3K+0}a`V9U>|?gJi
&8t14tƽDňk`R<D^;ϩ|>@y ?fJGj|:=L)SG,i2OD4MPFf?PlH7 I$y
BdPy Nj -]=M4/P+f ARcqǣHczB-5|Pd| WB!/x秒zOK7<\9GC$֍eCZdYc4E+#:ֹ.?K2ŌpъF~U N}UU-\/U<ghKx摚HT[nIWY1~G1|~ޝhWTRhVXXUY^F`B {zd'!h>ӱ1ЁI4yL#ch1S㤒b1Cĭ3]B3"2	VZJTV$ydz w*
~cv49*j_I]3Q}Maf2`@:t՞5):צrV/hJ]3O&eLI`cH#ԖuZc(N	?=/Y& >QT?҉%ȕP4011Im,,ITO1x#?MVR㱓SM-:32	妇C$UW {/@!JJT3u>*,tUUW%RrN%6VW`zX}@03%5'znIW
 b
sǌIN'+5p	{H6(8/I@	_\姫$:y.8U&[J.nOE<j	#>_/(՞UbUzjS420cY+JְN>>˯C"3o􏩞vuAC*)зkl~{Aijj>ϷKЀ ӏQ+OE&_ .DD4&LfK:G}/>fA8#&ku[ <t+:M*h`Z9y#b\JVjfP-qGmutb9z
k]Tz(ٚѺj*d}S`hwtH8)j$em?@=n!D4ίzSUv4~tjS5vJ)6?֥R5tzH lZxJ<xZ'v%J=6ݦmGNJک2\ZX'-!*~a{С= >k1#Muu^5>)*G(uGaTol$}OU /-cCQR)^>~Npr*j'-l8Zz$(k^xQ@EI"ćQO	M'kִת(5NGWJѱHR%V?Q'Rsq[`)?Zݳ3tϑ`&ӠXj"<2+G S<{PE+\7bXI$gB37jC;1:V)<yS$a?p}nt+]x@?iki1d*VVKVY58c2P=9B?NRXu5Tԏ =zNe3TQHŎL&Zji>efG4'4Lh3(|+QvimմT޶)Z*$+H7SȰ>rLllpG+.=cwVKr	^?z
щ̎Ef`ubI9ΤS_Ϩۺ>8seY}?ǡմm _FA[C
O~h&kEcKaGԏǶB6jh?YHnB(B(Ο 
}?_kEWյ#5']'dRA0cfW 57t W$q9#A]đ;Yc&? Ӣ3ҽb>__Q(%6`5ÀJ?<mڞkfn#<) UF Cĭٙa3=z&Ar-?ӏi$@xu1`I,_<DV0MawD`קX9ϮPv-Zp+:w7Sn>{ S=aRGrlq ]*s} 8)>x>4< m:1Q`ݑRWԌxe%"Fơ# @47 zJ]}4>޵>\lqK"Jb*@eHѫU {eοoZ@ӏkuI,K$xDjO [݄b Vi_tia	LH \{x{^gHwF~ZFgl⳧gC_TPRT5	!0ţkX}^)EUqN:1ZQSy *Z
ՠvR#	1sP3_s4up/eM>ܒgк4':B88tPg,z&M.^)BP*3s~A.4Nc pqyzHx^ie2cc2ИSIږdabR
qob{1 JϏˢo)ҿ+fjo&O-T24+,,*aư.l=)HjH?! .=զ@}=C(U8f:b4uuOd"m6$6K^hY ?=!$y?a}-&䫫S ɏzJRe3M"  -a}Zj  XM0DdeQP)UA"dHfXTTUEDR'&me>o@xSqoF1RjG5Njck!-UDK:QGMĵ)SD$лjH#P4=>GdLw@qa#YA;LAa1J;\#/M:X`-G Vz>ZHA DaGJˆGCQ9Hp5+{qac?aPq U:Rc4Xԉi0M+T`Mɰ܆ϣ_XT|<zQ[)pHpTETD7(`RHKHO zOLUAJQxpGs`4V&g̉4ԚsqcX17J}Rg?om.O5x)Gf4\Zď g/ʅC						
							if (this.isDateGroupFull(this.oldValue, group+2)) 
								// need to overwrite first char in the next digit group
								futureValue = this.oldValue.substring(0, this.selection.start) + pressed + this.oldValue.substring(this.selection.start + 1);
							else
								futureValue = this.oldValue.substring(0, this.selection.start) + pressed + this.oldValue.substring(this.selection.start);
								
							if (!this.isValueValid(futureValue, this.selection.start + 1, group +2 )) 
							{
								this.redTextFlash(); return false;						
							}
							else
							{
								this.setValue (futureValue);
								this.selection.moveTo(this.selection.start + 1, this.selection.start + 1);									
							}
							return false;					
						}
						else 
						{
							var autocomplete = this.dateAutocompleteCharacters[group+1];
							
							var insertedValue = autocomplete + pressed;
							futureValue = this.oldValue.substring(0, this.selection.start) + insertedValue + this.oldValue.substring(this.selection.start);
							if (!this.isValueValid(futureValue, this.selection.start + insertedValue.length, group +2 )) 
							{
								// block this type
								insertedValue = autocomplete;
								futureValue = this.oldValue.substring(0, this.selection.start) + insertedValue + this.oldValue.substring(this.selection.start);
								this.setValue (futureValue);
								this.selection.moveTo(this.selection.start + insertedValue.length, this.selection.start + insertedValue.length);									
								this.redTextFlash(); return false;
							}
							else 
							{
								this.setValue (futureValue);
								this.selection.moveTo(this.selection.start + insertedValue.length, this.selection.start + insertedValue.length);									
								return false;
							}
						}
						
					}
				}
				else
				{
					// it's not the end of the full digits group
					
					// overwrite
					var movePosition = 1;
					futureValue = this.oldValue.substring(0, this.selection.start) + pressed + this.oldValue.substring(this.selection.start + 1);
					if (!this.isValueValid(futureValue, this.selection.start + 1, group)) 
					{
						this.redTextFlash(); return false;
					}
					else 
					{
						if(this.isPositionAtEndOfGroup(futureValue, this.selection.start+1, group)) 
						{
							if (group != this.lastDateGroup)
							{
								if (this.nextDateDelimiterExists(futureValue, this.selection.start + 1, group))
								{
									var autocomplete = this.dateAutocompleteCharacters[group+1];
									movePosition = 1 + autocomplete.length;
								}
								else
								{
									var autocomplete = this.dateAutocompleteCharacters[group+1];
									futureValue = this.oldValue.substring(0, this.selection.start) + pressed + autocomplete + this.oldValue.substring(this.selection.start + 1);
									movePosition = 1 + autocomplete.length;
								}
							}
						}
						this.setValue (futureValue);
						this.selection.moveTo(this.selection.start + movePosition, this.selection.start + movePosition);									
						return false;							
					}			
				}
			}
			else
			{
				// date group is not full
				// insert
				futureValue = this.oldValue.substring(0, this.selection.start) + pressed + this.oldValue.substring(this.selection.start);
				var movePosition = 1;
				if (!this.isValueValid(futureValue, this.selection.start + 1, group) && !this.isValueValid(futureValue, this.selection.start + 1, group+1)) 
				{
					this.redTextFlash(); return false;
				}
				else 
				{
					var autocomplete = this.dateAutocompleteCharacters[group+1];
					if (pressed == autocomplete) 
					{
						if (this.nextDateDelimiterExists(this.oldValue, this.selection.start, group))
						{
							futureValue = this.oldValue;
							movePosition = 1;
						}
					}
					else
					{
						if(this.isPositionAtEndOfGroup(futureValue, this.selection.start+1, group)) 
						{
							if (group != this.lastDateGroup)
							{
								if (this.nextDateDelimiterExists(futureValue, this.selection.start + 1, group))
								{
									var autocomplete = this.dateAutocompleteC#=4sWS$4SH=Q	 fU)-~njֆ8N33;aij`c*"AkR\^%d*=0bcihcJinUQe-X 
 ϥݣ	BBEp-$:vJ gaD,
 .$OեkI@Djƿ0}@ SH 'LrEM<4D:PG0VTO29 ?:W4먤[Tx䙑RLE	# SCF)P}K-BUU˃ŕTmoJ?(5ҵq%XSNT%z.ڿ[QH4֝6)5pzctv2G>'pWU _ڀST/)ۃԇ1x07 R^O5hz PP}``&T4HcA{i21i8ةy*WX!fќ)%.) _l UGWV+=)3Ff܂@K۪Ghig=7$4LRw6D	}\
y9x{7ኆY4<A+"vp.-mnog.b	=:ΡVgJu[#Q2#=Ax?_ul@2F@Ŀ~G!ݥ6K𴨤"=) 7[Zjf)fjhCyAȊC^Ll<Q >.	*Aq}ۣrIG@VZErzܵDDNIHEȰqHEP|	qRF*OJ`Jqz; vxz:bĴvk)i no{{<p_oϠO5uf?^]*Zc;Ə1RRB	J}?G{>pF4lˤo+ąo '"U}4v2dF$D`5X[Gz(Y<pC?o(#ت:qd"4rvU4TR+\zytͬ}E[qAN,>=.۳bo=VZzi'Hi"ZR>C4"\:3`t`Jq8fUw\ۢ']SHX	-o=M$6E
r.J$	|-CHi\AAC?*1uUԃ$y4ph"nn%+s h^I5Ӂ}A'kmiU\z nRTd2Vc^?Vc3c롊DfnP2xٿ5WA U}xއL?>x~]<T3
q) ?F O`_ /zAr(8W?)ҟmgm4Tdx
DI [d׿2CN<Nji~H@$X=2=!a$Zj܍}9O(>ޒjpځR
ay?nIQ4D@ň)e&=,4Z 7	KSK4qR#f^8`Z+qJǟ˭42ք㎖:yZkC_N*u;	!G7J0ھMkV( ӥS4XaYrd%_"aM:HafH8@Je{_OzA,V<WzOGEJgWG]e浧Qrڟ 7\!=3S>FT1vkOz(Y4%94U&)4(̒C:#lbCN[Q<c%-zj	C%BKGu	 ~8H*3CӟSK?HrQcV(䫪ZƼ#,ʥX}CF=}xX:]v5KcZyfeeDдwkPtx 17ό U5T/dXTi.]iFЖJzq#XϪCGsuXhFƙb@5*r +ZzqQOUw+AS̐OV
JX[O 6ڄ>/! cdxYt'h1:H7g('P~IR	9<)_~]etIKMR)C=EDQz
y?O{0 zМYFXy洮з:sJY1oj*lJΔsV.9 2ͬIi3N<HAHd0֟ozkX1{+5.ҡh!J,_՜'qtOkjc~}yM*BM#&2kMUIZ'/SrAoF"v>ޔURcWPNN20#vI$#(_qSQBAjt:,QI,ˡWUӶ&)RGCB,p l-л
=+_:΋jG>{_X :! sT}~Txtf3hlT ۻ_G圪$* 	DVO΂1=EsҾ]( W(=v.Z=nyk1}˽Mꘂ$EnOh؎OSDQVC 5I Wz!:ih)M4Q<T3H#e)}č$u)}Oި(H#xXc4e#Z9c-$~ȱp50 H 	9;@E<қp&3~<F6*z%"7gbWo(|",C}Wx<Oa=2:1Q:z!YQVv즚)db
4o#2TAVP\uE"O Qy?t!5^^d磕O!H&IP$iU@ރ
T g̤ISW#{B5TaL)6BGwLH	er G'_DJ:_<cviUۛۋ_ߘ3=)_$68^5Jxxb1i	őpGϪVE!i)K"fSƑN&6N$&z1=OJPMMe,^Bpl
  aCwygxqt\JW"w1R߷s2 o`? Ac}2kΟzQdO*8X 		iߛmd_$:Efb"bmJ-ԑVJ`=1*<~j}PB(]OPaZŇ _oJ
r?=^*d?@!uO4L*HR/ /E
qEzO$yB2fDnA?SHjGΜi	aCN),=1M^Y3GnNR6${#`s VieeBcgi8Tԛ3*mkONH_ˠR aj c: r㟳_^u| #4T4o$q&DKu	:\ AJ$Dt |:{rUAHvڭxie<zI;HAg*28QGοoJ-ǝ+]C綎U->fk̔B)hY:@o'W&FoͥXq`\ƸsOC}t(l'C?-|4-
GUA=%FZUcA.U4Wy[50~KZ6>:W>Xi9K}OC5rxv]~-ȢeQ?,n$Rűɧ>?b*IOHeh)b@aq:f\|gKEp53Wfg9zkPW6<
^YgHoD+$i[Y qdPP >z3eQ9Oe方OU3Yb RIkcwXOΜ?}#T:GtTMIjhYlSM!l^7xjU9 Y>o$K$8Ӿ''JJ*$++޾%bVGp 7?wv*FZ")gˡV&0EQ0ImIUgb	"X®Ey?oG]kR?zAt49z k*Eۥ'guJQ[qqNT ?.0pG.)9{%ڢ7-A^V,2-bvMJp?;$
J:O*[-MKG̦i)2p@E>X26y# Y<evPG:ZjXSh?.?̤"b6M,R^Mij稩?F	 Թ4k^.b?VgGlbI/$4p5$;$ŮCsqceIMGzF!T8!icіt2@Lte%Ư$Mہ?{{o6\qoID=X_c_,%Jt	AJ`E̞~.95xaIqJSdҤ*tYgu>#VĀ1R	6~AlHM i~>N[O%I䁢`Ryt xTuG[Gh~k頮zSpSTt#,	DfX:7'Ks3>4qӔaU$q{{𙡡kc#%BpQ%AՐ`o{_\;9`8g<x~ꮚ4Wen穆;S(*FՆL)kj((g}@Y.F%J"Y!!^	p8Ew[mH|OMu%\WG1ɟ1QLe;I+`8*o~oR[_8_.MMT!EK'g4!y \=ȸ ~],Jq^kjb2r
yP$vu2[rE~02 =NO``ImhfHH"6ӈ0 
p=bҕ=	's[M$FV"¦+!y@b@Vh]MFG88)T0 	 W:1>\QQO&!3tc X;R4?z)\hިz)1ȴf2Z:,D'fU?N/wdV1$]|Y 'Evl.Ri6;xWVq"DU,Y䦬9@jeQGm|f Z)[S`M~OQpnrX(2t e9DUSTFH7S1Gm,c6]>|kOtP(v:tUw51O8K<;LrQۉ4Њf5ޝ
h @ݷ[V1EqVH*'ii"cö.=}Ry׆j>߷"jBEz|h#S6ޚcjޙU+	$^?) Ҵ>x{SR*~]2H2xॅNdC\C}jO48?>[ؼq,hO?6E|s)u"2W8 fKMw)h5J N~tp	W#Do'I5"H.kϺGr"lӢfǚPҙwK	V'/Ɗj1MY%HfH=`[\e*	)!\
<:ݏwfFZjYMXb1TIQMIŜE)4 1rĳӁ?5J)j~6zY<M2R	e6upx
>b<s Ӓ+k P-6Y ziWKXDTQS<qPIQ0ֽb;Mjթ/g<CMXTS?\_0Yk&c,WZzz4uOTRERl AbqXDf\&h}zK&GSaW><\Htf(wwPc Jnm&@ևMUMKZ9T3ZTbG)NCіԬO8lOL#Զʨ'eY'5nlYPL
~} Buy?V3}Vm(7'+ K&Z\?A(c b͚&`٩.
k0qSN9亾6,KfSn04perbЯXQX`j\4__^~]Ixz#(>tZٲyT5uԴYtOngصp_J-eE.d_SXp)o?RgOMMC 4A4C(Hqw$oAQvI!JYbU_k >A?+,s\ cߜCACŒ Qi`=%g@`f:ޠJbbB!tIX<*V(:usAQe0Hvb_jw"FQb[R^l-ƒ$),"j}M#H1 _r	uf
xN$VhFU@dU9a(xɸRQl_<{tJc:j\y ^f$eD@XbV0obl\@!?uoSIkZ	>w)1#)9EqPK6WCDmǨߋsQk P?FM*ԲutcmaǟT֥XEW0O7#{r3EPA@ Wz(DGEyNY#*}=XA鷒 + N˥#̭6_\FbTZuVg,	 y =pH?nt<cD$r@Јkzxm's$_#.[Q?*}z)fQD"59e4 :
X~/!e
TWm` V?Lt:K$)_[ PM=zԌJWo~Lv/Zl2ԊN+!N8boRjsOjeyB=o?0kSSy@
ERZǩРk[: _m?UX&LA[Ib>ܞ8 R(,!F,B)L u4UJ
p뉖74G3D!ȊJ*QJFJ:JֿO
6R!P*u]o"= ?NVd	0
0#BXB `=OMKQF#:̒F,0R5 ʨ8RGX'dנQh$pn,[k}=4ϤB0zu
d[~deYBc{-2+-'=*U>WH\iCT_s,lca{k[omrmatClass);
	this.removeClassName(this.element, this.invalidRangeMinClass);
	this.removeClassName(this.element, this.invalidRangeMaxClass);
	this.removeClassName(this.element, this.invalidCharsMinClass);
	this.removeClassName(this.element, this.invalidCharsMaxClass);
	this.removeClassName(this.element, this.validClass);

	//possible states: required, format, rangeMin, rangeMax, charsMin, charsMax
	if (this.validateOn & Spry.Widget.ValidationTextField.ONSUBMIT) {

		this.removeHint();
		this.doValidations(this.input.value, this.input.value);

		if(!this.flags.active) {
			var self = this;
			setTimeout(function() {self.putHint();}, 10);
		}
	}

	if (this.isRequired && this.errors & Spry.Widget.ValidationTextField.ERROR_REQUIRED) {
		this.addClassName(this.element, this.requiredClass);
		return false;
	}

	if (this.errors & Spry.Widget.ValidationTextField.ERROR_FORMAT) {
		this.addClassName(this.element, this.invalidFormatClass);
		return false;
	}

	if (this.errors & Spry.Widget.ValidationTextField.ERROR_RANGE_MIN) {
		this.addClassName(this.element, this.invalidRangeMinClass);
		return false;
	}

	if (this.errors & Spry.Widget.ValidationTextField.ERROR_RANGE_MAX) {
		this.addClassName(this.element, this.invalidRangeMaxClass);
		return false;
	}

	if (this.errors & Spry.Widget.ValidationTextField.ERROR_CHARS_MIN) {
		this.addClassName(this.element, this.invalidCharsMinClass);
		return false;
	}

	if (this.errors & Spry.Widget.ValidationTextField.ERROR_CHARS_MAX) {
		this.addClassName(this.element, this.invalidCharsMaxClass);
		return false;
	}

	this.addClassName(this.element, this.validClass);
	return true;
}

Spry.Widget.ValidationTextField.prototype.addClassName = function(ele, className)
{
	if (!ele || !className || (ele.className && ele.className.search(new RegExp("\\b" + className + "\\b")) != -1))
		return;
	ele.className += (ele.className ? " " : "") + className;
};

Spry.Widget.ValidationTextField.prototype.removeClassName = function(ele, className)
{
	if (!ele || !className || (ele.className && ele.className.search(new RegExp("\\b" + className + "\\b")) == -1))
		return;
	ele.className = ele.className.replace(new RegExp("\\s*\\b" + className + "\\b", "g"), "");
};

/**
 * SelectionDescriptor is a wrapper for input type text selection methods and properties 
 * as implemented by various  browsers
 */
Spry.Widget.SelectionDescriptor = function (element)
{
	this.element = element;
	this.update();
};

Spry.Widget.SelectionDescriptor.prototype.update = function()
{
	if (Spry.is.ie && Spry.is.windows) {
		if (this.element.nodeName == "TEXTAREA") {
		var range = this.element.ownerDocument.selection.createRange();
		if (range.parentElement() == this.element){
			var range_all = this.element.ownerDocument.body.createTextRange();
			range_all.moveToElementText(this.element);
			for (var sel_start = 0; range_all.compareEndPoints('StartToStart', range) < 0; sel_start ++){
			 	range_all.moveStart('character', 1);
			}
			this.start = sel_start;
			// create a selection of the whole this.element
			range_all = this.element.ownerDocument.body.createTextRange();
			range_all.moveToElementText(this.element);
			for (var sel_end = 0; range_all.compareEndPoints('StartToEnd', range) < 0; sel_end++){
				range_all.moveStart('character', 1);
			}
			this.end = sel_end;
			this.length = this.end - this.start;
			// get selected and surrounding text
			this.text = range.text;
		 }
		} else if (this.element.nodeName == "INPUT"){
			this.range = this.element.ownerDocument.selection.createRange();
			this.length = this.range.text.length;
			var clone = this.range.duplicate();
			this.start = -clone.moveStart("character", -10000);
			clone = this.range.duplicate();
			clone.collapse(false);
			this.end = -clone.moveStart("character", -10000);
			this.text = this.range.text;
		}
	} else {
		var tmp = this.element;
		var selectionStart = 0;
		var selectionEnd = 0;
		try { selectionStart = tmp.selectionStart;} catch(err) {}
		try { selectionEnd = tmp.selectionEnd;} catch(err) {}

		if (Spry.is.safari) {
			if (selectionStart == 2147483647) {
				selectionStart = 0;
			}
			if (selectionEnd == 2147483647) {
				selectionEnd = 0;
			}
		}
		this.start = selectionStart;
		this.end = selectionEnd;
		this.length = selectionEnd - selectionStart;
		this.text = this.element.value.substring(selectionStart, selectionEnd);
	}
};

Spry.Widget.SelectionDescriptor.prototype.destroy = function() {
	try { delete this.range} catch(err) {}
	try { delete this.element} catch(err) {}
};

Spry.Widget.SelectionDescriptor.prototype.move = function(amount)
{
	if (Spry.is.ie && Spry.is.windows) {
		this.range.move("character", amount);
		this.range.select();
	} else {
		try { this.element.selectionStart++;}catch(err) {}
	}
	this.update();
};

Spry.Widget.SelectionDescriptor.prototype.moveTo = function(start, end)
{
	if (Spry.is.ie && Spry.is.windows) {
		if (this.element.nodeName == "TEXTAREA") {
			var ta_range = this.element.createTextRange();
			this.range = this.element.createTextRange();
			this.range.move("character", start);
			this.range.moveEnd("character", end - start);
			
			var c1 = this.range.compareEndPoints("StartToStart", ta_range);
			if (c1 < 0) {
				this.range.setEndPoint("StartToStart", ta_range);
			}

			var c2 = this.range.compareEndPoints("EndToEnd", ta_range);
			if (c2 > 0) {
				this.range.setEndPoint("EndToEnd", ta_range);
			}
		} else if (this.element.nodeName == "INPUT"){
			this.range = this.element.ownerDocument.selection.createRange();
			this.range.move("character", -10000);
			this.start = this.range.moveStart("character", start);
			this.end = this.start + this.range.moveEnd("character", end - start);
		}
		this.range.select();
	} else {
		this.start = start;
		try { this.element.selectionStart = start;} catch(err) {}
		this.end = end;
		try { this.element.selectionEnd = end;} catch(err) {}
	}
	this.ignore = true;
	this.update();
};

Spry.Widget.SelectionDescriptor.prototype.moveEnd = function(amount)
{
	if (Spry.is.ie && Spry.is.windows) {
		this.range.moveEnd("character", amount);
		this.range.select();
	} else {
		try { this.element.selectionEnd++;} catch(err) {}
	}
	this.update();
};

Spry.Widget.SelectionDescriptor.prototype.collapse = function(begin)
{
	if (Spry.is.ie && Spry.is.windows) {
		this.range = this.element.ownerDocument.selection.createRange();
		this.range.collapse(begin);
		this.range.select();
	} else {
		if (begin) {
			try { this.element.selectionEnd = this.element.selectionStart;} catch(err) {}
		} else {
			try { this.element.selectionStart = this.element.selectionEnd;} catch(err) {}
		}
	}

	this.update();
};

//////////////////////////////////////////////////////////////////////
//
// Spry.Widget.Form - common for all widgets
//
//////////////////////////////////////////////////////////////////////

if (!Spry.Widget.Form) Spry.Widget.Form = {};
if (!Spry.Widget.Form.onSubmitWidgetQueue) Spry.Widget.Form.onSubmitWidgetQueue = [];

if (!Spry.Widget.Form.validate) {
	Spry.Widget.Form.validate = function(vform) {
		var isValid = true;
		var isElementValid = true;
		var q = Spry.Widget.Form.onSubmitWidgetQueue;
		var qlen = q.length;
		for (var i = 0; i < qlen; i++) {
			if (!q[i].isDisabled() && q[i].form == vform) {
				isElementValid = q[i].validate();
				isValid = isElementValid && isValid;
			}
		}
		return isValid;
	}
};

if (!Spry.Widget.Form.onSubmit) {
	Spry.Widget.Form.onSubmit = function(e, form)
	{
		if (Spry.Widget.Form.validate(form) == false) {
			return false;
		}
		return true;
	};
};

if (!Spry.Widget.Form.onReset) {
	Spry.Widget.Form.onReset = function(e, vform)
	{
		var q = Spry.Widget.Form.onSubmitWidgetQueue;
		var qlen = q.length;
		for (var i = 0; i < qlen; i++) {
			if (!q[i].isDisabled() && q[i].form == vform && typeof(q[i].reset) == 'function') {
				q[i].reset();
			}
		}
		return true;
	};
};

if (!Spry.Widget.Form.destroy) {
	Spry.Widget.Form.destroy = function(form)
	{
		var q = Spry.Widget.Form.onSubmitWidgetQueue;
		for (var i = 0; i < Spry.Widget.Form.onSubmitWidgetQueue.length; i++) {
			if (q[i].form == form && typeof(q[i].destroy) == 'function') {
				q[i].destroy();
				i--;
			}
		}
	}
};

if (!Spry.Widget.Form.destroyAll) {
	Spry.Widget.Form.destroyAll = function()
	{
		var q = Spry.Widget.Form.onSubmitWidgetQueue;
		for (var i = 0; i < Spry.Widget.Form.onSubmitWidgetQueue.length; i++) {
			if (typeof(q[i].destroy) == 'function') {
				q[i].destroy();
				i--;
			}
		}
	}
};

//////////////////////////////////////////////////////////////////////
//
// Spry.Widget.Utils
//
//////////////////////////////////////////////////////////////////////

if (!Spry.Widget.Utils)	Spry.Widget.Utils = {};

Spry.Widget.Utils.punycode_constants = {
	base : 36, tmin : 1, tmax : 26, skew : 38, damp : 700,
  initial_bias : 72, initial_n : 0x80, delimiter : 0x2D,
  maxint : 2<<26-1
};

Spry.Widget.Utils.punycode_encode_digit = function (d) {
  return String.fromCharCode(d + 22 + 75 * (d < 26));
};

Spry.Widget.Utils.punycode_adapt = function (delta, numpoints, firsttime) {
	delta = firsttime ? delta / this.punycode_constants.damp : delta >> 1;
	delta += delta / numpoints;
	
	for (var k = 0; delta > ((this.punycode_constants.base - this.punycode_constants.tmin) * this.punycode_constants.tmax) / 2; k += this.punycode_constants.base) {
		delta /= this.punycode_constants.base - this.punycode_constants.tmin;
	}
	return k + (this.punycode_constants.base - this.punycode_constants.tmin + 1) * delta / (delta + this.punycode_constants.skew);
};

/**
 * returns a 	Punicode representation of a UTF-8 string
 * adapted from http://tools.ietf.org/html/rfc3492
 */
Spry.Widget.Utils.punycode_encode = function (input, max_out) {
	var inputc = input.split("");
	input = [];
	for(var i=0; i<inputc.length; i++) {
		input.push(inputc[i].charCodeAt(0));
	}
	var output = '';

  var h, b, j, m, q, k, t;
	var input_len = input.length;
  var n = this.punycode_constants.initial_n;
  var delta = 0;
  var bias = this.punycode_constants.initial_bias;
  var out = 0;

  for (j = 0; j < input_len; j++) {
		if (input[j] < 128) {
			if (max_out - out < 2) {
				return false;
			}
			output += String.fromCharCode(input[j]);
			out++;
		}
	}

	h = b = out;
	if (b > 0) {
		output += String.fromCharCode(this.punycode_constants.delimiter);
		out++;
	}

  while (h < input_len)	{
		for (m = this.punycode_constants.maxint, j = 0; j < input_len; j++) {
			if (input[j] >= n && input[j] < m) {
				m = input[j];
			}
		}
		if (m - n > (this.punycode_constants.maxint - delta) / (h + 1)) {
			return false;
		}
		
		delta += (m - n) * (h + 1);
		n = m;

		for (j = 0; j < input_len; j++) {
			if (input[j] < n ) {
				if (++delta == 0) {
					return false;
				}
			}

			if (input[j] == n) {
				for (q = delta, k = this.punycode_constants.base;; k += this.punycode_constants.base) {
					if (out >= max_out) {
						return false;
					}

					t = k <= bias ? this.punycode_constants.tmin : k >= bias + this.punycode_constants.tmax ? this.punycode_constants.tmax : k - bias;
					if (q < t) {
						break;
					}

					output += this.punycode_encode_digit(t + (q - t) % (this.punycode_constants.base - t));
					out++;
					q = (q - t) / (this.punycode_constants.base - t);
				}

				output += this.punycode_encode_digit(q);
				out++;
				bias = this.punycode_adapt(delta, h + 1, h == b);
				delta = 0;
				h++;
			}
		}
		delta++, n++;
	}

  return output;
};

Spry.Widget.Utils.setOptions = function(obj, optionsObj, ignoreUndefinedProps)
{
	if (!optionsObj)
		return;
	for (var optionName in optionsObj)
	{
		if (ignoreUndefinedProps && optionsObj[optionName] == undefined)
			continue;
		obj[optionName] = optionsObj[optionName];
	}
};

Spry.Widget.Utils.firstValid = function() {
	var ret = null;
	for(var i=0; i<Spry.Widget.Utils.firstValid.arguments.length; i++) {
		if (typeof(Spry.Widget.Utils.firstValid.arguments[i]) != 'undefined') {
			ret = Spry.Widget.Utils.firstValid.arguments[i];
			break;
		}
	}
	return ret;
};


Spry.Widget.Utils.specialCharacters = ",8,9,16,17,18,20,27,33,34,35,36,37,38,40,45,144,192,63232,";
Spry.Widget.Utils.specialSafariNavKeys = "63232,63233,63234,63235,63272,63273,63275,63276,63277,63289,";
Spry.Widget.Utils.specialNotSafariCharacters = "39,46,91,92,93UL
0F	 ~9?_fQkHM(sR>Qr>2cx,ז]{D#S;#ERҿ!m=罙U̕c 5Hԓݾz oy ON|x !M+>f>3抓.y$fĉX, 
	,Bmc1<cJ+ƈgo7q=?w_#=Q*Sm5VS-4SA*9t)"ŀ`I0vSx)k_*{҇fwJ*:<rx(BBu }ț6 e<iw.TQu&`**O=Wܯ#43`mlf9!LD_rȷ,:RxGDqƱ.9I *xdap.nJt\UJbidft* n8 {jz(Ǧ9Sđ5,	W/p~ڃ2KV%cm$8N*P2mX1Ϯ 9YG[l8md_mi.R+Z .?X?Сj*"MJɻx6ßfVa}3bq=^эk*FUSad1n OeB"bX} H45vu|5YxIRQ̚h	uXzA_Ŵ?|اL^QPxtrT0ӥRj,+1OCUO}3[5yXviXetK,SO4yߴW'{yQ_ՠj~X};GUT#S˔FJɝ}it%AnA. z/Ixu"}]YeyM'ɭ "u {~dtKR Tbm[2+!y*j"F /8Q`ꈖS^pۛ=5l"/VTEIO7Fy$qYNzgp"vf=4G0BCS!*jkµ!]*<~Ҟzcо&Zjv
RX(PLEuި ?`?.G-vr	k*j垁\O<qT%-Q$#u:W>$GU, ..1L`82Rh<:e/-B&#qIUve yӠq#ryi#1v6q?y ac`\ǅ	7Jj*(~hJ)2T"m
<lPZ}<S?oHii(!9iFY>k~>OyGǪ(};V&HEY3H)ӻu(RT CdOE8uRq)ǤrlDxf
j#/,q48>H=-
E:UoOl1#Ɣ2^)ϽqAO=7)U W1̑<tQMY<QJGHQnW״mׯVSjiɮOnxڕ	?]#&:qӦ$L1	yŭ䐰>) 6?OmGא_O:]5=<8jwy(Ăuk~?hԚǥ@hIu=j,Z_leE2T#IpO>'kZT紐z*;MDqGaakYtDE+1z8o5?
` t{0;kA]G殺sVS2S[H'D~}pLS}Gӗ ` 'SwcnXܜzeI.[t8J N?QJp=	ԸunrOSGPU/e29Yɕ9Q,,Y>{ͰWza.V542mEژM}=uT3VRh~Ne$X8I#8j9>XOM:$JSp#5deÇY"XC'ܖ}d:l}~fta)^gDSVSϊf2B.S$yi<{pPC?ӤDRGKvW<UD"f^C7K2*?J)=][3
Z140S4M>E*ad5{Ȉ5 ygKmY:Z?zEsx<
Vϣ-v[2zX\ϷG+<|rp?oҰ'ҿSԩvuT5mf66G1r(g)N 6bG9?Xi5:Efe0'([H$OLvᥧb-GݕPudāҷ*Ld
~G5DRJy@A"ۢI8^R\Vu399c ޓdZ$U)Ģ w"aG%ƃI##iLzQCY]VSb㙀Zep契W-n/{[`WW׻}_ŗG[>f@<x3Qlf8EC5Q PGL.QY
܎6N,tuՏ3Rjy@uR?<{yI#Ϧ]q mOGiR5=<KL*\꿸uBqgU=\QRxոqSAV`uH"Gӣ(A%ВO<{, UOA+$uK"Md-49e+`X~O.U}U?T⢁id\Lbe)R @j KZ#BKNZhCG[`eK0<oI="GR(|L4G$^(şuXpYK}-qzS?fz0TT#??_&ԵK6>"j*d'K~fԏ-4/z*:v2,aV")J.#V6_<:qQtZLIZIL-#Z0黎".H8tIp 䑁\zw'67/#SK7dcfq8-GG69=  M*W1G?\֟?:\VUFNMO$pjzT Nd)QN(V??I`?g"E3T&0zبeATIٞPz 3}(j)fSܮUH<k{pDbe`\u K?ͩcO\9[g_@bq *Ϡc"oى3E#,qda:!UCq,ec7{rFB!Nw[S	ΝQPHb^`hQB#fId PyS\xQU2?hPQLp P(LA2