/**
 *	@desc 		Collection of functions that support the form framework
 *	@author		Tom Hogewind & Michael Clerx
 *	@version	1.3.5
 * 	Changes from version 1.3.4: 	Explicit call to form check in hrefSubmit()
 *									Updated dynamic values order function
 *									The post() function can now be used to dynamically submit a form or a fieldset
 *									Follow-ups now correctly display and hide error-messages
 *									Error notices inside fieldset will now appear after the h3
 */
var info = {};
var formInfo = {};
var fieldsetInfo = {};
var lang = 'nl';

var error = false;
var checked = false;

/**
 * Removes all errors from a field
 * @param	String	The id of the field
 */
function removeErrors(id)
{
	var dd = getContainer(id);
    //$('img.form-error',dd).remove();
	
    dd.removeClass('form-error');
    if(dd.attr('nodeName') == 'DD')
    {
    	dd.prev().removeClass('form-error');
    }

    var fieldsetId = getFieldsetId(id);
    var errorUL = $('#' + fieldsetId + '-errors');
    if(errorUL.size() == 0)
        return;

    $('li',errorUL).each(function()
    {
        if($(this).attr('id').substr(0,id.length) == id)
            $(this).addClass('solved');
    });
    var allSolved = true;
    $('li',errorUL).each(function()
    {
        if(!$(this).hasClass('solved'))
            allSolved = false;
    });
    if(allSolved)
    {
        errorUL.removeClass('negative');
        errorUL.addClass('positive');
    }

}

/**
 * Adds an error to a field
 * @param	String	The id of the field
 * @param   String  The id of the error (simply the number of the check that is performed)
 * @param   String  The error message (optional)
 */
function addError(id, errorId, msg)
{
    if(!msg)
        msg = '';
    error = true;
    var dd = getContainer(id);
    dd.addClass('form-error');

    /*
    if($('img.form-error',dd).size() == 0 || msg.length > 0)
    {
        $('img.form-error',dd).remove();
        dd.append('<img src="' + SITE_ROOT + 'img/icons/error.png" title="' + msg + '" alt="" class="form-error" />');
    }
    */
    if(dd.attr('nodeName') == 'DD')
    {
    	dd.prev().addClass('form-error');
    }

    // Add a notice to the fieldset
    if(msg != '')
    {
        var fieldsetId = getFieldsetId(id);
        var errorUL = $('#' + fieldsetId + '-errors');
        if(errorUL.size() == 0)
        {
			var html = '<ul id="' + fieldsetId + '-errors" class="notice negative"></ul>';
			if($('#' + fieldsetId + ' h3:first').size() == 1)
				$('#' + fieldsetId + ' h3:first').after(html);
			else
				$('#' + fieldsetId).prepend(html);
            errorUL = $('#' + fieldsetId + '-errors');
        }
        if($('#' + id + '__error-' + errorId,errorUL).size() > 0)
        {
            $('#' + id + '__error-' + errorId,errorUL).removeClass('solved');
        } else
        {
            // Check if there is an error with the same message
            var found = false;
            $('li',errorUL).each(function()
            {
                if($(this).attr('id').substr(0,id.length) == id && !found)
                {
                    if($(this).html() == msg)
                    {
                        $(this).removeClass('solved');
                        found = true;
                    }
                }
            });
            if(!found)
                errorUL.append('<li id="' + id + '__error-' + errorId +'" class="error">' + msg + '</li>');
        }
        //$('#' + id + '__error-' + errorId,errorUL).remove(); // Just to be sure that no duplicate errors appear

        errorUL.removeClass('positive');
        errorUL.addClass('negative');
    }


}

/**
 * Gets the id of the fieldset which contains the field with the given id
 * @param   String  The id of the field
 * @param   String  The id of the fieldset
 */
function getFieldsetId(fieldId)
{
    result = false;
    $.each(formInfo, function(index, value)
    {
        var sets = value.children;
        for(var x = 0; x < sets.length; x++)
        {
            var fields = fieldsetInfo[sets[x]].children;
            for(var y = 0; y < fields.length; y++)
            {
                //alert(fields[y] + '==' + fieldId + '=>' + sets[x]);
                if(fields[y] == fieldId)
                {
                    result = sets[x];
                    return;
                }
            }
        }
    });
    return result;
}

