

	var _starttime;
	function starttimer() {
		_starttime = new Date();
	}
	function stoptimer() {
		alert(new Date()-_starttime);
	}


	function SortableTableWithInterface() {
	
	// 	----------------------
	//  'CONSTRUCTOR'
	// 	----------------------
	//  used in this.sortData
		this.__sort_rating_arr = {};
		var letters = ['a','b','c','d','e','f'];
		var numbers = [3,2,1];
		var modifiers = ['+','1','','2','-','3']; // + for s&p, 123 for fitch. moodys doesn't have a modifier
		var c=0;
		for (var l=0;l<letters.length;l++) {
			var letter = letters[l];
			for (var n=0;n<numbers.length;n++) {
				var number = numbers[n];
				for (var m=0;m<modifiers.length;m++) {
					var modifier = modifiers[m];
					var k = '';
					for (var i=0;i<number;i++) k += letter;
					k += modifier;
					this.__sort_rating_arr[k] = c;
					c++;
				}
			}
		}
		
	// 	----------------------
		this.manageCheckBoxGroup = function(_checkbox) {
	// 	----------------------
			var checkboxes = document.forms['stwi-form'][_checkbox.name];
			if ('all' == _checkbox.value) {
				for (var c=0; c<checkboxes.length; c++) {
					var checkbox = checkboxes[c];
					if ('all' == checkbox.value) {
						checkbox.checked = true;
					} else {
						checkbox.checked = false;
					}
				}
			} else {
				var at_least_one_checked = false;
				for (var c=0; c<checkboxes.length; c++) {
					var checkbox = checkboxes[c];
					if ('all' != checkbox.value && checkbox.checked) {
						at_least_one_checked = true;
					}
				}
				var id = _checkbox.id.replace(/^([^\-]+\-[^\-]+\-).+$/,'$1') + 'all';
				document.getElementById(id).checked = !at_least_one_checked;
			}
		}
				
	// 	----------------------
		this.createInterface = function() {
	// 	----------------------
			var s = '';
			s += '<div id="stwi-inner">'; // using inner instead of form, cos form background renders a little funni
			s += '<h3>'+stwi_filter_title+'</h3>';
			s += '<form id="stwi-form" name="stwi-form" onsubmit="return false;">';
			for (var c=0; c<filter_cols.length; c++) {
				var filter_col = filter_cols[c];
				s += '<fieldset>';
				var clas = 0==c ? ' class="first"' : '';
				s += '<h4'+clas+'>'+filter_col.label+'</h4>'; // legend tag can't do bg colour 100% width.
				if (filter_col.type == 'select') {
					s += '<div class="checkbox-row">';
					s += '<label style="display:none;" for="'+filter_col.name+'">'+filter_col.label+'</label>'; // just for accesibility
					s += '<select id="'+filter_col.name+'" name="'+filter_col.name+'">';
					for (var o=0; o<filter_col.options.length; o++) {
						var option = filter_col.options[o];
						var selected = '';
						try {
							// this is here purely for the providers selector
							if (option.selected) selected = ' selected="selected"';
						} catch(e) {
							// no worries
						}
						s += '<option value="'+option.value+'"'+selected+'>'+option.label+'</option>';
					}
					s += '</select></div>';
				} else if (filter_col.type == 'checkbox') {
					s += '<div class="checkbox-con">';
					for (var o=0; o<filter_col.options.length; o++) {
						var option = filter_col.options[o];
						var iden = 'checkbox-'+filter_col.name+'-'+option.value;
						var checked = option.value == 'all' ? 'checked="checked"' : '';
						s += '<div class="checkbox-row"><input type="checkbox" id="'+iden+'" name="'+filter_col.name+'" value="'+option.value+'" '+checked+' onclick="sortable_table_with_interface.manageCheckBoxGroup(this);"/>';
						s += '<label class="right" for="'+iden+'">'+option.label+'</label></div>';
					}
					s += '</div>';
				}
				s += '</fieldset>';
			}
			s += '<fieldset class="button-container"><button onclick="sortable_table_with_interface.handleRefineButton();">Refine &gt;&gt;</button></fieldset>';
			s += '</form>';
			s += '</div>';
			var vc = $('verticalcontainer');
			var pn = vc.parentNode;
			var ns = vc.nextSibling;
			var div = document.createElement('div');
			div.id = 'stwi-div';
			div.innerHTML = s;
			if (ns) {
				pn.insertBefore(div,ns);
			} else {
				pn.appendChild(div);
			}
		    $('js-intro-target').innerHTML = stwi_intro;
		}
	
	// 	----------------------
		this.createSortableColumns = function() {
	// 	----------------------
			var ths = YAHOO.util.Dom.getElementsByClassName('sortable');
			for (var h=0;h<ths.length;h++) {
				var th = ths[h];
				var label = th.firstChild.nodeValue;
				th.removeChild(th.firstChild);
				var a = document.createElement('a');
				a.href = ' ';
				a.id = 'sortable-a-'+th.getAttribute('xname');
				a.setAttribute('xsortdir','1'); // -1 for reverse, used internally, don't set explicit!
				a.setAttribute('xflip',th.getAttribute('xarrow')=='up'?'1':'-1');
				a.setAttribute('xsorton',th.getAttribute('xname'));
				a.setAttribute('xnullgood',th.getAttribute('xnullgood')=='1'?'-1':'1');
				var text = '';
				var name = th.getAttribute('xname');
				text = 'Click here to sort by ' + label;
				new YAHOO.widget.Tooltip('avatar_tooltip_'+h, { 
					context:'sortable-a-'+th.getAttribute('xname'), 
					text:text,
					showDelay:0,
					hidedelay:0,
					autodismissdelay:99999,
					effect:{effect:YAHOO.widget.ContainerEffect.FADE,duration:0.18}
				});
				var thiz = this;
				a.onclick = function() {
					try {
						thiz.handleColumnSortButton(this);
						return false;
					} catch (e) {
						return false;
					}
				};
				a.appendChild(document.createTextNode(label));
				var img = document.createElement('img');
				img.src = ROOT_PATH + 'img/sort-arrow-'+th.getAttribute('xarrow')+'.gif';
				img.align = 'bottom';
				img.style.display = a.getAttribute('xsorton')==this.last_sort_on ? 'inline' : 'none';
				a.appendChild(img);
				th.appendChild(a);
			}
		}
	
	// 	----------------------
		this.onRefine = function() { // callback, used for term deposits
	// 	----------------------
		}
	
	// 	----------------------
		this.handleRefineButton = function() {
	// 	----------------------
			this.filterData(false);
			this.onRefine();
		}
		
		this.last_sort_on = 'name';
	// 	----------------------
		this.handleColumnSortButton = function(_a) {
	// 	----------------------
		// RESET ALL ARROWS
			var ths = YAHOO.util.Dom.getElementsByClassName('sortable');
			for (var h=0;h<ths.length;h++) {
				var th = ths[h];
				var img = th.getElementsByTagName('img')[0];
				var a = th.getElementsByTagName('a')[0];
				if (a.getAttribute('xsorton') != _a.getAttribute('xsorton') || a.getAttribute('xsorton') != this.last_sort_on) {
					a.setAttribute('xsortdir',1);
					img.src = ROOT_PATH + 'img/sort-arrow-'+th.getAttribute('xarrow')+'.gif';
					img.style.display = 'none';
				}
			}
		// TOGGLE CURRENT ARROW
			var img = _a.getElementsByTagName('img')[0];
			if (_a.getAttribute('xsorton') == this.last_sort_on) {
				_a.setAttribute('xsortdir',_a.getAttribute('xsortdir')=='1'?'-1':'1'); // flipping before so refine button works
				img.src = img.src.match(/up/) ? img.src.replace('up','down') : img.src.replace('down','up');
			}
			img.style.display = 'inline';
			this.filterData(_a.getAttribute('xsorton'));
			this.last_sort_on = _a.getAttribute('xsorton');
		}
		
	// 	----------------------
		this.filterData = function(_sort_on) {
	// 	----------------------
			var sort_on = _sort_on ? _sort_on : this.last_sort_on;
			var data_filtered;
			try {
				// this block is a hack for providers / term-deposits
				var amount = document.forms['stwi-form']['providers_amount'].value;
				data_filtered = data_providers[amount];
			} catch (e) {
				data_filtered = data;
			}
			for (var c=0; c<filter_cols.length; c++) {
				var filter_col = filter_cols[c];
				if ('sort' !== filter_col.name && 'providers_amount' !== filter_col.name) {
					data_filtered = this.filterDataOnKey(filter_col.name,this.getFormValues(filter_col.name),data_filtered);
				}
			}
			this.sortData(data_filtered,sort_on);
			this.createTable(data_filtered);
		}
	
	// 	----------------------
		this.filterDataOnKey = function(_column_name,_values,_data_filtered) {
	// 	----------------------
			var data_filtered = [];
			for (var d=0; d<_data_filtered.length; d++) {
				var r = _data_filtered[d];
				for (var v=0;v<_values.length;v++) {
					var value = _values[v];
					if (value === 'all' || r[_column_name].toLowerCase() == value.toLowerCase()) {
						data_filtered.push(r);
					}
				}
			}
			return data_filtered;
		}
	
	// 	----------------------
		this.getFormValues = function(_name) {
	// 	----------------------
			var elements = document.forms['stwi-form'][_name];
			if (elements.value) { // select
				return [elements.value];
			} else { // checkboxes
				var a = [];
				for (var e=0;e<elements.length;e++) {
					var element = elements[e];
					if (element.checked) {
						a.push(element.value);
					}
				}
				return a;
			}
		}
		
	// 	----------------------
		this.sortData = function(_data_filtered,_sort_on) { // _sort_on used for dynamic sortable columns
	// 	----------------------
			var null_good = Number($('sortable-a-'+_sort_on).getAttribute('xnullgood'));
			var sort_dir = Number($('sortable-a-'+_sort_on).getAttribute('xsortdir'));
			var flip = Number($('sortable-a-'+_sort_on).getAttribute('xflip'));
			var sort_rating_arr = this.__sort_rating_arr; // need to define here for sort fn scope
			var __sort_number = function(_a,_b) {
				if (_a[_sort_on] == '-' && _b[_sort_on] == '-') return __sort_on_name(_a,_b);
				if (_a[_sort_on] == '-') return 1*null_good;
				if (_b[_sort_on] == '-') return -1*null_good;
				var c = Number(_a[_sort_on].replace(/[^0-9]/g,"")) - Number(_b[_sort_on].replace(/[^0-9]/g,""));
				return c != 0 ? c*sort_dir*flip : __sort_on_name(_a,_b);
			}
			var __sort_string = function(_a,_b) {
				if (_a[_sort_on] == '-' && _b[_sort_on] == '-') return __sort_on_name(_a,_b);
				if (_a[_sort_on] == '-') return 1*null_good;
				if (_b[_sort_on] == '-') return -1*null_good;
				return _a[_sort_on].toLowerCase() == [_a[_sort_on].toLowerCase(),_b[_sort_on].toLowerCase()].sort()[0] ? -1*sort_dir*flip : 1*sort_dir*flip;
			}
			var __sort_rating = function(_a,_b) {
				if (_a[_sort_on] == 'NR' && _b[_sort_on] == 'NR') return __sort_on_name(_a,_b);
				if (_a[_sort_on] == 'NR') return 1;
				if (_b[_sort_on] == 'NR') return -1;
				var rating_a = sort_rating_arr[_a[_sort_on].replace(/^(.*) .*$/,'$1').toLowerCase()];
				var rating_b = sort_rating_arr[_b[_sort_on].replace(/^(.*) .*$/,'$1').toLowerCase()];
				var c = rating_a - rating_b;
				return c != 0 ? (c<0?-1:1)*sort_dir : __sort_on_name(_a,_b); 
			}
			var sort_dir_name = _sort_on == 'name' ? sort_dir : Number($('sortable-a-name').getAttribute('xsortdir'));
			var __sort_on_name = function(_a,_b) {
				return _a.name.toLowerCase() == [_a.name.toLowerCase(),_b.name.toLowerCase()].sort()[0] ? -1*sort_dir_name : 1*sort_dir_name;
			}
			var fn;
			if (_sort_on.match(/_(perc|cur)$/) || _sort_on.match(/^feedrate_/)) {
				fn = __sort_number;
			} else if (_sort_on == 'rating') {
				fn = __sort_rating;
			} else {
				fn  = __sort_string;
			}
			_data_filtered.sort(fn);
		}
	
		
		// IE7 - 190, FF 200, 219
	// 	----------------------	
		this.createTable = function(_data_filtered) {
	// 	----------------------
			var tbody = $('div-target').getElementsByTagName('tbody')[0];
			while (tbody.firstChild) tbody.removeChild(tbody.firstChild);
			if (_data_filtered.length == 0) {
				var tr = document.createElement('tr'); 
				tbody.appendChild(tr);
				tr.className = 'no-records-found';
				tr.colspan = data_cols.length;
				var td = document.createElement('td');
				tr.appendChild(td);
				td.appendChild(document.createTextNode(stwi_no_results));
			} else {
				for (var d = 0; d < _data_filtered.length; d++) {
					var row = _data_filtered[d];
					var clas = d%2==1 ? 'one' : 'two';
					var tr = document.createElement('tr');
					tbody.appendChild(tr);
					tr.className = clas;
					for (var c = 0; c < data_cols.length; c++) {
						var data_col = data_cols[c];
						var value = row[data_col.key];
						var td = document.createElement('td');
						tr.appendChild(td);
						if (c==0) td.style.textAlign = 'left';
						td.appendChild(document.createTextNode(value));
					}
					if ($('more_th')) { // hacked in for credit cards "additional information"
						var td = document.createElement('td');
						tr.appendChild(td);
						td.id = 'more_td_'+row.id;
						var span = document.createElement('span');
						td.appendChild(span);
						span.className = 'showMoreLink';
						var a = document.createElement('a');
						span.appendChild(a);
						a.href = 'javascript:showMore('+row.id+');';
						a.appendChild(document.createTextNode('more info'));
					}
				}
			}
		}
		
		
	}

