function create_option_element(val, id_prefix, opt_text) {
	var opt = document.createElement("option");
	opt.value = val;
	var postfix = "";
	if (val == -1) {
		// Otherwise we might have two elements with the same id.
		postfix = Math.random();
	}
	opt.id = id_prefix + val + postfix;
	opt.text = opt_text;
	return opt;
}

function reinitialise_subsets() {
	for (var i = 0; i < num_prefs; i++) {
		formatted_data[i] = [];
	}
}

function change_table_type() {
	make_type_specific_selectors();
	reset_tables();
}

function calculate_pref_table_col(col) {
	// Assumes that pref_table_data[col] already exists.
	
	var i, j, k, this_votes, this_group, sel, first_i;
	var table_type = get_table_type();
	
	pref_table_data[col] = [];
	
	// Initialise this column of the pref table data:
	for (i = 0; i < groups.length; i++) {
		pref_table_data[col].push([]);
		
		// First element of the array is the group:
		pref_table_data[col][i].push(i);
		
		// Then votes by division, then percentages, and total percentages:
		pref_table_data[col][i].push([]);
		pref_table_data[col][i].push([]);
		pref_table_data[col][i].push([]);
		
		for (j = 0; j < divs.length; j++) {
			pref_table_data[col][i][1].push(0);
			pref_table_data[col][i][2].push(0);
			pref_table_data[col][i][3].push(0);
		}
	}
	
	// Initialise an array to hold the sum of votes by division.
	var sum_votes = [];
	for (i = 0; i < formatted_data[col][0][1].length; i++) {
		sum_votes.push(0);
	}
	
	var use_formatted = false;
	if (table_type == "step_forward") { use_formatted = true; }
	if (table_type == "prefs_from_primary") {
		sel = document.getElementById("select_first_n");
		first_i = +sel.options[sel.selectedIndex].value;
		
		if (col < first_i) {
			use_formatted = true;
		}
	}
	
	// Tally the votes.
	for (i = 0; i < formatted_data[col].length; i++) {
		// Looping over each set of preferences.
		
		for (j = 0; j < formatted_data[col][i][1].length; j++) {
			// Looping over each division.
			
			if (use_formatted) {
				this_votes = formatted_data[col][i][1][j];
				this_group = formatted_data[col][i][0][col];
				if (this_group < 0) { this_group = groups.length - 1; }
				
				pref_table_data[col][this_group][1][j] += this_votes;
			} else if (table_type == "first_n_prefs") {
				this_votes = formatted_data[col][i][1][j];
				
				var max_k = get_first_n();
				
				if (formatted_data[col][i][0].length < max_k) {
					max_k = formatted_data[col][i][0].length;
				}
				
				for (k = 0; k < max_k; k++) {
					this_group = formatted_data[col][i][0][k];
					if (this_group < 0) { this_group = groups.length - 1; }
					
					if (selected_groups.indexOf(this_group) < 0) {
						pref_table_data[col][this_group][1][j] += this_votes;
					}
				}
			} else if (table_type == "prefs_from_primary") {
				// We must be in the "later preferences" part of the table,
				// because if we're in the early columns, use_formatted == true.
				
				this_votes = formatted_data[col][i][1][j];
				
				var max_k = get_upto_n();
				
				if (formatted_data[col][i][0].length < max_k) {
					max_k = formatted_data[col][i][0].length;
				}
				
				for (k = 0; k < max_k; k++) {
					this_group = formatted_data[col][i][0][k];
					if (this_group < 0) { this_group = groups.length - 1; }
					
					if (selected_groups.indexOf(this_group) < 0) {
						pref_table_data[col][this_group][1][j] += this_votes;
					}
				}
			} else if (table_type == "primaries_from_prefs") {
				var min_k = get_first_n();
				var max_k = get_upto_n();
				this_votes = formatted_data[col][i][1][j];
				
				if (formatted_data[col][i][0].length < max_k) {
					max_k = formatted_data[col][i][0].length;
				}
				
				if (col == 0) {
					for (k = min_k - 1; k < max_k; k++) {
						this_group = formatted_data[col][i][0][k];
						if (this_group < 0) { this_group = groups.length - 1; }
						
						pref_table_data[col][this_group][1][j] += this_votes;
					}
				} else {
					// Looking for primary votes.
					this_group = formatted_data[col][i][0][0];
					if (this_group < 0) { this_group = groups.length - 1; }
					
					pref_table_data[col][this_group][1][j] += this_votes;
				}
				
			} else if (table_type == "bidirectional") {
				
			}
			
			sum_votes[j] += this_votes;
		}
	}
	
	// Calculate the percentages.
	for (i = 0; i < pref_table_data[col].length; i++) {
		for (j = 0; j < pref_table_data[col][i][1].length; j++) {
			if (sum_votes[j] > 0) {
				pref_table_data[col][i][2][j] = 100 * pref_table_data[col][i][1][j] / sum_votes[j];
			} else {
				pref_table_data[col][i][2][j] = 0;
			}
			
			pref_table_data[col][i][3][j] = 100 * pref_table_data[col][i][1][j] / total_votes[j];
			
			pref_table_data[col][i][2][j] = pref_table_data[col][i][2][j].toFixed(2);
			pref_table_data[col][i][3][j] = pref_table_data[col][i][3][j].toFixed(2);
		}
	}
}

function right_most_col() {
	var col = selected_groups.length;
	var table_type = get_table_type();
	
	if ((selected_groups[col - 1] < 0) || (selected_groups[col - 1] == groups.length - 1)) {
		// Is "exhaust" -1 or the last entry?  It's one of the two....
		col--;
	}
	
	if ((table_type == "step_forward") || (table_type == "first_n_prefs")) {
		if (col == num_prefs) {
			col--;
		}
	}
	
	if (table_type == "first_n_prefs") {
		if (col == get_first_n()) {
			col--;
		}
	}
	
	if (table_type == "prefs_from_primary") {
		if (col == get_upto_n()) {
			col--;
		}
	}
	
	if (table_type == "primaries_from_prefs") {
		if (col == 2) {
			col = 1;
		}
	}
	
	return col;
}


function change_type() {
	var type_i = document.getElementById("select_type").selectedIndex + 1;
	var this_division_i = document.getElementById("select_division").selectedIndex;
	var this_group, this_group_name;
	
	var end_i = right_most_col();
	
	for (var i = 0; i <= end_i; i++) {
		for (var j = 0; j < pref_table_data[i].length; j++) {
			this_group = pref_table_data[i][j][0];
			if (this_group < 0) { this_group = groups.length - 1; }
			this_group_name = groups[this_group];
			
			if ((pref_table_data[i][j][1][this_division_i] == 0) && !((this_group_name == "Exh") && (i == 0))) {
				// No number present, no change.
			} else {
				try {
					document.getElementById("span_" + i + "_" + j).innerHTML = pref_table_data[i][j][type_i][this_division_i];
				} catch(err) {
					console.log(err);
					console.log([i, j, pref_table_data[i][j][1][this_division_i]].join());
					asdf = asdfasdf();
				}
			}
		}
	}
	
	update_divisions_table(true);
}

function change_division() {
	reprint_pref_table(1);
}


function reset_tables() {
	selected_groups = [];
	selected_rows = [];
	initialise_table_area();
	initialise_division_table();
	
	for (var i = 0; i < divs.length; i++) {
		document.getElementById("td_divs_votes_" + i).innerHTML = "&nbsp;";
	}
	document.getElementById("span_division_table_title").innerHTML = "<b>No selection</b>";
}

function change_first_n() {
	var table_type = get_table_type();
	
	if ((table_type == "prefs_from_primary") || (table_type == "primaries_from_prefs")) {
		make_upto_prefs_selector(true);
	}
	
	reset_tables();
}

function change_upto_n() {
	reset_tables();
}