/**
 * Shows a field
 * @param	String	The id of the field
 */
function show(id)
{
    var dd = $('#' + id);
    while(dd.attr('nodeName') != 'DD' && dd.length != 0)
        dd = dd.parent();
    var dt = dd.prev();

    //dd.slideDown(300);
    //dt.slideDown(300);
    if (!dt.hasClass('form-emptylabel'))
    {
        dt.removeClass('hide');
        dt.show();
    }
    dd.removeClass('hide');
    dd.show();

    var i = info[id];
    i.active = true;

    // TODO: update for other fields as well
    $('#' + id + ' input[type=radio]:checked, #' + id + ' select').trigger('click');
    $('#' + id + ' input[type=text], #' + id + ' textarea').trigger('keyup');
}

/**
 * Hides a field
 * @param	String	The id of the field
 */
function hide(id)
{
    var dd = $('#' + id);
    while(dd.attr('nodeName') != 'DD' && dd.length != 0)
        dd = dd.parent();
    var dt = dd.prev();

    //dt.slideUp(300);
    //dd.slideUp(300);
    dt.hide();
    dd.hide();

    var i = info[id];
    i.active = false;
    for(var x = 0; x < i.children.length; x++)
    {
        hide(i.children[x].key);
    }
}

/**
 * Tests if an array contains a given object
 * @param	array	The array
 * @param	object	The object that will be tested
 * @returns	boolean
 */
function contains(a, obj)
{
    var i = a.length;
    while (i--) if (a[i] === obj) return true;
    return false;
}

// Takes an array a of HtmlInputElements and checks if there value
//  equals obj
function containsWithValue(a, obj)
{
    var i = a.length;
    while (i--) if (a[i].value === obj) return true;
    return false;
}

/**
 * Very simple email check, coded to be permissive
 * @param	String	The string that will be checked
 * @returns	boolean
 */
function isEmail(str)
{
    str = jQuery.trim(str);
    parts = str.split('@');
    if (parts.length != 2) return false;
    if (parts[0].length < 1) return false;
    parts = parts[1].split('.');
    i = parts.length;
    if (i < 2) return false;
    while(i--) if (parts[i].length < 1) return false;
    return true;
}

// Takes an array of checkboxes and returns the name of each value
//  that's been checked. Id must include hash mark.
function checkToString(id)
{
    boxes = $(id+' input:checked');
    values = new Array();
    boxes.each(function(i) { values.push(this.value); });
    return values.join(", ");
}

/**
 * Toggles a field or fieldset
 * @param	String	The id of the field or fieldset
 */
function toggle(id)
{
    var e = $('#' +id);
    if(e.attr('nodeName') == 'FORM')
    {
    	var children = formInfo[id].children;
    	for(var i = 0; i < children.length; i++)
    	{
    		toggle(children[i]);
    	}
    	$('.edit-button', e).toggleClass('hide');
    	$('.submit-button', e).toggleClass('hide');
    } else if(e.attr('nodeName') == 'FIELDSET')
    {
    	$('dd',e).each(function()
    	{
    		$('.current-value',$(this)).toggleClass('hide');
    		$('.edit-value',$(this)).toggleClass('hide');
    	});
    } else
    {
    /*
    	var dd = e;
        while(dd.attr('nodeName') != 'DD' && dd.length != 0)
            dd = dd.parent(); */
        var dd = getContainer(id);
        $('.current-value',dd).toggleClass('hide');
        $('.edit-value',dd).toggleClass('hide');
    }
}

/**
 * Posts the value of a field to the server with an ajax-request
 * @param	String		The id of the field
 * @param	String		The name of the module that will process the request
 * @param	String		The function that will process the request
 * @param	Object		Object with additional vars
 */
