function setFilterGrid(id)
/*====================================================
	- Sets filters grid bar
	- Calls TF Constructor and generates grid bar
	- Params:
			- id: table id (string)
			- refRow (optional): row index (number)
			- config (optional): configuration 
			object (literal object)
	- Returns TF object
=====================================================*/
{
	if(arguments.length==0) return;
	eval('tf_'+id+' = new TF(arguments[0],arguments[1],arguments[2]);' +
		 'tf_'+id+'.AddGrid();');
	return window['tf_'+id];
}

/*===BEGIN removable section===========================
	- Unobtrusive grid bar generation using 
	'filterable' class
	- If you don't use it you can remove safely this 
	section
/*=====================================================*/
window['tf_isNotIE'] = !(/msie|MSIE/.test(navigator.userAgent));
tf_AddEvent(window, (tf_isNotIE ? 'DOMContentLoaded' : 'load'), initFilterGrid);

function initFilterGrid()
{
	if(!document.getElementsByTagName) return;
	var tbls = tf_Tag(document,'table'), config;
	for (var i=0; i<tbls.length; i++)
	{
		var cTbl = tbls[i], cTblId = cTbl.getAttribute('id');
		if(tf_HasClass(cTbl,'filterable') && cTblId)
		{
			if(tf_IsObj(cTblId+'_config'))
				config = window[cTblId+'_config'];
			else
				config = undefined;
			window[cTblId+'_isUnob'] = true;
			setFilterGrid(cTblId,config);
		}
	}// for i
}
/*===END removable section===========================*/

