function $validate(form, config, message){
	return function(){
		if(execute(form, config)){
			var f = form.elements;
			for(var i = 0; i < f.length; ++i)
				if(f[i].isNull && f[i].isNull()) f[i].value = '';
			return true;
		}
		return false;
	};
	function execute(form, config){
		for(var c in config){
			var el = form[c] || window[c];
			if(!el || !visible(el)) continue;
			var a = config[c].split(/; */);
			for(var i = 0; i < a.length; i++) if(!exec(el, a[i])) return false;
		}
		return true;
	}
	function exec(el, str){
		var a = str.split('|');
		var test = parse(a[0]);
		if(!test.call) test = test.test.bind(test);
		var msg = (message && message[a[1]]) || a[1];
		return test.call(form, val(el), el) || $alert(el, msg) && false;
	}
	function parse(str){
		if(!str) return null;
		if(str.indexOf('(') < 0) return window[str] || new RegExp(str);
		var m = str.trim().match(/^(\w+)\(([\w, ]*)\)$/);
		if(!m) return new Function('return true');
		var fn = window[m[1]] || new RegExp(m[1]);
		if(!m[2]) return fn;
		var arg = m[2].match(/\w+/g);
		if(!arg) return fn;
		for(var i = 0; i < arg.length; i++) arg[i] = form[arg[i]] || window[arg[i]] || arg[i];
		var n = arg.length;
		return function(){
			for(var i = 0;i < arguments.length;i++) arg[n+i]=arguments[i];
			return fn.apply(null, arg);
		};
	}
	function val(el){
		var v = el.value;
		if(el.isNull && el.isNull()) return '';
		return v;
	}
	function visible(el){
		return $(el).$getStyle('visibility') != 'hidden' && el.offsetWidth > 0 && el.offsetHeight > 0;
	}
}