function post(id, module, func, vars)
{
    if(!module && typeof(CURRENT_MODULE) != "undefined")
        module = CURRENT_MODULE;
    if(!module && typeof(AJAX_PATH) != "undefined")
    	module = AJAX_PATH;

    if(!func && typeof(CURRENT_FUNCTION) != "undefined")
        func = CURRENT_FUNCTION;
    if(!vars)
    	var vars = new Object();
    vars.__dynamic = 'true';
    var e = $('#' +id);
    var children, fields, i;

    if(formInfo[id])
	{
		if(check(id))
		{
			var sets = formInfo[id].children;
			for(var x = 0; x < sets.length; x++)
			{
				var fields = fieldsetInfo[sets[x]].children;
				for(var y = 0; y < fields.length; y++)
				{
					var i = info[fields[y]];
    				var keys = i.keys;
    				var values = i.values;
    				for(var x = 0; x < keys.length; x++)
    				{
    					eval('vars[\'' + keys[x] + '\'] = ' + values[x]);
    				}
				}
			}
		} else
			return false;
	} else if(fieldsetInfo[id])
	{
		var fields = fieldsetInfo[sets[x]].children;
		for(var y = 0; y < fields.length; y++)
		{
			var i = info[fields[y]];
    		var keys = i.keys;
    		var values = i.values;
    		for(var x = 0; x < keys.length; x++)
    		{
    			eval('vars[\'' + keys[x] + '\'] = ' + values[x]);
    		}
		}
	} else
    {
    	var i = info[id];
    	var keys = i.keys;
    	var values = i.values;
    	for(var x = 0; x < keys.length; x++)
    	{
    		eval('vars[\'' + keys[x] + '\'] = ' + values[x]);
    	}
    }
    
    if (typeof(ajaxModule) == "function")
    	ajaxModule(module,func,vars);
    else
   		ajax(module,vars);
}

/**
 * Checks a field, fieldset or form for input errors
 * @param	String		The id of the field, fieldset or form
 * @returns	boolean
 */
function check(id)
{
    var result = true;

    if(formInfo[id])
    {
    	var children = formInfo[id].children;
    	for(var i = 0; i < children.length; i++)
    	{
    		if(!check(children[i]))
    			result = false;
    	}
    } else if($('#' + id).attr('nodeName') == 'FIELDSET')
    {
    	var children = fieldsetInfo[id].children;
    	for(var i = 0; i < children.length; i++)
    	{
    		if(!check(children[i]))
    			result = false;
    	}
    } else
    {
    	removeErrors(id);
		var i = info[id];
		if(i.optional)
			return true;
		if(!i.checked)
		    bindErrorListeners(id);
		if(!i.active)
			return true;
		var checks = i.checks;
		var errors = i.errors;

		var result = true;
		for(var x = 0; x < checks.length; x++)
		{
			try
			{
				if(i.type == 'dynamicValues')
				{
					eval('if(' + checks[x] + '){result = false;}');
				} else
				{
					eval('if(' + checks[x] + '){addError(\'' + id + '\',' + x + ',"' + errors[x] + '");result = false;}');
				}

			} catch(e)
			{}
		}
        return result;
    }
    //alert(id + ' ' +result);
    return result;
}

/**
 * Binds listeners to fields that will check for input errors on the fly
 * @param	String		The id of the field
 */
function bindErrorListeners(id)
{
    if(formInfo[id])
    {
        var sets = formInfo[id].children;
        for(var x = 0; x < sets.length; x++)
        {
            var fields = fieldsetInfo[sets[x]].children;
            for(var y = 0; y < fields.length; y++)
            {
                bindErrorListeners(fields[y]);
            }
        }
        return;
    }
	var i = info[id];
	var selectors = i.updateSelectors;
	var events = i.updateEvents;

	for(var x = 0; x < selectors.length; x++)
	{
		$(selectors[x]).bind(events[x]  + '.error', function(){check(id)});
	}
	i.checked = true;
}

/**
 * Unbinds error-listeners
 * @param	String		The id of the field
 */
function unbindErrorListeners(id)
{
    if(formInfo[id])
    {
        var sets = formInfo[id].children;
        for(var x = 0; x < sets.length; x++)
        {
            var fields = fieldsetInfo[sets[x]].children;
            for(var y = 0; y < fields.length; y++)
            {
                unbindErrorListeners(fields[y]);
            }
        }
        return;
    }
	var i = info[id];
	var selectors = i.updateSelectors;
	var events = i.updateEvents;

	for(var x = 0; x < selectors.length; x++)
	{
		$(selectors[x]).unbind(events[x]  + '.error');
	}
	i.checked = false;
}

/**
 * Bind listeners to fields that have follow-up fields
 * @param	String		The id of the field or form
 */
