function gps(){
	var ajax;
	var loaded = new Array();
	var changed = new Array();
	var requested = new Array();
	var beforeLoad = new Array();
	
	
	/**
	 * setting up onChange event
	 * the function will be called with this params:
	 * 
	 * @param srcElement the HTMLSelectElement which
	 * 			was changed
	 * 
	 * @param parameters given to setRequestEvent method
	 *			after fRef parameter
	 *	
	*/
	
	var pushChangeEventToAjaxList = function(srcElement){
		
		if(changed.length > 0){
			var eventFunc = changed[0];
			
			if(changed.length == 1){
				eventFunc(srcElement); // just for readability
			}
			else{
				var evalString = "eventFunc(srcElement";
				for(var j=1; j<changed.length; j++){
					evalString += ", changed[" + j + "]";
				}
				evalString += ")";
				eval(evalString);
			}
		}
	}
	
	/**
	 * setting up onRequest event
	 * the function will be called with this params:
	 * 
	 * @param selectElement the HTMLSelectElement in which
	 * 			must be loaded the content
	 * 
	 * @param tBody table's HTMLTBodyElement in which
	 * 			selectElement is
	 * 
	 * @param templateID empty HTMLTRElement, the template
	 * 			for creating duplicated rows in which are
	 * 			selectElements
	 * 
	 * @param parameters given to setRequestEvent method
	 * 			after fRef parameter
	 * 
	*/
	var pushRequestEventToAjaxList = function(selectElement, tBody, templateID){
		
		if(requested.length == 1){
			ajax.addFunction(requested[0], selectElement, tBody, templateID); // just for readability
		}
		else{
			var evalString = "ajax.addFunction(requested[0], selectElement, tBody, templateID";
			for(var j=1; j<changed.length; j++){
				evalString += ", requested[" + j + "]";
			}
			evalString += ")";
			eval(evalString);
		}
	}
	
	/**
	 * setting up onLoad event
	 * the function will be called with this params:
	 * 
	 * @param selectElement the HTMLSelectElement in which
	 * 			must be loaded the content
	 * 
	 * @param tBody table's HTMLTBodyElement in which
	 * 			selectElement is
	 * 
	 * @param templateID empty HTMLTRElement, the template
	 * 			for creating duplicated rows in which are
	 * 			selectElements
	 * 
	 * @param parameters given to setRequestEvent method
	 * 			after fRef parameter
	 * 
	*/
	var pushLoadEventToAjaxList = function(selectElement, tBody, templateID){
		if(requested.length == 1){
			ajax.addFunction(loaded[0], selectElement, tBody, templateID); // just for readability
		}
		else{
			var evalString = "ajax.addFunction(loaded[0], selectElement, tBody, templateID";
			for(var j=1; j<changed.length; j++){
				evalString += ", loaded[" + j + "]";
			}
			evalString += ")";
			eval(evalString);
		}
	}
	
	
	this.getChilds = function(selectElement, path, eventPath, postVars, tBody, templateID, fRef){
		if(selectElement.nodeType == 1){
			var selectedID = new Number(selectElement.id.substr(5));
		}
		else if(typeof(selectElement) == typeof(0)){
			var selectedID = 0;
		}
		
		if(!eventPath){
			eventPath = path;
		}
		
		var rows;
		var i;
		for(i=0;i<tBody.childNodes.length;i++){
			var elem = tBody.childNodes[i];
			if(elem.nodeName.toLowerCase() == "tr"){
				var fieldID = new Number(elem.id.substr(10));
				if(elem.id.substr(0,10) == "cont_type_" && selectedID-fieldID==0){
					break;
				}
			}
		}
		var elems = new Array();
		for(i=i+1;i<tBody.childNodes.length;i++){
			if(tBody.childNodes[i].nodeName.toLowerCase() == "tr"){
				elems[elems.length] = tBody.childNodes[i];
			}
		}
		for(i=0;i<elems.length;i++){
			tBody.removeChild(elems[i]);
		}
		
		if(typeof(selectElement) == typeof(0)){
			var id = selectElement;
		}
		else if(getSelectValue(selectElement)){
			var id = getSelectValue(selectElement);	
		}
		else{
			return false;
		}
		
		var query = "id="+id+"&";
		if(postVars){
			if(typeof(postVars) == typeof("")){
				query = postVars;
			}
			else{
				for(name in postVars){
					query += name + '=' + escape(postVars[name]) + '&';
				}
				query = query.substring(0, query.length-1);
			}
		}
		
		ajax = new xAjax(path);
		ajax.startCheck();
		
		pushRequestEventToAjaxList(selectElement, tBody, templateID);
		
		/* main query */
		ajax.addRequest(query, gpsChildsResponse, fRef, eventPath, postVars, tBody, templateID);
		
		pushLoadEventToAjaxList(selectElement, tBody, templateID);
		
		/* equivalent onLoad event */
		ajax.addFunction(this.onLoad, selectElement, tBody, templateID);
		
		/* turning off ajax check after onLoad event */
		ajax.addFunction(function(){ajax.stopCheck()});
	}
	
	this.getAll = function(userID, path, eventPath, postVars, tBody, templateID){
		ajax = new xAjax(path);
		ajax.startCheck();
		
		if(!eventPath){
			eventPath = path;
		}
		
		var query = "id="+userID+"&";
		if(postVars){
			if(typeof(postVars) == typeof("")){
				query = postVars;
			}
			else{
				for(name in postVars){
					query += name + '=' + escape(postVars[name]) + '&';
				}
				query = query.substring(0, query.length-1);
			}
		}
		
		pushRequestEventToAjaxList(userID, tBody, templateID);
		
		/* main query */
		ajax.addRequest(query, gpsResponse, this.getChilds, eventPath, postVars, tBody, templateID);
		
		pushLoadEventToAjaxList(userID, tBody, templateID);
		
		/* onLoad equivalent */
		ajax.addFunction(this.onLoad, userID, tBody, templateID);
		
		/* turning off ajax check after onLoad event */
		ajax.addFunction(function(){ajax.stopCheck()});
	}
	
	/**
	 * response function for getAll method
	 * 
	 * @param {Object} responseXML
	 * @param {Object} getChilds
	 * @param {Object} path
	 * @param {Object} postVars
	 * @param {Object} tBody
	 * @param {Object} templateID
	 */
	var gpsResponse = function(responseXML, getChilds, path, postVars, tBody, templateID){
		var childs = new Array();
		for(var i=0;i<tBody.childNodes.length;i++){
			if(tBody.childNodes[i].id != templateID){
				childs[childs.length] = tBody.childNodes[i];
			}
		}
		for(i=0;i<childs.length;i++){
			tBody.removeChild(childs[i]);
		}
		gpsChildsResponse(responseXML, getChilds, path, postVars, tBody, templateID);
	}
	
	/**
	 * response function for getChilds and the part of gpsResponse function
	 *  
	 * @param {Object} responseXML
	 * @param {Object} getChilds
	 * @param {Object} path
	 * @param {Object} postVars
	 * @param {Object} tBody
	 * @param {Object} templateID
	 */	
	var gpsChildsResponse = function(responseXML, getChilds, path, postVars, tBody, templateID){
		
		/**
		 * setting up onBeforeLoad event
		 * the function will be called with this params:
		 * 
		 * @param selectElement the HTMLSelectElement in which
		 * 			must be loaded the content
		 * 
		 * @param tBody table's HTMLTBodyElement in which
		 * 			selectElement is
		 * 
		 * @param templateID empty HTMLTRElement, the template
		 * 			for creating duplicated rows in which are
		 * 			selectElements
		 * 
		 * @param parameters given to setRequestEvent method
		 * 			after fRef parameter
		 * 
		*/
		if(requested.length == 1){
			beforeLoad[0](); // just for readability
		}
		else{
			var evalString = "beforeLoad[0](";
			for(var j=1; j<changed.length; j++){
				evalString += ", beforeLoad[" + j + "]";
			}
			evalString += ")";
			eval(evalString);
		}
		/* end of setting up onBeforeLoad event */
		
		for(var i=0;i<tBody.childNodes.length;i++){
			if(tBody.childNodes[i].id == templateID){
				var tmpl = tBody.childNodes[i];
				break;
			}
		}
		if(!tmpl){
			return false;
		}
		stripChilds(tmpl, ['td']);
		hideElement(tmpl);
		var xml = responseXML.documentElement.childNodes;
		for(var i=0;i<xml.length;i++){
			var row = tmpl.cloneNode(false);
			showElement(row);
			row.setAttribute("id", "cont_"+xml[i].attributes.getNamedItem("id").value);
			var leftTD = tmpl.firstChild.cloneNode(false);
			showElement(leftTD);
			insertNodeText(leftTD, xml[i].attributes.getNamedItem("name").value);
			row.appendChild(leftTD);
			var rightTD = tmpl.lastChild.cloneNode(false);		
			showElement(rightTD);
			
			if(!xml[i].hasChildNodes()){
				var field = $E('INPUT');
				field.setAttribute("id", xml[i].attributes.getNamedItem("id").value);
				field.setAttribute("name", xml[i].attributes.getNamedItem("id").value);
				field.setAttribute("type", "text");
				field.setAttribute("value", xml[i].attributes.getNamedItem("value").value);
				field.className = xml[i].attributes.getNamedItem("class").value;
			}
			else{
				var field = $E('SELECT');
				field.setAttribute("id", xml[i].attributes.getNamedItem("id").value);
				field.setAttribute("name", xml[i].attributes.getNamedItem("id").value);
				field.className = xml[i].attributes.getNamedItem("class").value;
				
				var attach = function(DOMEvent){
					if(is_ie){
						var srcElement = window.event.srcElement;
					}
					else{
						var srcElement = DOMEvent.target;
					}
					getChilds(srcElement, path, null, postVars, tBody, templateID, getChilds);
					
					pushChangeEventToAjaxList(srcElement);
				}
				if(field.attachEvent){
					field.attachEvent("onchange", attach);
				}
				else{
					field.onchange = attach;
				}
				var nodes = xml[i].childNodes;
				for(var j=0; j<nodes.length; j++){
					var optionElement = $E('OPTION');
					insertNodeText(optionElement, nodes[j].firstChild.data);
					optionElement.setAttribute("value", nodes[j].attributes.getNamedItem("value").value);
					if(nodes[j].attributes.getNamedItem("value").value == xml[i].attributes.getNamedItem("value").value){
						optionElement.setAttribute("selected", "selected");
					}
					field.appendChild(optionElement);
				}
			}
			
			rightTD.appendChild(field);
			row.appendChild(rightTD);
			tBody.appendChild(row);
		}
	}
	
	this.onLoad = function(){}
	this.onRequest = function(){}
	
	/**
	 * set up a load event
	 * 
	 * @param {Function} fRef function reference of onLoad event
	 * 
	 * @param {Object} other parameters for fRef
	 * 					fRef will be run this way
	 * 					fRef(selectElement, tBody, templateID, {fRefParam1}, {fRefParam2}, ...)
	 * 
	 */
	
	this.setLoadEvent = function(fRef){
		loaded = [fRef];
		if(this.setLoadEvent.arguments.length > 1){
			 for(var i=1; i<this.setLoadEvent.arguments.length; i++){
				 loaded[i] = this.setLoadEvent.arguments[i];
			 }
		}
	}
	
	/**
	 * set up a change event
	 * 
	 * @param {Function} fRef function reference of onLoad event
	 * 
	 * @param {Object} other parameters for fRef
	 * 					fRef will be run this way
	 * 					fRef(srcElement, {fRefParam1}, {fRefParam2}, ...)
	 * 
	 */
	
	this.setChangeEvent = function(fRef){
		changed = [fRef];		
		if(this.setChangeEvent.arguments.length > 1){
			 for(var i=1; i<this.setChangeEvent.arguments.length; i++){
				 changed[i] = this.setChangeEvent.arguments[i];
			 }
		}
	}
	
	/**
	 * set up a request event
	 * 
	 * @param {Function} fRef function reference of onLoad event
	 * 
	 * @param {Object} other parameters for fRef
	 * 					fRef will be run this way
	 * 					fRef(selectElement, tBody, templateID, {fRefParam1}, {fRefParam2}, ...)
	 * 
	 */
	
	this.setRequestEvent = function(fRef){
		requested = [fRef];
		if(this.setRequestEvent.arguments.length > 1){
			 for(var i=1; i<this.setRequestEvent.arguments.length; i++){
				 requested[i] = this.setRequestEvent.arguments[i];
			 }
		}
	}
	
	/**
	 * set up a beforeLoad event
	 * 
	 * @param {Function} fRef function reference of onLoad event
	 * 
	 * @param {Object} other parameters for fRef
	 * 					fRef will be run this way
	 * 					fRef(selectElement, tBody, templateID, {fRefParam1}, {fRefParam2}, ...)
	 * 
	 */
	
	this.setBeforeLoadEvent = function(fRef){
		beforeLoad = [fRef];
		if(this.setBeforeLoadEvent.arguments.length > 1){
			 for(var i=1; i<this.setBeforeLoadEvent.arguments.length; i++){
				 beforeLoad[i] = this.setBeforeLoadEvent.arguments[i];
			 }
		}
	}
}