cmsForm = function( instance_name, id, cell, defs ) {

	// --------------------------------------------------------------------------------------
	// PRIVATE

	var _instance_name = instance_name;
	var _id = id;
	var _cell = cell;
	var _func = defs.func;
	var _glue = defs.glue;
	var _deps = defs.deps;
	var _obsr = defs.obsr;
	var _verr = defs.verr;
	var _dirty = {};
	var _invalid = {};
	var _changes = {};
	var _changequeue = [];
	var _currentnode = '';
	var _currentvalue = false;
	var _markinvalidempty = false;
	var _repeat_index = {};

	function Initialize() {

		// bind events
		for (f in _obsr) {
			for (var ix=0; ix<_obsr[f].length; ix++) {
				$("input, select, textarea", "#"+f+'_'+ix ).bind("focus", {id:f,ix:ix}, function(evt) {
					window[_instance_name].trackChange(evt.data.id,evt.data.ix);
				});
				$("input, select, textarea", "#"+f+'_'+ix ).bind("change", {id:f,ix:ix}, function(evt) {
					window[_instance_name].trackChange(evt.data.id,evt.data.ix);
				});
				// observe these click events for ie: change will be fired too late
				$("input:checkbox, input:radio", "#"+f+'_'+ix ).bind("click", {id:f,ix:ix}, function(evt) {
					window[_instance_name].trackChange(evt.data.id,evt.data.ix);
				});
				// observe onblur for firefox (change event won't be fired on autocomplete)
				$("input:file, input:text, select", "#"+f+'_'+ix ).bind("blur", {id:f,ix:ix}, function(evt) {
					window[_instance_name].trackChange(evt.data.id,evt.data.ix);
				});
			}
		}

		// set up any file uploads
		$('input:file', "#cell"+_cell).each(function() {

			var obj_container_div = $(this).parent().parent();
			$(obj_container_div).find(".cmsFormsUploadButtonWrapper").prepend('<button class="cmsFormsUploadButtonSelect"><span>'+CmsFormLabels.browseFiles+'</span></button>');
			$(obj_container_div).find(".cmsFormsUploadFilenameWrapper").prepend('<div class="cmsFormsFieldBorderInput"><input type="text" value="" readonly="readonly" class="cmsFormsUploadFilename cmsFormsFieldText" />');

			var onchange = function() {
				$(this).parent().parent().find("input[type=text].cmsFormsUploadFilename").val($(this).val());
				re = /^(.+)_(.+)f$/;
				var test = re.exec($(this).attr("id"));
				window[_instance_name].trackChange(test[1],test[2]);
			};
			$(this).bind("change", {}, onchange);

			obj_container_div.find(".cmsFormsUploadButtonClear").click(function(evt) {
				$(this).parent().parent().parent().each(function() {
					var orig=$(this).find("input:file");
				    if (jQuery.browser.msie) {
				        // IE will not allow you to modify the type attribute after an element is created
				        var clone = document.createElement('<input type="file" />');
						attributes = ["style", "id", "title", "name", "class"];
				    } else {
				        var clone = document.createElement('input');
						attributes = ["type", "style", "id", "title", "name", "class"];
				    };
					for (var i=0; i<attributes.length; i++) {
						$(clone).attr( attributes[i], $(orig).attr( attributes[i] ) );
					}
					$(clone).bind("change", {}, onchange);
					$(orig).after(clone);
					$(orig).remove();
					$(clone).change();
					evt.preventDefault();
				});
			});

			$(this).css({ 'position': 'absolute', 'z-index': 2, 'font-size': '120px', 'opacity': '0', 'right': '40px', 'top': '0px', 'cursor': 'pointer' });
			// IE needs for some reason a wrapper div
			$(this).wrap('<div style="width:100%;" />');

		});

		// set up any date pickers
		for (f in _glue) {
			if (_glue[f].type == 'da') for (var ix=0; ix<_obsr[f].length; ix++) {
				$("input:text", "#"+f+'_'+ix ).datePicker( {clickInput:true, createButton:false, verticalOffset:20} );
			}
		}

		// require valid fields for submit
		$('button.cmsFormsSubmit', "#cell"+_cell).bind("click", function(evt) {
			if (!window[_instance_name].allowSubmit(evt)) evt.preventDefault();
		});
		
		// set up field error messages
		$('div.cmsFormsInvalid', "#cell"+_cell).each( function() {
			var idstr = $(this).attr("id");
			var parts = idstr.split("_");
			if (parts.length == 2) {
				_dirty[idstr] = true;
				handleField(parts[0]);
			}
		});

		// set up captcha error message
		$('#cf'+_id+'captcha.cmsFormsInvalid').each( function() {
			var alertmsg = $("span.cmsFormsFieldAlert", this).attr("title") || "";
			if (alertmsg == "") alertmsg = CmsFormAlerts["captcha"];
			$(this).attr("title", alertmsg);
		});

		// check for validation errors
		for (var i=0; i<_verr.length; i++) {
			for (var ii=0; ii<_verr[i]['f'].length; ii++) {
				var id=_verr[i]['f'][ii];
				if (_obsr[id]) for (var ix=0; ix<_obsr[id].length; ix++) {
					var txt = CmsFormAlerts[_verr[i]['t']];
					var arg = CmsFormAlerts[_verr[i]['v']];
					var alertmsg = txt.replace(/%1/g,arg);
					$("#"+id+'_'+ix).addClass("cmsFormsInvalid");
					$("#"+id+'_'+ix).attr("title", alertmsg);
				}
			}
		}

	}

	function hasInvalidValues(parentid) {
		if (parentid != null) {
			var parent_node=$('#'+parentid);
			if (parent_node.length == 0) return false;
		}
		// we don't return true on first invalid hit - we want to validate ALL fields
		var has_invalid = false;
		for (f in _obsr) {
			for (var ix=0; ix<_obsr[f].length; ix++) {
				var fld = f+'_'+ix;
				if (((parentid != null) && ($("#"+fld,parent_node).length == 0))) continue;
				if ((_invalid[fld] === true) && (_dirty[fld] === false)) {
					// invalid fields now must be marked as invalid - they may have not in case of invalidempty
					_dirty[fld] = true;
					handleField(f);
					if (_invalid[fld] == true) has_invalid = true;
				} else if ((_invalid[fld] !== false) || (_dirty[fld] === true)) {
					// if the field is dirty we have to process dependencies too
					onChange(f, ix);
					if (_invalid[fld] == true) has_invalid = true;
				}
			}
		}
		return has_invalid;
	}


	function displayButtonAlert( button_node ) {
		var outer_node = $(button_node).parent().parent();
		var alert_node = $("span.cmsFormsButtonAlert", outer_node);
		if (alert_node && alert_node.attr("title")) alert(alert_node.attr("title"));
	}


	function requireValid(target,parentid) {
		_markinvalidempty = true;
		var has_invalid_values = hasInvalidValues(parentid);
		if (has_invalid_values) displayButtonAlert(target);
		_markinvalidempty = false;
		return !has_invalid_values;
	}


	function allowSubmit(evt) {
		_markinvalidempty = true;
		var has_invalid_values = hasInvalidValues();
		if (has_invalid_values) displayButtonAlert(evt.target);
		_markinvalidempty = false;
		return !has_invalid_values;
	}


	function preventChange( evt ) {
		evt.preventDefault();
	}


	function adjustValue( val, type ) {
		switch(type) {
			case "d": return (parseFloat(val) || 0); break;
			case "i": return intValue(val); break;
			case "b": return (val > 0) ? 1 : 0; break;
			case "da": return Date.toDateString(Date.fromString(val)); break;
			default:  return val;
		}
	}


	function getValue(ids, index, ix) {
		var val = getRawValue(ids, index, ix);
		if (index != null) {
			var type = getType(ids[index]);
			val = adjustValue(val, type);
		} else {
			for (var i=0; i<ids.length; i++) {
				var type = getType(ids[index]);
				val[i] = adjustValue(val[i], type);
			}
		}
		return val;
	}


	function getRawValue(ids, index, ix) {
		ix = (ix>0) ? ix : 0; // the reference index (multiple inputs for same node)
		var values = [];
		for (var i=0; i<ids.length; i++) {
			switch (_obsr[ids[i]][ix]) {
				case 'r': // radio
					var node =  $("#"+ids[i]+'_'+ix+'f0');
					var node_name = node.attr('name');
					var node = $("input:checked[name='"+node_name+"']");
					values.push(node.length ? node.val() : "");
					break;
				case 't': // text field
					var node = $("input", "#"+ids[i]+'_'+ix);
					values.push(node.length ? node.val() : "");
					break;
				case 'a': // text area
					var node = $("textarea", "#"+ids[i]+'_'+ix);
					values.push(node.length ? node.val() : "");
					break;
				case 'c': // checkbox
					var vals = [];
					$("input:checked", "#"+ids[i]+'_'+ix).each( function() { vals.push($(this).val()); } );
					var value = '';
					for (var ii=0; ii<vals.length; ii++) value += ((ii>0) ? ',' : '') + vals[ii];
					values.push(value);
					break;
				case 's': // select
					var vals = [];
					$("option:selected", "#"+ids[i]+'_'+ix).each( function() { vals.push($(this).val()); } );
					var value = '';
					for (var ii=0; ii<vals.length; ii++) value += ((ii>0) ? ',' : '') + vals[ii];
					values.push(value);
					break;
				case 'p': // password
					values.push('');
					break;
				case 'h': // hidden
					var node = $("#"+ids[i]+'_'+ix);
					values.push(node.length ? node.val() : "");
					break;
				case 'u': // upload
					var node = $("input", "#"+ids[i]+'_'+ix);
					values.push(node.length ? node.val() : "");
					break;
			}
		}
		if (index != null) {
			return values[index];
		} else {
			return values;
		}
	}


	function setValue(id, values) {
		if (_obsr[id]) for (var ix=0; ix<_obsr[id].length; ix++) {
			switch (_obsr[id][ix]) {
				case 't': // text field
				case 'p': // password
				case 'a': // text area
					var value = (typeof(values) == 'object') ? values[0] : values;
					$("input,textarea", "#"+id+'_'+ix).attr("value",value);
					break;
				case 'c': // checkbox
					values = (typeof(values) == 'object') ? values : values.split(",");
					$("input", "#"+id+'_'+ix).each(
						function() {
							if (inArray(values,$(this).val())) 
								$(this).attr('checked',true); 
							else 
								$(this).attr('checked',false);
						}
					);
					break;
				case 'r': // radio
					var value = (typeof(values) == 'object') ? values[0] : values;
					$("input", "#"+id+'_'+ix).each(
						function() {
							if ($(this).val() == value) 
								$(this).attr('checked',true); 
							else 
								$(this).attr('checked',false);
						}
					);
					break;
				case 's': // select
					values = (typeof(values) == 'object') ? values : values.split(",");
					$("option", "#"+id+'_'+ix).each(
						function() {
							if (inArray(values,$(this).val())) 
								$(this).attr("selected","selected");
							else 
								$(this).removeAttr("selected");
						}
					);
					break;
				case 'h': // hidden
					var value = (typeof(values) == 'object') ? values[0] : values;
					$("#"+id+'_'+ix).attr("value",value);
					break;
			}
		}
	}


	function adjustField(id, prop) {
		if (_obsr[id]) for (var ix=0; ix<_obsr[id].length; ix++) {
			// required
			if (prop["required"] === true)  $("#"+id+'_'+ix).addClass("cmsFormsRequired");
			if (prop["required"] === false) $("#"+id+'_'+ix).removeClass("cmsFormsRequired");
	
			// disabled
			if (prop["disabled"] === true)  $("#"+id+'_'+ix).addClass("cmsFormsDisabled");
			if (prop["disabled"] === false) $("#"+id+'_'+ix).removeClass("cmsFormsDisabled");

			if ( (prop["invalid"] === true) || ((prop["invalidempty"] === true) && (_markinvalidempty === true)) ) {
				var alertmsg = $("#"+id+'_'+ix+" span.cmsFormsFieldAlert").attr("title") || "";
				if (alertmsg == "") alertmsg = CmsFormAlerts[prop["invalidreason"]];
				if (alertmsg != "") alertmsg = alertmsg.replace(/\{0\}/g, getRawValue([id],0,ix));
				$("#"+id+'_'+ix).addClass("cmsFormsInvalid");
				$("#"+id+'_'+ix).attr("title", alertmsg);
			} else {
				$("#"+id+'_'+ix).removeClass("cmsFormsInvalid");
				$("#"+id+'_'+ix).removeAttr("title");
			}

			// relevant
			if (prop["relevant"] === true) {
				$("#"+id+'_'+ix).removeClass("cmsFormsNotRelevant");
			}
			if (prop["relevant"] === false) {
				$("#"+id+'_'+ix).addClass("cmsFormsNotRelevant");
			}
	
			// disabled: we must rescue the current value(s)
			if (typeof(prop["disabled"]) != 'undefined') {
				var backup_nodes = $("#"+id+'_'+ix+"disabled");
				if (prop["disabled"]) {
					if (backup_nodes.length == 0) {
						var copy = $("#"+id+'_'+ix).clone().appendTo( $("#"+id+'_'+ix).parent() );
						$(copy).attr("id", id+'_'+ix+"disabled");
						$(copy).css("display", "none");
						$("input, select", "#"+id+'_'+ix).attr("disabled", "true");
					}
				} else {
					if (backup_nodes.length > 0) {
						$("#"+id+'_'+ix+"disabled").remove();
						$("input, select", "#"+id+'_'+ix).removeAttr("disabled");
					}
				}
			}
			
			// calculate
			if (typeof(prop["calculate"]) != 'undefined') {
				setValue(id,prop["calculate"]);
			}
		}
	}


	function inArray( arr, val ) {
		if (arr) for (var i=0; i<arr.length; i++) if (arr[i] == val) return true;
		return false;
	}


	function intValue( mixed_var ) {
	    var tmp;
	    if( typeof( mixed_var ) == 'string' ){
	        tmp = parseInt(mixed_var*1,10);
	        if(isNaN(tmp) || !isFinite(tmp)){
	            return 0;
	        } else{
	            return tmp;
	        }
	    } else if( typeof( mixed_var ) == 'number' && isFinite(mixed_var) ){
	        return Math.floor(mixed_var);
	    } else{
	        return 0;
	    }
	}


	function adjustDependencies( id ) {
		if (_deps[id]) for (var i=0; i<_deps[id].length; i++) {
			var dep_id = _deps[id][i];
			if (dep_id.match(/^cf[0-9]+o[0-9]+$/)) {
				handleOutput(id, dep_id);
			} else if (dep_id.match(/^cf[0-9]+g[0-9]+$/)) {
				handleGroup(id, dep_id);
			} else if (id != dep_id) {
				onChange(dep_id, 0);
			}
		}
	}

	function calculateValue( id ) {
		var value = '';
		// obviously it makes no sense to calculate multiple times - first one wins:
		if (_glue[id].calculate.length > 0) {
			value += _func[_glue[id].calculate[0]].apply(window[_instance_name],[id]);
		}
		return value;
	}


	function getType( id ) {
		if (_glue[id] && _glue[id].type) {
			switch ( _glue[id].type[0] ) {
				case "i":
				case "d":
				case "b":
				case "e":
				case "da":
					return _glue[id].type[0];
					break;
				default:
					return "s";
			}
		} else {
			return "s";
		}
	}


	function typeCheck( id ) {
		var val = getRawValue([id], 0);
		if (val != '') {
			// regex tests - note that backslashes must be backslashed!
			switch(getType(id)) {
				case "i": var regx = new RegExp('^[0-9]+$'); break;
				case "d": var regx = new RegExp('^[0-9]+(\\.[0-9]*)?$'); break;
				case "b": var regx = new RegExp('^[0|1]?$'); break;
				case "e": var regx = new RegExp('^[_a-zA-Z0-9-]+(\\.[_a-zA-Z0-9-]+)*@([a-zA-Z0-9-]+\\.)+([a-zA-Z]{2,4})$'); break;
				case "s": var regx = new RegExp('.*'); break;
				default: var regx = false;
			}
			if ((regx) && (!regx.test(val))) return getType(id);
			// custom tests
			switch(_glue[id].type[0]) {
				case "da":  if (Date.fromString(val) === false) return "da"; break;
			}
		}
		return false;
	}

	function constraintCheck( id ) {
		var val = getRawValue([id], 0);
		if (val != '') for (var i=0; i<_glue[id].constraint.length; i++) {
			var pat = _func[_glue[id].constraint[i]].apply(window[_instance_name],[id]);
			var patmat = pat.match(/^(.)(.*)\1([a-z]*)$/);
			// return true if pattern is invalid
			if (!patmat) return true;
			var regx = new RegExp(patmat[2], patmat[3]);
			if (!regx.test(val)) return true;
		}
		return false;
	}


	function emptyCheck( id ) {
		var val = getRawValue([id], 0);
		return (val === '') ? true : false;
	}


	function boolCheck( property, id, logic ) {
		for (var i=0; i<_glue[id][property].length; i++) {
			if (_func[_glue[id][property][i]].apply(window[_instance_name],[id]) == logic) return true;
		}
		return false;
	}


	function markDependenciesDirty( id ) {
		if (_deps[id]) for (var i=0; i<_deps[id].length; i++) {
			var dep_id = _deps[id][i];
			if (!dep_id.match(/^cf[0-9]+[og][0-9]+$/)) {
				var was_dirty = true;
				// ignore output and group dependencies
				for (var ix=0; ix<_obsr[dep_id].length; ix++) {
					if (_dirty[dep_id+'_'+ix] !== true) {
						was_dirty = false;
					} else {
						_dirty[dep_id+'_'+ix] = true;
					}
				}
				if (!was_dirty) markDependenciesDirty(dep_id);
			}
		}
	}


	function onChange(id, ix) {
		var refval = getRawValue([id], 0, ix);

		// we first mark the field and all dependencies as dirty
		_dirty[id+'_'+ix] = true;
		markDependenciesDirty(id);

		// adjust values of fields with same data node
		if (_obsr[id].length > 0) {
			setValue(id, refval);
		}
		// handle binds and adjust field
		handleField(id);
	}



	function handleGroup(id, dep_id) {
		// groups may only have relevant binds
		var prop = {};
		if (_glue[id]) {
			if (_glue[id].relevant) {
				if (boolCheck('relevant', id, false)) {
					$("#"+dep_id).addClass("cmsFormsNotRelevant");
				} else {
					$("#"+dep_id).removeClass("cmsFormsNotRelevant");
				}
			}
		}
	}


	function handleOutput(id, dep_id) {
		// set current value
		var values = getRawValue([id],0);
		var val = (typeof(values) == 'object') ? values[0] : values;
		var nn = $("#"+dep_id).get(0).nodeName;
		switch(nn.toLowerCase()) {
			case 'a': $("#"+dep_id).attr('href',val); break;
			case 'img': $("#"+dep_id).attr('src',val); break;
			default: 
				var v=val.replace(/\r\n/g,"\n").replace(/\r/g,"\n").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/\n/g,"<br/>");
				$("#"+dep_id).html(v);
		}

		// outputs may only have relevant binds
		var prop = {};
		if (_glue[id]) {
			if (_glue[id].relevant) {
				if (boolCheck('relevant', id, false)) {
					$("#"+dep_id).addClass("cmsFormsNotRelevant");
				} else {
					$("#"+dep_id).removeClass("cmsFormsNotRelevant");
				}
			}
		}
	}



	function handleField(id) {

		var is_dirty = false;
		// check if field is dirty - cancel if not; may already have been cleaned
		for (var ix=0; ix<_obsr[id].length; ix++) {
			if (_dirty[id+'_'+ix] === true) {
				is_dirty = true;
				_dirty[id+'_'+ix] = false;
			}
		}
		if (!is_dirty) return true;

		var prop = {};
		// field may have no binds but dependencies	
		if (_glue[id]) {
			if (_glue[id].required)
				prop.required = boolCheck('required', id, true);
			if (_glue[id].disabled)
				prop.disabled = boolCheck('disabled', id, true);
			if (_glue[id].enabled)
				if (boolCheck('enabled', id, true)) prop.disabled = false;
			if (_glue[id].relevant) {
				if (boolCheck('relevant', id, false)) {
					prop.relevant = false;
				} else {
					prop.relevant = true;
				}
			}
			if (_glue[id].calculate)
			    prop.calculate = calculateValue(id);
			if ((_glue[id].constraint) && (constraintCheck(id))) {
			    	prop.invalid = true;
			    	prop.invalidreason = 'constraint';
			    }
			if (_glue[id].type) {
				var typecheck = typeCheck(id);
				if (typecheck !== false) {
					prop.invalid = true;
					prop.invalidreason = 'type_'+typecheck;
				}
			}
			if (prop.required) {
			    prop.invalidempty = emptyCheck(id);
				if (prop.invalidempty) prop.invalidreason = 'required';
			}
			if (prop.relevant === false) {
			    if (prop.invalidempty == true) prop.invalidempty = false;
			    if (prop.invalid == true) prop.invalid = false;
			    if (prop.required == true) prop.required = false;
			    prop.invalidreason = '';
			}
			for (var ix=0; ix<_obsr[id].length; ix++) {
				if ( prop.invalid == true || prop.invalidempty == true ) {
					_invalid[id+'_'+ix]=true;
				} else {
					_invalid[id+'_'+ix]=false;
				}
			}
		}
		adjustField( id, prop );
		adjustDependencies( id );
	}


	function processChanges() {
		while (_changequeue.length > 0) {
			onChange(_changequeue[0]['id'], _changequeue[0]['ix']);
			_changes[_changequeue[0]['id']+'_'+_changequeue[0]['ix']] = false;
			_changequeue.shift();
		}
	}


	function trackChange(id,ix) {
		var nodeid = id+'_'+ix;
		var refvalue = getRawValue([id], 0, ix);
		// ignore first event (click, focus, ...) but save current value
		if (_currentnode !== nodeid) {
			_currentnode = nodeid;
			if ((_obsr[id][ix] == 'c') || (_obsr[id][ix] == 'r')) {
				// checkbox and radio values are not reliable - value may already have changed on first event
				// therefore we set oldvalue to false to force a processChange on every event coming up
				_currentvalue = false;
			} else {
				_currentvalue = refvalue;
			}
		} else if ((_changes[nodeid] !== true) && (_currentvalue !== refvalue)) {
			_changes[nodeid] = true;
			_changequeue.push({id:id,ix:ix});
			_currentvalue = refvalue;
			window.setTimeout(_instance_name+'.processChanges()', 50);
		}
	}
	
	function doAction(target,ref,actionurl) {
		// set action
		$(target).parents('form').each(
			function() {
				$("input[name='_formaction']", this).val(ref);
				if (actionurl) $(this).attr('action',actionurl);
				$(this).submit();
			}
		);
	}
	
	function setRepeatIndex(target,index,repeatid,ref) {
		if (_repeat_index[repeatid] > 0 && _repeat_index[repeatid]!=index) {
			$("li:nth-child("+_repeat_index[repeatid]+")",$("#"+repeatid)).removeClass('cmsFormsRepeatActive');
		}
		_repeat_index[repeatid]=index;
		$(target).addClass('cmsFormsRepeatActive');
	}


	function getRepeatRef(repeatid) {
		return _repeat_index[repeatid];
	}


	// --------------------------------------------------------------------------------------
	// PUBLIC
	return({

		toString: function() {
			return _instance_name;	
		},

		// never forget the constructor ...
		constructor: cmsForm,
		
		Initialize: function() {
			return Initialize.call(this);
		},
		
		trackChange: function(id,ix) {
			return trackChange.apply(this,[id,ix]);
		},
		
		processChanges: function() {
			return processChanges.apply(this,[]);
		},

		getValue: function(ids, index) {
			return getValue.apply(this,[ids,index]);
		},

		setValue: function(id, value) {
			return setValue.apply(this,[id,value]);
		},

		fnSum: function( values ) {
			var sum=0;
			if (typeof(values)=='array' || typeof(values)=='object') {
				for (var i=0; i<values.length; i++) {
					if ((values[i] != '') && !isNaN(values[i])) sum+=parseFloat(values[i]);
				}
			}
			return sum;
		},

		fnContains: function( string1, string2 ) {
			var str=new String(string1);
			return (str.indexOf(string2) == -1) ? false : true;
		},

		fnSizeof: function( arr ) {
			if (typeof(arr)=='array' || typeof(arr)=='object') {
				return arr.length;
			} else {
				return 0;
			}
		},

		fnFormatnumber: function( val, dec ) {
			var n=new Number( val=='' ? 0 : val );
			return n.toFixed(dec);
		},

		fnSubstr: function( val, s, n ) {
			if (typeof(val)=='array' || typeof(val)=='object') {
				return '';
			} else {
				var t = '' + val;
				return t.substr(s,n);
			}
		},

		allowSubmit: function(evt) {
			return allowSubmit.apply(this,[evt]);
		},
		
		doAction: function(target,ref,actionurl) {
			return doAction.apply(this,[target,ref,actionurl]);	
		},

		requireValid: function(target,parentid) {
			return requireValid.apply(this,[target,parentid]);
		},

		setRepeatIndex: function(target,index,repeatid,ref) {
			return setRepeatIndex.apply(this,[target,index,repeatid,ref]);
		},

		setValueByPath: function(path, value) {
			re = /^(.+)_(.+)f$/;
			var test = re.exec($('*[name="'+'_cf'+_id+path+'"]').attr('id'));
			if (test) this.setValue(test[1], value);
		},

		getValueByPath: function(path) {
			re = /^(.+)_(.+)f$/;
			var test = re.exec($('*[name="'+'_cf'+_id+path+'"]').attr('id'));
			return (test ? this.getValue( [test[1]], 0 ) : '');
		}

	});

}

cmsForm.getInstance = function(instance) {
	return window['cmsForm'+instance];
}