var TF = function(id)
/*====================================================
	- TF object constructor
	- Params:
			- id: table id (string)
			- refRow (optional): row index (number)
			- config (optional): configuration 
			object (literal object)
=====================================================*/
{
	if(arguments.length==0) return;
	this.id = id;
	this.version = '1.9.9';
	this.tbl = tf_Id(id);
	this.startRow = undefined;
	this.refRow = null;
	this.headersRow = null;
	this.fObj = null;
	this.nbFilterableRows = null;
	this.nbRows = null;
	this.nbCells = null;
	this.hasGrid = false;
	this.enableModules = true;

	if(this.tbl != null && this.tbl.nodeName.tf_LCase() == 'table' && this.GetRowsNb())
    {
		if(arguments.length>1)
        {
            for(var i=0; i<arguments.length; i++)
            {
                var argtype = typeof arguments[i];
               
                switch(argtype.tf_LCase())
                {
                    case 'number':
                        this.startRow = arguments[i];
                    break;
                    case 'object':
                        this.fObj = arguments[i];
                    break;
                }//switch                           
            }//for
        }//if
		
		var f = !this.fObj ? {} : this.fObj;
		
		//Start row et cols nb
		this.refRow = this.startRow==undefined ? 2 : (this.startRow+1);
		try{ this.nbCells = this.GetCellsNb(this.refRow) }
		catch(e){ this.nbCells = this.GetCellsNb(0) }
		
		if(this.enableModules){
			/*** Modules: features of the script ***/
			this.registeredModules = []; //modules to be loaded
			this.alreadyImportedModules = []; //modules already imported in the page
			this.importedModules = []; //modules imported by the TF script
			this.modulesPath = f!=undefined && f.modules_path!=undefined ? f.modules_path : 'TF_Modules/'; //js modules files path
			this.module = {
				populateSelect:{ name:'populateSelect', desc:'Builds select type filters', 
					path: this.modulesPath + 'tf_populateSelect.js', loaded:0,
					init: function(o) { o.module.populateSelect.loaded = 1; }			
				},
				populateCheckList:{ name:'populateCheckList', desc:'Builds checklist type filters', 
					path: this.modulesPath + 'tf_populateCheckList.js', loaded:0,
					init: function(o) { o.module.populateCheckList.loaded = 1; }
				},
				gridLayout: { name:'gridLayout', desc:'Grid layout feature', 
					path: this.modulesPath + 'tf_gridLayout.js', loaded:0,
					init: function(o) { o.module.gridLayout.loaded = 1; }
				},
				paging: { name:'paging', desc:'Paging feature', 
					path: this.modulesPath + 'tf_paging.js', loaded:0, 
					init: function(o) { o.module.paging.loaded = 1; }
				},
				sort: { name:'sort', desc:'Sort feature', 
					path: this.modulesPath + 'tf_sort.js', loaded:0, 
					init: function(o) { o.module.sort.loaded = 1; }
				},
				popUpFilters: { name:'popUpFilters', desc:'Filters in pop-up container feature', 
					path: this.modulesPath + 'tf_popupFilters.js', loaded:0,
					init: function(o) { o.module.popUpFilters.loaded = 1; }
				},
				themes: { name:'themes', desc:'Themes loading feature', 
					path: this.modulesPath + 'tf_themes.js', loaded:0, 
					init: function(o) { o.module.themes.loaded = 1; }
				},
				colOps: { name:'colOps', desc:'Columns operations feature', 
					path:this.modulesPath + 'tf_colOps.js', loaded:0, 
					init: function(o){ o.module.colOps.loaded = 1; }
				},
				fixedHeaders: {	name:'fixedHeaders', desc:'Fixed headers feature - Deprecated', 
					path:this.modulesPath + 'tf_fixedHeaders.js', loaded:0, 
					init: function(o){ o.module.fixedHeaders.loaded = 1; }
				},
				rowsCounter: { name:'rowsCounter', desc:'Rows counter feature', 
					path:this.modulesPath + 'tf_rowsCounter.js', loaded:0, 
					init: function(o){ o.module.rowsCounter.loaded = 1; }
				},			
				loader: { name:'loader', desc:'Loader feature', 
					path:this.modulesPath + 'tf_loader.js', loaded:0,
					init: function(o){ o.module.loader.loaded = 1; }
				},
				statusBar: { name:'statusBar', desc:'Status bar feature', 
					path:this.modulesPath + 'tf_statusBar.js', loaded:0, 
					init: function(o){ o.module.statusBar.loaded = 1; }
				},
				resetBtn:{ name:'resetBtn', desc:'Reset button feature', 
					path:this.modulesPath + 'tf_resetBtn.js', loaded:0, 
					init: function(o){ o.module.resetBtn.loaded = 1; }
				},
				helpInstructions:{ name:'helpInstructions', desc:'Help, About', 
					path:this.modulesPath + 'tf_resetBtn.js', loaded:0, 
					init: function(o){ o.module.helpInstructions.loaded = 1; }
				},
				alternateRows:{ name:'alternateRows', desc:'Alternating rows color feature', 
					path:this.modulesPath + 'tf_alternateRows.js', loaded:0,
					init: function(o){ o.module.alternateRows.loaded = 1; }
				},
				cookies:{ name:'cookies', desc:'Remember values feature (cookies)', 
					path:this.modulesPath + 'tf_cookies.js', loaded:0,
					init: function(o){ o.module.cookies.loaded = 1; }
				},
				highlightKeywords:{	name:'highlightKeywords', desc:'Remember values feature (cookies)', 
					path:this.modulesPath + 'tf_highlightKeywords.js', loaded:0,
					init: function(o){ o.module.highlightKeywords.loaded = 1; }
				},
				refreshFilters:{ name:'refreshFilters', desc:'Refresh filters feature', 
					path:this.modulesPath + 'tf_refreshFilters.js', loaded:0, 
					init: function(o){ o.module.refreshFilters.loaded = 1; }
				},
				extensions:{ name:'extensions', desc:'Extensions loading feature', 
					path:this.modulesPath + 'tf_extensions.js', loaded:0,
					init: function(o){ o.module.extensions.loaded = 1; }
				},
				watermark:{ name:'watermark', desc:'Watermark feature', 
					path:this.modulesPath + 'tf_watermark.js', loaded:0,
					init: function(o){ o.module.watermark.loaded = 1; }
				},
				publicMethods:{ name:'publicMethods', desc:'Additional public methods for developers', 
					path:this.modulesPath + 'tf_publicMethods.js', loaded:0,
					init: function(o){ o.module.publicMethods.loaded = 1; }
				}
			};
		}
		/*** filter types ***/
		this.fltTypeInp =			'input';
		this.fltTypeSlc =			'select';
		this.fltTypeMulti =			'multiple';
		this.fltTypeCheckList =		'checklist';
		this.fltTypeNone =			'none';
		this.fltCol = 				[]; //filter type of each column
		
		for(var i=0; i<this.nbCells; i++){
			if(this['col'+i]==undefined)
				this['col'+i] = (f['col_'+i]==undefined) 
					? this.fltTypeInp : f['col_'+i].tf_LCase();
			this.fltCol.push(this['col'+i]);
		}
		
		if(this.enableModules){
			//Registers select and checklist scripts if needed
			if(this.fltCol.tf_Has(this.fltTypeSlc) || 
				this.fltCol.tf_Has(this.fltTypeMulti)) 
				this.registeredModules.push(this.module.populateSelect.name);
			if(this.fltCol.tf_Has(this.fltTypeCheckList)) this.registeredModules.push(this.module.populateCheckList.name);
		}
		
		/*** Developer additional methods ***/
		this.publicMethods = f!=undefined && f.public_methods!=undefined ? f.public_methods : false;
		
		/*** filters' grid properties ***/
		this.fltGrid = 				f!=undefined && f.grid==false ? false : true; //enables/disables filter grid
		
		/*** Grid layout ***/
		this.gridLayout = 			f!=undefined && f.grid_layout ? true : false; //enables/disables grid layout (fixed headers)		
		this.hasGridWidthsRow =		false; //flag indicating if the grid has an additional row for column widths (IE<=7)
		this.gridColElms =			[];
		this.sourceTblHtml =		null;
		if(this.gridLayout){
			if(this.tbl.outerHTML==undefined) tf_SetOuterHtml();  //Firefox does not support outerHTML property...
			this.sourceTblHtml = 		this.tbl.outerHTML; //original table html
		}												
		/*** ***/
								
		this.filtersRowIndex =		f!=undefined && f.filters_row_index!=undefined //defines in which row filters grid bar is generated
										? f.filters_row_index>1 ? 1 : f.filters_row_index : 0;
		this.fltCellTag =			f!=undefined && f.filters_cell_tag!=undefined //defines tag of the cells containing filters (td/th)
										? (f.filters_cell_tag!='th' ? 'td' : 'th') : 'td';		
		this.fltIds = 				[]; //stores filters ids
		this.fltElms =				[]; //stores filters DOM elements
		this.searchArgs =			null; //stores filters values
		this.tblData =				[]; //stores table data
		this.validRowsIndex =		null; //stores valid rows indexes (rows visible upon filtering)
		this.fltGridEl =			null; //stores filters row element
		this.isFirstLoad =			true; //is first load boolean 
		this.infDiv =				null; //container div for paging elements, reset btn etc.
		this.lDiv =					null; //div for rows counter
		this.rDiv =					null; //div for reset button and results per page select
		this.mDiv =					null; //div for paging elements
		this.contDiv =				null; //table container div for fixed headers (IE only)
		this.infDivCssClass =		f!=undefined && f.inf_div_css_class!=undefined	//defines css class for div containing
										? f.inf_div_css_class : 'inf';				//paging elements, rows counter etc.
		this.lDivCssClass =			f!=undefined && f.left_div_css_class!=undefined	//defines css class for left div 
										? f.left_div_css_class : 'ldiv';
		this.rDivCssClass =			f!=undefined && f.right_div_css_class!=undefined //defines css class for right div 
										? f.right_div_css_class : 'rdiv';
		this.mDivCssClass =			f!=undefined && f.middle_div_css_class!=undefined //defines css class for mid div 
										? f.middle_div_css_class : 'mdiv';
		this.contDivCssClass =		f!=undefined && f.content_div_css_class!=undefined 
										? f.content_div_css_class : 'cont';	//table container div css class
		
		/*** filters' grid appearance ***/
		this.stylesheet =   		f!=undefined && f.stylesheet!=undefined ? f.stylesheet : 'filtergrid.css'; //stylesheet file
		this.stylesheetId =			this.id + '_style';
		this.fltsRowCssClass =		f!=undefined && f.flts_row_css_class!=undefined //defines css class for filters row
										? f.flts_row_css_class : 'fltrow';		
		this.alternateBgs =			f!=undefined && f.alternate_rows ? true : false; //enables/disbles rows alternating bg colors
		this.hasColWidth =			f!=undefined && f.col_width ? true : false; //defines widths of columns
		this.colWidth =				f!=undefined && this.hasColWidth ? f.col_width : null;
		this.fixedHeaders =			f!=undefined && f.fixed_headers ? true : false; //enables/disables fixed headers
		this.tBodyH = 				f!=undefined && f.tbody_height ? f.tbody_height : 200; //tbody height if fixed headers enabled
		this.fltCssClass =			f!=undefined && f.flt_css_class!=undefined //defines css class for filters
										? f.flt_css_class : 'flt';
		this.fltMultiCssClass =		f!=undefined && f.flt_multi_css_class!=undefined //defines css class for multiple selects filters
										? f.flt_multi_css_class : 'flt_multi';
		this.fltSmallCssClass =		f!=undefined && f.flt_small_css_class!=undefined //defines css class for filters
										? f.flt_small_css_class : 'flt_s';
		this.singleFltCssClass =	f!=undefined && f.single_flt_css_class!=undefined //defines css class for single-filter
										? f.single_flt_css_class : 'single_flt';	
		this.isStartBgAlternate =	true;
		this.rowBgEvenCssClass =	f!=undefined && f.even_row_css_class!=undefined //defines css class for even rows
										? f.even_row_css_class :'even';
		this.rowBgOddCssClass =		f!=undefined && f.odd_row_css_class!=undefined //defines css class for odd rows
										? f.odd_row_css_class :'odd';
		
		/*** filters' grid behaviours ***/
		this.enterKey =				f!=undefined && f.enter_key==false ? false : true; //enables/disables enter key
		this.isModFilterFn = 		f!=undefined && f.mod_filter_fn ? true : false; //enables/disables alternative fn call		
		this.modFilterFn =			this.isModFilterFn ? f.mod_filter_fn : null;// used by tf_DetectKey fn
		this.onBeforeFilter =		f!=undefined && tf_IsFn(f.on_before_filter) //calls function before filtering starts
										? f.on_before_filter : null;
		this.onAfterFilter =		f!=undefined && tf_IsFn(f.on_after_filter) //calls function after filtering
										? f.on_after_filter : null;								
		this.matchCase =			f!=undefined && f.match_case ? true : false; //enables/disables case sensitivity
		this.exactMatch =			f!=undefined && f.exact_match ? true : false; //enables/disbles exact match for search
		this.refreshFilters =		f!=undefined && f.refresh_filters ? true : false; //refreshes drop-down lists upon validation
		this.activeFlt =			null; //stores active filter element
		this.activeFilterId =		null; //id of active filter
		this.hasColOperation =		f!=undefined && f.col_operation ? true : false; //enables/disbles column operation(sum,mean)
		this.colOperation =			null;
		this.hasVisibleRows = 		f!=undefined && f.rows_always_visible ? true : false; //enables always visible rows
		this.visibleRows =			this.hasVisibleRows ? f.rows_always_visible : [];//array containing always visible rows
		this.searchType =			f!=undefined && f.search_type!=undefined //defines search type: include or exclude
										? f.search_type : 'include';
		this.isExternalFlt =		f!=undefined && f.external_flt_grid ? true : false; //enables/disables external filters generation
		this.externalFltTgtIds =	f!=undefined && f.external_flt_grid_ids!=undefined //array containing ids of external elements containing filters
										? f.external_flt_grid_ids : null;
		this.externalFltEls =		[]; //stores filters elements if isExternalFlt is true		
		this.execDelay =			f!=undefined && f.exec_delay ? parseInt(f.exec_delay) : 100; //delays filtering process if loader true
		this.status =				f!=undefined && f.status ? true : false; //enables/disables status messages
		this.onFiltersLoaded =		f!=undefined && tf_IsFn(f.on_filters_loaded) //calls function when filters grid loaded
										? f.on_filters_loaded : null;
		this.singleSearchFlt =		f!=undefined && f.single_search_filter ? true : false; //enables/disables single filter search
		this.onRowValidated =		f!=undefined && tf_IsFn(f.on_row_validated) //calls function after row is validated
									 	? f.on_row_validated : null;
		this.customCellDataCols =	f!=undefined && f.custom_cell_data_cols ? f.custom_cell_data_cols : []; //array defining columns for customCellData event 	
		this.customCellData =		f!=undefined && tf_IsFn(f.custom_cell_data) //calls custom function for retrieving cell data
									 	? f.custom_cell_data : null;
		this.inpWatermark = 		f!=undefined && f.input_watermark!=undefined ? f.input_watermark : ''; //input watermark text array
		this.inpWatermarkCssClass =	f!=undefined && f.input_watermark_css_class!=undefined //defines css class for input watermark
										? f.input_watermark_css_class : 'fltWatermark';
		this.isInpWatermarkArray =	f!=undefined && f.input_watermark!=undefined
										? (tf_IsArray(f.input_watermark) ? true : false) : false;
		this.toolBarTgtId =			f!=undefined && f.toolbar_target_id!=undefined //id of toolbar container element
										? f.toolbar_target_id : null;
		this.helpInstructions = 	f!=undefined && (f.help_instructions!=undefined) ? f.help_instructions : null; //enables/disables help div
		this.popUpFilters =			f!=undefined && f.popup_filters!=undefined ? f.popup_filters : false; //popup filters 
		if(this.popUpFilters)       (!this.gridLayout) ? this.filtersRowIndex = 0 : this.filtersRowIndex = 1;
		this.markActiveColumns =	f!=undefined && f.mark_active_columns!=undefined ? f.mark_active_columns : false; //active columns color
		this.activeColumnsCssClass = f!=undefined && f.active_columns_css_class!=undefined //defines css class for active column header
										? f.active_columns_css_class : 'activeHeader';
		this.onBeforeActiveColumn = f!=undefined && tf_IsFn(f.on_before_active_column) //calls function before active column header is marked
										? f.on_before_active_column : null;
		this.onAfterActiveColumn = f!=undefined && tf_IsFn(f.on_after_active_column) //calls function after active column header is marked
										? f.on_after_active_column : null;
		
		/*** selects customisation and behaviours ***/
		this.displayAllText =		f!=undefined && f.display_all_text!=undefined ? f.display_all_text : ''; //defines 1st option text
		this.enableEmptyOption =	f!=undefined && f.enable_empty_option ? true : false; //enables/disables empty option in combo-box filters
		this.emptyText =			f!=undefined && f.empty_text!=undefined ? f.empty_text : '(Empty)'; //defines empty option text
		this.enableNonEmptyOption =	f!=undefined && f.enable_non_empty_option ? true : false; //enables/disables non empty option in combo-box filters
		this.nonEmptyText =			f!=undefined && f.non_empty_text!=undefined ? f.non_empty_text : '(Non empty)'; //defines empty option text
		this.onSlcChange = 			f!=undefined && f.on_change==false ? false : true; //enables/disables onChange event on combo-box 
		this.sortSlc =				f!=undefined && f.sort_select==false ? false : true; //enables/disables select options sorting
		this.isSortNumAsc =			f!=undefined && f.sort_num_asc ? true : false; //enables/disables ascending numeric options sorting
		this.sortNumAsc =			this.isSortNumAsc ? f.sort_num_asc : null;
		this.isSortNumDesc =		f!=undefined && f.sort_num_desc ? true : false; //enables/disables descending numeric options sorting
		this.sortNumDesc =			this.isSortNumDesc ? f.sort_num_desc : null;
		this.slcFillingMethod =		f!=undefined && f.slc_filling_method!=undefined //sets select filling method: 'innerHTML' or 
										? f.slc_filling_method : 'createElement';	//'createElement'
		this.fillSlcOnDemand =		f!=undefined && f.fill_slc_on_demand ? true : false; //enabled selects are populated on demand
		this.activateSlcTooltip =	f!=undefined && f.activate_slc_tooltip!=undefined //IE only, tooltip text appearing on select 
										? f.activate_slc_tooltip : 'Click to activate'; // before it is populated
		this.multipleSlcTooltip =	f!=undefined && f.multiple_slc_tooltip!=undefined //tooltip text appearing on multiple select 
										? f.multiple_slc_tooltip : 'Use Ctrl key for multiple selections';
		this.hasCustomSlcOptions =	f!=undefined && f.custom_slc_options && tf_IsObj(f.custom_slc_options)
										? true : false;	
		this.customSlcOptions =		f!=undefined && f.custom_slc_options!=undefined
										? f.custom_slc_options : null;
		this.onBeforeOperation =	f!=undefined && tf_IsFn(f.on_before_operation) //calls function before col operation
										? f.on_before_operation : null;
		this.onAfterOperation =		f!=undefined && tf_IsFn(f.on_after_operation) //calls function after col operation
										? f.on_after_operation : null;
		
		/*** checklist customisation and behaviours ***/
		this.checkListDiv = 		[]; //checklist container div
		this.checkListDivCssClass = f!=undefined && f.div_checklist_css_class!=undefined 
										? f.div_checklist_css_class : 'div_checklist'; //defines css class for div containing checklist filter
		this.checkListCssClass =	f!=undefined && f.checklist_css_class!=undefined //defines css class for checklist filters
										? f.checklist_css_class : 'flt_checklist';
		this.checkListItemCssClass = f!=undefined && f.checklist_item_css_class!=undefined //defines css class for checklist item (li)
										? f.checklist_item_css_class : 'flt_checklist_item';
		this.checkListSlcItemCssClass = f!=undefined && f.checklist_selected_item_css_class!=undefined //defines css class for selected checklist item (li)
										? f.checklist_selected_item_css_class : 'flt_checklist_slc_item';								
		this.activateCheckListTxt =	f!=undefined && f.activate_checklist_text!=undefined //Load on demand text 
										? f.activate_checklist_text : 'Click to load data';
		/*** Filter operators ***/
		this.emOperator =			f!=undefined && f.empty_operator!=undefined ? f.empty_operator : '[empty]';
		this.nmOperator =			f!=undefined && f.nonempty_operator!=undefined ? f.nonempty_operator : '[nonempty]';		
		this.orOperator =			f!=undefined && f.or_operator!=undefined ? f.or_operator : '||';
		this.anOperator =			f!=undefined && f.and_operator!=undefined ? f.and_operator : '&&';
		this.grOperator = 			f!=undefined && f.greater_operator!=undefined ? f.greater_operator : '>';
		this.lwOperator =			f!=undefined && f.lower_operator!=undefined ? f.lower_operator : '<';
		this.leOperator =			f!=undefined && f.lower_equal_operator!=undefined ? f.lower_equal_operator : '<=';
		this.geOperator =			f!=undefined && f.greater_equal_operator!=undefined ? f.greater_equal_operator : '>=';
		this.dfOperator =			f!=undefined && f.different_operator!=undefined ? f.different_operator : '!';
		this.lkOperator =			f!=undefined && f.like_operator!=undefined ? f.like_operator : '*';
		this.eqOperator =			f!=undefined && f.equal_operator!=undefined ? f.equal_operator : '=';
		this.stOperator =			f!=undefined && f.start_with_operator!=undefined ? f.start_with_operator : '{';
		this.enOperator =			f!=undefined && f.end_with_operator!=undefined ? f.end_with_operator : '}';
		this.curExp =				f!=undefined && f.cur_exp!=undefined ? f.cur_exp : '^[¥£€$]';
		this.separator = 			f!=undefined && f.separator!=undefined ? f.separator : ',';
		
		/*** rows counter ***/
		this.rowsCounter = 			f!=undefined && f.rows_counter ? true : false; //show/hides rows counter		
		
		/*** status bar ***/
		this.statusBar =			f!=undefined && f.status_bar ? f.status_bar : false; //show/hides status bar			
		
		/*** loader ***/
		this.loader =				f!=undefined && f.loader ? true : false; //enables/disables loader					
		
		/*** validation - reset buttons/links ***/
		this.displayBtn =			f!=undefined && f.btn ? true : false; //show/hides filter's validation button
		this.btnText =				f!=undefined && f.btn_text!=undefined ? f.btn_text : 'go'; //defines validation button text
		this.btnCssClass =			f!=undefined && f.btn_css_class!=undefined //defines css class for validation button
										? f.btn_css_class : 'btnflt';
		this.btnReset = 			f!=undefined && f.btn_reset ? true : false; //show/hides reset link
		this.btnResetCssClass =		f!=undefined && f.btn_reset_css_class!=undefined //defines css class for reset button
									? f.btn_reset_css_class :'reset';
		
		/*** paging ***/
		this.paging =				f!=undefined && f.paging ? true : false; //enables/disables table paging		
		this.hasResultsPerPage =	f!=undefined && f.results_per_page ? true : false; //enables/disables results per page drop-down
		this.btnPageCssClass =		f!=undefined && f.paging_btn_css_class!=undefined
										? f.paging_btn_css_class :'pgInp'; //css class for paging buttons (previous,next,etc.)
		this.pagingSlc =			null; //stores paging select element
		this.resultsPerPage =		null; //stores results per page text and values
		this.resultsPerPageSlc =	null; //results per page select element
		this.isPagingRemoved =		false; //indicates if paging elements were previously removed
		this.nbVisibleRows	=		0; //nb visible rows
		this.nbHiddenRows =			0; //nb hidden rows
		this.startPagingRow =		0; //1st row index of current page
		this.nbPages = 				0; //total nb of pages
		this.currentPageNb =		1; //current page nb
		
		/*** webfx sort adapter ***/
		this.sort =					f!=undefined && f.sort ? true : false; //enables/disables default table sorting
		this.isSortEnabled =		false; //indicates if sort is set (used in tfAdapter.sortabletable.js)
		this.sorted =				false; //indicates if tables was sorted
		this.sortConfig =			f!=undefined && f.sort_config!=undefined 
										? f.sort_config : {};
		this.sortConfig.name =		f!=undefined && f.sort_config!=undefined && f.sort_config.name
										? f.sort_config.name : 'sortabletable';
		this.sortConfig.src =		f!=undefined && f.sort_config!=undefined && f.sort_config.src
										? f.sort_config.src : 'sortabletable.js';
		this.sortConfig.adapterSrc =f!=undefined && f.sort_config!=undefined && f.sort_config.adapter_src
										? f.sort_config.adapter_src : 'tfAdapter.sortabletable.js';
		this.sortConfig.initialize =f!=undefined && f.sort_config!=undefined && f.sort_config.initialize
										? f.sort_config.initialize
										: function(o){ if(o.SetSortTable) o.SetSortTable(); };
		this.sortConfig.sortTypes =	f!=undefined && f.sort_config!=undefined && f.sort_config.sort_types
										? f.sort_config.sort_types : [];
		this.sortConfig.sortCol =	f!=undefined && f.sort_config!=undefined && f.sort_config.sort_col!=undefined
										? f.sort_config.sort_col : null;
		this.sortConfig.asyncSort =	f!=undefined && f.sort_config!=undefined && f.sort_config.async_sort
										? true : false;
		this.sortConfig.triggerIds =f!=undefined && f.sort_config!=undefined && f.sort_config.sort_trigger_ids
										? f.sort_config.sort_trigger_ids : [];									
		
		/*** onkeyup event ***/
		this.onKeyUp =				f!=undefined && f.on_keyup ? true : false; //enables/disables onkeyup event, table is filtered when user stops typing
		this.onKeyUpDelay =			f!=undefined && f.on_keyup_delay!=undefined ? f.on_keyup_delay : 900; //onkeyup delay timer (msecs)
		this.isUserTyping = 		null; //typing indicator
		this.onKeyUpTimer = 		undefined;		
		
		/*** keyword highlighting ***/
		this.highlightKeywords = 	f!=undefined && f.highlight_keywords ? true : false; //enables/disables keyword highlighting
		this.highlightCssClass =	f!=undefined && f.highlight_css_class!=undefined //defines css class for highlighting
										? f.highlight_css_class : 'keyword';	
		
		/*** data types ***/
		this.defaultDateType =		f!=undefined && f.default_date_type!=undefined //defines default date type (european DMY)
										? f.default_date_type : 'DMY';
		this.thousandsSeparator =	f!=undefined && f.thousands_separator!=undefined //defines default thousands separator 
										? f.thousands_separator : ','; //US = ',' EU = '.'
		this.decimalSeparator = 	f!=undefined && f.decimal_separator!=undefined //defines default decimal separator 
										? f.decimal_separator : '.'; //US & javascript = '.' EU = ','
		this.hasColNbFormat = 		f!=undefined && f.col_number_format ? true : false; //enables number format per column
		this.colNbFormat = 			f!=undefined && this.hasColNbFormat ? f.col_number_format : null; //array containing columns nb formats
		this.hasColDateType = 		f!=undefined && f.col_date_type ? true : false; //enables date type per column
		this.colDateType =			f!=undefined && this.hasColDateType ? f.col_date_type : null; //array containing columns date type
		
		/*** status messages ***/
		this.msgFilter =			f!=undefined && f.msg_filter!=undefined //filtering
										? f.msg_filter : 'Filtering data...'; 
		this.msgPopulate =			f!=undefined && f.msg_populate!=undefined //populating drop-downs
										? f.msg_populate : 'Populating filter...'; 
		this.msgPopulateCheckList =	f!=undefined && f.msg_populate_checklist!=undefined //populating drop-downs
										? f.msg_populate_checklist : 'Populating list...'; 
		this.msgChangePage =		f!=undefined && f.msg_change_page!=undefined //changing paging page
										? f.msg_change_page : 'Collecting paging data...';
		this.msgClear =				f!=undefined && f.msg_clear!=undefined //clearing filters
										? f.msg_clear : 'Clearing filters...';
		this.msgChangeResults =		f!=undefined && f.msg_change_results!=undefined //changing nb results/page
										? f.msg_change_results : 'Changing results per page...';
		this.msgResetValues =		f!=undefined && f.msg_reset_grid_values!=undefined //re-setting grid values
										? f.msg_reset_grid_values : 'Re-setting filters values...';
		this.msgResetPage =			f!=undefined && f.msg_reset_page!=undefined //re-setting page
										? f.msg_reset_page : 'Re-setting page...';
		this.msgResetPageLength =	f!=undefined && f.msg_reset_page_length!=undefined //re-setting page length
										? f.msg_reset_page_length : 'Re-setting page length...';
		this.msgSort =				f!=undefined && f.msg_sort!=undefined //table sorting
										? f.msg_sort : 'Sorting data...';
		this.msgLoadExtensions =	f!=undefined && f.msg_load_extensions!=undefined //extensions loading
										? f.msg_load_extensions : 'Loading extensions...';
		this.msgLoadThemes =		f!=undefined && f.msg_load_themes!=undefined //themes loading
										? f.msg_load_themes : 'Loading theme(s)...';			

		/*** ids prefixes ***/
		this.prfxTf =				'TF'; //css class name added to table
		this.prfxFlt =				'flt'; //filters (inputs - selects)
		this.prfxValButton =		'btn'; //validation button
		this.prfxInfDiv =			'inf_'; //container div for paging elements, rows counter etc.
		this.prfxLDiv =				'ldiv_'; //left div
		this.prfxRDiv =				'rdiv_'; //right div
		this.prfxMDiv =				'mdiv_'; //middle div
		this.prfxContentDiv =		'cont_'; //table container if fixed headers enabled
		this.prfxCheckListDiv =		'chkdiv_'; //checklist filter container div
		this.prfxSlcPages =			'slcPages_'; //pages select
		this.prfxSlcResults = 		'slcResults_'; //results per page select
		this.prfxSlcResultsTxt =	'slcResultsTxt_'; //label preciding results per page select	
		this.prfxBtnNextSpan =		'btnNextSpan_'; //span containing next page button
		this.prfxBtnPrevSpan =		'btnPrevSpan_'; //span containing previous page button
		this.prfxBtnLastSpan =		'btnLastSpan_'; //span containing last page button
		this.prfxBtnFirstSpan =		'btnFirstSpan_'; //span containing first page button
		this.prfxBtnNext =			'btnNext_'; //next button
		this.prfxBtnPrev =			'btnPrev_'; //previous button
		this.prfxBtnLast =			'btnLast_'; //last button
		this.prfxBtnFirst =			'btnFirst_'; //first button
		this.prfxPgSpan =			'pgspan_'; //span for tot nb pages
		this.prfxPgBeforeSpan =		'pgbeforespan_'; //span preceding pages select (contains 'Page')
		this.prfxPgAfterSpan =		'pgafterspan_'; //span following pages select (contains ' of ')
		this.prfxCounter =			'counter_'; //rows counter div
		this.prfxTotRows =			'totrows_span_'; //nb displayed rows label
		this.prfxTotRowsTxt =		'totRowsTextSpan_'; //label preceding nb rows label
		this.prfxResetSpan =		'resetspan_'; //span containing reset button
		this.prfxLoader =			'load_'; //loader div
		this.prfxStatus =			'status_'; //status bar div
		this.prfxStatusSpan =		'statusSpan_'; //status bar label
		this.prfxStatusTxt =		'statusText_';//text preceding status bar label
		this.prfxCookieFltsValues =	'tf_flts_'; //filter values cookie
		this.prfxCookiePageNb =		'tf_pgnb_'; //page nb cookie
		this.prfxCookiePageLen = 	'tf_pglen_'; //page length cookie
		this.prfxMainTblCont =		'gridCont_'; //div containing grid elements if grid_layout true
		this.prfxTblCont =			'tblCont_'; //div containing table if grid_layout true
		this.prfxHeadTblCont = 		'tblHeadCont_'; //div containing headers table if grid_layout true
		this.prfxHeadTbl =			'tblHead_';	//headers' table if grid_layout true
		this.prfxGridFltTd =		'_td_'; //id of td containing the filter if grid_layout true
		this.prfxGridTh =			'tblHeadTh_'; //id of th containing column header if grid_layout true
		this.prfxHelpSpan =			'helpSpan_'; //id prefix for help elements
		this.prfxHelpDiv =			'helpDiv_'; //id prefix for help elements
		this.prfxPopUpSpan =		'popUpSpan_'; //id prefix for pop-up filter span
		this.prfxPopUpDiv =			'popUpDiv_'; //id prefix for pop-up div containing filter

		/*** cookies ***/
		this.hasStoredValues =		false;
		this.rememberGridValues =	f!=undefined && f.remember_grid_values ? true : false; //remembers filters values on page load
		this.fltsValuesCookie =		this.prfxCookieFltsValues + this.id; //cookie storing filter values
		this.rememberPageNb =		this.paging && f!=undefined && f.remember_page_number
										? true : false; //remembers page nb on page load	
		this.pgNbCookie =			this.prfxCookiePageNb + this.id; //cookie storing page nb
		this.rememberPageLen =		this.paging && f!=undefined && f.remember_page_length
										? true : false; //remembers page length on page load
		this.pgLenCookie =			this.prfxCookiePageLen + this.id; //cookie storing page length
		this.cookieDuration =		f!=undefined && f.set_cookie_duration 
										? parseInt(f.set_cookie_duration) :100000; //cookie duration
		
		/*** extensions ***/
		this.hasExtensions =		f!=undefined && f.extensions ? true : false; //imports external script
		this.extensions =			(this.hasExtensions) ? f.extensions : null;
		
		/*** themes ***/
		this.enableDefaultTheme =	f!=undefined && f.enable_default_theme ? true : false;	
		this.hasThemes =			f!=undefined && (f.enable_default_theme 
										|| (f.themes && tf_IsObj(f.themes))) ? true : false; //imports themes
		this.themes =				(this.hasThemes) ? f.themes : null;

		/***(deprecated: backward compatibility) ***/
		this.hasBindScript =		f!=undefined && f.bind_script ? true : false; //imports external script
		this.bindScript =			(this.hasBindScript) ? f.bind_script : null;
		
		/*** TF events ***/
		var o = this;
		this.Evt = {
			name: {
				filter: 'Filter',
				populateselect: 'Populate',
				populatechecklist: 'PopulateCheckList',
				changepage: 'ChangePage',
				clear: 'Clear',
				changeresultsperpage: 'ChangeResults',
				resetvalues: 'ResetValues',
				resetpage: 'ResetPage',
				resetpagelength: 'ResetPageLength',
				sort: 'Sort',
				loadextensions: 'LoadExtensions',
				loadthemes: 'LoadThemes'			
			},
			_DetectKey: function(e)
			/*====================================================
				- common fn that detects return key for a given
				element (onkeypress for inputs)
			=====================================================*/
			{
				if(!o.enterKey) return;
				var evt = e || window.event;
				if(evt)
				{
					var key=(evt.charCode)?evt.charCode:
						((evt.keyCode)?evt.keyCode:((evt.which)?evt.which:0));
					if(key=='13')
					{
						o.Filter();
						tf_CancelEvent(evt);
						tf_StopEvent(evt);						
					} else { 
						o.isUserTyping = true;
						window.clearInterval(o.onKeyUpTimer);
						o.onKeyUpTimer = undefined; 
					}
				}//if evt
			},
			_OnKeyUp: function(e)
			/*====================================================
				- onkeyup event for text filters 
				(onKeyUp property)
			=====================================================*/
			{
				if(!o.onKeyUp) return;
				var evt = e || window.event;
				var key=(evt.charCode)?evt.charCode:
						((evt.keyCode)?evt.keyCode:((evt.which)?evt.which:0));
				o.isUserTyping = false;
				
				if(key!=13 && key!=9 && key!=27 && key!=38 && key!=40)
				{
					function filter()
					{
						window.clearInterval(o.onKeyUpTimer);
						o.onKeyUpTimer = undefined;
						if(!o.isUserTyping)
						{
							o.Filter();
							o.isUserTyping = null;			
						}
					}
					if(o.onKeyUpTimer==undefined)
						o.onKeyUpTimer = window.setInterval(filter, o.onKeyUpDelay);
				} else { 
					window.clearInterval(o.onKeyUpTimer); 
					o.onKeyUpTimer = undefined; 
				}
			},
			_OnKeyDown: function(e)
			/*====================================================
				- onkeydown event for input filters 
				(onKeyUp property)
			=====================================================*/
			{
				if(!o.onKeyUp) return;
				o.isUserTyping = true;
			},
			_OnInpBlur: function(e)
			/*====================================================
				- onblur event for input filters (onKeyUp property)
			=====================================================*/
			{
				if(o.onKeyUp){
					o.isUserTyping = false; 
					window.clearInterval(o.onKeyUpTimer);
				}
				//Watermark
				if(this.value == '' && o.inpWatermark != ''){ 
					this.value = (o.isInpWatermarkArray) 
						? o.inpWatermark[this.getAttribute('ct')]  : o.inpWatermark;
					tf_AddClass(this, o.inpWatermarkCssClass);
				}
			},
			_OnInpFocus: function(e)
			/*====================================================
				- onfocus event for input filters
			=====================================================*/
			{
				var evt = e || window.event;
				o.activeFilterId = this.getAttribute('id');
				o.activeFlt = tf_Id(o.activeFilterId);
				//Watermark
				if(!o.isInpWatermarkArray){
					if(this.value == o.inpWatermark && o.inpWatermark != ''){					
						this.value = ''; 
						tf_RemoveClass(this, o.inpWatermarkCssClass);
					}
				} else {
					var inpWatermark = o.inpWatermark[this.getAttribute('ct')];
					if(this.value == inpWatermark && inpWatermark != ''){ 
						this.value = '';
						tf_RemoveClass(this, o.inpWatermarkCssClass);
					}
				}
				if(o.popUpFilters){
					tf_CancelEvent(evt);
					tf_StopEvent(evt);
				}
			},
			_OnSlcFocus: function(e)
			/*====================================================
				- onfocus event for select filters
			=====================================================*/
			{
				var evt = e || window.event;
				o.activeFilterId = this.getAttribute('id');
				o.activeFlt = tf_Id(o.activeFilterId);
				if(o.fillSlcOnDemand && this.getAttribute('filled') == '0')
				{// select is populated when element has focus
					var ct = this.getAttribute('ct');
					o.PopulateSelect(ct);
					if(!tf_isIE) this.setAttribute('filled','1');
				}
				if(o.popUpFilters){
					tf_CancelEvent(evt);
					tf_StopEvent(evt);
				}
			},
			_OnSlcChange: function(e)
			/*====================================================
				- onchange event for select filters
			=====================================================*/
			{
				var evt = e || window.event;
				if(o.popUpFilters) tf_StopEvent(evt);
				if(o.onSlcChange) o.Filter();
			},
			_OnSlcBlur: function()
			/*====================================================
				- onblur event for select filters
			=====================================================*/
			{	
			},
			_OnCheckListClick: function()
			/*====================================================
				- onclick event for checklist filters
			=====================================================*/
			{
				if(o.fillSlcOnDemand && this.getAttribute('filled') == '0')
				{
					var ct = this.getAttribute('ct');
					o.PopulateCheckList(ct);
					o.checkListDiv[ct].onclick = null;
					o.checkListDiv[ct].title = '';
				}
			},
			_OnCheckListFocus: function()
			/*====================================================
				- onclick event for checklist filter container
			=====================================================*/
			{
				o.activeFilterId = this.firstChild.getAttribute('id');
				o.activeFlt = tf_Id(o.activeFilterId);
			},
			_OnBtnClick: function()
			/*====================================================
				- onclick event for validation button 
				(btn property)
			=====================================================*/
			{
				o.Filter();
			},
			_OnSlcPagesChangeEvt: null, //used by sort adapter
			_EnableSlc: function()
			/*====================================================
				- onclick event slc parent node (enables filters)
				IE only
			=====================================================*/
			{
				this.firstChild.disabled = false;							
				this.firstChild.focus();							
				this.onclick = null;
			},
			_Clear: function()
			/*====================================================
				- clears filters
			=====================================================*/
			{
				o.ClearFilters();
			},
			_OnHelpBtnClick: function()
			/*====================================================
				- Help button onclick event
			=====================================================*/
			{
				o._ToggleHelp();
			},
			_Paging: { //used by sort adapter
				nextEvt: null,
				prevEvt: null,
				lastEvt: null,
				firstEvt: null
			}
		};
		
		if(this.enableModules){
			//Register modules to be imported
			var m = this.module, rm = this.registeredModules;
			if(this.loader || this.statusBar || this.status || this.hasThemes || this.publicMethods) 
				rm.push(m.loader.name);
			if(this.hasThemes || this.publicMethods) rm.push(m.themes.name);
			if(this.paging || this.publicMethods) rm.push(m.paging.name);
			if(this.gridLayout || this.publicMethods) rm.push(m.gridLayout.name);
			if(this.sort || this.publicMethods) rm.push(m.sort.name);
			if(this.popUpFilters || this.publicMethods) rm.push(m.popUpFilters.name);
			if(this.rowsCounter || this.publicMethods) rm.push(m.rowsCounter.name);
			if(this.fixedHeaders || this.publicMethods) rm.push(m.fixedHeaders.name);
			if(this.rememberGridValues || this.rememberPageLen || this.rememberPageNb || this.publicMethods)
				rm.push(m.cookies.name);
			if(this.statusBar|| this.status || this.loader || this.hasThemes || this.publicMethods) rm.push(m.statusBar.name);
			if(this.btnReset || this.publicMethods) rm.push(m.resetBtn.name);
			if((this.helpInstructions || this.helpInstructions==null)|| this.publicMethods) rm.push(m.helpInstructions.name);
			if(this.alternateBgs || this.publicMethods) rm.push(m.alternateRows.name);
			if(this.highlightKeywords || this.publicMethods) rm.push(m.highlightKeywords.name);
			if(this.refreshFilters || this.publicMethods) rm.push(m.refreshFilters.name);
			if(this.hasColOperation || this.publicMethods) rm.push(m.colOps.name);
			if(this.hasExtensions || this.gridLayout || this.publicMethods){				
				rm.push(m.extensions.name);
				rm.push(this.module.populateCheckList.name);
			}
			if(this.inpWatermark != '') rm.push(m.watermark.name);
			if(this.publicMethods || this.hasExtensions || 
				this.popUpFilters || this.markActiveColumns) rm.push(m.publicMethods.name);

			//Import modules
			for(var i=0; i<rm.length; i++){
				var module = m[rm[i]];
				if(tf_IsImported(module.path)){
					module.loaded = 1;
					this.alreadyImportedModules.push(module.name);
				} else { this.ImportModule(module); this.importedModules.push(module.name) };
			}
		}		
    }//if tbl!=null		
}