function change_pref(col, row) {
	if (selected_rows[col] == row) {
		null_td_click = true;
		return;
	}
	
	var table_type = get_table_type();
	
	if (col == 0) {
		if (pref_table_data[0][row][0] == groups.length - 1) {
			// 1 Exh
			if (table_type != "primaries_from_prefs") {
				null_td_click = true;
				return;
			}
		}
	}
	
	var this_division_i = document.getElementById("select_division").selectedIndex;
	var type_i = document.getElementById("select_type").selectedIndex + 1;
	
	
	
	if (col > selected_groups.length) { return; }
	
	if (document.getElementById("td_" + col + "_" + row).innerHTML == "&nbsp;") {
		// Haaaaaaack. :(
		// (Problem is that in some cases the elements of pref_table_data say that
		// there are votes there, even though it's really a blank cell.)
		null_td_click = true;
		return;
	}
	
	var this_votes, this_group, this_group_name;
	var need_subset = true;
	var clicked_exh = false;
	
	var min_pref, max_pref, fixed_pref;
	
	if (col == num_prefs - 1) {
		need_subset = false;
	}
	
	if (table_type == "first_n_prefs") {
		min_pref = 0;
		max_pref = get_first_n();
		if (col == max_pref - 1) {
			need_subset = false;
		}
	}
	
	if (table_type == "prefs_from_primary") {
		min_pref = 0;
		max_pref = get_upto_n();
		fixed_pref = get_first_n();
		if (col == max_pref - 1) {
			need_subset = false;
		}
	}
	
	if (table_type == "primaries_from_prefs") {
		min_pref = get_first_n() - 1;
		max_pref = get_upto_n();
		if (col == 1) {
			need_subset = false;
		}
	}
	
	if (groups[pref_table_data[col][row][0]] == "Exh") {
		if (table_type != "primaries_from_prefs") {
			need_subset = false;
		}
		clicked_exh = true;
	}
	
	
	
	var i, this_group;
	
	
	if (selected_groups.length > col) {
		// Undo the the highlight in the previously
		// highlighted cell in this column.
		try {
			// Maybe the "selected" cell is empty.
			document.getElementById("td_" + col + "_" + selected_rows[col]).style.backgroundColor = "transparent";
		} catch(err) {
			// Carry on.
		}
	}
	
	for (i = 0; i < groups.length; i++) {
		if (i != row) {
			document.getElementById("td_" + col + "_" + i).style.color = "#808080";
		} else {
			document.getElementById("td_" + col + "_" + i).style.color = "#000000";
		}
	}
	
	document.getElementById("td_" + col + "_" + row).style.backgroundColor = highlighted_color;
	var old_selected_groups = JSON.parse(JSON.stringify(selected_groups));
	var old_selected_rows = JSON.parse(JSON.stringify(selected_rows));
	
	selected_groups = [];
	selected_rows = [];
	for (i = 0; i < col; i++) {
		selected_groups.push(old_selected_groups[i]);
		selected_rows.push(old_selected_rows[i]);
	}
	
	selected_groups.push(pref_table_data[col][row][0]);
	selected_rows.push(row);
	
	if (need_subset) {
		this_group = selected_groups[col];
		
		if ((table_type == "step_forward") || ((table_type == "prefs_from_primary") && (col < fixed_pref))) {
			formatted_data[col+1] = formatted_data[col].filter(function(d) {
				return (d[0][col] == this_group);
			});
		} else if ((table_type == "first_n_prefs") || (table_type == "prefs_from_primary") || (table_type == "primaries_from_prefs")) {
			formatted_data[col+1] = formatted_data[col].filter(function(d) {
				var have_group = false;
				var test_group;
				for (var k = min_pref; k < max_pref; k++) {
					test_group = d[0][k];
					if (test_group < 0) { test_group = groups.length - 1; }
					
					if (test_group == this_group) {
						have_group = true;
						break;
					}
				}
				return have_group;
			});
		} 
		
		// If we didn't need to subset some data, then the
		// columns of the table aren't changing, so the following
		// goes inside this if block.
		
		for (i = col + 1; i <= selected_groups.length; i++) {
			calculate_pref_table_col(i);
			
			if (sorting_pref_table_by == "votes") {
				pref_table_data[i].sort(function(a, b) { return b[type_i][this_division_i] - a[type_i][this_division_i]; } );
			} else {
				pref_table_data[i].sort(function(a, b) { return a[0] - b[0]; } );
			}
			
			for (j = 0; j < pref_table_data[i].length; j++) {
				this_votes = pref_table_data[i][j][1][this_division_i];
				
				this_group = pref_table_data[i][j][0];
				if (this_group < 0) { this_group = groups.length - 1; }
				
				this_group_name = groups[this_group];
				
				if ((this_votes == 0) && !((this_group_name == "Exh") && (i == 0))) {
					td_html = "&nbsp;";
				} else {
					td_html = this_group_name + "<br><span id=\"span_" + i + "_" + j + "\">" + pref_table_data[i][j][type_i][this_division_i] + "</span>";
				}
				td_element = document.getElementById("td_" + i + "_" + j);
				td_element.innerHTML = td_html;
				
				if (i < selected_groups.length) {
					if (selected_groups[i] == pref_table_data[i][j][0]) {
						if (this_votes > 0) {
							td_element.style.backgroundColor = highlighted_color;
							td_element.style.color = "#000000";
						} else {
							td_element.style.backgroundColor = "transparent";
						}
						
						// If the division was changed, the selected
						// rows might have changed even though the
						// selected groups remained as is, so update
						// the selected_rows array just in case.
						selected_rows[i] = j;
					} else {
						td_element.style.backgroundColor = "transparent";
						td_element.style.color = "#808080";
					}
				} else {
					td_element.style.backgroundColor = "transparent";
					td_element.style.color = "#000000";
				}
			}
		}
	}
	
	var start_i = selected_groups.length + 1;
	if (clicked_exh && (table_type != "primaries_from_prefs")) { start_i--; }
	
	var end_i = num_prefs;
	if (table_type == "first_n_prefs") {
		end_i = get_first_n();
	}
	
	if (table_type == "prefs_from_primary") {
		end_i = get_upto_n();
	}
	
	if (table_type == "primaries_from_prefs") {
		end_i = 2;
	}
	
	for (i = start_i; i < end_i; i++) {
		for (j = 0; j < pref_table_data[0].length; j++) {
			td_element = document.getElementById("td_" + i + "_" + j);
			td_element.innerHTML = "&nbsp;";
			td_element.style.backgroundColor = "transparent";
			td_element.style.color = "#000000";
		}
	}
	
	update_divisions_table(true);
}

function sort_divs_aux(a, b) {
	// If sorting by division, want the state at the end.
	if (a == divs[divs.length - 1]) {
		return 1;
	} else if (b == divs[divs.length - 1]) {
		return -1;
	} else {
		return a.localeCompare(b);
	}
}

function sort_division_table(col, swap) {
	// col: column to sort by
	// swap (0 or 1): do we swap the sort order?
	
	if (selected_groups.length == 0) { return; }
	
	sorting_division_table_by[0] = col;
	
	if (swap == 1) {
		sorting_division_table_by[1] *= -1;
	}
	
	var sort_factor = sorting_division_table_by[1];
	
	if (col == 0) {
		// Sorting by division
		division_table_data.sort(function(a, b) { return sort_factor * sort_divs_aux(divs[a[0]], divs[b[0]]); } );
	} else {
		// Sorting by vote
		division_table_data.sort(function(a, b) { return sort_factor * (a[1] - b[1]); } );
	}
	
	update_divisions_table(false);
}

function update_divisions_table(do_sort) {
	if (selected_groups.length == 0) { return; }
	
	var i, this_group, wanted_table_row, wanted_table_col;
	var type_i = document.getElementById("select_type").selectedIndex + 1;
	
	var table_type = get_table_type();
	
	wanted_table_col = selected_groups.length - 1;
		
	var last_selected_group = selected_groups[wanted_table_col];
	// Find which row this is:
	for (i = 0; i < pref_table_data[wanted_table_col].length; i++) {
		if (pref_table_data[wanted_table_col][i][0] == last_selected_group) {
			wanted_table_row = i;
			break;
		}
	}
	
	// Create the table/legend title.
	if (table_type == "step_forward") {
		var division_table_title = "";
		
		if (type_i != 2) {
			// For percentages, only bold the last preference.
			division_table_title += "<b>";
		}
		
		for (i = 0; i < selected_groups.length; i++) {
			this_group = selected_groups[i];
			if (this_group < 0) { this_group = groups.length - 1; }
			
			if ((type_i == 2) && (i == selected_groups.length - 1)) {
				division_table_title += "<b>";
			}
			division_table_title += (i + 1) + "&nbsp;" + groups[this_group] + " ";
		}
		
		division_table_title += "</b>";

	} else if (table_type == "first_n_prefs") {
		var last_selected_group = selected_groups[wanted_table_col];
		
		var division_table_title = "In first " + get_first_n() + " prefs: <b>";
		var comma = ", ";
		
		if (type_i == 2) {
			// Percentages.
			
			var last_group = selected_groups[selected_groups.length - 1];
			if (last_group < 0) { last_group = groups.length - 1; }
			
			division_table_title += groups[last_group] + "</b>";
			
			if (selected_groups.length > 1) {
				division_table_title += " given ";
			}
			
			for (i = 0; i < selected_groups.length - 1; i++) {
				this_group = selected_groups[i];
				if (this_group < 0) { this_group = groups.length - 1; }
				
				if (i == selected_groups.length - 2) {
					comma = "";
				}
				
				division_table_title += groups[this_group] + comma;
			}
		} else {
			for (i = 0; i < selected_groups.length; i++) {
				this_group = selected_groups[i];
				if (this_group < 0) { this_group = groups.length - 1; }
				
				if (i == selected_groups.length - 1) {
					comma = "";
				}
				
				division_table_title += groups[this_group] + comma;
			}
			
			division_table_title += "</b>";
		}
	} else if (table_type == "prefs_from_primary") {
		var last_selected_group = selected_groups[wanted_table_col];
		var fixed_prefs = get_first_n();
		
		if (wanted_table_col < fixed_prefs) {
			// Identical title to table_type == "step_forward".
			
			var division_table_title = "";
			
			if (type_i != 2) {
				// For percentages, only bold the last preference.
				division_table_title += "<b>";
			}
			
			for (i = 0; i < selected_groups.length; i++) {
				this_group = selected_groups[i];
				if (this_group < 0) { this_group = groups.length - 1; }
				
				if ((type_i == 2) && (i == selected_groups.length - 1)) {
					division_table_title += "<b>";
				}
				division_table_title += (i + 1) + "&nbsp;" + groups[this_group] + " ";
			}
			
			division_table_title += "</b>";
		} else {
			var division_table_title = "<b>";
			var comma = ", ";
			
			if (type_i == 2) {
				// Percentages.
				
				var last_group = selected_groups[selected_groups.length - 1];
				if (last_group < 0) { last_group = groups.length - 1; }
				
				division_table_title += groups[last_group] + "</b> in first " + get_upto_n() + " prefs, given ";
				
				var final_space = " ";
				
				for (i = 0; i < get_first_n(); i++) {
					
					this_group = selected_groups[i];
					if (this_group < 0) { this_group = groups.length - 1; }
					
					if (i == get_first_n() - 1) {
						if (i == selected_groups.length - 2) {
							final_space = "";
						} else {
							final_space = "; ";
						}
					}
						
					division_table_title += (i + 1) + "&nbsp;" + groups[this_group] + final_space;
				}
				
				for (i = get_first_n(); i < selected_groups.length - 1; i++) {
					if (i == selected_groups.length - 2) { comma = " in first " + get_upto_n() + " prefs"; }
					
					this_group = selected_groups[i];
					if (this_group < 0) { this_group = groups.length - 1; }
					
					division_table_title += groups[this_group] + comma;
				}
			} else {
				
				var final_space = " ";
				
				for (i = 0; i < get_first_n(); i++) {
					this_group = selected_groups[i];
					if (this_group < 0) { this_group = groups.length - 1; }
					
					if (i == get_first_n() - 1) {
						final_space = "; ";
					}
					
					division_table_title += (i + 1) + "&nbsp;" + groups[this_group] + final_space;
				}
				
				for (i = get_first_n(); i < selected_groups.length; i++) {
					if (i == selected_groups.length - 1) { comma = " in first " + get_upto_n() + " prefs"; }
					
					this_group = selected_groups[i];
					if (this_group < 0) { this_group = groups.length - 1; }
					
					division_table_title += groups[this_group] + comma;
				}
				
				division_table_title += "</b>";
			}
		}
	} else if (table_type == "primaries_from_prefs") {
		var min_pref = get_first_n();
		var max_pref = get_upto_n();
		var pref_str = " " + min_pref + "-" + max_pref;
		var flip_order = false;
		if (min_pref == max_pref) {
			pref_str = " " + min_pref + " ";
			flip_order = true;
		}
		
		var division_table_title = "<b>";
		
		if (wanted_table_col == 0) {
			// Preferences
			this_group = selected_groups[0];
			if (this_group < 0) { this_group = groups.length - 1; }
			
			division_table_title += groups[this_group] + pref_str + "</b>";
			
		} else {
			// Primaries given preferences.
			if (type_i == 2) {
				// Percentages
				
				this_group = selected_groups[1];
				if (this_group < 0) { this_group = groups.length - 1; }
				
				division_table_title += "1 " + groups[this_group] + "</b> given ";
				
				this_group = selected_groups[0];
				if (this_group < 0) { this_group = groups.length - 1; }
				
				if (flip_order) {
					division_table_title += pref_str + groups[this_group];
				} else {
					division_table_title += groups[this_group] + pref_str;
				}
			} else {
				this_group = selected_groups[1];
				if (this_group < 0) { this_group = groups.length - 1; }
				
				division_table_title += "1 " + groups[this_group] + ", ";
				
				this_group = selected_groups[0];
				if (this_group < 0) { this_group = groups.length - 1; }
				
				if (flip_order) {
					division_table_title += pref_str + groups[this_group];
				} else {
					division_table_title += groups[this_group] + pref_str;
				}
				
				division_table_title += "</b>";
			}
		}
		
	} else if (table_type == "bidirectional") {
		
	}
	
	
	for (i = 0; i < divs.length; i++) {
		this_group = division_table_data[i][0];
		if (this_group < 0) { this_group = groups.length - 1; }
		
		division_table_data[i][1] = pref_table_data[wanted_table_col][wanted_table_row][type_i][division_table_data[i][0]];
		document.getElementById("td_divs_votes_" + i).innerHTML = division_table_data[i][1];
	}
	
	if (do_sort) {
		sort_division_table(sorting_division_table_by[0], 0);
	}
	
	for (i = 0; i < divs.length; i++) {
		if (division_table_data[i][0] == divs.length - 1) {
			// Bold the row for the state total.
			document.getElementById("tr_divs_" + i).style.fontWeight = "bold";
		} else {
			document.getElementById("tr_divs_" + i).style.fontWeight = "normal";
			
		}
		
		document.getElementById("td_divs_name_" + i).innerHTML = divs[division_table_data[i][0]];
		document.getElementById("td_divs_votes_" + i).innerHTML = division_table_data[i][1];
	}
	
	document.getElementById("span_division_table_title").innerHTML = division_table_title;
}