function bindFollowUpListeners(id)
{
	// If the given id belongs to a form -> iterate through the fieldsets and fields
	if(formInfo[id])
	{
		var sets = formInfo[id].children;
		for(var x = 0; x < sets.length; x++)
		{
			var fields = fieldsetInfo[sets[x]].children;
			for(var y = 0; y < fields.length; y++)
			{
				bindFollowUpListeners(fields[y]);
			}
		}
		return;
	}

	var i = info[id];
	var children = i.children;
	var selectors = i.updateSelectors;
	var events = i.updateEvents;
	var child;

	// For each selector... (some fields have more than one input field)
	for(var y = 0; y < selectors.length; y++)
	{
		// For each event... (some fields have multiple events such as onchange and onclick)
		$(selectors[y]).bind(events[y], function()
		{
			
			// For each child...
			for(var x = 0; x < children.length; x++)
			{
				// Show if the conditions are met
				child = children[x];
				if((child.v && check(id)) || contains(child.values, getValue(id)))
				{
						show(child.key);
						if(info[child.key].checked)
							check(child.key);
				}
				else
				{
						hide(child.key);
						if(info[child.key].checked)
							check(child.key);
				}
			}

		});
	}

}

/**
 * Returns the value of a field
 * @param	String		The id of the field
 * @returns	String		The value of the field
 */
function getValue(id)
{
	if(formInfo[id])
	{
		var value = {};
		var fieldsets = formInfo[id].children;
		for(var x in fieldsets)
		{
			var fields = fieldsetInfo[fieldsets[x]].children;
			for(var y in fields)
			{
				value[fields[y]] = getValue(fields[y]);
			}
		}
		return value;
	}
	var i = info[id];
	var type = i.type;
	switch(type)
	{
		case "textarea":
		case "text":
		case "password":
			return $('#' + id).val();
		case "radio":
			return  $('#' + id +' input:checked').val();
		case "select":
			return $('#' + id +' option:selected').val();
		case "check":
			return $('#' + id + ':checked').size() == 1? 'on':'off';
        
        case "datetime":
            var parent = $('#' + id).parent();
            var year = $('select.form-date-year',parent).val();
            var date = new Date($('select.form-date-year',parent).val(), $('select.form-date-month',parent).val() - 1, $('select.form-date-day',parent).val(), $('select.form-date-hour',parent).val(), $('select.form-date-minute',parent).val(), 0,0);
            return Math.round(date.getTime() / 1000);
        case "date":
        	var parent = $('#' + id).parent();
            var year = $('select.form-date-year',parent).val();
            var month = $('select.form-date-month', parent).val();
            var day = $('select.form-date-day',parent).val();
            if(year == "__null" || month == "__null" || day == "__null")
            {
            	return "null";
			}
            var date = new Date(year, month - 1, day, 0, 0, 0, 0);
            return Math.round(date.getTime() / 1000);
        default:
    		alert('todo: implement!');
	}

}

/**
 * Resets a dynamicField (hides the input fields and resets their value)
 * @param	String 		The id of the field
 */

function resetDynamicField(id)
{
	if($('#' + id).attr('tagName') == 'FORM')
	{
		var children = formInfo[id].children;
    	for(var i = 0; i < children.length; i++)
    	{
    		resetDynamicField(children[i]);
    	}
    	return;
	}
	if($('#' + id).attr('tagName') == 'FIELDSET')
	{
		var children = fieldsetInfo[id].children;
		for(var i = 0; i < children.length; i++)
		{
			resetDynamicField(children[i]);
		}
		return;
	}
    var i = info[id];
    if(!i.dynamic)
    	return;
    var type = i.type;
    switch(type)
    {
    	case "textarea":
    	case "text":
    		$('#' + id).val(i.currentValue);
    	break;
    	case "radio":
	  		$('#' + id +' input:checked').removeAttr('checked');
	  		$('#' + id +' input[value=' + i.currentValue +']').attr('checked','checked');

    	break;
    	case "select":
    		$('#' + id +' option:selected').removeAttr('selected');
	  		$('#' + id +' option[value=' + i.currentValue +']').attr('selected','selected');
	  		$('#' + id).trigger('change');
    	break;
        case "tinymce":
            tinyMCE.execInstanceCommand(id,'mceSetContent',false,i.currentValue);
        break;
        case "datetime":
        case "date":
        	var container = getContainer(id);
        	var value = i.currentValue;
        	$('select',container).removeAttr('selected');
        	$('.form-date-day option[value=' + date('j',i.currentValue) + ']', container).attr('selected','selected');
        	$('.form-date-month option[value=' + date('n',i.currentValue) + ']', container).attr('selected','selected');
        	$('.form-date-year option[value=' + date('Y',i.currentValue) + ']', container).attr('selected','selected');
        	$('.form-date-hour option[value=' + date('H',i.currentValue) + ']', container).attr('selected','selected');
        	$('.form-date-minute option[value=' + date('i',i.currentValue) + ']', container).attr('selected','selected');
        break;
        case "dynamicValues":
        	for(var x = 0; x < i.additional.constructorKeys.length; x++)
        	{
        		resetDynamicField(i.additional.constructorKeys[x]);
        	}
        break;
    }

}