TF.prototype = {
	
	AddGrid: function()
	{
		if(this.enableModules){
			if(this.isFirstLoad){
				var o = this;
				if(tf_isNotIE){
					window[this.id + '_DelayAddGrid'] = function()
					{
						if(arguments.callee.done) return;
						//Chrome & Safari do not seem to fire window.onload event
						//Sorry for this ugly solution, one more ;-)
						setTimeout(function(){ o._AddGrid(); },1);
						arguments.callee.done = 1;
					}
					tf_AddEvent(window, 'load', window[this.id + '_DelayAddGrid']);
				} else {
					//Under IE script continues execution before dynamically imported scripts are fully loaded
					function checkLoadedModules(){
						var modulesFullyImported = true;						
						for(var i=0; i<o.registeredModules.length; i++){
							var module = o.module[o.registeredModules[i]];
							if(!module.loaded){ 
								modulesFullyImported = false;
								break;
							}
						}
						if(modulesFullyImported){ 
							clearInterval(pe);
							o._AddGrid();
						}
					}
					var pe = setInterval(checkLoadedModules, 10);
				}

			} else this._AddGrid();
		} else this._AddGrid();
	}, Init : function(){ this.AddGrid(); }, Initialize : function(){ this.AddGrid(); },
	init : function(){ this.AddGrid(); }, initialize : function(){ this.AddGrid(); },
	
	_AddGrid: function()
	/*====================================================
		- adds row with filtering grid bar and sets grid 
		behaviours and layout
	=====================================================*/
	{
		if(this.hasGrid) return;
		if(this.gridLayout) this.refRow = this.startRow==undefined ? 0 : this.startRow;
		this.headersRow = (this.filtersRowIndex==0 && this.fltGrid) ? 1 : 0;
		var f = !this.fObj ? {} : this.fObj;
		var n = (this.singleSearchFlt) ? 1 : this.nbCells, inpclass;
		if(window['tf_'+this.id] == undefined) window['tf_'+this.id] = this;

		//loads stylesheet if not imported
		//Issues with browsers != IE, IE rules in this case
		this.IncludeFile(this.stylesheetId, this.stylesheet, null, 'link');
		
		//loads theme
		if(this.hasThemes) this._LoadThemes();

		if(this.gridLayout)
		{
			this.isExternalFlt = true;
			this.SetGridLayout();
			//Once grid generated 1st filterable row is 0 again
			this.refRow = (tf_isIE || tf_isIE7) ? (this.refRow+1) : 0;
		}
				
		if(this.loader) this.SetLoader();
		
		if(this.popUpFilters) this.SetPopupFilterIcons();
		
		if(this.hasResultsPerPage)
		{ 
			this.resultsPerPage = f['results_per_page']!=undefined   
				? f['results_per_page'] : this.resultsPerPage;
			if(this.resultsPerPage.length<2)
				this.hasResultsPerPage = false;
			else
				this.pagingLength = this.resultsPerPage[1][0];
		}
		
		if(!this.fltGrid)
		{//filters grid is not genetared
			this.refRow = (this.refRow-1);
			if(this.gridLayout) this.refRow = 0;
			this.nbFilterableRows = this.GetRowsNb();
			this.nbVisibleRows = this.nbFilterableRows;
			this.nbRows = this.nbFilterableRows + this.refRow;
		} else {
			if(this.isFirstLoad)
			{
				if(!this.gridLayout){
					var fltrow;
					var thead = tf_Tag(this.tbl,'thead');
					if(thead.length>0)
						fltrow = thead[0].insertRow(this.filtersRowIndex);
					else
						fltrow = this.tbl.insertRow(this.filtersRowIndex);
					
					if(this.fixedHeaders) this.SetFixedHeaders();
					
					fltrow.className = this.fltsRowCssClass;
					//Disable for grid_layout
					if(this.isExternalFlt && (!this.gridLayout || this.popUpFilters)) fltrow.style.display = 'none';				
				}
				
				this.nbFilterableRows = this.GetRowsNb();
				this.nbVisibleRows = this.nbFilterableRows;
				this.nbRows = this.tbl.rows.length;
				
				for(var i=0; i<n; i++){// this loop adds filters
					var fltcell = tf_CreateElm(this.fltCellTag);
					if(this.singleSearchFlt) fltcell.colSpan = this.nbCells;
					if(!this.gridLayout) fltrow.appendChild(fltcell);
					inpclass = (i==n-1 && this.displayBtn) ? this.fltSmallCssClass : this.fltCssClass;
					
					if(this.popUpFilters) this.SetPopupFilter(i);
					
					if(this['col'+i]==undefined)
						this['col'+i] = (f['col_'+i]==undefined) 
							? this.fltTypeInp : f['col_'+i].tf_LCase();
							
					if(this.singleSearchFlt)
					{//only 1 input for single search
						this['col'+i] = this.fltTypeInp;
						inpclass = this.singleFltCssClass;
					}
	
					if(this['col'+i]==this.fltTypeSlc || this['col'+i]==this.fltTypeMulti)
					{//selects					
						var slc = tf_CreateElm(this.fltTypeSlc,
							['id',this.prfxFlt+i+'_'+this.id],
							['ct',i],['filled','0']);
						if(this['col'+i]==this.fltTypeMulti)
						{
							slc.multiple = this.fltTypeMulti;
							slc.title = this.multipleSlcTooltip;
						}
						slc.className = (this['col'+i].tf_LCase()==this.fltTypeSlc) 
							? inpclass : this.fltMultiCssClass;// for ie<=6
						
						if(this.isExternalFlt && this.externalFltTgtIds && tf_Id(this.externalFltTgtIds[i]))
						{//filter is appended in desired element
							tf_Id(this.externalFltTgtIds[i]).appendChild(slc);
							this.externalFltEls.push(slc);
						} else {
							fltcell.appendChild(slc);
						}
						
						this.fltIds.push(this.prfxFlt+i+'_'+this.id);
						
						if(!this.fillSlcOnDemand) this._PopulateSelect(i);
						
						slc.onkeypress = this.Evt._DetectKey;
						slc.onchange = this.Evt._OnSlcChange;
						slc.onfocus = this.Evt._OnSlcFocus;
						slc.onblur = this.Evt._OnSlcBlur;
						
						if(this.fillSlcOnDemand)
						{//1st option is created here since PopulateSelect isn't invoked
							var opt0 = tf_CreateOpt(this.displayAllText,'');
							slc.appendChild(opt0);						
						}
						
						/* 	Code below for IE: it prevents select options to
							slide out before select it-self is populated.
							This is an unexpeted behavior for users since at
							1st click options are empty. Work around: 
							select is disabled and by clicking on element 
							(parent td), users enable drop-down and select is
							populated at same time.  */
						if(this.fillSlcOnDemand && tf_isIE)
						{
							slc.disabled = true;
							slc.title = this.activateSlcTooltip;
							slc.parentNode.onclick = this.Evt._EnableSlc;
							if(this['col'+i]==this.fltTypeMulti)
								this.__deferMultipleSelection(slc,0);
						}
					}
					
					else if(this['col'+i]==this.fltTypeCheckList)
					{// checklist
						var divCont = tf_CreateElm('div',
										['id',this.prfxCheckListDiv+i+'_'+this.id],
										['ct',i],['filled','0']);
						divCont.className = this.checkListDivCssClass;
						
						if(this.isExternalFlt && this.externalFltTgtIds
							&& tf_Id(this.externalFltTgtIds[i]))
						{//filter is appended in desired element
							tf_Id(this.externalFltTgtIds[i]).appendChild(divCont);
							this.externalFltEls.push(divCont);
						} else {
							fltcell.appendChild(divCont);
						}
						
						this.checkListDiv[i] = divCont;
						this.fltIds.push(this.prfxFlt+i+'_'+this.id);
						if(!this.fillSlcOnDemand) this._PopulateCheckList(i);
						
						divCont.onclick = this.Evt._OnCheckListFocus;
						
						if(this.fillSlcOnDemand)
						{
							divCont.onclick = this.Evt._OnCheckListClick;
							divCont.appendChild(tf_CreateText(this.activateCheckListTxt));
						}
					}
					
					else
					{
						var inptype;
						(this['col'+i]==this.fltTypeInp) ? inptype='text' : inptype='hidden';//show/hide input	
						var inp = tf_CreateElm(this.fltTypeInp,['id',this.prfxFlt+i+'_'+this.id],['type',inptype],['ct',i]);	
						if(inptype!='hidden')
							inp.value = (this.isInpWatermarkArray) ? this.inpWatermark[i] : this.inpWatermark;					
						inp.className = inpclass;// for ie<=6
						if(this.inpWatermark!='') tf_AddClass(inp, this.inpWatermarkCssClass); //watermark css class
						inp.onfocus = this.Evt._OnInpFocus;
						
						if(this.isExternalFlt && this.externalFltTgtIds && tf_Id(this.externalFltTgtIds[i]))
						{//filter is appended in desired element
							tf_Id(this.externalFltTgtIds[i]).appendChild(inp);
							this.externalFltEls.push(inp);
						} else {
							fltcell.appendChild(inp);
						}
						
						this.fltIds.push(this.prfxFlt+i+'_'+this.id);
						
						inp.onkeypress = this.Evt._DetectKey;
						inp.onkeydown = this.Evt._OnKeyDown;
						inp.onkeyup = this.Evt._OnKeyUp;
						inp.onblur = this.Evt._OnInpBlur;
						
						if(this.rememberGridValues)
						{
							var flts = tf_ReadCookie(this.fltsValuesCookie); //reads the cookie
							var reg = new RegExp(',','g');
							var flts_values = flts.split(reg); //creates an array with filters' values
							if(flts_values[i]!=' ')
								this.SetFilterValue(i,flts_values[i],false);					
						}
					}
					
					if(i==n-1 && this.displayBtn)// this adds validation button
					{
						var btn = tf_CreateElm(this.fltTypeInp,['id',this.prfxValButton+i+'_'+this.id],
												['type','button'], ['value',this.btnText]);
						btn.className = this.btnCssClass;
						
						if(this.isExternalFlt && this.externalFltTgtIds && tf_Id(this.externalFltTgtIds[i])) 
						//filter is appended in desired element
							tf_Id(this.externalFltTgtIds[i]).appendChild(btn);
						else
							fltcell.appendChild(btn);
						
						btn.onclick = this.Evt._OnBtnClick;				
					}//if
					
				}// for i
				
			} else {
				this.__resetGrid();			
			}//if isFirstLoad
		}//if this.fltGrid
		
		/* Filter behaviours */	
		if(this.rowsCounter) this.SetRowsCounter();
		if(this.statusBar) this.SetStatusBar();
		if(this.fixedHeaders && !this.isFirstLoad) this.SetFixedHeaders();
		if(this.paging)	this.SetPaging();
		if(this.hasResultsPerPage && this.paging) this.SetResultsPerPage();
		if(this.btnReset) this.SetResetBtn();
		if(this.helpInstructions) this.SetHelpInstructions();
		
		if(this.hasColWidth && !this.gridLayout) this.SetColWidths();

		if(this.alternateBgs && this.isStartBgAlternate)
			this.SetAlternateRows(); //1st time only if no paging and rememberGridValues

		if(this.hasColOperation && this.fltGrid)
		{
			this.colOperation = f.col_operation;
			this.SetColOperation();
		}

		if(this.sort) this.SetSort();

		/* Deprecated Loads external script */
		if(this.hasBindScript)
		{
			if(this.bindScript['src']!=undefined)
			{
				var scriptPath = this.bindScript['src'];
				var scriptName = (this.bindScript['name']!=undefined)
									? this.bindScript['name'] : '';
				this.IncludeFile(scriptName,scriptPath,this.bindScript['target_fn']);
			}
		}//if bindScript
		/* */
		
		this.isFirstLoad = false;
		this.hasGrid = true;
		
		if(this.rememberGridValues || this.rememberPageLen || this.rememberPageNb)
			this.ResetValues();
		
		//TF css class is added to table
		tf_AddClass(this.tbl, this.prfxTf); 
		
		if(this.loader) this.ShowLoader('none');

		/* Loads extensions */
		if(this.hasExtensions) this.LoadExtensions();		
		
		if(this.onFiltersLoaded)
			this.onFiltersLoaded.call(null,this);

	},// AddGrid
	
	EvtManager: function(evt,s)
	/*====================================================
		- TF events manager
		- Params: 
			- event name (string)
			- config object (optional literal object)
	=====================================================*/
	{
		var o = this;
		var slcIndex = (s!=undefined && s.slcIndex!=undefined) ? s.slcIndex : null;
		var slcExternal = (s!=undefined && s.slcExternal!=undefined) ? s.slcExternal : false;
		var slcId = (s!=undefined && s.slcId!=undefined) ? s.slcId : null;
		var pgIndex = (s!=undefined && s.pgIndex!=undefined) ? s.pgIndex : null;
		function efx(){
			if(evt!=undefined)
			switch(evt)
			{
				case o.Evt.name.filter:
					(o.isModFilterFn) 
						? o.modFilterFn.call(null,o)
						: o._Filter();
				break;
				case o.Evt.name.populateselect:
					(o.refreshFilters) 
						? o._PopulateSelect(slcIndex,true) 
						: o._PopulateSelect(slcIndex,false,slcExternal,slcId);
				break;
				case o.Evt.name.populatechecklist:
					o._PopulateCheckList(slcIndex,slcExternal,slcId);
				break;
				case o.Evt.name.changepage:
					o._ChangePage(pgIndex);
				break;
				case o.Evt.name.clear:
					o._ClearFilters(); 
					o._Filter();
				break;
				case o.Evt.name.changeresultsperpage:
					o._ChangeResultsPerPage();
				break;
				case o.Evt.name.resetvalues:
					o._ResetValues();					
					o._Filter();
				break;
				case o.Evt.name.resetpage:
					o._ResetPage(o.pgNbCookie);
				break;
				case o.Evt.name.resetpagelength:
					o._ResetPageLength(o.pgLenCookie);
				break;
				case o.Evt.name.sort:
					void(0);
				break;
				case o.Evt.name.loadextensions:
					o._LoadExtensions();
				break;
				case o.Evt.name.loadthemes:
					o._LoadThemes();
				break;
				default: //to be used by extensions events when needed
					o['_'+evt].call(null,o,s);
				break;
			}
			if(o.status || o.statusBar) o.StatusMsg('');
			if(o.loader) o.ShowLoader('none');
		}

		if(this.loader || this.status || this.statusBar)
		{
			try{
				this.ShowLoader('');
				this.StatusMsg(o['msg'+evt]);
			} catch(e){}
			window.setTimeout(efx,this.execDelay);
		} else efx();
	},
	
	ImportModule: function(module)
	{
		if(!module.path || !module.name) return;
		this.IncludeFile(module.name, module.path, module.init);
	},
	
	RemoveGrid: function()
	/*====================================================
		- removes a filter grid
	=====================================================*/
	{
		if(this.fltGrid && this.hasGrid)
		{
			var rows = this.tbl.rows;
			if(this.paging) this.RemovePaging();
			if(this.statusBar) this.RemoveStatusBar();
			if(this.rowsCounter) this.RemoveRowsCounter();
			if(this.btnReset) this.RemoveResetBtn();
			if(this.helpInstructions || this.helpInstructions==null) this.RemoveHelpInstructions();
			if(this.paging) this.RemoveResultsPerPage();
			if(this.isExternalFlt && !this.popUpFilters) this.RemoveExternalFlts();
			if(this.fixedHeaders) this.RemoveFixedHeaders();
			if(this.infDiv) this.RemoveTopDiv();
			if(this.highlightKeywords) this.UnhighlightAll();
			if(this.sort) this.RemoveSort();
			if(this.loader) this.RemoveLoader();
			if(this.popUpFilters) this.RemovePopupFilters();
			if(this.markActiveColumns) this.ClearActiveColumns();
			
			for(var j=this.refRow; j<this.nbRows; j++)
			{//this loop shows all rows and removes validRow attribute			
				rows[j].style.display = '';
				try
				{ 
					if(rows[j].hasAttribute('validRow')) 
						rows[j].removeAttribute('validRow');
				} //ie<=6 doesn't support hasAttribute method
				catch(e){
					for(var x = 0; x < rows[j].attributes.length; x++) 
					{
						if(rows[j].attributes[x].nodeName.tf_LCase()=='validrow') 
							rows[j].removeAttribute('validRow');
					}//for x
				}//catch(e)
				
				//removes alterning colors
				if(this.alternateBgs) this.RemoveRowBg(j);
				
			}//for j
	
			if(this.fltGrid && !this.gridLayout)
			{
				this.fltGridEl = rows[this.filtersRowIndex];			
				this.tbl.deleteRow(this.filtersRowIndex);
			}
			if(this.gridLayout) this.RemoveGridLayout();
			tf_RemoveClass(this.tbl, this.prfxTf);
			this.activeFlt = null;
			this.isStartBgAlternate = true;
			this.hasGrid = false;
	
		}//if this.fltGrid
	},
	
	SetTopDiv: function()
	/*====================================================
		- Generates div above table where paging,
		reset button, rows counter label etc. are placed
	=====================================================*/
	{
		if(this.infDiv!=null) return;
	
		/*** container div ***/
		var infdiv = tf_CreateElm('div',['id',this.prfxInfDiv+this.id]);
		infdiv.className = this.infDivCssClass;// setAttribute method doesn't seem to work on ie<=6
		
		if(this.toolBarTgtId) //custom container
			tf_Id(this.toolBarTgtId).appendChild(infdiv);
		else if(this.fixedHeaders && this.contDiv) //fixed headers
			this.contDiv.parentNode.insertBefore(infdiv, this.contDiv);
		else if(this.gridLayout){ //grid-layout
			this.tblMainCont.appendChild(infdiv);
			infdiv.className = this.gridInfDivCssClass;
		}
		else //default location: above table
			this.tbl.parentNode.insertBefore(infdiv, this.tbl);
		this.infDiv = tf_Id(this.prfxInfDiv+this.id);
		
		/*** left div containing rows # displayer ***/
		var ldiv = tf_CreateElm('div',['id',this.prfxLDiv+this.id]);
		ldiv.className = this.lDivCssClass;/*'ldiv'*/;
		infdiv.appendChild(ldiv);
		this.lDiv = tf_Id(this.prfxLDiv+this.id);		
		
		/*** 	right div containing reset button 
				+ nb results per page select 	***/	
		var rdiv = tf_CreateElm('div',['id',this.prfxRDiv+this.id]);
		rdiv.className = this.rDivCssClass/*'rdiv'*/;
		infdiv.appendChild(rdiv);
		this.rDiv = tf_Id(this.prfxRDiv+this.id);
		
		/*** mid div containing paging elements ***/
		var mdiv = tf_CreateElm('div',['id',this.prfxMDiv+this.id]);
		mdiv.className = this.mDivCssClass/*'mdiv'*/;						
		infdiv.appendChild(mdiv);
		this.mDiv = tf_Id(this.prfxMDiv+this.id);
		
		if(this.helpInstructions==null) this.SetHelpInstructions();
	},
	
	RemoveTopDiv: function()
	/*====================================================
		- Removes div above table where paging,
		reset button, rows counter label etc. are placed
	=====================================================*/
	{
		if(this.infDiv==null) return;
		this.infDiv.parentNode.removeChild(this.infDiv);
		this.infDiv = null;
	},
	
	RemoveExternalFlts: function()
	/*====================================================
		- removes external filters
	=====================================================*/
	{
		if(!this.isExternalFlt && !this.externalFltTgtIds) return;
		for(var ct=0; ct<this.externalFltTgtIds.length; ct++)
			if(tf_Id(this.externalFltTgtIds[ct]))
				tf_Id(this.externalFltTgtIds[ct]).innerHTML = '';
	},
	
	Filter: function()
	{
		this.EvtManager(this.Evt.name.filter); 
	},
	_Filter: function()
	/*====================================================
		- Filtering fn
		- retrieves data from each td in every single tr
		and compares to search string for current
		column
		- tr is hidden if all search strings are not 
		found
	=====================================================*/
	{
		if(!this.fltGrid || (!this.hasGrid && !this.isFirstLoad)) return;
		//invokes eventual onbefore method
		if(this.onBeforeFilter) this.onBeforeFilter.call(null,this);
		
		if(this.inpWatermark != '') this.SetWatermark(false);
		
		var row = this.tbl.rows;	
		f = this.fObj!=undefined ? this.fObj : [];
		var hiddenrows = 0;
		this.validRowsIndex = [];
		var o = this;		
		
		//removes keyword highlighting
		if(this.highlightKeywords) this.UnhighlightAll();
		//removes popup filters active icons 
		if(this.popUpFilters) this.SetAllPopupFiltersIcon();
		//removes active column header class
		if(this.markActiveColumns) this.ClearActiveColumns();
		//search args re-init
		this.searchArgs = this.GetFiltersValue(); 
		
		var num_cell_data, nbFormat;
		var re_le = new RegExp(this.leOperator), re_ge = new RegExp(this.geOperator);
		var re_l = new RegExp(this.lwOperator), re_g = new RegExp(this.grOperator);
		var re_d = new RegExp(this.dfOperator), re_lk = new RegExp(tf_RegexpEscape(this.lkOperator));
		var re_eq = new RegExp(this.eqOperator), re_st = new RegExp(this.stOperator);
		var re_en = new RegExp(this.enOperator), re_an = new RegExp(this.anOperator);
		var re_cr = new RegExp(this.curExp), re_em = this.emOperator;
		var re_nm = this.nmOperator;
		
		function highlight(str,ok,cell){//keyword highlighting
			if(o.highlightKeywords && ok){
				str = str.replace(re_lk,'');
				str = str.replace(re_eq,'');
				str = str.replace(re_st,'');
				str = str.replace(re_en,'');
				var w = str;
				if(re_le.test(str) || re_ge.test(str) || re_l.test(str) || re_g.test(str) || re_d.test(str))	
					w = tf_GetNodeText(cell);
				if(w!='')
					tf_HighlightWord(cell,w,o.highlightCssClass);
			}
		}
		
		//looks for search argument in current row
		function hasArg(sA,cell_data,j)
		{
			var occurence;
			//Search arg operator tests
			var hasLO = re_l.test(sA), hasLE = re_le.test(sA);
			var hasGR = re_g.test(sA), hasGE = re_ge.test(sA);
			var hasDF = re_d.test(sA), hasEQ = re_eq.test(sA);
			var hasLK = re_lk.test(sA), hasAN = re_an.test(sA);
			var hasST = re_st.test(sA), hasEN = re_en.test(sA);
			var hasEM = (re_em == sA), hasNM = (re_nm == sA);
			
			//Search arg dates tests
			var isLDate = (hasLO && tf_IsValidDate(sA.replace(re_l,''),dtType));
			var isLEDate = (hasLE && tf_IsValidDate(sA.replace(re_le,''),dtType));
			var isGDate = (hasGR && tf_IsValidDate(sA.replace(re_g,''),dtType));
			var isGEDate = (hasGE && tf_IsValidDate(sA.replace(re_ge,''),dtType));
			var isDFDate = (hasDF && tf_IsValidDate(sA.replace(re_d,''),dtType));
			var isEQDate = (hasEQ && tf_IsValidDate(sA.replace(re_eq,''),dtType));

			if(tf_IsValidDate(cell_data,dtType))
			{//dates
				var dte1 = tf_FormatDate(cell_data,dtType);
				if(isLDate) 
				{// lower date
					var dte2 = tf_FormatDate(sA.replace(re_l,''),dtType);
					occurence = (dte1 < dte2);
				}
				else if(isLEDate) 
				{// lower equal date
					var dte2 = tf_FormatDate(sA.replace(re_le,''),dtType);
					occurence = (dte1 <= dte2);
				}
				else if(isGEDate) 
				{// greater equal date
					var dte2 = tf_FormatDate(sA.replace(re_ge,''),dtType);
					occurence = (dte1 >= dte2);
				}
				else if(isGDate) 
				{// greater date
					var dte2 = tf_FormatDate(sA.replace(re_g,''),dtType);
					occurence = (dte1 > dte2);
				}
				else if(isDFDate) 
				{// different date
					var dte2 = tf_FormatDate(sA.replace(re_d,''),dtType);
					occurence = (dte1.toString() != dte2.toString());
				}
				else if(isEQDate) 
				{// equal date
					var dte2 = tf_FormatDate(sA.replace(re_eq,''),dtType);
					occurence = (dte1.toString() == dte2.toString());
				}
				else if(re_lk.test(sA)) // searched keyword with * operator doesn't have to be a date
				{// like date
					occurence = o.__containsStr(sA.replace(re_lk,''),cell_data,null,false);
				}
				else if(tf_IsValidDate(sA,dtType))
				{
					var dte2 = tf_FormatDate(sA,dtType);
					occurence = (dte1.toString() == dte2.toString());
				}
				else if(hasEM) //empty
					occurence = (cell_data.tf_Trim()=='' ? true : false);
				
				else if(hasNM) //non-empty
					occurence = (cell_data.tf_Trim()!='' ? true : false);
			}
			
			else 
			{						
				//first numbers need to be formated
				if(o.hasColNbFormat && o.colNbFormat[j]!=null)
				{
					num_cell_data = tf_RemoveNbFormat(cell_data,o.colNbFormat[j]);
					nbFormat = o.colNbFormat[j];
				} else {
					if(o.thousandsSeparator==',' && o.decimalSeparator=='.')
					{
						num_cell_data = tf_RemoveNbFormat(cell_data,'us');
						nbFormat = 'us';
					} else {
						num_cell_data = tf_RemoveNbFormat(cell_data,'eu');
						nbFormat = 'eu';
					}
				}
				
				// first checks if there is any operator (<,>,<=,>=,!,*,=,{,})
				if(hasLE) //lower equal
					occurence = num_cell_data <= tf_RemoveNbFormat(sA.replace(re_le,''),nbFormat);
				
				else if(hasGE) //greater equal
					occurence = num_cell_data >= tf_RemoveNbFormat(sA.replace(re_ge,''),nbFormat);
				
				else if(hasLO) //lower
					occurence = num_cell_data < tf_RemoveNbFormat(sA.replace(re_l,''),nbFormat);
					
				else if(hasGR) //greater
					occurence = num_cell_data > tf_RemoveNbFormat(sA.replace(re_g,''),nbFormat);							
					
				else if(hasDF) //different
					occurence = o.__containsStr(sA.replace(re_d,''),cell_data) ? false : true;
			
				else if(hasLK) //like
					occurence = o.__containsStr(sA.replace(re_lk,''),cell_data,null,false);
				
				else if(hasEQ) //equal
					occurence = o.__containsStr(sA.replace(re_eq,''),cell_data,null,true);
				
				else if(hasST) //starts with
					occurence = cell_data.indexOf(sA.replace(re_st,''))==0 ? true : false;
				
				else if(hasEN) //ends with
				{
					var searchArg = sA.replace(re_en,'');
					occurence = cell_data.lastIndexOf(searchArg,cell_data.length-1)==(cell_data.length-1)-(searchArg.length-1)
						&& cell_data.lastIndexOf(searchArg,cell_data.length-1) > -1
						? true : false;
				}
				
				else if(hasEM) //empty
					occurence = (cell_data.tf_Trim()=='' ? true : false);
				
				else if(hasNM) //non-empty
					occurence = (cell_data.tf_Trim()!='' ? true : false);
 
				else
					occurence = o.__containsStr(sA,cell_data,(f['col_'+j]==undefined) ? this.fltTypeInp : f['col_'+j]);
				
			}//else
			return occurence;
		}//fn
		
		for(var k=this.refRow; k<this.nbRows; k++)
		{
			/*** if table already filtered some rows are not visible ***/
			if(row[k].style.display == 'none') row[k].style.display = '';
					
			var cell = row[k].cells;
			var nchilds = cell.length;	
			
			// checks if row has exact cell #
			if(nchilds != this.nbCells) continue;
	
			var occurence = [];
			var isRowValid = (this.searchType=='include') ? true : false;
			var singleFltRowValid = false; //only for single filter search
			
			for(var j=0; j<nchilds; j++)
			{// this loop retrieves cell data
				var sA = this.searchArgs[(this.singleSearchFlt) ? 0 : j]; //searched keyword
				var dtType = (this.hasColDateType) ? this.colDateType[j] : this.defaultDateType;
				if(sA=='') continue;
				
				var cell_data = this.GetCellData(j, cell[j]).tf_MatchCase(this.matchCase);
	
				var sAOrSplit = sA.split(this.orOperator);//multiple search parameter operator ||
				var hasMultiOrSA = (sAOrSplit.length>1) ? true : false;//multiple search || parameter boolean
				var sAAndSplit = sA.split('&&');//multiple search parameter operator &&
				var hasMultiAndSA = (sAAndSplit.length>1) ? true : false;//multiple search && parameter boolean

				if(hasMultiOrSA || hasMultiAndSA)
				{//multiple sarch parameters
					var cS, occur = false;
					var s = (hasMultiOrSA) ? sAOrSplit : sAAndSplit;
					for(var w=0; w<s.length; w++)
					{
						cS = s[w].tf_Trim();
						occur = hasArg(cS,cell_data,j);
						highlight(cS,occur,cell[j]);
						if(hasMultiOrSA && occur) break;
						if(hasMultiAndSA && !occur) break;
					}
					occurence[j] = occur;
				}
				else {//single search parameter		
					occurence[j] = hasArg(sA.tf_Trim(),cell_data,j);
					highlight(sA,occurence[j],cell[j]);
				}//else single param
				
				if(!occurence[j]) isRowValid = (this.searchType=='include') ? false : true;
				if(this.singleSearchFlt && occurence[j]) singleFltRowValid = true;
				if(this.popUpFilters) this.SetPopupFilterIcon(j, true);
				if(this.markActiveColumns){
					if(k == this.refRow){
						if(this.onBeforeActiveColumn) this.onBeforeActiveColumn.call(null, this, j);
						tf_AddClass(this.GetHeaderElement(j), this.activeColumnsCssClass);
						if(this.onAfterActiveColumn) this.onAfterActiveColumn.call(null, this, j);
					}
				}
			}//for j
			
			if(this.singleSearchFlt && singleFltRowValid) isRowValid = true;
			
			if(!isRowValid)
			{
				this.SetRowValidation(k,false);
				// always visible rows need to be counted as valid
				if(this.hasVisibleRows && this.visibleRows.tf_Has(k) && !this.paging)
					this.validRowsIndex.push(k);
				else
					hiddenrows++;
			} else {
				this.SetRowValidation(k,true);
				this.validRowsIndex.push(k);
				if(this.alternateBgs) this.SetRowBg(k,this.validRowsIndex.length);
				if(this.onRowValidated) this.onRowValidated.call(null,this,k);
			}
			
		}// for k
		
		this.nbVisibleRows = this.validRowsIndex.length;
		this.nbHiddenRows = hiddenrows;
		this.isStartBgAlternate = false;
		if(this.rememberGridValues) this.RememberFiltersValue(this.fltsValuesCookie);
		if(!this.paging) this.ApplyGridProps();//applies filter props after filtering process
		if(this.paging){ 
			this.startPagingRow = 0; 
			this.currentPageNb = 1;
			this.SetPagingInfo(this.validRowsIndex); 
		}//starts paging process
		//invokes eventual onafter function
		if(this.onAfterFilter) this.onAfterFilter.call(null,this);
	},
	
	ApplyGridProps: function()
	/*====================================================
		- checks methods that should be called
		after filtering and/or paging process
	=====================================================*/
	{
		if(this.activeFlt && this.activeFlt.nodeName.tf_LCase()==this.fltTypeSlc && !this.popUpFilters)
		{// blurs active filter (IE)
			this.activeFlt.blur(); 
			if(this.activeFlt.parentNode) this.activeFlt.parentNode.focus();
		}
		
		if(this.visibleRows) this.SetVisibleRows();//shows rows always visible
		if(this.colOperation) this.SetColOperation();//makes operation on a col
		if(this.refreshFilters) this.RefreshFiltersGrid();//re-populates drop-down filters
		var nr = (!this.paging && this.hasVisibleRows) 
					? (this.nbVisibleRows - this.visibleRows.length) : this.nbVisibleRows;
		if(this.rowsCounter) this.RefreshNbRows(nr);//refreshes rows counter
		
		if(this.inpWatermark != '') this.SetWatermark(true);
		if(this.popUpFilters) this.CloseAllPopupFilters();
	},
	
	GetColValues: function(colindex,num,exclude)
	/*====================================================
		- returns an array containing cell values of
		a column
		- needs following args:
			- column index (number)
			- a boolean set to true if we want only 
			numbers to be returned
			- array containing rows index to be excluded
			from returned values
	=====================================================*/
	{
		if(!this.fltGrid) return;
		var row = this.tbl.rows;
		var colValues = [];
	
		for(var i=this.refRow; i<this.nbRows; i++)//iterates rows
		{
			var isExludedRow = false;
			if(exclude!=undefined && tf_IsObj(exclude))
			{ // checks if current row index appears in exclude array
				isExludedRow = exclude.tf_Has(i); //boolean
			}
			var cell = row[i].cells;
			var nchilds = cell.length;
			
			if(nchilds == this.nbCells && !isExludedRow)
			{// checks if row has exact cell # and is not excluded
				for(var j=0; j<nchilds; j++)// this loop retrieves cell data
				{
					if(j==colindex && row[i].style.display=='')
					{
						var cell_data = this.GetCellData(j, cell[j]).tf_LCase();
						var nbFormat = this.colNbFormat ? this.colNbFormat[colindex] : null;
						(num) ? colValues.push(tf_RemoveNbFormat(cell_data,nbFormat)) 
								: colValues.push(cell_data);
					}//if j==k
				}//for j
			}//if nchilds == this.nbCells
		}//for i
		return colValues;	
	},
	
	GetFilterValue: function(index)
	/*====================================================
		- Returns value of a specified filter
		- Params:
			- index: filter column index (numeric value)
	=====================================================*/
	{
		if(!this.fltGrid) return;
		var fltValue;
		var flt = this.GetFilterElement(index);
		if(flt==null) return fltValue='';
		
		if(this['col'+index]!=this.fltTypeMulti && 
			this['col'+index]!=this.fltTypeCheckList)
			fltValue = flt.value;
		else if(this['col'+index] == this.fltTypeMulti)
		{//mutiple select
			fltValue = '';
			for(var j=0; j<flt.options.length; j++) 
				if(flt.options[j].selected)
					fltValue = fltValue.concat(
								flt.options[j].value+' ' +
								this.orOperator + ' '
								);
			//removes last operator ||
			fltValue = fltValue.substr(0,fltValue.length-4);
		}
		else if(this['col'+index]==this.fltTypeCheckList)
		{//checklist
			if(flt.getAttribute('value')!=null)
			{
				fltValue = flt.getAttribute('value');
				//removes last operator ||
				fltValue = fltValue.substr(0,fltValue.length-3);
			} else fltValue = '';
		}			
		return fltValue;
	},
	
	GetFiltersValue: function()
	/*====================================================
		- Returns the value of every single filter
	=====================================================*/
	{
		if(!this.fltGrid) return;
		var searchArgs = [];
		for(var i=0; i<this.fltIds.length; i++)
			searchArgs.push(
				this.GetFilterValue(i).tf_MatchCase(this.matchCase).tf_Trim()
			);
		return searchArgs;
	},
	
	GetFilterId: function(index)
	/*====================================================
		- Returns filter id of a specified column
		- Params:
			- index: column index (numeric value)
	=====================================================*/
	{
		if(!this.fltGrid) return;
		return this.fltIds[i];
	},
	
	GetFiltersByType: function(type,bool)
	/*====================================================
		- returns an array containing ids of filters of a 
		specified type (inputs or selects)
		- Note that hidden filters are also returned
		- Needs folllowing args:
			- filter type string ('input','select',
			'multiple')
			- optional boolean: if set true method
			returns column indexes otherwise filters ids
	=====================================================*/
	{
		if(!this.fltGrid) return;
		var arr = [];
		for(var i=0; i<this.fltIds.length; i++)
		{
			var fltType = this['col'+i];
			if(fltType == type.tf_LCase())
			{
				var a = (bool) ? i : this.fltIds[i];
				arr.push(a);
			}
		}
		return arr;
	},
	
	GetFilterElement: function(index)
	/*====================================================
		- returns filter DOM element for a given column
		index
	=====================================================*/
	{
		if(!this.fltGrid) return null;
		return tf_Id(this.fltIds[index]);
	},
	
	GetCellsNb: function(rowIndex)
	/*====================================================
		- returns number of cells in a row
		- if rowIndex param is passed returns number of 
		cells of specified row (number)
	=====================================================*/
	{
		var tr = (rowIndex == undefined) ? this.tbl.rows[0] : this.tbl.rows[rowIndex];
		return tr.cells.length;
	},
	
	GetRowsNb: function()
	/*====================================================
		- returns total nb of filterable rows starting 
		from reference row if defined
	=====================================================*/
	{
		var s = this.refRow==undefined ? 0 : this.refRow;
		var ntrs = this.tbl.rows.length;
		return parseInt(ntrs-s);
	},
	
	GetCellData: function(i, cell)
	/*====================================================
		- returns text content of a given cell
		- Params:
			- i: index of the column (number)
			- cell: td DOM object
	=====================================================*/
	{
		if(i==undefined || cell==null) return "";
		//First checks for customCellData event
		if(this.customCellData && this.customCellDataCols.tf_Has(i))
			return this.customCellData.call(null,this,cell,i);
		else
			return tf_GetNodeText(cell);
	},
	
	GetRowDisplay: function(row)
	{
		if(!this.fltGrid && !tf_IsObj(row)) return;
		return row.style.display;
	},
	
	SetRowValidation: function(rowIndex,isValid)
	/*====================================================
		- Validates/unvalidates row by setting 'validRow' 
		attribute and shows/hides row
		- Params:
			- rowIndex: index of the row (number)
			- isValid: boolean
	=====================================================*/
	{
		var row = this.tbl.rows[rowIndex];
		if(!row || (typeof isValid).tf_LCase()!='boolean') return;
	
		// always visible rows are valid
		if(this.hasVisibleRows && this.visibleRows.tf_Has(rowIndex) && !this.paging)
			isValid = true;
		
		var displayFlag = (isValid) ? '' : 'none';
		var validFlag = (isValid) ? 'true' : 'false';		
		row.style.display = displayFlag;
		
		if(this.paging) 
			row.setAttribute('validRow',validFlag);
	},
	
	ValidateAllRows: function()
	/*====================================================
		- Validates all filterable rows
	=====================================================*/
	{
		if(!this.hasGrid) return;
		this.validRowsIndex = [];
		for(var k=this.refRow; k<this.nbFilterableRows; k++)
		{
			this.SetRowValidation(k,true);
			this.validRowsIndex.push(k);
		}
	},
	
	SetFilterValue: function(index,searcharg,doFilter)
	/*====================================================
		- Inserts value in a specified filter
		- Params:
			- index: filter column index (numeric value)
			- searcharg: search string
			- doFilter: optional boolean for multiple
			selects: executes filtering when multiple 
			select populated... IE only!
	=====================================================*/
	{
		if((!this.fltGrid && !this.isFirstLoad) || this.GetFilterElement(index)==null) return;
		var slc = this.GetFilterElement(index);
		var execFilter = (doFilter==undefined) ? true : doFilter;
		searcharg = (searcharg==undefined) ? '' : searcharg;
		
		if(this['col'+index]!=this.fltTypeMulti && 
			this['col'+index]!=this.fltTypeCheckList){
			slc.value = searcharg;
			if(this['col'+index]==this.fltTypeInp && this.inpWatermark!='')
				tf_RemoveClass(slc, this.inpWatermarkCssClass);
		}
			
		else if(this['col'+index] == this.fltTypeMulti)
		{//multiple selects
			var s = searcharg.split(' '+this.orOperator+' ');
			var ct = 0; //keywords counter
			for(var j=0; j<slc.options.length; j++) 
			{
				if(s=='') slc.options[j].selected = false;
				if(slc.options[j].value=='') slc.options[j].selected = false;
				if(slc.options[j].value!='' && s.tf_Has(slc.options[j].value,true))
				{
					if(tf_isIE)
					{// IE multiple selection work-around
						//when last value reached filtering can be executed
						var filter = (ct==(s.length-1) && execFilter) ? true : false;
						this.__deferMultipleSelection(slc,j,filter);
						ct++;
					}					
					else
						slc.options[j].selected = true;
				}//if
			}//for j
		}
		
		else if(this['col'+index]==this.fltTypeCheckList)
		{//checklist
			searcharg = searcharg.tf_MatchCase(this.matchCase);
			var s = searcharg.split(' '+this.orOperator+' ');
			var fltValue = slc.setAttribute('value','');
			var fltIndex = slc.setAttribute('indexes','');
			for(var k=0; k<tf_Tag(slc,'li').length; k++) 
			{
				var li = tf_Tag(slc,'li')[k];
				var lbl = tf_Tag(li,'label')[0];
				var chk = tf_Tag(li,'input')[0];
				var lblTxt = tf_GetNodeText(lbl).tf_MatchCase(this.matchCase);
				if(lblTxt!='' && s.tf_Has(lblTxt,true))
				{
					chk.checked = true;
					this.__setCheckListValues(chk);
				}
				else{ 
					chk.checked = false;
					this.__setCheckListValues(chk);
				}
			}
		}
	},

	SetColWidths: function(rowIndex)
	/*====================================================
		- sets coluun widths in pixels
	=====================================================*/
	{
		if(!this.fltGrid || !this.hasColWidth) return;
		var o = this, rIndex;
		if(rowIndex==undefined) rIndex = this.tbl.rows[0].style.display!='none' ? 0 : 1;
		else rIndex = rowIndex;
		setWidths(this.tbl.rows[rIndex]);

		function setWidths(row)
		{
			if(!o && (o.nbCells!=o.colWidth.length)) return;
			if(o.nbCells==row.cells.length)
				for(var k=0; k<o.nbCells; k++)
					row.cells[k].style.width = o.colWidth[k];
		}
	},
	
	SetVisibleRows: function()
	/*====================================================
		- makes a row always visible
		- Note this works only if paging is false
	=====================================================*/
	{
		if(this.hasGrid && this.hasVisibleRows && !this.paging)
		{
			for(var i=0; i<this.visibleRows.length; i++)
			{
				if(this.visibleRows[i]<=this.nbRows)//row index cannot be > nrows
					this.SetRowValidation(this.visibleRows[i],true);
			}//for i
		}//if hasGrid
	},
	
	ClearFilters: function()
	{ 
		this.EvtManager(this.Evt.name.clear); 
	},	
	_ClearFilters: function()
	/*====================================================
		- clears grid filters
	=====================================================*/
	{
		if(!this.fltGrid) return;
		for(var i=0; i<this.fltIds.length; i++)
			this.SetFilterValue(i,'');
		if(this.refreshFilters){
			this.activeFilterId = '';	
			this.RefreshFiltersGrid();
		}
		if(this.rememberPageLen) tf_RemoveCookie(this.pgLenCookie);
		if(this.rememberPageNb) tf_RemoveCookie(this.pgNbCookie);
	},
		
	ClearActiveColumns: function()
	/*====================================================
		- clears active columns header class name
	=====================================================*/
	{
		for(var i=0; i<this.fltIds.length; i++)
			tf_RemoveClass(this.GetHeaderElement(i), this.activeColumnsCssClass);
	},
	
	RefreshGrid: function(config)
	/*====================================================
		- Re-generates filters grid
	=====================================================*/
	{
		var configObj = !config ? this.fObj : config;
		var hasSort = this.sort;
		if(hasSort) this.sort = false; //sort property is set to false in order to avoid sort object re-instanciation
		this.RemoveGrid();
		window['tf_'+this.id] = new TF(this.id, this.startRow, configObj);
		this.isFirstLoad = true;
		this.fltIds = [];
		this._AddGrid();
		if(hasSort){
			//New tbody content needs to be referenced in sortabletable script with setTBody() method
			//this.st =  SortableTable object
			this.st.setTBody(this.tbl.tBodies[0]); //Note this is a method of the Sortable Table 1.12 script (Erik Arvidsson)
			this.sort = true; //finally sort property is enabled again
		}
	},
	
	/*====================================================
		- Private methods
	=====================================================*/
	
	__resetGrid: function()
	/*====================================================
		- Only used by AddGrid() method
		- Resets filtering grid bar if previously removed
	=====================================================*/
	{
		if(this.isFirstLoad) return;
		
		// grid was removed, grid row element is stored in fltGridEl property
		if(!this.gridLayout){
			var thead = tf_Tag(this.tbl,'thead');
			if(thead.length>0)
				if(this.filtersRowIndex == 0)
					thead[0].rows[this.filtersRowIndex].parentNode.insertBefore( 
						this.fltGridEl,
						thead[0].rows[this.filtersRowIndex]
					);
				else
					thead[0].appendChild(this.fltGridEl);
			else
				this.tbl.rows[this.filtersRowIndex].parentNode.insertBefore( 
					this.fltGridEl,
					this.tbl.rows[this.filtersRowIndex]
				);
		}
		
		if(this.isExternalFlt)
		{// filters are appended in external placeholders elements
			for(var ct=0; ct<this.externalFltTgtIds.length; ct++)
				if(tf_Id(this.externalFltTgtIds[ct])){
					tf_Id(this.externalFltTgtIds[ct]).appendChild(this.externalFltEls[ct]);
					
					//IE special treatment for gridLayout, appended filters are empty
					if(this.gridLayout && this.externalFltEls[ct].innerHTML=='' && this['col'+ct] != this.fltTypeInp){
						if(this['col'+ct] == this.fltTypeSlc || this['col'+ct] == this.fltTypeMulti) 
							this.PopulateSelect(ct);
						if(this['col'+ct] == this.fltTypeCheckList) this.PopulateCheckList(ct);
					}
				}
		}
				
		this.nbFilterableRows = this.GetRowsNb();
		this.nbVisibleRows = this.nbFilterableRows;
		this.nbRows = this.tbl.rows.length;
		if(this.isSortEnabled) this.sort = true;

		if(this.tbl.rows[this.filtersRowIndex].innerHTML=='')
			refreshFilters(this);
		else
			if(this.popUpFilters) this.SetPopupFilters();
			
		/*** 	ie bug work-around, filters need to be re-generated
				since row is empty; insertBefore method doesn't seem to work properly 
				with previously generated DOM nodes modified by innerHTML 	***/
		function refreshFilters(o){
			o.tbl.deleteRow(o.filtersRowIndex);
			o.RemoveGrid();
			o.fltIds = [];
			o.isFirstLoad = true;
			if(o.popUpFilters) o.RemovePopupFilters();
			o._AddGrid();
		}
		
		tf_AddClass(this.tbl, this.prfxTf);
		this.hasGrid = true;
	},
	
	__containsStr: function(arg,data,fltType,forceMatch)
	/*==============================================
		- Checks if data contains searched arg,
		returns a boolean
		- Params:
			- arg: searched string
			- data: data string
			- fltType: filter type (string, 
			exact match by default for selects - 
			optional)
			- forceMatch: boolean forcing exact
			match (optional)
	===============================================*/
	{
		// Improved by Cedric Wartel (cwl)
		// automatic exact match for selects and special characters are now filtered
		var regexp;
		var modifier = (this.matchCase) ? 'g' : 'gi';
		var exactMatch = (forceMatch==undefined) ? this.exactMatch : forceMatch;
		if(exactMatch || (fltType!=this.fltTypeInp && fltType!=undefined))//Váry Péter's patch
			regexp = new RegExp('(^\\s*)'+tf_RegexpEscape(arg)+'(\\s*$)', modifier);							
		else
			regexp = new RegExp(tf_RegexpEscape(arg), modifier);
		return regexp.test(data);
	},
	
	IncludeFile: function(fileId, filePath, callback, type)
	{
		var ftype = (type==undefined) ? 'script' : type;
		var isImported = tf_IsImported(filePath, ftype);
		if(isImported) return;
		var o = this, isLoaded = false, file;			
		var head = tf_Tag(document,'head')[0];
		
		if(ftype.tf_LCase() == 'link')
			file = tf_CreateElm(
						'link', ['id',fileId], ['type','text/css'],
						['rel','stylesheet'], ['href',filePath]
					);
		else
			file = tf_CreateElm(
						'script', ['id',fileId], 
						['type','text/javascript'], ['src',filePath]
					);
		
		file.onload = file.onreadystatechange = function()
		{//Browser <> IE onload event works only for scripts, not for stylesheets
			if(!isLoaded && 
				(!this.readyState || this.readyState == 'loaded' || this.readyState == 'complete')) 
			{
				isLoaded = true;
				if(typeof callback === 'function')	callback.call(null,o);
			}
		}
		head.appendChild(file);
	}
}