function reprint_pref_table(do_sort) {
	var this_division_i = document.getElementById("select_division").selectedIndex;
	var type_i = document.getElementById("select_type").selectedIndex + 1;
	var i, j, td_element, td_html, this_votes, this_group, this_group_name;
	var end_i = right_most_col();
	
	if (do_sort == 1) {
		change_pref_table_sort(sorting_pref_table_by);
	}
	
	selected_rows = [];
	
	for (i = 0; i <= end_i; i++) {
		for (j = 0; j < groups.length; j++) {
			td_element = document.getElementById("td_" + i + "_" + j);
			this_votes = pref_table_data[i][j][1][this_division_i];
			
			this_group = pref_table_data[i][j][0];
			if (this_group < 0) { this_group = groups.length - 1; }
			this_group_name = groups[this_group];
			
			if ((this_votes == 0) && !((this_group_name == "Exh") && (i == 0))) {
				td_html = "&nbsp;";
				td_element.style.color = "#000000";
				td_element.style.backgroundColor = "transparent";
			} else {
				td_html = this_group_name + "<br><span id=\"span_" + i + "_" + j + "\">" + pref_table_data[i][j][type_i][this_division_i] + "</span>";
				
				// Undo/redo highlighting
				if (i <= selected_groups.length - 1) {
					if (pref_table_data[i][j][0] == selected_groups[i]) {
						td_element.style.color = "#000000";
						td_element.style.backgroundColor = highlighted_color;
						selected_rows.push(j);
					} else {
						td_element.style.color = "#808080";
						td_element.style.backgroundColor = "transparent";
					}
				} else {
					td_element.style.color = "#000000";
					td_element.style.backgroundColor = "transparent";
				}
			}
			
			td_element.innerHTML = td_html;
		}
	}
}


function division_value(division_name) {
	var division_i = divs.indexOf(division_name);
	
	// Look away, I'm just going to loop through the table
	// to find the division.
	
	for (i = 0; i < division_table_data.length; i++) {
		if (division_table_data[i][0] == division_i) {
			needed_i = i;
			break;
		}
	}
	
	return division_table_data[needed_i][1];;
}

function polygon_fill_colour(division_name) {
	if (selected_groups.length == 0) { return "#000000"; }

	this_value = division_value(division_name);
	
	var t = 255*(this_value - map_colour_scale[0]) / (map_colour_scale[1] - map_colour_scale[0]);
	
	if (t > 255) { t = 255; }
	if (t < 0) { t = 0; }
	
	var t_i_min = Math.floor(t);
	var t_i_max = Math.ceil(t);
	
	if (t_i_max == t_i_min) {
		if (t_i_max == 255) {
			t_i_min--;
		} else {
			t_i_max++;
		}
	}
	
	var s = (t - t_i_min) / (t_i_max - t_i_min);
	
	var this_rgb = [0, 0, 0];
	
	for (i = 0; i < 3; i++) {
		try {
			this_rgb[i] = Math.round(inferno_scale[t_i_min][i] + s*(inferno_scale[t_i_max][i] - inferno_scale[t_i_min][i]));
		} catch(err) {
			console.log([t_i_min, t, t_i_max].join());
			asdf = asdfasd();
		}
		if (this_rgb[i] > 255) { this_rgb[i] = 255; }
	}
	
	return "rgb(" + this_rgb.join() + ")";
}



function change_pref_table_sort_prep() {
	var span_html;
	
	if (sorting_pref_table_by == "posn") {
		sorting_pref_table_by = "votes";
		span_html = "ballot paper order";
	} else if (sorting_pref_table_by == "votes") {
		sorting_pref_table_by = "posn";
		span_html = "vote % order";
	}
	
	document.getElementById("span_pref_table_sort").innerHTML = span_html;
	change_pref_table_sort(sorting_pref_table_by);
}

function change_pref_table_sort(sort_by) {
	var i;
	var type_i = document.getElementById("select_type").selectedIndex + 1;
	var this_division_i = document.getElementById("select_division").selectedIndex;
	
	if (sort_by == "posn") {
		for (i = 0; i < pref_table_data.length; i++) {
			pref_table_data[i].sort(function(a, b) { return a[0] - b[0]; } );
		}
	} else if (sort_by == "votes") {
		for (i = 0; i < pref_table_data.length; i++) {
			pref_table_data[i].sort(function(a, b) { return b[type_i][this_division_i] - a[type_i][this_division_i]; } );
		}
	}
	
	sorting_pref_table_by = sort_by;
	reprint_pref_table(0);
}

function scroll_to(div) {
	document.getElementById(div).scrollIntoView();
}

function even_odd_color(i) {
	if (i % 2 == 0) {
		return "#e0e0e0";
	} else {
		return "#ffffff";
	}
}

function freeze_pane_listener(parent_elt, table_class) {
	var i;
	var translate_y = "translate(0," + parent_elt.scrollTop + "px)";
	var translate_x = "translate(" + parent_elt.scrollLeft + "px,0px)";
	var translate_xy = "translate(" + parent_elt.scrollLeft + "px," + parent_elt.scrollTop + "px)";

	var fixed_vertical_elts = document.getElementsByClassName(table_class + " fixed_vertical");
	var fixed_horizontal_elts = document.getElementsByClassName(table_class + " fixed_horizontal");
	var fixed_both_elts = document.getElementsByClassName(table_class + " fixed_both_ways");

	for (i = 0; i < fixed_horizontal_elts.length; i++) {
		fixed_horizontal_elts[i].style.webkitTransform = translate_x;
		fixed_horizontal_elts[i].style.transform = translate_x;
	}

	for (i = 0; i < fixed_vertical_elts.length; i++) {
	   fixed_vertical_elts[i].style.webkitTransform = translate_y;
	   fixed_vertical_elts[i].style.transform = translate_y;
	}

	for (i = 0; i < fixed_both_elts.length; i++) {
	   fixed_both_elts[i].style.webkitTransform = translate_xy;
	   fixed_both_elts[i].style.transform = translate_xy;
	}
}