/**
 * Updates a dynamic field (set the current-value)
 * @param	String		The id of the field
 */
function updateDynamicField(id)
{
    var i = info[id];
    var dd = getContainer(id);
    switch(i.type)
    {
    	case "textarea":
    	case "text":
    		var value = $('#' + id).val();
    		i.currentValue = value;
    		$('.current-value',dd).html(htmlEntities(value));
    	break;
    	case "radio":
    		i.currentValue = $('#' + id +' input:checked').val();
    		$('.current-value',dd).html($('#' + id +' input:checked').next().html());
    	break;
    	case "select":
    		i.currentValue = $('#' + id + ' option:selected').val();
    		$('.current-value',dd).html($('#' + id + ' option:selected').html());
    	break;
        case "tinymce":
            i.currentValue = $("#" + id + "_parent iframe").contents().find("#tinymce").html();
            $('.current-value',dd).html(i.currentValue);
        break;
        case "datetime":
        	i.currentValue = getValue(id);
            $('.current-value',dd).html(date(i.additional.format, i.currentValue));
        break;
        case "check":
        	alert('todo: implement');
        break;
    }
}

/**
 * Replaces all special characters in the given string to html-entities and returns it
 * @param	String		The initial text
 * @returns	String
 */
function htmlEntities(text)
{
    var c;
    var r = '';


    for(var i=0; i < text.length; i++)
    {
        c = text.charCodeAt(i);
        if((c >= 48 && c <= 57) || (c >= 65 && c <= 90) || (c >= 97 && c <= 121))
        {
            r += text[i];
        }else
        {
            r += "&#" + c + ";";
        }
    }
    return r;
}

/**
 * Returns the container element that contains the field with the given id. This is usually a dd element
 * @param	String		The id of the field
 * @returns	JQueryObject
 */
function getContainer(id)
{
	var c = $('#' + id);
	while(c.attr('nodeName') != 'DD' && !c.hasClass('field-container') && c.length != 0)
		c = c.parent();

	if(c.length == false)
		return false;
	return c;
}
/**
 * A multilangue javascript equivalent of the php date function
 * @param	String	The format of the date (see www.php.net/date)
 * @param	int		Timestamp
 * @returns String	The formatted string
 */