/* --- */

/*====================================================
	- General TF utility fns below
=====================================================*/

function tf_GetNodeText(n)
/*====================================================
	- returns text + text of child nodes of a node
=====================================================*/
{
	var s = n.textContent || n.innerText || n.innerHTML.replace(/\<[^<>]+>/g, '');
	return s.replace(/^\s+/, '').replace(/\s+$/, '').tf_Trim();
	//return s.tf_Trim();
}

function tf_IsObj(v)
/*====================================================
	- checks if var exists and is an object
	- returns a boolean
=====================================================*/
{
	var isO = false;
	if((typeof v).tf_LCase()=='string'){
		if(window[v] && (typeof window[v]).tf_LCase()=='object')
			isO = true;
	} else {
		if(v && (typeof v).tf_LCase()=='object')
			isO = true;
	}
	return isO;
}

function tf_IsFn(fn)
/*====================================================
	- checks if passed param is a function
	- returns a boolean
=====================================================*/
{
	return (fn && fn.constructor == Function);
}

function tf_IsArray(obj){
/*====================================================
	- checks if passed param is an array
	- returns a boolean
=====================================================*/
	return obj.constructor == Array;
}

function tf_Id(id)
/*====================================================
	- this is just a getElementById shortcut
=====================================================*/
{
	return document.getElementById(id);
}