function make_cross_table() {
	var i, j, this_span;
	var div = document.getElementById("div_cross_table");
	if (!div) {
		var main_div = document.getElementById("div_arrangement");
		var new_div = document.createElement("div");
		
		new_div.id = "div_cross_table_preamble";
		new_div.className = "maintext";
		
		main_div.appendChild(new_div);
		
		var div_html = "<p>The cross tables will not update until you generate new ones, but you can click on group or row titles to sort. ";
		div_html += "All percentages which round to 0.00 become blank in the cross table &ndash; sorry! ";
		div_html += "<span class=\"js_link\" onclick=\"scroll_to('div_cross_table_divisions_preamble')\">Go to divisions table</span> | <span class=\"js_link\" onclick=\"scroll_to('div_selectors')\">Back to top</span>.</p>";
		div_html += "<span id=\"span_cross_table_errors\"></span>";
		div_html += "<p><span class=\"js_link\" onclick=\"sort_cross_table_rows(-1)\">Sort rows to column order</span>.<br>";
		div_html += "<p><span class=\"js_link\" onclick=\"sort_cross_table_rows(-2)\">Sort rows to ballot order</span>.<br>";
		div_html += "<p><span class=\"js_link\" onclick=\"sort_cross_table_cols(-1)\">Sort columns to row order</span>.<br>";
		div_html += "<p><span class=\"js_link\" onclick=\"sort_cross_table_cols(-2)\">Sort columns to ballot order</span>.<br>";
		div_html += "<p><span id=\"span_cross_table_title\">[title of table]</span></p>";
		
		document.getElementById("div_cross_table_preamble").innerHTML = div_html;
		
		new_div = document.createElement("div");
		new_div.id = "div_cross_table";
		new_div.style.marginLeft = "20px";
		
		var window_width = window.innerWidth;
		var window_height = window.innerHeight;
		
		if (window_width > 900) {
			new_div.style.maxWidth = (window_width - 40) + "px";
		}
		
		if (window_height > 300) {
			new_div.style.maxHeight = (window_height - 100) + "px";
		}
		
		
		main_div.appendChild(new_div);
		
		div = document.getElementById("div_cross_table");
		div.className = "scrolly_table";
		
		div_html = "<table>";
		div_html += "<tr><th class=\"right_align subtle_js_link cross_table fixed_both_ways\" onclick=\"sort_cross_table_rows(-99)\">Base</th>";
		div_html += "<th class=\"left_align cross_table fixed_both_ways\">Grp</th>";
		for (i = 0; i < groups.length; i++) {
			div_html += "<th class=\"right_align subtle_js_link cross_table fixed_vertical\" id=\"th_cross_col_" + i + "\" onclick=\"sort_cross_table_rows(" + i + ")\">" + groups[i] + "</th>";
		}
		div_html += "</tr>";
		
		for (i = 0; i < groups.length; i++) {
			div_html += "<tr class=\"tr_shaded\"><td class=\"right_align cross_table fixed_horizontal\" style=\"background-color:" + even_odd_color(i) + ";\" id=\"td_cross_base_" + i + "\"></td>";
			div_html += "<td class=\"left_align subtle_js_link cross_table fixed_horizontal\" style=\"background-color:" + even_odd_color(i) + ";font-weight:bold;\" id=\"th_cross_row_" + i + "\" onclick=\"sort_cross_table_cols(" + i + ")\">" + groups[i] + "</td>";
			
			for (j = 0; j < groups.length; j++) {
				div_html += "<td id=\"td_cross_" + i + "_" + j + "\" class=\"right_align\"></td>";
			}
			
			div_html += "</tr>";
		}
		div_html += "</table>";
		
		div.innerHTML = div_html;
		
		document.getElementById("div_cross_table").addEventListener("scroll",function(){
			freeze_pane_listener(this, "cross_table");
		});
		
		// And now the divisions table:
		new_div = document.createElement("div");
		new_div.id = "div_cross_table_divisions_preamble";
		new_div.className = "maintext";
		main_div.appendChild(new_div);
		
		div_html = "<p><br><br><span class=\"js_link\" onclick=\"scroll_to('div_cross_table_preamble')\">Go to main cross table</span> | <span class=\"js_link\" onclick=\"scroll_to('div_selectors')\">Back to top</span>.</p>";
		div_html += "<p style=\"margin-left:20px\"><span id=\"span_cross_table_divisions_title\">[title of divisions table]</span></p>";
		document.getElementById("div_cross_table_divisions_preamble").innerHTML = div_html;
		
		new_div = document.createElement("div");
		new_div.id = "div_cross_table_divisions";
		new_div.style.marginLeft = "20px";
		
		if (window_width > 900) {
			new_div.style.maxWidth = (window_width - 40) + "px";
		}
		
		if (window_height > 300) {
			new_div.style.maxHeight = (window_height - 100) + "px";
		}
		
		main_div.appendChild(new_div);
		
		div_div = document.getElementById("div_cross_table_divisions");
		div_div.className = "scrolly_table";
		
		div_html = "<table>";
		div_html += "<tr><th class=\"left_align subtle_js_link cross_divisions_table fixed_both_ways\" onclick=\"sort_cross_table_divisions_rows(-1)\">Division</th>";
		for (i = 0; i < groups.length; i++) {
			div_html += "<th class=\"right_align subtle_js_link cross_divisions_table fixed_vertical\" id=\"th_cross_divisions_col_" + i + "\" onclick=\"sort_cross_table_divisions_rows(" + i + ")\">" + groups[i] + "</th>";
		}
		div_html += "</tr>";
		
		for (i = 0; i < divs.length; i++) {
			div_html += "<tr class=\"tr_shaded\" id=\"tr_cross_divisions_" + i + "\"><td class=\"left_align subtle_js_link cross_divisions_table fixed_horizontal\" style=\"background-color:" + even_odd_color(i) + "\" id=\"th_cross_divisions_row_" + i + "\" onclick=\"sort_cross_table_divisions_cols(" + i + ")\">" + divs[i] + "</td>";
			
			for (j = 0; j < groups.length; j++) {
				div_html += "<td id=\"td_cross_divisions_" + i + "_" + j + "\" class=\"right_align\"></td>";
			}
			
			div_html += "</tr>";
		}
		
		div_html += "</table>";
		
		new_div.innerHTML = div_html;
		
		document.getElementById("div_cross_table_divisions").addEventListener("scroll",function(){
			freeze_pane_listener(this, "cross_divisions_table");
		});
	}
	
	var prev_pref_table_sort = sorting_pref_table_by;
	// This whole routine is an add-on and rather than re-writing
	// everything I'm just going to simulate clicks down the column
	// of the preference table.  The issue is that these clicks
	// might not do anything (if, e.g., the first cell in the column
	// is already highlighted), so we have to make sure that the first
	// click is an active one.
	
	var click_col_i = selected_groups.length - 1;
	var current_selected_row;
	
	var table_type = get_table_type();
	var cross_divisions_only = false;
	var blank_divisions_table = false;
	
	// If the right-most clicked cell is in the
	// final column, then don't calculate the
	// main cross table, only the divisions table.
	
	if (table_type == "primaries_from_prefs") {
		if (click_col_i == 1) {
			cross_divisions_only = true;
		}
	} else {
		if (click_col_i == num_prefs - 1) {
			cross_divisions_only = true;
		}
	}
	
	
	if (cross_divisions_only) {
		document.getElementById("span_cross_table_title").innerHTML = "<b>Error:</b> The last highlighted cell is in the right-most column of the table, so the first cross table cannot be filled.";
		div = document.getElementById("div_cross_table_divisions");
	} else {
		div = document.getElementById("div_cross_table_preamble");
	}
	
	
	if (click_col_i < 0) {
		// No cells highlighted; sort by votes and click on the first cell.
		
		if (sorting_pref_table_by == "posn") {
			change_pref_table_sort_prep();
		}
		
		change_pref(0, 0);
		click_col_i = 0;
		current_selected_row = 0;
	} else {
		current_selected_row = selected_rows[click_col_i];
		
		// Need to make sure that there's at least two highlighted cells in
		// the selected column.
		
		if (sorting_pref_table_by == "posn") {
			change_pref_table_sort_prep();
		}
		
		this_span = document.getElementById("span_" + click_col_i + "_1");
		
		if (!this_span) {
			document.getElementById("span_cross_table_title").innerHTML = "<b>Error:</b> Only one non-zero row in last table column.";
			blank_divisions_table = true;
			
			blank_cross_table();
			blank_cross_divisions_table();
			
			document.getElementById("div_cross_table").scrollIntoView();
			return;
		}
	}
	
	if (sorting_pref_table_by == "votes") {
		change_pref_table_sort_prep();
	}
	
	// Need to ensure that the currently-clicked cell will not be the first
	// clicked during the loop, otherwise change_pref will say null_td_click = true.
	var cell_ct = 0;
	for (i = 0; i < groups.length; i++) {
		this_span = document.getElementById("span_" + click_col_i + "_" + i);
		if (!!this_span) {
			cell_ct++;
			if (cell_ct == 2) {
				change_pref(click_col_i, i);
				break;
			}
		}
	}
	
	
	var read_col_i = click_col_i + 1;
	
	
	div.scrollIntoView();
	
	var pref_td_span, cross_td, this_votes;
	
	var cross_table_title, cross_table_divisions_title;
	var temp_group_row, temp_group_col, temp_divisions_group;
	
	calculating_cross_table = true;
	
	var type_i = document.getElementById("select_type").selectedIndex + 1;
	var this_division_i = document.getElementById("select_division").selectedIndex;
	
	// The main loop here just simulates clicks down
	// each cell of the main table, then reads off the
	// relevant span of each table cell.
	for (var row_i = 0; row_i < groups.length; row_i++) {
		null_td_click = false;
		change_pref(click_col_i, row_i);
		
		if (row_i == 0) {
			cross_table_divisions_title = document.getElementById("span_division_table_title").innerHTML;
			temp_divisions_group = pref_table_data[click_col_i][row_i][0];
		}
		
		if (!cross_divisions_only) {
			cross_table_data_ij[row_i].group = row_i;
			cross_table_data_ji[row_i].group = row_i;
			
			if (null_td_click) {
				cross_table_data_ij[row_i].base = 0;
				
				for (i = 0; i < groups.length; i++) {
					cross_table_data_ij[row_i].votes[i] = 0;
					cross_table_data_ji[i].votes[row_i] = 0;
				}
			} else {
				cross_table_data_ij[row_i].base = pref_table_data[click_col_i][row_i][type_i][this_division_i];
				
				for (i = 0; i < groups.length; i++) {
					pref_td_span = document.getElementById("span_" + read_col_i + "_" + i);
					
					if (!!pref_td_span) {
						this_votes = pref_table_data[read_col_i][i][type_i][this_division_i];
						
						cross_table_data_ij[row_i].votes[i] = this_votes;
						cross_table_data_ji[i].votes[row_i] = this_votes;
					} else {
						cross_table_data_ij[row_i].votes[i] = 0;
						cross_table_data_ji[i].votes[row_i] = 0;
					}
				}
			}
		}
		
		// Now the divisions cross table.
		// row_i is now a column index, whoops.
		
		if (row_i == 0) {
			for (i = 0; i < divs.length; i++) {
				cross_table_divisions_ij[i].division = i;
			}
		}
		
		cross_table_divisions_ji[row_i].group = row_i;
		if (null_td_click) {
			for (i = 0; i < divs.length; i++) {
				cross_table_divisions_ij[i].votes[row_i] = 0;
				cross_table_divisions_ji[row_i].votes[i] = 0;
			}
		} else {
			for (i = 0; i < divs.length; i++) {
				this_votes = pref_table_data[click_col_i][row_i][type_i][i];
				
				cross_table_divisions_ij[i].votes[row_i] = this_votes;
				cross_table_divisions_ji[row_i].votes[i] = this_votes;
			}
		}
	}
	
	if (!cross_divisions_only) {
		if (sorting_pref_table_by == "posn") {
			change_pref_table_sort_prep();
		}
		
		// Click on some cells to make the title appear
		// in the main division table, then replace
		// relevant group names there with "Row" and "Column".
		change_pref(click_col_i, 0);
		change_pref(click_col_i + 1, 0);
		
		cross_table_title = document.getElementById("span_division_table_title").innerHTML;
		
		temp_group_row = pref_table_data[click_col_i][0][0];
		temp_group_col = pref_table_data[click_col_i + 1][0][0];
		
		if (temp_group_row < 0) { temp_group_row = groups.length - 1; }
		if (temp_group_col < 0) { temp_group_col = groups.length - 1; }
		
		temp_group_row = groups[temp_group_row];
		temp_group_col = groups[temp_group_col];
		
		var row_pattern = new RegExp("\\b" + temp_group_row.replace(/\//, "\/") + "\\b");
		var col_pattern = new RegExp("\\b" + temp_group_col.replace(/\//, "\/") + "\\b");
		
		cross_table_title = cross_table_title.replace(row_pattern, "Row");
		cross_table_title = cross_table_title.replace(col_pattern, "Column");
		cross_table_title = divs[this_division_i] + ": " + cross_table_title;
		
		document.getElementById("span_cross_table_title").innerHTML = cross_table_title;
		
		change_pref(click_col_i, 1);
		populate_cross_table();
	} else {
		blank_cross_table();
	}
	
	// Now the divisions title
	if (temp_divisions_group < 0) { temp_divisions_group = groups.length - 1; }
	temp_divisions_group = groups[temp_divisions_group];
	
	var temp_pattern = new RegExp("\\b" + temp_divisions_group.replace(/\//, "\/") + "\\b");
	
	cross_table_divisions_title = cross_table_divisions_title.replace(temp_pattern, "Column");
	document.getElementById("span_cross_table_divisions_title").innerHTML = cross_table_divisions_title;
	
	populate_cross_divisions_table();
	
	
	calculating_cross_table = false;
	
	// Reset to previous sort and highlighted cell:
	
	if (prev_pref_table_sort != sorting_pref_table_by) {
		change_pref_table_sort_prep();
	}
	
	change_pref(click_col_i, current_selected_row);
}

function blank_cross_table() {
	for (var i = 0; i < groups.length; i++) {
		document.getElementById("td_cross_base_" + i).innerHTML = "";
		
		for (var j = 0; j < groups.length; j++) {
			document.getElementById("td_cross_" + i + "_" + j).innerHTML = "";
		}
	}
}

function blank_cross_divisions_table() {
	for (var i = 0; i < divs.length; i++) {
		for (var j = 0; j < groups.length; j++) {
			document.getElementById("td_cross_divisions_" + i + "_" + j).innerHTML = "";
		}
	}
}

function populate_cross_table() {
	var i, j, td, this_votes;
	
	for (i = 0; i < groups.length; i++) {
		document.getElementById("th_cross_row_" + i).innerHTML = groups[cross_table_data_ij[i].group];
		document.getElementById("th_cross_col_" + i).innerHTML = groups[cross_table_data_ji[i].group];
		
		document.getElementById("td_cross_base_" + i).innerHTML = cross_table_data_ij[i].base;
		
		for (j = 0; j < groups.length; j++) {
			this_votes = cross_table_data_ij[i].votes[j];
			
			if (this_votes == 0) {
				document.getElementById("td_cross_" + i + "_" + j).innerHTML = "";
			} else {
				document.getElementById("td_cross_" + i + "_" + j).innerHTML = this_votes;
			}
		}
	}
}

function populate_cross_divisions_table() {
	var i, j, td, this_votes, tr;
	
	for (i = 0; i < divs.length; i++) {
		document.getElementById("th_cross_divisions_row_" + i).innerHTML = divs[cross_table_divisions_ij[i].division];
		
		
		for (j = 0; j < groups.length; j++) {
			if (i == 0) {
				document.getElementById("th_cross_divisions_col_" + j).innerHTML = groups[cross_table_divisions_ji[j].group];
			}
			
			this_votes = cross_table_divisions_ij[i].votes[j];
			
			if (this_votes == 0) {
				document.getElementById("td_cross_divisions_" + i + "_" + j).innerHTML = "";
			} else {
				document.getElementById("td_cross_divisions_" + i + "_" + j).innerHTML = this_votes;
			}
		}
		
		tr = document.getElementById("tr_cross_divisions_" + i);
		if (cross_table_divisions_ij[i].division == divs.length - 1) {
			tr.style.fontWeight = "bold";
		} else {
			tr.style.fontWeight = "normal";
		}
	}
}

function sort_cross_aux(a, b, sort_i) {
	/* The following should make "Exh" be sorted last,
	 * but we might not want that in all tables, so
	 * it's commented out.
	if (a.group == groups.length - 1) {
		return -1;
	} else {
		return a.votes[sort_i] - b.votes[sort_i];
	}
	*/
	return a.votes[sort_i] - b.votes[sort_i];
}


function sort_cross_table_rows(sort_col) {
	var i, j, row_to_copy, wanted_group, table_copy, sort_factor;
	
	if (sort_col == -1) {
		// Sort the rows to match the order of the columns.
		table_copy = JSON.parse(JSON.stringify(cross_table_data_ij));
		
		for (i = 0; i < groups.length; i++) {
			wanted_group = cross_table_data_ji[i].group;
			
			for (j = 0; j < groups.length; j++) {
				if (table_copy[j].group == wanted_group) {
					row_to_copy = j;
					break;
				}
			}
			
			cross_table_data_ij[i].group = wanted_group;
			
			for (j = 0; j < groups.length; j++) {
				cross_table_data_ij[i].votes[j] = table_copy[row_to_copy].votes[j]; 
			}
		}
		
		// [[row, direction], [column, direction]]:
		//var sorting_cross_table_by = [[-1, 1], [-1, 1]];
		
		sorting_cross_table_by[1][0] = -1;
		sorting_cross_table_by[1][1] = 1;
	} else if (sort_col == -2) {
		// Sorting to ballot order.
		cross_table_data_ij.sort(function(a, b) { return a.group - b.group; } );
		
		sorting_cross_table_by[1][0] = -1;
		sorting_cross_table_by[1][1] = 1;
	} else if (sort_col == -99) {
		// Sorting by base value
		
		if (sorting_cross_table_by[1][0] == sort_col) {
			sorting_cross_table_by[1][1] *= -1;
		} else {
			sorting_cross_table_by[1][1] = -1;
		}
		
		sorting_cross_table_by[1][0] = sort_col;
		sort_factor = sorting_cross_table_by[1][1];
		
		cross_table_data_ij.sort(function(a, b) {
			/*
			if (a.group == groups.length - 1) {
				return -sort_factor;
			} else {
				return sort_factor*(a.base - b.base);
			}
			*/
			return sort_factor*(a.base - b.base);
		} );
	} else {
		if (sorting_cross_table_by[1][0] == sort_col) {
			sorting_cross_table_by[1][1] *= -1;
		} else {
			sorting_cross_table_by[1][1] = -1;
		}
		
		sorting_cross_table_by[1][0] = sort_col;
		sort_factor = sorting_cross_table_by[1][1];
		
		cross_table_data_ij.sort(function(a, b) { return sort_factor * sort_cross_aux(a, b, sort_col); } );
	}
	
	
	// Re-calculate the columns data
	for (i = 0; i < groups.length; i++) {
		for (j = 0; j < groups.length; j++) {
			cross_table_data_ji[i].votes[j] = cross_table_data_ij[j].votes[i];
		}
	}
	
	populate_cross_table();
}

function sort_cross_table_divisions_rows(sort_col) {
	var i, j, sort_factor;
	
	if (sorting_cross_divisions_table_by[1][0] == sort_col) {
		sorting_cross_divisions_table_by[1][1] *= -1;
	} else {
		sorting_cross_divisions_table_by[1][1] = -1;
	}
	
	sorting_cross_divisions_table_by[1][0] = sort_col;
	sort_factor = sorting_cross_divisions_table_by[1][1];
	
	if (sort_col == -1) {
		// Sorting to division order.
		cross_table_divisions_ij.sort(function(a, b) { return sort_factor * sort_divs_aux(divs[a.division], divs[b.division]); } );
	} else {
		cross_table_divisions_ij.sort(function(a, b) { return sort_factor * sort_cross_aux(a, b, sort_col); } );
	}
	
	
	// Re-calculate the columns data
	for (i = 0; i < groups.length; i++) {
		for (j = 0; j < divs.length; j++) {
			cross_table_divisions_ji[i].votes[j] = cross_table_divisions_ij[j].votes[i];
		}
	}
	
	populate_cross_divisions_table();
}

function sort_cross_table_cols(sort_row) {
	var i, j, col_to_copy, wanted_group, table_copy, sort_factor;
	
	if (sort_row == -1) {
		// Sort the cols to match the order of the rows.
		table_copy = JSON.parse(JSON.stringify(cross_table_data_ji));
		
		for (i = 0; i < groups.length; i++) {
			wanted_group = cross_table_data_ij[i].group;
			
			for (j = 0; j < groups.length; j++) {
				if (table_copy[j].group == wanted_group) {
					col_to_copy = j;
					break;
				}
			}
			
			cross_table_data_ji[i].group = wanted_group;
			
			for (j = 0; j < groups.length; j++) {
				cross_table_data_ji[i].votes[j] = table_copy[col_to_copy].votes[j];
			}
		}
		
		// [[col, direction], [row, direction]]:
		//var sorting_cross_table_by = [[-1, 1], [-1, 1]];
		
		sorting_cross_table_by[0][0] = -1;
		sorting_cross_table_by[0][1] = 1;
	} else if (sort_row == -2) {
		// Sorting to ballot order.
		cross_table_data_ji.sort(function(a, b) { return a.group - b.group; } );
		
		sorting_cross_table_by[0][0] = -1;
		sorting_cross_table_by[0][1] = 1;
	} else {
		if (sorting_cross_table_by[0][0] == sort_row) {
			sorting_cross_table_by[0][1] *= -1;
		} else {
			sorting_cross_table_by[0][1] = -1;
		}
		
		sorting_cross_table_by[0][0] = sort_row;
		sort_factor = sorting_cross_table_by[0][1];
		
		cross_table_data_ji.sort(function(a, b) { return sort_factor * (a.votes[sort_row] - b.votes[sort_row]); } );
	}
	
	
	// Re-calculate the rows data
	for (i = 0; i < groups.length; i++) {
		for (j = 0; j < groups.length; j++) {
			cross_table_data_ij[i].votes[j] = cross_table_data_ji[j].votes[i];
		}
	}
	
	populate_cross_table();
}

function sort_cross_table_divisions_cols(sort_row) {
	var i, j, sort_factor;
	
	if (sorting_cross_divisions_table_by[0][0] == sort_row) {
		sorting_cross_divisions_table_by[0][1] *= -1;
	} else {
		sorting_cross_divisions_table_by[0][1] = -1;
	}
	
	sorting_cross_divisions_table_by[0][0] = sort_row;
	sort_factor = sorting_cross_divisions_table_by[0][1];
	
	cross_table_divisions_ji.sort(function(a, b) { return sort_factor * (a.votes[sort_row] - b.votes[sort_row]); } );

	
	
	// Re-calculate the rows data
	for (i = 0; i < divs.length; i++) {
		for (j = 0; j < groups.length; j++) {
			cross_table_divisions_ij[i].votes[j] = cross_table_divisions_ji[j].votes[i];
		}
	}
	
	populate_cross_divisions_table();
}

function load_map() {
	// Load the Google Map -- should be called once on load.
	// Also initialises the legend's title and colour scale.
	
	document.getElementById("div_map_title").innerHTML = "<span id=\"span_map_title_division\"><b>&nbsp;</b></span><br><span id=\"span_map_title_value\"><b>&nbsp;</b></span>";
	
	var i;
	
	var init_zoom = init_map_params[2];
	if (document.getElementById("div_map").offsetWidth < 500) {
		init_zoom--;
	}
	
	var electorate_map_geo = topojson.feature(electorate_map_topo, electorate_map_topo.objects[geo_layer_name]).features;
	
	var div_width = document.getElementById("div_map").offsetWidth;
	if (div_width > 500) { div_width = 500; }
	var map_margin = 20;
	var map_width = div_width - map_margin;
	var map_height = div_width - map_margin;
	
	var map_div = document.getElementById("div_map");
	
	map_div.style.marginLeft = map_margin + "px";
	map_div.style.width = map_width + "px";
	map_div.style.height = map_height + "px";
	
	var google_params = {
		zoom: init_zoom,
		mapTypeId: google.maps.MapTypeId.ROADMAP,
		center: new google.maps.LatLng(init_map_params[0], init_map_params[1])
	}
	
	var google_map = new google.maps.Map(document.getElementById("div_map"), google_params);
	var map_overlay = new google.maps.OverlayView();
	map_overlay.onAdd = function () {
			var map_layer = d3.select(this.getPanes().overlayMouseTarget).append("div").attr("class", "svg_overlay");
			var map_svg = map_layer.append("svg");
			var map_electorates = map_svg.append("g").attr("class", "electorates");
			var map_data = electorate_map_geo;
			
			map_overlay.draw = function () {
				var markerOverlay = this;
				var overlayProjection = markerOverlay.getProjection();

				var googleMapProjection = function (coordinates) {
					var googleCoordinates = new google.maps.LatLng(coordinates[1], coordinates[0]);
					var pixelCoordinates = overlayProjection.fromLatLngToDivPixel(googleCoordinates);
					return [pixelCoordinates.x + 4000, pixelCoordinates.y + 4000];
				}

				path = d3.geo.path().projection(googleMapProjection);
				map_electorates.selectAll("path")
					.data(map_data)
					.attr("d", path)
				.enter().append("svg:path")
					.attr("d", path)
					.style("fill", function(d) {
						return polygon_fill_colour(d.properties.Division);
					})
					.on("mouseover", function(d) {
						d3.select(this).style("fill-opacity", 1);
						document.getElementById("span_map_title_division").innerHTML = "<b>" + d.properties.Division + "</b>";
						
						if (selected_groups.length > 0) {
							document.getElementById("span_map_title_value").innerHTML = division_value(d.properties.Division);
						}
					})
					.on("mouseout", function(d) {
						d3.select(this).style("fill-opacity", 0.7);
						document.getElementById("span_map_title_division").innerHTML = "<b>&nbsp;</b>";
						document.getElementById("span_map_title_value").innerHTML = "<b>&nbsp;</b>";
					});
			}
		}
	
	map_overlay.setMap(google_map);
	
	var canvas_html = "<p class=\"center_align\"><span id=\"span_legend_title\"></span><br><canvas id=\"canvas_map_legend\" width=\"300\" height=\"50\"></canvas></p>";
	document.getElementById("div_map_legend").innerHTML = canvas_html;
	
	var c = document.getElementById("canvas_map_legend");
	var ctx = c.getContext("2d");
	
	var legend_width = 256;
	var offset_i = 20;
	var scale_height = 15;
	var rgb_colour;
	
	for (i = 0; i < legend_width; i++) {
		rgb_colour = "rgb(" + inferno_scale[i].join() + ")";
		
		ctx.beginPath();
		ctx.moveTo(i + offset_i, 0);
		ctx.lineTo(i + offset_i, scale_height - 1);
		ctx.lineWidth = 1;
		ctx.strokeStyle = rgb_colour;
		ctx.stroke();
	}
}

function initialise_table_area() {
	var table_type = get_table_type();
	
	// Calculate the first column of the preference table data,
	// which (being primary votes), won't need to be changed.
	// pref_table_data[i] is of form
	// [group[i], [votes by division], [percentages by division], [total percentages by division]]
	pref_table_data = [[]];
	var div_html;
	
	if (table_type == "step_forward") {
		calculate_pref_table_col(0);
		
		// Initialise the preference table with empty td's.
		div_html = "<p class=\"left_align\"><i>Sort instead by <span class=\"js_link\" id=\"span_pref_table_sort\" onclick=\"change_pref_table_sort_prep()\">ballot paper order</span>.<br></i>";
		div_html += "<i><span class=\"js_link\" onclick=\"make_cross_table()\">Generate cross table</span>.</i></p>";
		
		div_html += "<table><tr>";
		for (i = 0; i < num_prefs; i++) {
			div_html += "<th>Pref " + (i + 1) + "</th>";
		}
		div_html += "</tr>";

		for (i = 0; i < groups.length; i++) {
			div_html += "<tr class=\"tr_shaded\">";
			for (j = 0; j < num_prefs; j++) {
				div_html += "<td id=\"td_" + j + "_" + i + "\" onclick='change_pref(" + j + "," + i + ")'>&nbsp;</td>";
			}
			div_html += "</tr>";
		}
		div_html += "</table>";

		document.getElementById("td_pref_table").innerHTML = div_html;

		// Fill in the first column of the table.
		change_pref_table_sort(sorting_pref_table_by);
		var type_i = document.getElementById("select_type").selectedIndex + 1;
		var this_division_i = document.getElementById("select_division").selectedIndex;
		var td_html;

		for (i = 0; i < pref_table_data[0].length; i++) {
			td_html = groups[pref_table_data[0][i][0]] + "<br><span id=\"span_0_" + i + "\">" + pref_table_data[0][i][type_i][this_division_i] + "</span>";
			document.getElementById("td_0_" + i).innerHTML = td_html;
		}
	} else if (table_type == "first_n_prefs") {
		calculate_pref_table_col(0);
		var sel = document.getElementById("select_first_n");
		var max_pref = sel.options[sel.selectedIndex].value;
		
		// Initialise the preference table with empty td's.
		div_html = "<p class=\"left_align\"><i>Sort instead by <span class=\"js_link\" id=\"span_pref_table_sort\" onclick=\"change_pref_table_sort_prep()\">ballot paper order</span>.<br></i>";
		div_html += "<i><span class=\"js_link\" onclick=\"make_cross_table()\">Generate cross tables</span>.</i></p>";
		
		div_html += "<table><tr>";
		for (i = 0; i < max_pref; i++) {
			div_html += "<th>By " + max_pref + "</th>";
		}
		div_html += "</tr>";

		for (i = 0; i < groups.length; i++) {
			div_html += "<tr class=\"tr_shaded\">";
			for (j = 0; j < max_pref; j++) {
				div_html += "<td id=\"td_" + j + "_" + i + "\" onclick='change_pref(" + j + "," + i + ")'>&nbsp;</td>";
			}
			div_html += "</tr>";
		}
		div_html += "</table>";

		document.getElementById("td_pref_table").innerHTML = div_html;

		// Fill in the first column of the table.
		change_pref_table_sort(sorting_pref_table_by);
		var type_i = document.getElementById("select_type").selectedIndex + 1;
		var this_division_i = document.getElementById("select_division").selectedIndex;
		var td_html;

		for (i = 0; i < pref_table_data[0].length; i++) {
			td_html = groups[pref_table_data[0][i][0]] + "<br><span id=\"span_0_" + i + "\">" + pref_table_data[0][i][type_i][this_division_i] + "</span>";
			document.getElementById("td_0_" + i).innerHTML = td_html;
		}
	} else if (table_type == "prefs_from_primary") {
		calculate_pref_table_col(0);
		var sel = document.getElementById("select_first_n");
		var max_fixed_pref = +sel.options[sel.selectedIndex].value;
		
		sel = document.getElementById("select_upto_n");
		var max_pref = +sel.options[sel.selectedIndex].value;
		
		// Initialise the preference table with empty td's.
		div_html = "<p class=\"left_align\"><i>Sort instead by <span class=\"js_link\" id=\"span_pref_table_sort\" onclick=\"change_pref_table_sort_prep()\">ballot paper order</span>.<br></i>";
		div_html += "<i><span class=\"js_link\" onclick=\"make_cross_table()\">Generate cross table</span>.</i></p>";
		
		div_html += "<table><tr>";
		for (i = 0; i < max_fixed_pref; i++) {
			div_html += "<th>Pref " + (i + 1) + "</th>";
		}
		
		for (i = 0; i < max_pref - max_fixed_pref; i++) {
			div_html += "<th>By " + max_pref + "</th>";
		}
		
		div_html += "</tr>";
		
		
		
		for (i = 0; i < groups.length; i++) {
			div_html += "<tr class=\"tr_shaded\">";
			for (j = 0; j < max_pref; j++) {
				div_html += "<td id=\"td_" + j + "_" + i + "\" onclick='change_pref(" + j + "," + i + ")'>&nbsp;</td>";
			}
			div_html += "</tr>";
		}
		div_html += "</table>";

		document.getElementById("td_pref_table").innerHTML = div_html;
		
		// Fill in the first column of the table.
		change_pref_table_sort(sorting_pref_table_by);
		var type_i = document.getElementById("select_type").selectedIndex + 1;
		var this_division_i = document.getElementById("select_division").selectedIndex;
		var td_html;

		for (i = 0; i < pref_table_data[0].length; i++) {
			td_html = groups[pref_table_data[0][i][0]] + "<br><span id=\"span_0_" + i + "\">" + pref_table_data[0][i][type_i][this_division_i] + "</span>";
			document.getElementById("td_0_" + i).innerHTML = td_html;
		}
		
	} else if (table_type == "primaries_from_prefs") {
		calculate_pref_table_col(0);
		var min_pref = get_first_n();
		var max_pref = get_upto_n();
		
		// Initialise the preference table with empty td's.
		div_html = "<p class=\"left_align\"><i>Sort instead by <span class=\"js_link\" id=\"span_pref_table_sort\" onclick=\"change_pref_table_sort_prep()\">ballot paper order</span>.<br></i>";
		div_html += "<i><span class=\"js_link\" onclick=\"make_cross_table()\">Generate cross table</span>.</i></p>";
		
		div_html += "<table><tr>";
		div_html += "<th>" + min_pref + "-" + max_pref + "</th>";
		div_html += "<th>Pref 1</th></tr>";
		
		for (i = 0; i < groups.length; i++) {
			div_html += "<tr class=\"tr_shaded\">";
			for (j = 0; j < 2; j++) {
				div_html += "<td id=\"td_" + j + "_" + i + "\" onclick='change_pref(" + j + "," + i + ")'>&nbsp;</td>";
			}
			div_html += "</tr>";
		}
		
		div_html += "</table>";
		
		document.getElementById("td_pref_table").innerHTML = div_html;
		
		// Fill in the first column of the table.
		change_pref_table_sort(sorting_pref_table_by);
		var type_i = document.getElementById("select_type").selectedIndex + 1;
		var this_division_i = document.getElementById("select_division").selectedIndex;
		var td_html;

		for (i = 0; i < pref_table_data[0].length; i++) {
			td_html = groups[pref_table_data[0][i][0]] + "<br><span id=\"span_0_" + i + "\">" + pref_table_data[0][i][type_i][this_division_i] + "</span>";
			document.getElementById("td_0_" + i).innerHTML = td_html;
		}
		
	} else if (table_type == "bidirectional") {
		
	}
	
	cross_table_data_ij = [];
	cross_table_data_ji = [];
	cross_table_divisions_ij = [];
	cross_table_divisions_ji = [];
	
	for (i = 0; i < groups.length; i++) {
		cross_table_data_ij.push({"base":-1, "group":-1, "votes":[]});
		cross_table_data_ji.push({"group":-1, "votes":[]});
		
		for (j = 0; j < groups.length; j++) {
			cross_table_data_ij[i].votes.push(0);
			cross_table_data_ji[i].votes.push(0);
		}
	}
	
	// The divisions cross table is asymmetric, so two sets of loops for it.
	for (i = 0; i < divs.length; i++) {
		cross_table_divisions_ij.push({"division":-1, "votes":[]});
		
		for (j = 0; j < groups.length; j++) {
			cross_table_divisions_ij[i].votes.push(0);
		}
	}
	
	for (i = 0; i < groups.length; i++) {
		cross_table_divisions_ji.push({"group":-1, "votes":[]});
		
		for (j = 0; j < divs.length; j++) {
			cross_table_divisions_ji[i].votes.push(0);
		}
	}
}

function initialise_division_table() {
	division_table_data = [];
	
	for (var i = 0; i < divs.length; i++) {
		division_table_data.push([]);
		division_table_data[i].push(i);
		division_table_data[i].push(0);
	}
}

function make_upto_prefs_selector(keep_selected) {
	var table_type = get_table_type();
	var sel = document.getElementById("select_first_n");
	var start_i = +sel.options[sel.selectedIndex].value;
	
	var sel = document.getElementById("select_upto_n");
	var new_i = -1;
	
	if (keep_selected) {
		var current_val = sel.options[sel.selectedIndex].value;
		sel.options.length = 0;
	}
	
	if (table_type == "prefs_from_primary") {
		start_i++;
	}
	
	var j = 0;
	for (i = start_i; i <= num_prefs; i++) {
		sel.add(create_option_element(i, "option_type_", i));
		if (i == current_val) { new_i = j; }
		j++;
	}
	
	if (keep_selected && (new_i >= 0)) {
		sel.options[new_i].selected = true;
	} else {
		sel.options[sel.options.length - 1].selected = true;
	}
}

function make_type_specific_selectors() {
	var table_type = get_table_type();
	var div_html = "";
	var i, sel;
	
	if (table_type == "step_forward") {
		// No optional selectors.
		document.getElementById("div_selectors_type").innerHTML = div_html;
	} else if (table_type == "first_n_prefs") {
		div_html += "Consider first <select id=\"select_first_n\" onchange='change_first_n()'></select> preferences.\n";
		document.getElementById("div_selectors_type").innerHTML = div_html;
		
		sel = document.getElementById("select_first_n");
		for (i = 2; i <= num_prefs; i++) {
			sel.add(create_option_element(i, "option_type_", i));
		}
		
		sel.options[sel.options.length - 1].selected = true;
	} else if (table_type == "prefs_from_primary") {
		
		div_html += "Fix first <select id=\"select_first_n\" onchange='change_first_n()'></select> preferences and ";
		div_html += "consider up to preference <select id=\"select_upto_n\" onchange='change_upto_n()'></select>.\n";
		document.getElementById("div_selectors_type").innerHTML = div_html;
		
		sel = document.getElementById("select_first_n");
		for (i = 1; i <= num_prefs - 1; i++) {
			sel.add(create_option_element(i, "option_type_", i));
		}
		sel.options[0].selected = true;
		
		make_upto_prefs_selector(false);
	} else if (table_type == "primaries_from_prefs") {
		div_html += "Consider preferences <select id=\"select_first_n\" onchange='change_first_n()'></select> to ";
		div_html += "<select id=\"select_upto_n\" onchange='change_upto_n()'></select>.\n";
		document.getElementById("div_selectors_type").innerHTML = div_html;
		
		sel = document.getElementById("select_first_n");
		for (i = 1; i <= num_prefs; i++) {
			sel.add(create_option_element(i, "option_type_", i));
		}
		sel.options[1].selected = true;
		
		make_upto_prefs_selector(false);
	} else if (table_type == "bidirectional") {
		// No optional selectors.
		document.getElementById("div_selectors_type").innerHTML = div_html;
	}
}

function get_table_type() {
	var sel = document.getElementById("select_table_type");
	return sel.options[sel.selectedIndex].value;
}

function get_first_n() {
	var sel = document.getElementById("select_first_n");
	return +sel.options[sel.selectedIndex].value;
}

function get_upto_n() {
	var sel = document.getElementById("select_upto_n");
	return +sel.options[sel.selectedIndex].value;
}


var i, j, this_group, this_number, this_votes, this_division;

var formatted_data = [[]];
var codes = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
var alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXY";

var selected_groups = [];
var selected_rows = [];

var highlighted_color = "#e0b0b0";

groups.push("Exh");

var num_prefs = 0;
var this_num_prefs, this_sum_votes;

var num_combs = pref_data.length / 2;
var sorting_pref_table_by = "votes";

// [column, direction]:
var sorting_division_table_by = [0, 1];

// [[row, direction], [column, direction]]:
var sorting_cross_table_by = [[-1, 1], [-1, 1]];
var sorting_cross_divisions_table_by = [[-1, 1], [-1, 1]];

var total_votes = [];
for (i = 0; i < divs.length; i++) {
	// Loop over divisions.
	total_votes.push(0);
}

// Taking the strings in the original data set 
// and turning them into arrays.
for (i = 0; i < num_combs; i++) {
	formatted_data[0].push([]);
	formatted_data[0][i].push([]);
	formatted_data[0][i].push([]);
	
	this_num_prefs = pref_data[2*i].length;
	if (this_num_prefs > num_prefs) {
		num_prefs = this_num_prefs;
	}
	
	for (j = 0; j < this_num_prefs; j++) {
		this_group = pref_data[2*i].substr(j, 1);
		
		if (this_group == "Z") {
			// Exhaust
			this_group = -1;
		} else {
			this_group = alphabet.indexOf(this_group);
		}
		
		formatted_data[0][i][0].push(this_group);
	}
	
	this_sum_votes = 0;
	
	if (typeof pref_data[2*i + 1] == "string") {
		for (j = 0; j < pref_data[2*i + 1].length; j++) {
			this_number = codes.indexOf(pref_data[2*i + 1].substr(j, 1));
			formatted_data[0][i][1].push(this_number);
			this_sum_votes += this_number;
			total_votes[j] += this_number;
		}
	} else {
		// Already an array
		for (j = 0; j < pref_data[2*i + 1].length; j++) {
			formatted_data[0][i][1].push(pref_data[2*i + 1][j]);
			this_sum_votes += pref_data[2*i + 1][j];
			total_votes[j] += pref_data[2*i + 1][j];
		}
	}
	
	// Append the state-wide vote tally after the divisions:
	formatted_data[0][i][1].push(this_sum_votes);
	total_votes[total_votes.length - 1] += this_sum_votes;
}

for (i = 1; i < num_prefs; i++) {
	formatted_data.push([]);
}



// Will store the numbers in the main preference table:
var pref_table_data;

// Will hold the cross table data (duplicated by rows and columns):
var cross_table_data_ij, cross_table_data_ji, cross_table_divisions_ij, cross_table_divisions_ji;

var division_table_data = [];
initialise_division_table();


var calculating_cross_table = false;
var null_td_click = false;


// Create the selectors for table type, number type and division.
var div_html = "<br><table>";
div_html += "<tr><td class=\"right_align\" style=\"padding-bottom:10px\">Table type:</td><td class=\"left_align\" style=\"padding-bottom:10px\"><select id=\"select_table_type\" onchange='change_table_type()'></select></td></tr>\n";
div_html += "<tr><td class=\"right_align\" style=\"padding-bottom:10px\">Show</td><td class=\"left_align\" style=\"padding-bottom:10px\"><select id=\"select_type\" onchange='change_type()'></select></td></tr>\n";
div_html += "<tr><td class=\"right_align\" style=\"padding-bottom:10px\">in</td><td class=\"left_align\" style=\"padding-bottom:10px\"><select id=\"select_division\" onchange='change_division()'></select></td></tr>\n";
div_html += "</table>";

document.getElementById("div_selectors").innerHTML = div_html;

var sel = document.getElementById("select_type");
sel.add(create_option_element("votes", "option_type_", "Votes"));
sel.add(create_option_element("perc", "option_type_", "Percentages"));
sel.add(create_option_element("total_perc", "option_type_", "Total percentages"));
sel.options[0].selected = true;

sel = document.getElementById("select_division");
for (i = 0; i < divs.length; i++) {
	sel.add(create_option_element(divs[i], "option_division_", divs[i]));
}

sel.options[sel.options.length - 1].selected = true;

sel = document.getElementById("select_table_type");
sel.add(create_option_element("step_forward", "option_type_", "Step forward"));
sel.add(create_option_element("first_n_prefs", "option_type_", "In first N preferences"));
sel.add(create_option_element("prefs_from_primary", "option_type_", "Later preferences"));
sel.add(create_option_element("primaries_from_prefs", "option_type_", "Preference sources"));

// It's after 11pm, this next one's not getting written.
//sel.add(create_option_element("bidirectional", "option_type_", "Forwards and backwards"));

sel.options[0].selected = true;

make_type_specific_selectors();

var td_width_css = ["", ""];
if (using_wide_layout) {
	td_width_css[0] = " style=\"width:325px;";
	td_width_css[1] = ";word-break:normal";
}

div_html = "<table>";
div_html += "<tr><td id=\"td_pref_table\"" + td_width_css[0] + "\"></td><td id=\"td_division_table\" style=\"vertical-align:top" + td_width_css[1] + "\"></td></tr>";
div_html += "</table>";
document.getElementById("div_table").innerHTML = div_html;


initialise_table_area();



// Now the division table.
var division_table_sorting = [0, 1];

div_html = "<p class=\"left_align\"><i>Click on a column header to sort.</i>";
div_html = "<br><span id=\"span_division_table_title\"><b>No selection</b></span></p>";
div_html += "<table>";
div_html += "<tr><th class=\"left_align subtle_js_link\" onclick='sort_division_table(0, 1)'>Division</th>";
div_html += "<th class=\"right_align subtle_js_link\"  onclick='sort_division_table(1, 1)'>Vote</th></tr>";

var divs_sorted = JSON.parse(JSON.stringify(divs));
divs_sorted.sort(function(a, b) { return sort_divs_aux(a, b); });

for (i = 0; i < divs.length; i++) {
	div_html += "<tr class=\"tr_shaded\" id=\"tr_divs_" + i + "\"><td class=\"left_align\" id=\"td_divs_name_" + i + "\">" + divs_sorted[i] + "</td>";
	div_html += "<td class=\"right_align\" id=\"td_divs_votes_" + i + "\"></td></tr>";
}
div_html += "</table>";
document.getElementById("td_division_table").innerHTML = div_html;

document.getElementById("tr_divs_" + (divs.length - 1)).style.fontWeight = "bold";


var inferno_scale = [
[0,0,4],
[1,0,5],
[1,1,6],
[1,1,8],
[2,1,10],
[2,2,12],
[2,2,14],
[3,2,16],
[4,3,18],
[4,3,20],
[5,4,23],
[6,4,25],
[7,5,27],
[8,5,29],
[9,6,31],
[10,7,34],
[11,7,36],
[12,8,38],
[13,8,41],
[14,9,43],
[16,9,45],
[17,10,48],
[18,10,50],
[20,11,52],
[21,11,55],
[22,11,57],
[24,12,60],
[25,12,62],
[27,12,65],
[28,12,67],
[30,12,69],
[31,12,72],
[33,12,74],
[35,12,76],
[36,12,79],
[38,12,81],
[40,11,83],
[41,11,85],
[43,11,87],
[45,11,89],
[47,10,91],
[49,10,92],
[50,10,94],
[52,10,95],
[54,9,97],
[56,9,98],
[57,9,99],
[59,9,100],
[61,9,101],
[62,9,102],
[64,10,103],
[66,10,104],
[68,10,104],
[69,10,105],
[71,11,106],
[73,11,106],
[74,12,107],
[76,12,107],
[77,13,108],
[79,13,108],
[81,14,108],
[82,14,109],
[84,15,109],
[85,15,109],
[87,16,110],
[89,16,110],
[90,17,110],
[92,18,110],
[93,18,110],
[95,19,110],
[97,19,110],
[98,20,110],
[100,21,110],
[101,21,110],
[103,22,110],
[105,22,110],
[106,23,110],
[108,24,110],
[109,24,110],
[111,25,110],
[113,25,110],
[114,26,110],
[116,26,110],
[117,27,110],
[119,28,109],
[120,28,109],
[122,29,109],
[124,29,109],
[125,30,109],
[127,30,108],
[128,31,108],
[130,32,108],
[132,32,107],
[133,33,107],
[135,33,107],
[136,34,106],
[138,34,106],
[140,35,105],
[141,35,105],
[143,36,105],
[144,37,104],
[146,37,104],
[147,38,103],
[149,38,103],
[151,39,102],
[152,39,102],
[154,40,101],
[155,41,100],
[157,41,100],
[159,42,99],
[160,42,99],
[162,43,98],
[163,44,97],
[165,44,96],
[166,45,96],
[168,46,95],
[169,46,94],
[171,47,94],
[173,48,93],
[174,48,92],
[176,49,91],
[177,50,90],
[179,50,90],
[180,51,89],
[182,52,88],
[183,53,87],
[185,53,86],
[186,54,85],
[188,55,84],
[189,56,83],
[191,57,82],
[192,58,81],
[193,58,80],
[195,59,79],
[196,60,78],
[198,61,77],
[199,62,76],
[200,63,75],
[202,64,74],
[203,65,73],
[204,66,72],
[206,67,71],
[207,68,70],
[208,69,69],
[210,70,68],
[211,71,67],
[212,72,66],
[213,74,65],
[215,75,63],
[216,76,62],
[217,77,61],
[218,78,60],
[219,80,59],
[221,81,58],
[222,82,56],
[223,83,55],
[224,85,54],
[225,86,53],
[226,87,52],
[227,89,51],
[228,90,49],
[229,92,48],
[230,93,47],
[231,94,46],
[232,96,45],
[233,97,43],
[234,99,42],
[235,100,41],
[235,102,40],
[236,103,38],
[237,105,37],
[238,106,36],
[239,108,35],
[239,110,33],
[240,111,32],
[241,113,31],
[241,115,29],
[242,116,28],
[243,118,27],
[243,120,25],
[244,121,24],
[245,123,23],
[245,125,21],
[246,126,20],
[246,128,19],
[247,130,18],
[247,132,16],
[248,133,15],
[248,135,14],
[248,137,12],
[249,139,11],
[249,140,10],
[249,142,9],
[250,144,8],
[250,146,7],
[250,148,7],
[251,150,6],
[251,151,6],
[251,153,6],
[251,155,6],
[251,157,7],
[252,159,7],
[252,161,8],
[252,163,9],
[252,165,10],
[252,166,12],
[252,168,13],
[252,170,15],
[252,172,17],
[252,174,18],
[252,176,20],
[252,178,22],
[252,180,24],
[251,182,26],
[251,184,29],
[251,186,31],
[251,188,33],
[251,190,35],
[250,192,38],
[250,194,40],
[250,196,42],
[250,198,45],
[249,199,47],
[249,201,50],
[249,203,53],
[248,205,55],
[248,207,58],
[247,209,61],
[247,211,64],
[246,213,67],
[246,215,70],
[245,217,73],
[245,219,76],
[244,221,79],
[244,223,83],
[244,225,86],
[243,227,90],
[243,229,93],
[242,230,97],
[242,232,101],
[242,234,105],
[241,236,109],
[241,237,113],
[241,239,117],
[241,241,121],
[242,242,125],
[242,244,130],
[243,245,134],
[243,246,138],
[244,248,142],
[245,249,146],
[246,250,150],
[248,251,154],
[249,252,157],
[250,253,161],
[252,255,164]];