function date(format, timestamp)
{
	var daysShort = {'nl':['Zo','Ma','Di','Wo','Do','Vr','Za'], 'en':['Sun','Mon','Tue','Wed','Thu','Fri','Sat']};
	var daysLong = {'nl':['Zondag','Maandag','Dinsdag','Woensdag','Donderdag','Vrijdag','Zaterdag'], 'en':['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday']};
	var monthsShort = {'nl':['Jan','Feb','Mrt','Apr','Mei','Jun','Jul','Aug','Sep','Okt','Nov','Dec'], 'en':['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']};
	var monthsLong = {'nl':['Januari','Februari','Maart','April','Mei','Juni','Juli','Augustus','September','Oktober','November','December'], 'en':['January','Febuary','March','April','May','June','July','August','Sep','October','November','December']};

	if(!lang)
		var lang = 'en';

	for(var i = format.length; i > 0; i--)
	{
		format = format.substr(0,i - 1) + '_' + format.substr(i - 1);
	}

	var d;
	if(timestamp)
    {
        timezone = 1; // one extra hour (Amsterdam)
        d = new Date((timestamp + (timezone * 3600)) * 1000);
    }

	else
		d = new Date();
	var output = format;

	output = output.replace('_d',d.getUTCDate() < 10? '0'+d.getUTCDate():d.getUTCDate());
	output = output.replace('_D',daysShort[lang][d.getUTCDay()]);
	output = output.replace('_j',d.getUTCDate());
	output = output.replace('_l',daysLong[lang][d.getUTCDay()]);
	output = output.replace('_N',d.getUTCDay() == 0? 7:d.getUTCDay());
	output = output.replace('_w',d.getUTCDay());

	output = output.replace('_F', monthsLong[lang][d.getUTCMonth()]);
	output = output.replace('_m',d.getUTCMonth() < 9? '0'+(d.getUTCMonth()+1):d.getUTCMonth()+1);
	output = output.replace('_M', monthsShort[lang][d.getUTCMonth()]);
	output = output.replace('_n', d.getUTCMonth()+1);

	output = output.replace('_Y', d.getUTCFullYear());
	output = output.replace('_y', d.getUTCFullYear().toString().substr(2));

	output = output.replace('_a', d.getUTCHours() < 12? 'am':'pm');
	output = output.replace('_A', d.getUTCHours() < 12? 'AM':'PM');
	output = output.replace('_g', d.getUTCHours()%12 == 0? 12:d.getUTCHours()%12);
	output = output.replace('_G', d.getUTCHours());
	output = output.replace('_h', d.getUTCHours()%12 == 0? 12:(d.getUTCHours()%12 < 10? '0'+d.getUTCHours()%12:d.getUTCHours()%12));
	output = output.replace('_H', d.getUTCHours() < 10? '0'+d.getUTCHours():d.getUTCHours());
	output = output.replace('_i', d.getUTCMinutes() < 10? '0' + d.getUTCMinutes():d.getUTCMinutes());
	output = output.replace('_s', d.getUTCSeconds() < 10? '0' + d.getUTCSeconds():d.getUTCSeconds());
	output = output.replace('_u', d.getTime());

	return output.split('_').join('');


}

/**
 * Used to submit a form from a href
 */
function hrefSubmit(id)
{
    $('#'+id).before('<input type="hidden" class="hide" name="'+id+'" />');
    var form = $('#'+id).parents('form');
    if (check(form.attr('id'))) form.submit();
}

///////////////////////////////
/// DynamicValues functions ///
///////////////////////////////

/**
 * Orders the fields and their action buttons
 * @param	String		The id of the DynamicValues field
 */
function dynamicValues_order(id)
{
	var size = info[id].additional.valueKeys.length;
	var fieldset = $('#' + getFieldsetId(id));

	var sorted = false;

	var progress = 0;
	
	if(info[id].additional.sortable)
	{
		while(!sorted && progress <= size)
		{
			progress++;
			sorted = true;
			var values = $('dd.__' + id + '.value',fieldset);

			for(var x = 0; x < size; x++)
			{
				var key = info[id].additional.valueKeys[x];

				if(!values.eq(x).hasClass('__' + key))
				{
					var dd = getContainer(key);
					var dt = dd.prev();

					values.eq(x).prev().before(dd);
					dd.before(dt);
					sorted = false;
					break;
				}
			}
		}
	}

	// Place the label
	var labels = $('dt.value.__' + id + ' label');
	labels.addClass('hide');
	labels.eq(0).removeClass('hide');

	if(size == 0)
	{
		$('dt.empty.__' + id +',dd.empty.__' + id).removeClass('hide');
	} else
	{
		$('dt.empty.__' + id +',dd.empty.__' + id).addClass('hide');
	}

	for(var x = 0; x < size; x++)
	{
		var key = info[id].additional.valueKeys[x];
		var c = getContainer(key);

		if(x + 1 == size)
			$('.field-actions a.move-down',c).addClass('hide');
		else
			$('.field-actions a.move-down',c).removeClass('hide');

		if(x == 0)
			$('.field-actions a.move-up',c).addClass('hide');
		else
			$('.field-actions a.move-up',c).removeClass('hide');
	}
}

/**
 * Removes a field from the form
 * @param	String		The id of the field
 */
function dynamicValues_removeField(id)
{
	var c = getContainer(id);
	c.prev().remove();
	c.remove();
}