function tf_Tag(o,tagname)
/*====================================================
	- this is just a getElementsByTagName shortcut
=====================================================*/
{
	return o.getElementsByTagName(tagname);
}

function tf_RegexpEscape(s)
/*====================================================
	- escapes special characters [\^$.|?*+() 
	for regexp
	- Many thanks to Cedric Wartel for this fn
=====================================================*/
{
	// traite les caractères spéciaux [\^$.|?*+()
	//remplace le carctère c par \c
	function escape(e)
	{
		a = new RegExp('\\'+e,'g');
		s = s.replace(a,'\\'+e);
	}

	chars = new Array('\\','[','^','$','.','|','?','*','+','(',')');
	//for(e in chars) escape(chars[e]); // compatibility issue with prototype
	for(var e=0; e<chars.length; e++) escape(chars[e]);
	return s;
}

function tf_CreateElm(tag)
/*====================================================
	- creates an html element with its attributes
	- accepts the following params:
		- a string defining the html tag
		to create
		- an undetermined # of arrays containing the
		couple 'attribute name','value' ['id','myId']
=====================================================*/
{
	if(tag==undefined || tag==null || tag=='') return;
	var el = document.createElement(tag);		
	if(arguments.length>1)
	{
		for(var i=0; i<arguments.length; i++)
		{
			var argtype = typeof arguments[i];
			switch(argtype.tf_LCase())
			{
				case 'object':
					if(arguments[i].length==2)
					{						
						el.setAttribute(arguments[i][0],arguments[i][1]);
					}//if array length==2
				break;
			}//switch
		}//for i
	}//if args
	return el;	
}

function tf_CreateText(node)
/*====================================================
	- this is just a document.createTextNode shortcut
=====================================================*/
{
	return document.createTextNode(node);
}

function tf_AddEvent(obj,event_name,func_name){
	if(obj.attachEvent)
		obj.attachEvent('on'+event_name, func_name);
	else if(obj.addEventListener)
		obj.addEventListener(event_name,func_name,true);
	else
		obj['on'+event_name] = func_name;
}

function tf_RemoveEvent(obj,event_name,func_name){
	if(obj.detachEvent)
		obj.detachEvent('on'+event_name,func_name);
	else if(obj.removeEventListener)
		obj.removeEventListener(event_name,func_name,true);
	else
		obj['on'+event_name] = null;
}

function tf_StopEvent(e){
	if(!e) e = window.event;
	if(e.stopPropagation) {
		e.stopPropagation();
	} else {
		e.cancelBubble = true;
	}
}

function tf_CancelEvent(e){
	if(!e) e = window.event;
	if(e.preventDefault) {
		e.preventDefault();
	} else {
		e.returnValue = false;
	}
}

function tf_ObjPosition(obj, tag){
	var l = 0, t = 0;
	if (obj && obj.offsetParent && tag.tf_Has(obj.nodeName.tf_LCase())) {
		do {
			  l += obj.offsetLeft;
			  t += obj.offsetTop;
		} while (obj = obj.offsetParent);
	}
	return [l,t];
}

function tf_NumSortAsc(a, b){ return (a-b); }

function tf_NumSortDesc(a, b){ return (b-a); }

function tf_IgnoreCaseSort(a, b){
	var x = a.tf_LCase();
	var y = b.tf_LCase();
	return ((x < y) ? -1 : ((x > y) ? 1 : 0));
}

String.prototype.tf_MatchCase = function (mc){
	if(!mc) return this.tf_LCase();
	else return this.toString();
}

String.prototype.tf_Trim = function()
{//optimised by Anthony Maes
	return this.replace(/(^[\s\xA0]*)|([\s\xA0]*$)/g,'');
}

String.prototype.tf_LCase = function(){
	return this.toLowerCase();
}

String.prototype.tf_UCase = function(){
	return this.toUpperCase();
}

Array.prototype.tf_Has = function(s,mc){
	//return this.indexOf(s) >= 0;
	var sCase = (mc==undefined) ? false : mc;
	for (i=0; i<this.length; i++)
		if(this[i].toString().tf_MatchCase(sCase)==s) return true;
	return false;
}

Array.prototype.tf_IndexByValue = function(s,mc){
	var sCase = (mc==undefined) ? false : mc;
	for (i=0; i<this.length; i++)
		if(this[i].toString().tf_MatchCase(sCase)==s) return i;
	return (-1);
}

// Is this IE 6? the ultimate browser sniffer ;-)
//window['tf_isIE'] = (window.innerHeight) ? false : true;
window['tf_isIE'] = (window.innerHeight) ? false : /msie|MSIE 6/.test(navigator.userAgent) ? true : false;
window['tf_isIE7'] = (window.innerHeight) ? false : /msie|MSIE 7/.test(navigator.userAgent) ? true : false;

function tf_HasClass(elm,cl){
	if(!elm) return false;
	return elm.className.match(new RegExp('(\\s|^)'+cl+'(\\s|$)'));
}

function tf_AddClass(elm,cl){
	if(!elm) return;
	if(!tf_HasClass(elm,cl))
		elm.className += ' '+cl;
}

function tf_RemoveClass(elm,cl){
	if(!elm) return;
	if(!tf_HasClass(elm,cl)) return;
	var reg = new RegExp('(\\s|^)'+cl+'(\\s|$)');
	elm.className = elm.className.replace(reg,'');
}

function tf_IsValidDate(dateStr, format){
	if(format == null) { format = 'DMY'; }
	format = format.toUpperCase();
	if(format.length != 3) { format = 'DMY'; }
	if((format.indexOf('M') == -1) || (format.indexOf('D') == -1) ||
		(format.indexOf('Y') == -1)) { format = 'DMY'; }
	if(format.substring(0, 1) == 'Y') { // If the year is first
		  var reg1 = /^\d{2}(\-|\/|\.)\d{1,2}\1\d{1,2}$/;
		  var reg2 = /^\d{4}(\-|\/|\.)\d{1,2}\1\d{1,2}$/;
	} else if(format.substring(1, 2) == 'Y') { // If the year is second
		  var reg1 = /^\d{1,2}(\-|\/|\.)\d{2}\1\d{1,2}$/;
		  var reg2 = /^\d{1,2}(\-|\/|\.)\d{4}\1\d{1,2}$/;
	} else { // The year must be third
		  var reg1 = /^\d{1,2}(\-|\/|\.)\d{1,2}\1\d{2}$/;
		  var reg2 = /^\d{1,2}(\-|\/|\.)\d{1,2}\1\d{4}$/;
	}
	// If it doesn't conform to the right format (with either a 2 digit year or 4 digit year), fail
	if((reg1.test(dateStr) == false) && (reg2.test(dateStr) == false)) { return false; }
	var parts = dateStr.split(RegExp.$1); // Split into 3 parts based on what the divider was
	// Check to see if the 3 parts end up making a valid date
	if(format.substring(0, 1) == 'M') { var mm = parts[0]; } else
		if(format.substring(1, 2) == 'M') { var mm = parts[1]; } else { var mm = parts[2]; }
	if(format.substring(0, 1) == 'D') { var dd = parts[0]; } else
		if(format.substring(1, 2) == 'D') { var dd = parts[1]; } else { var dd = parts[2]; }
	if(format.substring(0, 1) == 'Y') { var yy = parts[0]; } else
		if(format.substring(1, 2) == 'Y') { var yy = parts[1]; } else { var yy = parts[2]; }
	if(parseFloat(yy) <= 50) { yy = (parseFloat(yy) + 2000).toString(); }
	if(parseFloat(yy) <= 99) { yy = (parseFloat(yy) + 1900).toString(); }
	var dt = new Date(parseFloat(yy), parseFloat(mm)-1, parseFloat(dd), 0, 0, 0, 0);
	if(parseFloat(dd) != dt.getDate()) { return false; }
	if(parseFloat(mm)-1 != dt.getMonth()) { return false; }
	return true;
}

function tf_FormatDate(dateStr, format){
	if(format==null) format = 'DMY';
	var oDate, parts;
	
	function y2kDate(yr){
		if(yr == undefined) return 0;
		if(yr.length>2) return yr;
		var y;
		if(yr <= 99 && yr>50) //>50 belong to 1900
			y = '19' + yr;
		if(yr<50 || yr =='00') //<50 belong to 2000
			y = '20' + yr;
		return y;
	}
	
	switch(format.toUpperCase())
	{
		case 'DMY':
			parts = dateStr.replace(/^(0?[1-9]|[12][0-9]|3[01])([- \/.])(0?[1-9]|1[012])([- \/.])((\d\d)?\d\d)$/,'$1 $3 $5').split(' ');
			oDate = new Date(y2kDate(parts[2]),parts[1]-1,parts[0]);
		break;
		case 'MDY':
			parts = dateStr.replace(/^(0?[1-9]|1[012])([- \/.])(0?[1-9]|[12][0-9]|3[01])([- \/.])((\d\d)?\d\d)$/,'$1 $3 $5').split(' ');
			oDate = new Date(y2kDate(parts[2]),parts[0]-1,parts[1]);
		break;
		case 'YMD':
			parts = dateStr.replace(/^((\d\d)?\d\d)([- \/.])(0?[1-9]|1[012])([- \/.])(0?[1-9]|[12][0-9]|3[01])$/,'$1 $4 $6').split(' ');
			oDate = new Date(y2kDate(parts[0]),parts[1]-1,parts[2]);
		break;
		default: //in case format is not correct
			parts = dateStr.replace(/^(0?[1-9]|[12][0-9]|3[01])([- \/.])(0?[1-9]|1[012])([- \/.])((\d\d)?\d\d)$/,'$1 $3 $5').split(' ');
			oDate = new Date(y2kDate(parts[2]),parts[1]-1,parts[0]);
		break;
	}
	return oDate;
}

function tf_RemoveNbFormat(data,format){
	if(data==null) return;
	if(format==null) format = 'us';
	var n = data;
	if(format.tf_LCase()=='us')
		n =+ n.replace(/[^\d\.-]/g,'');
	else
		n =+ n.replace(/[^\d\,-]/g,'').replace(',','.');
	return n;
}

function tf_IsImported(filePath,type){
	var isImported = false; 
	var importType = (type==undefined) ? 'script' : type;
	var attr = importType == 'script' ? 'src' : 'href';
	var files = tf_Tag(document,importType);
	for (var i=0; i<files.length; i++)
	{
		if(files[i][attr] == undefined) continue;
		if(files[i][attr].match(filePath))
		{
			isImported = true;	
			break;
		}
	}
	return isImported;
}

function tf_IsStylesheetImported(stylesheet){
	var isImported = false;
	if(!document.styleSheets) return isImported;
	var s = document.styleSheets;
	var regexp = new RegExp(stylesheet);
	for(var i=0; i<s.length; i++){
		if(s[i].imports){ //IE
			var imp = s[i].imports;
			for(var j=0; j<imp.length; j++){
				if(imp[j].href.tf_LCase() == stylesheet.tf_LCase()){
					isImported = true; break;
				}
			}
		} else {
			var r =  (s[i].cssRules ? s[i].cssRules : s[i].rules);
			for(var j=0; j<r.length; j++){
				if(regexp.test(r[j].cssText)){ 
					isImported = true; break;
				}
			}
		}
	}
	return isImported;
}

function tf_WriteCookie(name, value, hours){
	var expire = '';
	if(hours != null)
	{
		expire = new Date((new Date()).getTime() + hours * 3600000);
		expire = '; expires=' + expire.toGMTString();
	}
	document.cookie = name + '=' + escape(value) + expire;
}

function tf_ReadCookie(name){
	var cookieValue = '';
	var search = name + '=';
	if(document.cookie.length > 0)
	{ 
		offset = document.cookie.indexOf(search);
		if(offset != -1)
		{ 
			offset += search.length;
			end = document.cookie.indexOf(';', offset);
			if(end == -1) end = document.cookie.length;
			cookieValue = unescape(document.cookie.substring(offset, end))
		}
	}
	return cookieValue;
}

function tf_CookieValueArray(name){
	var val = tf_ReadCookie(name); //reads the cookie
	var arr = val.split(','); //creates an array with filters' values
	return arr;
}

function tf_CookieValueByIndex(name, index){
	var val = tf_CookieValueArray(name); //reads the cookie
	return val[index];
}

function tf_RemoveCookie(name){
	tf_WriteCookie(name,'',-1);
}

//Firefox does not support outerHTML property
function tf_SetOuterHtml(){
	if(document.body.__defineGetter__) {
		if(HTMLElement) {
			var element = HTMLElement.prototype;
			if(element.__defineGetter__) {
				element.__defineGetter__("outerHTML",
					function(){
						var parent = this.parentNode;
						var el = tf_CreateElm(parent.tagName);
						el.appendChild(this);
						var shtml = el.innerHTML;
						parent.appendChild(this);
						return shtml;
					}
				);
			}
		}
	}
	
	if(element.__defineSetter__) {
		HTMLElement.prototype.__defineSetter__("outerHTML", function(sHTML) {
		   var r = this.ownerDocument.createRange();
		   r.setStartBefore(this);
		   var df = r.createContextualFragment(sHTML);
		   this.parentNode.replaceChild(df, this);	
		   return sHTML;
		});
	}
}
/* --- */

/*====================================================
	- Backward compatibility fns
=====================================================*/
function grabEBI(id){ return tf_Id(id); }
function grabTag(obj,tagname){ return tf_Tag(obj,tagname); }
function tf_GetCellText(n){ return tf_GetNodeText(n); }
function tf_isObject(varname){ return tf_IsObj(varname); }
function tf_isObj(v){ return tf_IsObj(v); }
function tf_isFn(fn){ return tf_IsFn(fn); }
function tf_isArray(obj){ return tf_IsArray(obj); }
function tf_addEvent(obj,event_name,func_name){ return tf_AddEvent(obj,event_name,func_name); }
function tf_removeEvent(obj,event_name,func_name){ return tf_RemoveEvent(obj,event_name,func_name); }
function tf_addClass(elm,cl){ tf_AddClass(elm,cl); }
function tf_removeClass(elm,cl){ return tf_RemoveClass(elm,cl); }
function tf_hasClass(elm,cl){ return tf_HasClass(elm,cl); }
function tf_isValidDate(dateStr,format){ return tfeval(function(p,a,c,k,e,d){e=function(c){return(c<a?"":e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)d[e(c)]=k[c]||e(c);k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1;};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p;}('b 33(q){n(p.y==0)T;5g(\'1i\'+q+\' = 4X 12(p[0],p[1],p[2]);\'+\'1i\'+q+\'.4W();\');T H[\'1i\'+q]}H[\'3A\']=!(/4V|50/.4Z(4Y.4U));4Q(H,(3A?\'4P\':\'2g\'),3r);b 3r(){n(!2F.4O)T;u 14=4T(2F,\'2V\'),P;A(u i=0;i<14.y;i++){u 13=14[i],w=13.4S(\'q\');n(4R(13,\'5a\')&&w){n(1A(w+\'2y\'))P=H[w+\'2y\'];59 P=4;H[w+\'58\']=8;33(w,P)}}}u 12=b(q){n(p.y==0)T;3.q=q;3.5d=\'1.9.9\';3.C=5c(q);3.L=4;3.1h=6;3.5b=6;3.Z=6;3.57=6;3.53=6;3.V=6;3.52=5;3.18=8;n(3.C!=6&&3.C.51.1a()==\'2V\'&&3.56()){n(p.y>1){A(u i=0;i<p.y;i++){u 2P=55 p[i];54(2P.1a()){2Q\'4N\':3.L=p[i];2R;2Q\'4w\':3.Z=p[i];2R}}}u f=!3.Z?{}:3.Z;3.1h=3.L==4?2:(3.L+1);4v{3.V=3.35(3.1h)}4u(e){3.V=3.35(0)}n(3.18){3.1q=[];3.4z=[];3.4y=[];3.h=f!=4&&f.2Z!=4?f.2Z:\'4x/\';3.d={U:{a:\'U\',l:\'30 3p 32 E\',j:3.h+\'4t.g\',7:0,k:b(o){o.d.U.7=1}},S:{a:\'S\',l:\'30 2e 32 E\',j:3.h+\'4p.g\',7:0,k:b(o){o.d.S.7=1}},v:{a:\'v\',l:\'4o 4n m\',j:3.h+\'4s.g\',7:0,k:b(o){o.d.v.7=1}},x:{a:\'x\',l:\'4r m\',j:3.h+\'4q.g\',7:0,k:b(o){o.d.x.7=1}},D:{a:\'D\',l:\'4J m\',j:3.h+\'4I.g\',7:0,k:b(o){o.d.D.7=1}},G:{a:\'G\',l:\'4H 4M 4L-4K 4G m\',j:3.h+\'4C.g\',7:0,k:b(o){o.d.G.7=1}},1b:{a:\'1b\',l:\'4B 1t m\',j:3.h+\'4A.g\',7:0,k:b(o){o.d.1b.7=1}},1k:{a:\'1k\',l:\'4F 4E m\',j:3.h+\'4D.g\',7:0,k:b(o){o.d.1k.7=1}},W:{a:\'W\',l:\'5O 5N m - 5M\',j:3.h+\'5R.g\',7:0,k:b(o){o.d.W.7=1}},J:{a:\'J\',l:\'5Q 5P m\',j:3.h+\'5L.g\',7:0,k:b(o){o.d.J.7=1}},z:{a:\'z\',l:\'5H m\',j:3.h+\'5G.g\',7:0,k:b(o){o.d.z.7=1}},O:{a:\'O\',l:\'5F 5K m\',j:3.h+\'5J.g\',7:0,k:b(o){o.d.O.7=1}},11:{a:\'11\',l:\'5I 61 m\',j:3.h+\'38.g\',7:0,k:b(o){o.d.11.7=1}},Q:{a:\'Q\',l:\'60, 5Z\',j:3.h+\'38.g\',7:0,k:b(o){o.d.Q.7=1}},1m:{a:\'1m\',l:\'64 63 62 m\',j:3.h+\'5Y.g\',7:0,k:b(o){o.d.1m.7=1}},B:{a:\'B\',l:\'3f 15 m (B)\',j:3.h+\'5U.g\',7:0,k:b(o){o.d.B.7=1}},X:{a:\'X\',l:\'3f 15 m (B)\',j:3.h+\'5T.g\',7:0,k:b(o){o.d.X.7=1}},I:{a:\'I\',l:\'5S E m\',j:3.h+\'5X.g\',7:0,k:b(o){o.d.I.7=1}},M:{a:\'M\',l:\'5W 1t m\',j:3.h+\'5V.g\',7:0,k:b(o){o.d.M.7=1}},1p:{a:\'1p\',l:\'5E m\',j:3.h+\'5n.g\',7:0,k:b(o){o.d.1p.7=1}},K:{a:\'K\',l:\'5m 5l 5q A 5p\',j:3.h+\'5o.g\',7:0,k:b(o){o.d.K.7=1}}}}3.2c=\'5k\';3.2s=\'3p\';3.2o=\'25\';3.2n=\'2e\';3.5f=\'5e\';3.F=[];A(u i=0;i<3.V;i++){n(3[\'17\'+i]==4)3[\'17\'+i]=(f[\'2q\'+i]==4)?3.2c:f[\'2q\'+i].1a();3.F.1o(3[\'17\'+i])}n(3.18){n(3.F.1g(3.2s)||3.F.1g(3.2o))3.1q.1o(3.d.U.a);n(3.F.1g(3.2n))3.1q.1o(3.d.S.a)}3.K=f!=4&&f.1V!=4?f.1V:5;3.5j=f!=4&&f.5i==5?5:8;3.v=f!=4&&f.5h?8:5;3.5A=5;3.5z=[];3.21=6;n(3.v){n(3.C.23==4)5y();3.21=3.C.23;}3.1d=f!=4&&f.1n!=4?f.1n>1?1:f.1n:0;3.5D=f!=4&&f.2l!=4?(f.2l!=\'2d\'?\'2f\':\'2d\'):\'2f\';3.5C=[];3.5B=[];3.5x=6;3.5t=[];3.5s=6;3.5r=6;3.5w=8;3.5v=6;3.5u=6;3.4m=6;3.3R=6;3.3I=6;3.3M=f!=4&&f.1L!=4?f.1L:\'3P\';3.4b=f!=4&&f.20!=4?f.20:\'48\';3.47=f!=4&&f.2b!=4?f.2b:\'3X\';3.3Y=f!=4&&f.1w!=4?f.1w:\'3V\';3.45=f!=4&&f.1M!=4?f.1M:\'42\';3.1l=f!=4&&f.1l!=4?f.1l:\'41.40\';3.43=3.q+\'46\';3.44=f!=4&&f.3e!=4?f.3e:\'3U\';3.3T=f!=4&&f.3W?8:5;3.3q=f!=4&&f.3z?8:5;3.3Z=f!=4&&3.3q?f.3z:6;3.W=f!=4&&f.4h?8:5;3.4g=f!=4&&f.2w?f.2w:4f;3.4i=f!=4&&f.2A!=4?f.2A:\'2x\';3.4l=f!=4&&f.2N!=4?f.2N:\'4k\';3.4j=f!=4&&f.36!=4?f.36:\'4a\';3.49=f!=4&&f.2S!=4?f.2S:\'4e\';3.4d=8;3.4c=f!=4&&f.2U!=4?f.2U:\'3K\';3.3Q=f!=4&&f.34!=4?f.34:\'3N\';3.3S=f!=4&&f.3L==5?5:8;3.3t=f!=4&&f.3E?8:5;3.3F=3.3t?f.3E:6;3.3G=f!=4&&t(f.3c)?f.3c:6;3.3O=f!=4&&t(f.3h)?f.3h:6;3.3H=f!=4&&f.3J?8:5;3.8E=f!=4&&f.8D?8:5;3.I=f!=4&&f.8C?8:5;3.8F=6;3.8I=6;3.8H=f!=4&&f.8G?8:5;3.8B=6;3.2H=f!=4&&f.2M?8:5;3.8w=3.2H?f.2M:[];3.8v=f!=4&&f.2C!=4?f.2C:\'8u\';3.8x=f!=4&&f.8A?8:5;3.8z=f!=4&&f.2W!=4?f.2W:6;3.8y=[];3.8T=f!=4&&f.2T?8S(f.2T):8R;3.2X=f!=4&&f.2X?8:5;3.8U=f!=4&&t(f.2O)?f.2O:6;3.8X=f!=4&&f.8W?8:5;3.8V=f!=4&&t(f.37)?f.37:6;3.8Q=f!=4&&f.2Y?f.2Y:[];3.8L=f!=4&&t(f.31)?f.31:6;3.8K=f!=4&&f.R!=4?f.R:\'\';3.8J=f!=4&&f.2z!=4?f.2z:\'8M\';3.8P=f!=4&&f.R!=4?(8O(f.R)?8:5):5;3.8N=f!=4&&f.2B!=4?f.2B:6;3.Q=f!=4&&(f.2u!=4)?f.2u:6;3.G=f!=4&&f.2t!=4?f.2t:5;n(3.G)(!3.v)?3.1d=0:3.1d=1;3.8a=f!=4&&f.2K!=4?f.2K:5;3.89=f!=4&&f.2E!=4?f.2E:\'88\';3.8b=f!=4&&t(f.3v)?f.3v:6;3.8e=f!=4&&t(f.3y)?f.3y:6;3.8d=f!=4&&f.3s!=4?f.3s:\'\';3.8c=f!=4&&f.87?8:5;3.82=f!=4&&f.3B!=4?f.3B:\'(81)\';3.80=f!=4&&f.83?8:5;3.86=f!=4&&f.3a!=4?f.3a:\'(85 2a)\';3.84=f!=4&&f.8p==5?5:8;3.8o=f!=4&&f.8n==5?5:8;3.1s=f!=4&&f.1r?8:5;3.8q=3.1s?f.1r:6;3.1K=f!=4&&f.1H?8:5;3.8t=3.1K?f.1H:6;3.8s=f!=4&&f.1J!=4?f.1J:\'8r\';3.8m=f!=4&&f.8h?8:5;3.8g=f!=4&&f.2h!=4?f.2h:\'1C 1z 8f\';3.8i=f!=4&&f.1R!=4?f.1R:\'8l 8k 8j A 25 8Y\';3.9B=f!=4&&f.N&&1A(f.N)?8:5;3.9A=f!=4&&f.N!=4?f.N:6;3.9z=f!=4&&t(f.1I)?f.1I:6;3.9C=f!=4&&t(f.1y)?f.1y:6;3.9F=[];3.9E=f!=4&&f.1Q!=4?f.1Q:\'9D\';3.9u=f!=4&&f.1D!=4?f.1D:\'9t\';3.9s=f!=4&&f.1O!=4?f.1O:\'9v\';3.9y=f!=4&&f.1F!=4?f.1F:\'9x\';3.9w=f!=4&&f.1u!=4?f.1u:\'1C 1z 2g Y\';3.9N=f!=4&&f.2i!=4?f.2i:\'[2a]\';3.9P=f!=4&&f.2r!=4?f.2r:\'[9Q]\';3.9I=f!=4&&f.1W!=4?f.1W:\'||\';3.9O=f!=4&&f.29!=4?f.29:\'&&\';3.9G=f!=4&&f.2j!=4?f.2j:\'>\';3.9J=f!=4&&f.24!=4?f.24:\'<\';3.9M=f!=4&&f.22!=4?f.22:\'<=\';3.9L=f!=4&&f.28!=4?f.28:\'>=\';3.9K=f!=4&&f.26!=4?f.26:\'!\';3.9H=f!=4&&f.27!=4?f.27:\'*\';3.98=f!=4&&f.1T!=4?f.1T:\'=\';3.97=f!=4&&f.1U!=4?f.1U:\'{\';3.96=f!=4&&f.1S!=4?f.1S:\'}\';3.99=f!=4&&f.1Y!=4?f.1Y:\'^[¥£€$]\';3.1j=f!=4&&f.1j!=4?f.1j:\',\';3.J=f!=4&&f.9c?8:5;3.O=f!=4&&f.1Z?f.1Z:5;3.z=f!=4&&f.z?8:5;3.9b=f!=4&&f.2v?8:5;3.9a=f!=4&&f.1X!=4?f.1X:\'91\';3.90=f!=4&&f.2m!=4?f.2m:\'8Z\';3.92=f!=4&&f.95?8:5;3.94=f!=4&&f.2k!=4?f.2k:\'93\';3.x=f!=4&&f.x?8:5;3.9d=f!=4&&f.9n?8:5;3.9m=f!=4&&f.2p!=4?f.2p:\'9l\';3.9o=6;3.9r=6;3.9q=6;3.9p=5;3.9g=0;3.9f=0;3.9e=0;3.9h=0;3.9k=1;3.D=f!=4&&f.D?8:5;3.9j=5;3.9i=5;3.r=f!=4&&f.c!=4?f.c:{};3.r.a=f!=4&&f.c!=4&&f.c.a?f.c.a:\'1e\';3.r.16=f!=4&&f.c!=4&&f.c.16?f.c.16:\'1e.g\';3.r.7Z=f!=4&&f.c!=4&&f.c.1B?f.c.1B:\'6I.1e.g\';3.r.19=f!=4&&f.c!=4&&f.c.19?f.c.19:b(o){n(o.1G)o.1G()};3.r.6H=f!=4&&f.c!=4&&f.c.1P?f.c.1P:[];3.r.6G=f!=4&&f.c!=4&&f.c.1N!=4?f.c.1N:6;3.r.6J=f!=4&&f.c!=4&&f.c.6M?8:5;3.r.6L=f!=4&&f.c!=4&&f.c.1E?f.c.1E:[];3.6K=f!=4&&f.6B?8:5;3.6A=f!=4&&f.1v!=4?f.1v:6z;3.6C=6;3.6F=4;3.X=f!=4&&f.6E?8:5;3.6D=f!=4&&f.1x!=4?f.1x:\'6N\';3.6X=f!=4&&f.3j!=4?f.3j:\'6W\';3.6V=f!=4&&f.3k!=4?f.3k:\',\';3.6Y=f!=4&&f.3i!=4?f.3i:\'.\';3.3l=f!=4&&f.3o?8:5;3.71=f!=4&&3.3l?f.3o:6;3.3m=f!=4&&f.3n?8:5;3.70=f!=4&&3.3m?f.3n:6;3.6Z=f!=4&&f.3b!=4?f.3b:\'6Q Y...\';3.6P=f!=4&&f.39!=4?f.39:\'3d 6O...\';3.6R=f!=4&&f.3g!=4?f.3g:\'3d 6U...\';3.6T=f!=4&&f.3C!=4?f.3C:\'6S x Y...\';3.6y=f!=4&&f.3D!=4?f.3D:\'6e E...\';3.6d=f!=4&&f.3u!=4?f.3u:\'6c 6f 6i 1f...\';3.6h=f!=4&&f.3x!=4?f.3x:\'10-1c E 15...\';3.6g=f!=4&&f.3w!=4?f.3w:\'10-1c 1f...\';3.67=f!=4&&f.2G!=4?f.2G:\'10-1c 1f y...\';3.66=f!=4&&f.2D!=4?f.2D:\'65 Y...\';3.68=f!=4&&f.2L!=4?f.2L:\'2J M...\';3.6b=f!=4&&f.2I!=4?f.2I:\'2J 6a(s)...\';3.69=\'12\';3.6j=\'2x\';3.6t=\'2v\';3.6s=\'6r\';3.6u=\'6x\';3.6w=\'6v\';3.6m=\'6l\';3.6k=\'6n\';3.6q=\'6p\';3.6o=\'7F\';3.7E=\'7D\';3.7G=\'7J\';3.7I=\'7H\';3.7y=\'7x\';3.7w=\'7z\';3.7C=\'7B\';3.7A=\'7K\';3.7U=\'7T\';3.7S=\'7V\';3.7Y=\'7X\';3.7W=\'7N\';3.7M=\'7L\';3.7O=\'7R\';3.7Q=\'7P\';3.7v=\'7b\';3.7a=\'79\';3.7c=\'7f\';3.7e=\'7d\';3.74=\'73\';3.72=\'75\';3.78=\'77\';3.76=\'7g\';3.7q=\'7p\';3.7o=\'7r\';3.7u=\'7t\';3.7s=\'7j\';3.7i=\'7h\';3.7k=\'7n\';3.7m=\'7l\';',62,611,'|||this|undefined|false|null|loaded|true||name|function|sort_config|module|||js|modulesPath||path|init|desc|feature|if||arguments|id|sortConfig||tf_IsFn|var|gridLayout|cTblId|paging|length|loader|for|cookies|tbl|sort|filters|fltCol|popUpFilters|window|refreshFilters|rowsCounter|publicMethods|startRow|extensions|custom_slc_options|statusBar|config|helpInstructions|input_watermark|populateCheckList|return|populateSelect|nbCells|fixedHeaders|highlightKeywords|data|fObj|Re|resetBtn|TF|cTbl|tbls|values|src|col|enableModules|initialize|tf_LCase|themes|setting|filtersRowIndex|sortabletable|page|tf_Has|refRow|tf_|separator|colOps|stylesheet|alternateRows|filters_row_index|push|watermark|registeredModules|sort_num_asc|isSortNumAsc|loading|activate_checklist_text|on_keyup_delay|middle_div_css_class|highlight_css_class|on_after_operation|to|tf_IsObj|adapter_src|Click|checklist_css_class|sort_trigger_ids|checklist_selected_item_css_class|SetSortTable|sort_num_desc|on_before_operation|slc_filling_method|isSortNumDesc|inf_div_css_class|content_div_css_class|sort_col|checklist_item_css_class|sort_types|div_checklist_css_class|multiple_slc_tooltip|end_with_operator|equal_operator|start_with_operator|public_methods|or_operator|btn_text|cur_exp|status_bar|left_div_css_class|sourceTblHtml|lower_equal_operator|outerHTML|lower_operator|multiple|different_operator|like_operator|greater_equal_operator|and_operator|empty|right_div_css_class|fltTypeInp|th|checklist|td|load|activate_slc_tooltip|empty_operator|greater_operator|btn_reset_css_class|filters_cell_tag|btn_css_class|fltTypeCheckList|fltTypeMulti|paging_btn_css_class|col_|nonempty_operator|fltTypeSlc|popup_filters|help_instructions|btn|tbody_height|flt|_config|input_watermark_css_class|flt_css_class|toolbar_target_id|search_type|msg_sort|active_columns_css_class|document|msg_reset_page_length|hasVisibleRows|msg_load_themes|Loading|mark_active_columns|msg_load_extensions|rows_always_visible|flt_multi_css_class|on_filters_loaded|argtype|case|break|single_flt_css_class|exec_delay|even_row_css_class|table|external_flt_grid_ids|status|custom_cell_data_cols|modules_path|Builds|custom_cell_data|type|setFilterGrid|odd_row_css_class|GetCellsNb|flt_small_css_class|on_row_validated|tf_resetBtn|msg_populate|non_empty_text|msg_filter|on_before_filter|Populating|flts_row_css_class|Remember|msg_populate_checklist|on_after_filter|decimal_separator|default_date_type|thousands_separator|hasColNbFormat|hasColDateType|col_date_type|col_number_format|select|hasColWidth|initFilterGrid|display_all_text|isModFilterFn|msg_change_results|on_before_active_column|msg_reset_page|msg_reset_grid_values|on_after_active_column|col_width|tf_isNotIE|empty_text|msg_change_page|msg_clear|mod_filter_fn|modFilterFn|onBeforeFilter|matchCase|contDiv|match_case|even|enter_key|infDivCssClass|odd|onAfterFilter|inf|rowBgOddCssClass|mDiv|enterKey|alternateBgs|fltrow|mdiv|alternate_rows|rdiv|mDivCssClass|colWidth|css|filtergrid|cont|stylesheetId|fltsRowCssClass|contDivCssClass|_style|rDivCssClass|ldiv|singleFltCssClass|flt_s|lDivCssClass|rowBgEvenCssClass|isStartBgAlternate|single_flt|200|tBodyH|fixed_headers|fltCssClass|fltSmallCssClass|flt_multi|fltMultiCssClass|rDiv|layout|Grid|tf_populateCheckList|tf_paging|Paging|tf_gridLayout|tf_populateSelect|catch|try|object|TF_Modules|importedModules|alreadyImportedModules|tf_themes|Themes|tf_popupFilters|tf_colOps|operations|Columns|container|Filters|tf_sort|Sort|up|pop|in|number|getElementsByTagName|DOMContentLoaded|tf_AddEvent|tf_HasClass|getAttribute|tf_Tag|userAgent|msie|AddGrid|new|navigator|test|MSIE|nodeName|hasGrid|nbRows|switch|typeof|GetRowsNb|nbFilterableRows|_isUnob|else|filterable|headersRow|tf_Id|version|none|fltTypeNone|eval|grid_layout|grid|fltGrid|input|public|Additional|tf_watermark|tf_publicMethods|developers|methods|fltGridEl|validRowsIndex|tblData|lDiv|infDiv|isFirstLoad|searchArgs|tf_SetOuterHtml|gridColElms|hasGridWidthsRow|fltElms|fltIds|fltCellTag|Watermark|Status|tf_loader|Loader|Reset|tf_statusBar|bar|tf_rowsCounter|Deprecated|headers|Fixed|counter|Rows|tf_fixedHeaders|Refresh|tf_highlightKeywords|tf_cookies|tf_extensions|Extensions|tf_refreshFilters|tf_alternateRows|About|Help|button|color|rows|Alternating|Sorting|msgSort|msgResetPageLength|msgLoadExtensions|prfxTf|theme|msgLoadThemes|Changing|msgChangeResults|Clearing|results|msgResetPage|msgResetValues|per|prfxFlt|prfxContentDiv|mdiv_|prfxMDiv|cont_|prfxSlcPages|chkdiv_|prfxCheckListDiv|inf_|prfxInfDiv|prfxValButton|prfxLDiv|rdiv_|prfxRDiv|ldiv_|msgClear|900|onKeyUpDelay|on_keyup|isUserTyping|highlightCssClass|highlight_keywords|onKeyUpTimer|sortCol|sortTypes|tfAdapter|asyncSort|onKeyUp|triggerIds|async_sort|keyword|filter|msgPopulate|Filtering|msgPopulateCheckList|Collecting|msgChangePage|list|thousandsSeparator|DMY|defaultDateType|decimalSeparator|msgFilter|colDateType|colNbFormat|prfxStatusSpan|status_|prfxStatus|statusSpan_|prfxCookieFltsValues|statusText_|prfxStatusTxt|totRowsTextSpan_|prfxTotRowsTxt|totrows_span_|prfxResetSpan|load_|prfxLoader|resetspan_|tf_flts_|tblHeadCont_|prfxHeadTblCont|tblCont_|prfxHeadTbl|_td_|prfxGridFltTd|tblHead_|prfxCookiePageLen|tf_pgnb_|prfxCookiePageNb|tf_pglen_|prfxTblCont|gridCont_|prfxMainTblCont|prfxTotRows|prfxBtnLastSpan|btnPrevSpan_|prfxBtnPrevSpan|btnLastSpan_|prfxBtnNext|btnFirstSpan_|prfxBtnFirstSpan|slcResults_|prfxSlcResults|slcPages_|prfxSlcResultsTxt|btnNextSpan_|prfxBtnNextSpan|slcResultsTxt_|btnNext_|pgbeforespan_|prfxPgBeforeSpan|pgspan_|prfxPgAfterSpan|counter_|prfxCounter|pgafterspan_|prfxBtnLast|btnPrev_|prfxBtnPrev|btnLast_|prfxPgSpan|btnFirst_|prfxBtnFirst|adapterSrc|enableNonEmptyOption|Empty|emptyText|enable_non_empty_option|onSlcChange|Non|nonEmptyText|enable_empty_option|activeHeader|activeColumnsCssClass|markActiveColumns|onBeforeActiveColumn|enableEmptyOption|displayAllText|onAfterActiveColumn|activate|activateSlcTooltip|fill_slc_on_demand|multipleSlcTooltip|key|Ctrl|Use|fillSlcOnDemand|sort_select|sortSlc|on_change|sortNumAsc|createElement|slcFillingMethod|sortNumDesc|include|searchType|visibleRows|isExternalFlt|externalFltEls|externalFltTgtIds|external_flt_grid|colOperation|refresh_filters|exact_match|exactMatch|activeFlt|col_operation|hasColOperation|activeFilterId|inpWatermarkCssClass|inpWatermark|customCellData|fltWatermark|toolBarTgtId|tf_IsArray|isInpWatermarkArray|customCellDataCols|100|parseInt|execDelay|onFiltersLoaded|onRowValidated|single_search_filter|singleSearchFlt|selections|btnflt|btnCssClass|go|btnReset|reset|btnResetCssClass|btn_reset|enOperator|stOperator|eqOperator|curExp|btnText|displayBtn|rows_counter|hasResultsPerPage|startPagingRow|nbHiddenRows|nbVisibleRows|nbPages|sorted|isSortEnabled|currentPageNb|pgInp|btnPageCssClass|results_per_page|pagingSlc|isPagingRemoved|resultsPerPageSlc|resultsPerPage|checkListItemCssClass|flt_checklist|checkListCssClass|flt_checklist_item|activateCheckListTxt|flt_checklist_slc_item|checkListSlcItemCssClass|onBeforeOperation|customSlcOptions|hasCustomSlcOptions|onAfterOperation|div_checklist|checkListDivCssClass|checkListDiv|grOperator|lkOperator|orOperator|lwOperator|dfOperator|geOperator|leOperator|emOperator|anOperator|nmOperator|nonempty'.split('|'),0,{}))
_IsValidDate(dateStr,format); }
function tf_formatDate(dateStr,format){ return tf_FormatDate(dateStr,format); }
function tf_removeNbFormat(data,format){ return tf_RemoveNbFormat(data,format); }
/* --- */

