/* init.js
 * http://tasuke.dna.affrc.go.jp/
 *
 * Author: Jungsok Kim, Ryutaro Itoh
 *
 * Copyright (c) 2013 National Institute of Agrobiological Sciences   
 *
 */
var DEBUG_MODE = false;
//var DEBUG_MODE = true;

var cvs0;
var ctx0;
var cvs1;
var ctx1;
var cvs2;
var ctx2;
var cvs3;
var ctx3;
var cvs4;
var ctx4;
var cvs5;
var ctx5;
var cvs6;
var ctx6;
var cvs7;
var ctx7;
var cvs8;
var ctx8;
var cvs9;
var ctx9;
var cvs10;
var ctx10;
var cvs11;
var ctx11;
var cvs12;
var ctx12;
var cvs13;
var ctx13;
var cvs14;
var ctx14;
var cvs15;
var ctx15;
var cvs16;
var ctx16;
var cvs17;
var ctx17;
var cvs18;
var ctx18;
var cvs19;
var ctx19;

var treeobj;	// phyloTreeCreater instance
var flgUpdateTree = false;
//var flgUsingPhylipTree = false;
var currentPhyloTarget = {};	// Retains gene ID, genome position, settings of the last applied phylip tree. 
var phylipCollapsedBranch = {};	// Needed to return PhylipTree to Unsort.
//var dispTreeLoadProgressAccNum = 700;	// Min Accs to show tree creation progress.

var listListManager = null;
var phyListManager = null;

var frameCell;
var frameCellwoI;
//var frameCellViewport = {'data':null, 'y':null};
//var frameCellwoI = {'data':null, 'y':null};
var frameTitle;
//var frameTitlewoI = {'data':null, 'y':null};
var frameNav;
var frameChr;
var frameTrack;
var frameTrackwR;
var frameSNP;
var frameZoomb;
var framePlot;
var ONSEARCH = false;
var RELOAD = false;
var PROGRESSTIMER;
var BUSYDETECTTIMER;
var Objects=new Object();
var timerArray = new Array();
var drawBlastStr = '';
var drawlPrmStr = '';
var drawrPrmStr = '';
var drawTargetStr = '';
var primer3ArrayForBLASTRight='';
var primer3ArrayForBLASTLeft='';
var minPos = new Array();
//var winFront = new Array();
var maxDialogZindex = 1000;
var lastClickDialogName = '';

// use phenotype browser or not
var phenotypeStr = _getphenotypeFlg();
var phenotypeFlg = "";
if (phenotypeStr == "false") {
	phenotypeFlg = false;
} else if (phenotypeStr == "true") {
	phenotypeFlg = true;
}

var systreeFlg = false;

//var DEF_QUAL = 20;
//var DEF_DP = 2;
//var DEF_DP4 = 2;
var DEF_QUAL = 1;
var DEF_DP = 1;
var DEF_DP4 = 1;

var DAMMY_KEYWORD = 'the target';
//var VERSION = '20240326';	// Move to env.js
var DEF_PLACEHOLDER_TOPSEARCH = 'eg.Os01g0100100-01,chr01:1-100';
var DEF_PLACEHOLDER_POSSEARCH = 'eg. chr01:1-100';
var DEF_PLACEHOLDER_KWSEARCH = '(eg. Os01g0100100-01)';

var STR_SYSTREE_MODE_DIST = 'dist';
//var STR_SYSTREE_MODE_PHY = 'phy';
var STR_SYSTREE_MODE_NEWICK = 'newick';

// for Track scroll event listener
//var VIEWSTART=0;
//var VIEWLEN=0;
var SCRTIMER;
var FROMSCROLL;

// Threads number to get Variant/Depth track.
var DEF_TRACK_THREADNUM = 4;

/*
 * render() and renderInner() are called only when TASUKE is initialized and are not called after that.
 */

/**
 * Asynchronous Ajax
 */
function render() {
	// If you want to run multipl ajax in sequence, you need to nest.
	// This is implemented by the recursive processing.
	var sendData = {};
	var procs = [];
	if(_isEmpty(storage.getItem("_Env"))){
		procs.push({
			"url": "./bin/env.php",
			"type": "GET",
			"preFunc": null,
			"func": function(data) {
				storage.setItem("_Env", data);
			},
			"errorFunc": function() { alert("Failed to get settings from server."); }
		});
	}

	if(_isEmpty(storage.getItem("_Lists"))){
		procs.push({
			"url": "./bin/list.php",
			"type": "POST",
			"preFunc": function() {
				// for "URL?acc=acc1,acc2,acc3...."
				sendData = {"prm_ext_acc": ""};
			},
			"func": function(data) {
				var a=data.split("|");
				var accArray = JSON.parse(a[0]);
				_setAccListObjArray("_Lists-origin", accArray);
				if(!_isEmpty(storage.getItem("_Ext_accessions"))) {
					var listsAccs = storage.getItem("_Ext_accessions").split(",");
					storage.removeItem("_Ext_accessions");
					_reset_accession_lists_byArray(listsAccs);
				} else {
					_setAccListObjArray("_Lists", accArray);
				} 
				storage.setItem("_Tracks", a[1]);
				storage.setItem("_Conditions", a[2]);
				if(phenotypeFlg){
					storage.setItem("_PhenotypeExpressions", a[3]);
					storage.setItem("_PhenotypePapers", a[4]);
				}
			},
			"errorFunc": function() { alert("Failed to get accession list from server."); }
		});
	}

	if(_isEmpty(storage.getItem("_Chr"))){
		procs.push({
			"url": "./bin/chr.php",
			"type": "GET",
			"preFunc": null,
			"func": function(data) {
				storage.setItem("_Chrs", data);
//				storage.setItem("_Chr", _getChr().id);
			},
			"errorFunc": function() { alert("Failed to get chromosome list from server."); }
		});
	}

	if(_isEmpty(storage.getItem("_AllPhenoExp"))) {
		procs.push({
			"url": "./bin/getAllPhenoexp.php",
			"type": "GET",
			"preFunc": null,
			"func": function(data) {
				storage.setItem("_AllPhenoExp", data);
			},
			"errorFunc": function() { alert("Failed to get Phenotype-Exp table from server."); }
		});
	}

	var recProc = function() {
		var proc = procs.shift();
		if(proc == null) {
			renderInner();
			return;
		}
		if(proc.preFunc != null) proc.preFunc();

		$.ajax({
			"url": proc.url,
			"cache": false,
			"type": proc.type,
			"async": false,
			"data": sendData
		}).done(function(data){
			proc.func(data);
			sendData = {};
			recProc();	// Recursive processing
		}).fail(function(){
			proc.errorFunc();
		});
	};
	recProc();
}
function renderInner() {
        // Checking HTML5
        var canvasSupported = !!window.HTMLCanvasElement;
        if (!canvasSupported) document.location="./bin/error.php?prm_error_mode=HTML5";
        cvs0=document.getElementById("cvs_track_list");
        ctx0=cvs0.getContext("2d");
        cvs1=document.getElementById("cvs_tracks");
        ctx1=cvs1.getContext("2d");
        cvs2=document.getElementById("cvs_nav");
        ctx2=cvs2.getContext("2d");
        cvs3=document.getElementById("cvs_list");
        ctx3=cvs3.getContext("2d");
        cvs4=document.getElementById("cvs_view");
        ctx4=cvs4.getContext("2d");
        cvs5=document.getElementById("cvs_snpt");
        ctx5=cvs5.getContext("2d");
        cvs6=document.getElementById("cvs_snpg");
        ctx6=cvs6.getContext("2d");
        cvs7=document.getElementById("cvs_ind");
        ctx7=cvs7.getContext("2d");
        cvs8=document.getElementById("cvs_ind_blk");
        ctx8=cvs8.getContext("2d");
        cvs9=document.getElementById("cvs_zbar");
        ctx9=cvs9.getContext("2d");
        cvs10=document.getElementById("cvs_cellinf");
        ctx10=cvs10.getContext("2d");
        cvs11=document.getElementById("cvs_refname");
        ctx11=cvs11.getContext("2d");
        if(phenotypeFlg){
                cvs12=document.getElementById("cvs_plot_view");
                ctx12=cvs12.getContext("2d");
                cvs13=document.getElementById("cvs_plot_y_scale");
                ctx13=cvs13.getContext("2d");
                //cvs14=document.getElementById("show_phenotype");
                //ctx14=cvs14.getContext("2d");
        }
        cvs14=document.getElementById("cvs_errmsg");
        ctx14=cvs14.getContext("2d");
        cvs15=document.getElementById("cvs_clserr");
        ctx15=cvs14.getContext("2d");

	cvs16 = document.getElementById("blkcvs");
  	ctx16 = cvs16.getContext('2d');
        cvs17 = document.getElementById("dentitlecvs");
        ctx17 = cvs17.getContext('2d');
        cvs18 = document.getElementById("dencvs");
        ctx18 = cvs18.getContext('2d');
        cvs19 = document.getElementById("phenotitlecvs");
        ctx19 = cvs19.getContext('2d');

        // Clear localStorage when url is sub directory on same domain
        var crntUrl = location.href.split("?");
        RELOAD = true;
        _showLoadingDialog();
//        _showLoading();
        _initCache();

	var en = new Object(JSON.parse(storage.getItem("_Env")));
	if(en.useSystemTree === "1" || en.useSystemTreeLW === "1") {
		systreeFlg = true;
	} else {
		systreeFlg = false;
	}
	initSystemTreeObj();
        var willBeReplaced = _externalParser();	// Use systreeFlg and treeobj in this.
	if(willBeReplaced) return;

	initSelect2();	// for select2.js

	if(isPhylipTreeUsing()) {
		// If apply PhylipTree and reload(F5) with node collapsing, must expand Accs.
		syncStorage2PhylipTree2Lists();
		clearPhylipTreeCache();
//		storage.removeItem("_PhylipTreeNewick");

		// If SystemTree is not deleted, it will be reproduced before Acc is selected in the phylogenetic analysis.
		clearSystemTreeCache();
	}

	// For SystemTree using newick.
	if('systreeNewickLW' in en && en['systreeNewickLW']) {
		// First time Load
		// This block will be skipped during F5 Reload. Because en['systreeNewickLW'] is deleted in "finally" below.
		if(DEBUG_MODE) console.log("[using Newick] Set SystemTree to storage");
		var localTreeObj = null;
		try {
			localTreeObj = new PhyloTreeCreater(null);
			localTreeObj.parseNewick(en['systreeNewickLW']);
			removeNotExistAccFromTreeObj(localTreeObj);	// Delete Acc that does not exist in _Lists from Newick.
			convSystreeId2Db(localTreeObj);
			var nwk = localTreeObj.tree.getNewick();
			storage.setItem('_SysTreeNewickLW', nwk);
//			storage.setItem('_SysTreeNewick', nwk);

			var threshold = parseFloat(storage.getItem("_SystemTreeAutoCollapseThreshold"));
			collapseTreeNode(localTreeObj, threshold);
		} catch(e) {
			console.error(e);
			storage.setItem('_SysTreeNewickLW', '');
		} finally {
			storage.setItem("_CurrentSystemTreeMode", STR_SYSTREE_MODE_NEWICK);
			if(localTreeObj) localTreeObj.initTree();
			delete en['systreeNewickLW'];
			var data = JSON.stringify(en);
			storage.setItem("_Env", data);
		}
	}

	if(isTreeAvailable() && storage.getItem("_SystemTreeDefaultDisplay") === 'off') {
		storage.setItem('_SYSTREE', 'off');
		storage.removeItem("_ListsTgt");
		FROMSCROLL=false;
		if(!_isEmpty(storage.getItem("_SysTreeNewick"))) {
			// For reload(F5). Reuse SystemTree in session storage and Reproduce hiding SystemTree.
			updateSystemTreeByStorage();
			var lastLeafOrder = treeobj.getNameOrder();
			storage.setItem("_SystemTreeLastLeafOrder", JSON.stringify(lastLeafOrder));
		}
		_showLoading();
		_execCanvas();
	} else if(isTreeUsing()) {
		if(_isEmpty(storage.getItem("_SysTreeNewick"))) {
			// First SystemTree load
			var threshold = parseFloat(storage.getItem("_SystemTreeAutoCollapseThreshold"));
			syncListsAndSystemTreeDefault(threshold);
//			syncListsAndSystemTree(threshold);
		} else {
			// For reload(F5) SystemTree
			syncStorage2SystemTree2Lists();
		}
	} else {
		// Don't Use SystemTree
		if(isTreeAvailable()) updateSystemTreeByStorage();	// If you reload(F5) with Tree:off, valid treeobj. 
		if(storage.getItem("_SYSTREE") === 'on') {
			// Close Tree, If SystemTree is not availabled and reloaded while using PhylipTree.
			storage.setItem("_SYSTREE","off");
		}
		_showLoading();
		_execCanvas();
	}

	// Note that the following process in parallel with drawing Track&Tree because ajax is executed.

        RELOAD = false;
        // When first time
        if ( storage.getItem('_Count') == "1" ) {storage.setItem('_Count',"2");}
        $("#tasuke").css("background-color",_setColor().bgcolor);
	if(!phenotypeFlg) {
        	$("#GWAS_plot").css('display','none');
        	$("#show_phenotype").css('display','none');
        	$("#select_phenotype").css('display','none');
		$("#menu .GWAS").css('display','none');
		$("#menu .GWAS_dlg").css('display','none');
	} else if (phenotypeFlg) {
                $("#GWAS_plot").css('display','block');
                $("#show_phenotype").css('display','block');
                $("#select_phenotype").css('display','block');
                $("#menu .GWAS").css('display','block');
                $("#menu .GWAS_dlg").css('display','block');
	}

	// Init Accession Manager list(standard);
	try {
		listListManager = initAccManagerTabulatorList('list');
		phyListManager = initAccManagerTabulatorList('phy');
	} catch(e) {
		console.log(e);
	}

	setSearchPlaceholder();
	setVersionToAbout();
	// Check if using a serial table.
	if(en.autoDetectSerialTable == 0 && isUsingSerialTable()) {
		alert("Message for web page administrator:\nSerial table is used because of the large number of reference seqs registered. Please change conf/config.php as follow:\n\$autoDetectSerialTable = 1;");
	}
}
function initAccManagerTabulatorList(type) {
	// Init Accession Manager list(standard)
	var accColumns = TasukeTabulatorManager.getStandardColumns();
	var lists = _getAccListObjArray("_Lists-origin").concat();	// Sallow copy(not reference)
	if(storage.getItem('_AllPhenoExp')) {
		// Get Gwas expression and add it's column.
		var acc2list = [];
		for(var i=0,len=lists.length; i<len; i++) {
			lists[i] = Object.assign({}, lists[i]);	//Copy object(not reference)
			acc2list[lists[i].id] = lists[i];
		}
		var phenoExpObjs = JSON.parse(storage.getItem('_AllPhenoExp'));
		var phenoids = Object.keys(phenoExpObjs);
		for(var i=0,iLen=phenoids.length; i<iLen; i++) {
			var nameAndExps = phenoExpObjs[phenoids[i]];
			var gwasColumn = TasukeTabulatorManager.getPhenotypeColumn(phenoids[i], nameAndExps[0]);
			accColumns.push(gwasColumn);

			var accs = Object.keys(nameAndExps[1]);
			for(var j=0,jLen=accs.length; j<jLen; j++) {
				if(!acc2list[accs[j]]) continue;
				acc2list[accs[j]][phenoids[i]] = parseFloat(nameAndExps[1][accs[j]]);
			}
		}
	}
	var callbacks = {
		tableBuilt: function(manager) {
//			manager.initActionSelector(type + "_std_actSelector");
//			manager.initActionSelectorBtnList(type + "_std_actSelect_b");
			manager.initActionSelectorSimple(type + '_std_actCheck', type + '_std_actUncheck', type + '_std_actToggle');
			manager.initSelectColumnSelector(type + "_std_colSelector");
			manager.initSearchSelect2(type + '_std_search', type + '_std_search_parent');
			manager.initSelectChangeUsing(type + '_std_selectCangeUsing');
			manager.syncFormAfterChecking();
			$("#" + type + "_acc_tabulator").resizable({
				"handles":"s",
				"minHeight":100,
				"maxHeight":800
			});
			$("#" + type + "_acc_tabulator .ui-resizable-s").css( {"bottom":"-1px", "height":"4px", "width":"100%"});
		},
		dataFiltered: function(manager, filters, rows) {
			manager.setCurrentRows(rows);
		}
	};

	var opt = {};
	if(type === "phy") opt["movableRows"] = false;

	var tgtManager = new TasukeTabulatorManager(type + "_acc_tabulator", accColumns, lists, callbacks, opt);
	tgtManager.verbose = DEBUG_MODE;
	tgtManager.spanIdCurrentRows = type + "_std_CurrentRows";
	tgtManager.spanIdCheckedRows = type + "_std_CheckedRows";
//	tgtManager.buttonIdClearAllFilter = "tabulator_btn_allclear";
	tgtManager.funcDisableBtnMoveRow = _disabled_list_sort;
	tgtManager.buttonIdUndo = type + "_std_btnUndo";
	tgtManager.buttonIdRedo = type + "_std_btnRedo";

	return tgtManager;
}
function isUsingSerialTable() {
	var isUsing = false;
        $.ajax({
                url: "./bin/"+_backendSelector("isUsingSerialTable.php"),
                type: "POST",
                async:false,
                cache: false,
                success: function(data) {
                        if(data === "1") isUsing = true;
                }
        });
        return isUsing;
}
function removeNotExistAccFromTreeObj(treeObj) {
	var lists = _getAccListObjArray('_Lists-origin');
	var existIds = {};
	for(var i=0,len=lists.length; i<len; i++) existIds[lists[i].id] = true;

	var treeAccs = treeObj.getNameOrder();
	var delAccs = [];
	for(var i=0,len=treeAccs.length; i<len; i++) {
		if( !(treeAccs[i] in existIds) ) {
			delAccs.push(treeAccs[i]);
			if(DEBUG_MODE) console.log("Remove from LW tree:" + treeAccs[i]);
		}
	}

	if(delAccs.length !== 0) treeObj.removeLeafsAndUpdate(delAccs);
}

var timeoutListSearch = null;
function initSelect2() {
        // init Select2

        // Add search form to Chr selection pull-down by select2 library
/*
	var en=new Object(JSON.parse(storage.getItem("_Env")));
	chrs =new Object(JSON.parse(storage.getItem("_Chrs")));
	var chrsArray = [];
	for (var i=0,len=chrs.length; i<len; i++){
		chrsArray.push({"id":chrs[i].id, "text":en.chromosome_name+chrs[i].id});
	}
	$("#prm_chr").select2({
		dropdownAutoWidth: true,
		width: 'auto',
		dropdownParent: $('#prm_chr_parent'),
		data:chrsArray
	});
*/
        $('.js-example-basic-single').select2({
                dropdownAutoWidth: true,
                width: 'auto'
        });
/*
	if(!isSmartPhone()) {
		$('#prm_chr').select2({
			dropdownAutoWidth: true,
			width: 'auto'
		});
	}
*/
	// Search dialog: Accession
	$("#prm_accession_search").select2({
		dropdownAutoWidth: true,
		width: 'auto',
//		dropdownParent:$('#prm_accession_search_parent'),
		dropdownParent:$(document.body),
		closeOnSelect: false,
		placeholder: "Filter by keyword"
	});
//	$("#prm_accession_search").on('select2:open', function(e) {
//console.log($('#' + this.id + '_parent .select2-dropdown')[0]);
//$($('#' + this.id + '_parent .select2-dropdown')[0]).css('z-index', 9981);
//	});
	$("#prm_accession_search_parent").find('.select2-container').css('min-width', '128px');
	$("#prm_accession_search_parent").find('.select2-container--default').css('overflow-y', 'visible');

	// AccManager & PhylogeneticTree Acc List Search Form.
	//TODO left alignment of dropdown
	// https://stackoverflow.com/questions/51703078/right-align-dropdown-menu-in-select2
	var lstIds = ['lstBox1_search', 'lstBox2_search', 'idlst_search', 'tree_qry_search'];
	for(var i=0,len=lstIds.length; i<len; i++) {
		var lstId = '#' + lstIds[i];
		var lstParentId = lstId + '_parent';
		var $lst = $(lstId);
		$lst.select2({
			dropdownAutoWidth: true,
			width: 'auto',
			placeholder: "Filter by keyword",
			closeOnSelect: false,
			dropdownParent: $(lstParentId)
		});
		$lst.on('select2:open', function (e) {
			// Set dropdown height.
			// Since the dropdown does not exist in the initial state, it must be prepared in the "select2:open" event.
			$('#' + this.id + '_parent .select2-results__options').css('max-height', '150px');

			var thisObj = this;

			$('#' + thisObj.id + '_parent .select2-dropdown').css('background', '#f6f2f0');
			if(this.id === 'lstBox2_search' || this.id === 'tree_qry_search') {
				var $objs = $('#' + thisObj.id + '_parent').find('.select2-container--open');
				var defaultStyle = $($objs[1]).attr('style');
				$($objs[1]).css('cssText', defaultStyle + 'right:0px; left:auto; width:500px;');
			} else {
/*
				var $objs = $('#' + thisObj.id + '_parent').find('.select2-container--open');
				var defaultStyle = $($objs[1]).attr('style');
setTimeout(function() {
				$($objs[1]).css('cssText', defaultStyle + 'background:gray;');
}, 1);
*/
			}

			// Below, there is a timelag in updating ".select2-results__options", so setTimeout is required.
			setTimeout(function() {
				// Apply highlights after opening the dropdown.
				markSelect2Options(thisObj);
			}, 10);
			$('#' + this.id + '_parent .select2-search__field').on('input', function(e) {
				// Update highlights after filtering by keyword.
				clearTimeout(timeoutListSearch);
				timeoutListSearch = setTimeout(function() {
					markSelect2Options(thisObj);
					timeoutListSearch = null;
				}, 100);
			});
		});
//		$(lstParentId + ' .select2-selection--single').css('height', '13px');
		$(lstParentId + ' .select2-selection__rendered').css('font-size', '11px');
//		$(lstParentId + ' .select2-selection__rendered').css('line-height', '13px');
//		$(lstParentId + ' .select2-selection__arrow').css('height', '13px');
	}

        // GWAS dialog: If you change chr pulldown, there is a problem that dialog cannot be scrolled. So set it individually.
        $("#pheno_chr").select2({
                dropdownAutoWidth: true,
                width: 'auto',
                dropdownParent: $('#pheno_chr_parent')
        });
        $('#pheno_chr').on('select2:open', function (e) {
          const evt = "scroll.select2";
          $(e.target).parents().off(evt);
          $(window).off(evt);
        });

        // TSV export dialog: Since select2 of modal dialog cannot inputed in search form, set it individually.
        $("#prm_csv_chr").select2({
                dropdownAutoWidth: true,
                width: 'auto',
                dropdownParent: $('#prm_csv_chr_parent')
        });

	$("#prm_rp3_chr").select2({
		dropdownAutoWidth: true,
		width: 'auto',
		dropdownParent: $('#prm_rp3_chr_parent')
	});

	$("#prm_p3_chr").select2({
		dropdownAutoWidth: true,
		width: 'auto',
		dropdownParent: $('#prm_p3_chr_parent')
	});

/*
	$("#prm_fa_chr").select2({
		dropdownAutoWidth: true,
		width: 'auto',
		dropdownParent: $('#prm_fa_chr_parent')
	});
*/
}
function isTreeAvailable() {
	// using System or Phylip tree
	return (systreeFlg || treeobj.isTreeUsing());
}
function isTreeUsing() {
	return (isTreeAvailable() && storage.getItem("_SYSTREE") === 'on');
}
function isPhylipTreeUsing() {
	return !(_isEmpty(storage.getItem("_PhylipTreeNewick")));
}
function syncStorage2PhylipTree2Lists() {
	var phylipTreeobj = new PhyloTreeCreater(null);
	try {
		phylipTreeobj.parseNewick(storage.getItem("_PhylipTreeNewick"));
		convSystreeDb2Id(phylipTreeobj);	// changeLeafName accDb -> accId
		var type = storage.getItem("_SystemTreeSortType");
		var xscend = storage.getItem("_SystemTreeSort");
		if(xscend !== "") phylipTreeobj.sortByLength(xscend, type);

		var allLeafs = phylipTreeobj.getAllPotentialNameOrder();
		_reset_accession_lists_byArray(allLeafs);
	} catch(error) {
		console.error(error);
	} finally {
		phylipTreeobj.initTree();	// If not executed, a memory leak will occur intensely.
	}
}

function setSearchPlaceholder() {
	var en = new Object(JSON.parse(storage.getItem("_Env")));
	if('placeholder' in en && 'kwsearch' in en['placeholder'] && en['placeholder'].kwsearch) {
		$("#eg_kw_search").html(en['placeholder'].kwsearch);
        } else {
		$("#eg_kw_search").html(DEF_PLACEHOLDER_KWSEARCH);
	}

	if('placeholder' in en && 'possearch' in en['placeholder'] && en['placeholder'].possearch) {
		$("#prm_position").prop('placeholder', en['placeholder'].possearch);
	} else {
		$("#prm_position").prop('placeholder', DEF_PLACEHOLDER_POSSEARCH);
	}

	if('placeholder' in en && 'topsearch' in en['placeholder'] && en['placeholder'].topsearch) {
		$("#searchTrk").prop('placeholder', en['placeholder'].topsearch);
	} else {
		$("#searchTrk").prop('placeholder', DEF_PLACEHOLDER_TOPSEARCH);
	}
}
//function setVersionToAbout() {
//	$("#dialog_about_version").html(VERSION);
//}

var treeIconPos = {};	// Hold TreeIcon position. Set in draw.js:_drawTreeFooter() and use in event.js
function positioningTreeHeader() {
	var divHeader = $("#div_tree_header");
	var divContent = $("#content");
	var cvsTree = $("#cvs_tree");
	var cvsTreeHeader = $("#cvs_tree_header");

	var height = 12;
	var width = cvsTree.width();
	var flgDraw = true;
	if(height > divContent.height()) {
		flgDraw = false;
		height = 1;
	}
	divHeader.width(width);
	divHeader.height(height);
	document.getElementById('cvs_tree_header').width = width;
	document.getElementById('cvs_tree_header').height = height;

	if(!flgDraw) return;

	var ctxH = cvsTreeHeader[0].getContext("2d");
	_drawTreeHeader(ctxH, treeobj, 0, 0, width-2);
}
function positioningTreeFooter() {
	var divFooter = $("#div_tree_footer");
	var divContent = $("#content");
	var cvsTree = $("#cvs_tree");
	var cvsTreeFooter = $("#cvs_tree_footer");

	var height = 12;
	var width = cvsTree.width();
	if(!isTreeUsing()) {
		width = height;
	}
	var top = divContent.offset().top + divContent.height() - height + 1;
	var flgDraw = true;
	if(top <= divContent.offset().top) {
		flgDraw = false;
		top = divContent.offset().top + divContent.height() - 1;
		height = 1;
	}
        divFooter.width(width);
	divFooter.height(height);
	document.getElementById('cvs_tree_footer').width = width;
	document.getElementById('cvs_tree_footer').height = height;	

	if(!flgDraw) return;

	var ctxF = cvsTreeFooter[0].getContext("2d");
	_drawTreeFooter(ctxF, treeobj, 0, 0);
}

///////////////////////////////////////////////////////////
//Initialize webStorage
///////////////////////////////////////////////////////////
function _initCache() {
	if(DEBUG_MODE) console.log("_initCache");
	storage.removeItem("_ListsTgt");

        if(_isEmpty(storage.getItem("_Url"))){
                var crntUrl = location.href.split("?");
                storage.setItem("_Url",crntUrl[0].replace("index.html",""));
        }
        if(_isEmpty(storage.getItem("_Ref"))){
                storage.setItem("_Ref","Reference");
        }

        if(_isEmpty(storage.getItem("_Block"))){
                storage.setItem("_Block","100");
        }
	if(_isEmpty(storage.getItem("_Zoom"))){
		storage.setItem("_Zoom","1k");
	}
	var setDefPos = false;
	if(_isEmpty(storage.getItem("_Chr"))) setDefPos = changetoDefaultPos();
	if(!setDefPos) {
		if(_isEmpty(storage.getItem("_Chr"))) storage.setItem("_Chr", _getChr().id);
	        if(_isEmpty(storage.getItem("_Pos"))) storage.setItem("_Pos","1");
	}

        if(_isEmpty(storage.getItem("_Mode"))){
                storage.setItem("_Mode","si");
                storage.setItem("_sFlg","1");
                storage.setItem("_iFlg","1");
                storage.setItem("_dpFlg","0");
        }
	if(_isEmpty(storage.getItem("_ColorMode"))){
		storage.setItem("_ColorMode","");
	}
        if(_isEmpty(storage.getItem("_Eff"))){
                storage.setItem("_Eff","off");
        }
	if(phenotypeFlg) {
                storage.setItem("_GWAS","on");
	}
        if(_isEmpty(storage.getItem("_Snpblock"))){
                storage.setItem("_Snpblock","off");
        }
	if(_isEmpty(storage.getItem("_CursorLines"))){
		storage.setItem("_CursorLines", "off");
	}
        if(_isEmpty(storage.getItem("_QUAL"))){
		storage.setItem("_QUAL", String(DEF_QUAL));
//                storage.setItem("_QUAL","20");
        }
        if(_isEmpty(storage.getItem("_DP"))){
		storage.setItem("_DP", String(DEF_DP));
//                storage.setItem("_DP","2");
        }
        if(_isEmpty(storage.getItem("_DP4"))){
		storage.setItem("_DP4", DEF_DP4);
//                storage.setItem("_DP4","2");
        }
	if(_isEmpty(storage.getItem("_EffGrps"))){
		storage.setItem("_EffGrps", JSON.stringify(_getEffNoFilterArray()));	// Order does not make sense
	}
        if(_isEmpty(storage.getItem("_titleFlg")) && _isEmpty(storage.getItem("_Name")) && _isEmpty(storage.getItem("_NameSub"))){
                storage.setItem("_titleFlg","1");
        }
	if(storage.getItem("_titleFlg") == 1) {
        	titlestr = _getTitle();
        	var titleary = titlestr.split(",");
        	var title = titleary[0];
        	var subtitle = titleary[1];
        	Objects.Name=title;
        	Objects.NameSub=subtitle;
		if(Objects.Name != "") {
        		storage.setItem("_Name",title);
		} else {
			storage.setItem("_Name","id");
		}
                if(Objects.NameSub != "") {
                        storage.setItem("_NameSub",subtitle);
                } else {
                        storage.setItem("_NameSub","subvariety");
                }
        	//storage.setItem("_NameSub",subtitle);
        	storage.setItem("_titleFlg","0");
  	}
        if(_isEmpty(storage.getItem("_BlockW"))){
                storage.setItem("_BlockW","10");
        }
        if(_isEmpty(storage.getItem("_BlockH"))){
                storage.setItem("_BlockH","12");
        }
	adjustBlockHForFirefox();	// Also calling _drawCanvas() and _drawSystemTree().
/*
        if(_isEmpty(storage.getItem("_Block"))){
                storage.setItem("_Block","100");
        }
*/
        if(_isEmpty(storage.getItem("_Indicator"))){
                storage.setItem("_Indicator","on");
        }
        if(_isEmpty(storage.getItem("_Amino"))){
                storage.setItem("_Amino","on");
        }
        if(_isEmpty(storage.getItem("_DirRef"))){
                storage.setItem("_DirRef","+");
        }
        if(_isEmpty(storage.getItem("_Null"))){
                storage.setItem("_Null","true");
        }
        if(_isEmpty(storage.getItem("_Keyword"))){
                storage.setItem("_Keyword","");
        }
	if(_isEmpty(storage.getItem("_HighlightVariantGene"))){
		storage.setItem("_HighlightVariantGene","");
	}
	if(_isEmpty(storage.getItem("_HighlightVariantExclUpDown"))){
		storage.setItem("_HighlightVariantExclUpDown","");
	}
        if(_isEmpty(storage.getItem("_History"))){
                storage.setItem("_History","[]");
        }
        if(_isEmpty(storage.getItem("_Color"))){
                storage.setItem("_Color","0");
        }
        if(_isEmpty(storage.getItem("_Count"))){
                storage.setItem("_Count","1");
        }
        if(_isEmpty(storage.getItem("_ListsDeleted"))){
//                storage.setItem("_ListsDeleted","[]");
		_setAccListObjArray("_ListsDeleted", []);
        }
        if(_isEmpty(storage.getItem("_TitleW"))) {
            storage.setItem("_TitleW", getTitleWidth()); 
        }

	var en=new Object(JSON.parse(storage.getItem("_Env")));

	if("accmanager_list_type" in en && en.accmanager_list_type != "") {
		storage.setItem("_AccmanagerListType", en.accmanager_list_type);
	} else {
		storage.setItem("_AccmanagerListType", "standard");
	}

	if(_isEmpty(storage.getItem("_SystemTreeW"))) {
		if("systreeWidth" in en && en.systreeWidth != "" && parseInt(en.systreeWidth) > 0) {
			storage.setItem("_SystemTreeW", String(parseInt(en.systreeWidth)));
		} else {
			storage.setItem("_SystemTreeW", 100);
		}
	}
	if(_isEmpty(storage.getItem("_SystemTreeCollapsedBranch"))) {
		storage.setItem("_SystemTreeCollapsedBranch", "{}");
	}
	if(!_isEmpty(storage.getItem("_SYSTREE"))) {
		// Continue current state
	} else if(en.useSystemTree === "1" || en.useSystemTreeLW === "1") {	// can't use systreeFlg yet.
		storage.setItem("_SYSTREE","on");
	} else {
		storage.setItem("_SYSTREE","off");
	}
	if(!_isEmpty(storage.getItem("_SystemTreeDefaultDisplay"))) {
		// Continue current state
	} else if(!("systreeDefaultOn" in en) || en.systreeDefaultOn == "1") {
		storage.setItem("_SystemTreeDefaultDisplay", "on");	// Default
	} else {
		storage.setItem("_SystemTreeDefaultDisplay", "off");
	}
	if(_isEmpty(storage.getItem("_SystemTreeMode"))) {
		storage.setItem("_SystemTreeMode", "phylogram");
//		storage.setItem("_SystemTreeMode", "cladogram");
	}
//	if(_isEmpty(storage.getItem("_SystemTreeCorrect"))) {
	if(storage.getItem("_SystemTreeCorrect") == null) {
		if("systreeCorrection" in en && /^asec/.test(en.systreeCorrection)) {
//		if("systreeCorrection" in en && en.systreeCorrection === "asec") {
			storage.setItem("_SystemTreeCorrect", en.systreeCorrection);
		} else {
			storage.setItem("_SystemTreeCorrect", "");	// None
		}
	}
	if(_isEmpty(storage.getItem("_SystemTreeAutoCollapseThreshold"))) {
		if(en.systreeAutoCollapseThreshold && en.systreeAutoCollapseThreshold != 0) {
			storage.setItem("_SystemTreeAutoCollapseThreshold", en.systreeAutoCollapseThreshold);
		} else { 
			storage.setItem("_SystemTreeAutoCollapseThreshold", "0");
		}
	}
	if(_isEmpty(storage.getItem("_SystemTreeAutoCollapseType"))) {
		if(en.systreeAutoCollapseType) {
			storage.setItem("_SystemTreeAutoCollapseType", en.systreeAutoCollapseType);
		} else {
			storage.setItem("_SystemTreeAutoCollapseType", "height");
		}
	}
//	if(_isEmpty(storage.getItem("_SystemTreeSort"))) {
	if(storage.getItem("_SystemTreeSort") == null) {
		if("systreeSort" in en && (en.systreeSort === "asc" || en.systreeSort === "desc")) {
			storage.setItem("_SystemTreeSort", en.systreeSort);
		} else {
			storage.setItem("_SystemTreeSort", "desc");
		}
	}
	if(_isEmpty(storage.getItem("_SystemTreeSortType"))) {
		if(en.systreeSortType) {
			storage.setItem("_SystemTreeSortType", en.systreeSortType);
		} else {
			storage.setItem("_SystemTreeSortType", 'subtree');
		}
	}

	if(_isEmpty(storage.getItem("_CurrentSystemTreeMode"))) storage.setItem("_CurrentSystemTreeMode", STR_SYSTREE_MODE_DIST);

        if(_isEmpty(storage.getItem("_Update"))){
                var str = _checkUpdate();
                storage.setItem("_Update", str);
        }else{
                var str = _checkUpdate();
                if(storage.getItem("_Update")!=str){
                        _dlg_reset_confirm();
                }
        }
        if(_isEmpty(storage.getItem("_CrtCondition"))){
                storage.setItem("_CrtCondition", "0|||");
        }
        if(_isEmpty(storage.getItem("_Onebase"))){
                storage.setItem("_Onebase", "on");
        }
        if(_isEmpty(storage.getItem("_CSTM"))){
                if(en.cstm_track=="enabled"){
                        storage.setItem("_CSTM", "off");
                }else{
                        storage.setItem("_CSTM", "disabled");
                }
        }
        if(_isEmpty(storage.getItem("_TrackID"))){
                storage.setItem("_TrackID","off");
        }
        if(_isEmpty(storage.getItem("_ColorCode")) || _isEmpty(storage.getItem("_GrpCol"))){
                storage.setItem("_ColorCode","off");
                _setTitleColor();
        }
        if(!_isEmpty(en.color_acc_group)){
                if(en.color_acc_group=="enabled"){
                        storage.setItem("_ColorCode", "on");
                }else{
                        storage.setItem("_ColorCode", "off");
                }
        }
/*
        if(_isEmpty(storage.getItem("_TitleW"))){
                if(_isEmpty(en.accession_cvs_width)){
                        storage.setItem("_TitleW", parseInt(160));
                }else{
                        storage.setItem("_TitleW", parseInt(en.accession_cvs_width));
                }
        }
*/
	if(en['title_id_width_rate'] != null && en['title_id_width_rate'] !== "") {
		storage.setItem("title_id_width_rate", en['title_id_width_rate']);
	} else {
		storage.setItem("title_id_width_rate", 0.55);
	}

        if(_isEmpty(storage.getItem("_Conditions"))){
                storage.setItem("_Conditions", "[{\"\id\":\"\"}]");
        }
        if(phenotypeFlg && _isEmpty(storage.getItem("_Phenotype"))){
                _execPhenotype();
                var phenotype = _getPhenotype();
                storage.setItem("_Phenotype", phenotype);
                $("#plot_img").attr("src", "images/plot/plot_" + phenotype + ".png");
        }
	if(_isEmpty(storage.getItem("_Phenostr"))) {
		storage.setItem("_Phenostr","heading-date");
	}
        if(_isEmpty(storage.getItem("_blstHistFlg"))) {
                storage.setItem("_blstHistFlg",0);
        }
        if(_isEmpty(storage.getItem("_existDst"))) {
                storage.setItem("_existDst",0);
        }
        //storage.setItem("_exportFlg",0);

	// Enable the following to turn off highlights on reload
//	storage.setItem("_RegHighlights", "[]");
}
function changetoDefaultPos() {
	var changed = false;
	var en=new Object(JSON.parse(storage.getItem("_Env")));
	if( !('_default_position' in en) ) return changed;

	var blockVar = ["1b","2b","3b","4b","5b","6b","7b","8b","9b","10b","20b","30b","40b","50b","60b","70b","80b","90b",
		"100b","200b","300b","400b","500b","600b","700b","800b","900b","1k",
		"2k","3k","4k","5k","6k","7k","8k","9k","10k","20k","30k","40k","50k","60k","70k","80k","90k","100k"];

	try {
		var obj = en["_default_position"];
		if('chr' in obj && obj['chr'] && 'start' in obj && obj['start']) {
			var chr = obj['chr'];
/*
			var st = obj['start'];
			var en;
			if('end' in obj && obj['end']) {
				en = parseInt(obj['end']);
			} else {
				var zoomStr;
				if('blocksize' in obj && obj['blocksize']) {
					zoomStr = obj['blocksize'];
				} else {
					zoomStr = '1k';
				}
				zoom = convZoomStr2Num(zoomStr);
				en = en = st + zoom * blocks - 1;
			}
			_changeAutoPosZoom(chr, st, en);
*/
			var preSt = parseInt(obj['start']);
			var preEn;
			var blocks = parseInt(storage.getItem('_Block'));
			var st;
			var en;
			var zoom;
			if('end' in obj && obj['end']) {
				preEn = parseInt(obj['end']);
				var startZoom = getAdjustedZoom(preSt, preEn, blocks);
				st = startZoom['start'];
				zoom = startZoom['zoom'];
			} else {
				var zoomStr;
				if('blocksize' in obj && obj['blocksize']) {
					var hitSize = false;
					for(var i=0,len=blockVar.length; i<len; i++) {
						if(blockVar[i] === obj['blocksize']) {
							hitSize = true;
							break;
						}
					}
					if(!hitSize) throw new Error('Invalid blocksize:' + obj['blocksize']);
					zoomStr = obj['blocksize'];
				} else {
					zoomStr = '1k';
				}
				zoom = convZoomStr2Num(zoomStr);
				st = Math.floor((preSt - 1) / zoom) * zoom + 1;
			}
			var en = st + zoom * blocks - 1;
			console.log("Moveto pre-default-pos:" + chr + ":" + st + "-" + en);
			_changeAutoPosZoom(chr, st, en);

			changed = true;
		} else {
			// The default hash for config.php contains only the key and an empty value. In this case it will not raise an error.
//			throw new Error('chr and start are required for default-position(' + JSON.stringify(obj) + ')');
		}
	} catch(e) {
		console.error(e);
	}
	return changed;
}
/////////////////////////////////////////////// Synchronize content width
function _syncContentWidth() {
	var en=new Object(JSON.parse(storage.getItem("_Env")));
	contentW = getContentWidth();

	// Width of content body
	$("#track").css('width', contentW);
	$("#GWAS_plot").css('width', contentW);
	$("#content").css('width', contentW);
	$("#content2").css('width', contentW);

	// Title(Row header) width
	var systemTreeWidth = getSystemTreeWidth();
	titlew = parseInt(storage.getItem("_TitleW")) + 3;
	titlew2 = parseInt(storage.getItem("_TitleW")) + 1;
	$(".title").css('width', parseInt(titlew)+systemTreeWidth);
	$(".title2").css('width',parseInt(titlew));
	$(".systemtree").css('width', systemTreeWidth);

	// Canvas size is changed in initCanvas()
//	document.getElementById('cvs_tree').width = systemTreeWidth;

	// Track width is the difference between content body and row header.
}
///////////////////////////////////////////// Cheking empty
function adjustBlockHForFirefox() {
	if(!isFirefox()) return;

	var currentH = parseInt(storage.getItem('_BlockH'));
	var numAccs = _getAccListObjArray('_Lists').length;
	if(!validBlockHForFirefox(numAccs, currentH)) {
		// Get BlockH list
		var blockHs = [];
		$("#prm_bh  option").each(function() {
			blockHs.push( parseInt($(this).val()) );
		});
//		console.log(blockHs);
		var newH = 1;
//		for(var i=numAccs-1; i>=0; i--) {
		for(var i=blockHs.length-1; i>=0; i--) {
			if(validBlockHForFirefox(numAccs, blockHs[i])) {
				newH = blockHs[i];
				break;
			}
		}
		storage.setItem('_BlockH', newH);
		console.log('Adjust _BlockH :' + currentH + ' => ' + newH);
	}
}
function validBlockHForFirefox(numAccs, blockH) {
	var maxH = 32767;
	return numAccs * blockH <= maxH;
}

function _isEmpty(value){
        return (value == null || value.length == 0);
}

///////////////////////////////////////////////////////////
//Ajax: get environment settings
///////////////////////////////////////////////////////////
function _checkUpdate() {
/*
        var date="";
        $.ajax({
                url: "./bin/"+_backendSelector("dbupdate.php"),
                cache: false,
                async: false,
                success: function(data) {
                        date=data;
                }
        });
*/
	date = VERSION + ":1999-01-01 00:00:00";
//        date = tasuke_version()+":"+date;
        return date;
}

///////////////////////////////////////////////////////////
//Ajax: get environment settings
///////////////////////////////////////////////////////////
/*
function _execEnv() {
        $.ajax({
                url: "./bin/env.php",
                cache: false,
                async: false,
                success: function(data) {
                        storage.setItem("_Env", data);
                }
        });
}
///////////////////////////////////////////////////////////
//Ajax: get chromosome
///////////////////////////////////////////////////////////
function _execChr() {
        $.ajax({
                url: "./bin/"+_backendSelector("chr.php"),
                cache: false,
                async: false,
                success: function(data) {
                        storage.setItem("_Chrs", data);
                }
        });
}
*/
///////////////////////////////////////////////////////////
//Ajax: get snpblock
///////////////////////////////////////////////////////////
function _execSnpblock(keyword) {
        $.ajax({
                url: "./bin/snpblock.php",
                cache: false,
                async: false,
                data: {
                        "prm_accession": keyword
                },
                success: function(data) {
                        storage.setItem("_Snpblock", data.replace(/^[ 　\t\r\n]+|[ 　\t\r\n]+$/g, ""));
                }
        });
}

///////////////////////////////////////////////////////////
//Ajax: get list of accessions & tracks
///////////////////////////////////////////////////////////
/*
function _execLists() {
        var accessions = "";
        if(!_isEmpty(storage.getItem("_Ext_accessions"))){
                accessions = storage.getItem("_Ext_accessions");
                storage.removeItem("_Ext_accessions");
        }
        $.ajax({
                url: "./bin/"+_backendSelector("list.php"),
                cache: false,
                type: "POST",
                async: false,
                data: {
                        "prm_ext_acc":accessions
                },
                success: function(data) {
                        var a=data.split("|");
			var accArray = JSON.parse(a[0]);
			_setAccListObjArray("_Lists", accArray);
			_setAccListObjArray("_Lists-origin", accArray);
//                        storage.setItem("_Lists", a[0]);
//                        storage.setItem("_Lists-origin", a[0]);

                        storage.setItem("_Tracks", a[1]);
                        storage.setItem("_Conditions", a[2]);
                        if(phenotypeFlg){
                                storage.setItem("_PhenotypeExpressions", a[3]);
                                storage.setItem("_PhenotypePapers", a[4]);
                        }
                }
        });
}
*/

///////////////////////////////////////////////////////////
//Ajax: Load information of cell
///////////////////////////////////////////////////////////
function _execInfoCell(x,y) {
        _windowGffClose();
//        var o=new Object(JSON.parse(storage.getItem('_Lists')));
	var o = _getAccListObjArray('_Lists');
        var ct=-2;
        for(var i in o){ct++;}
        if(y >(Objects.BlockH*ct)){
                y=Objects.BlockH*ct;
        }else if(y < 0){
                y=0;
        }
        var id=o[parseInt(y/Objects.BlockH)].db;
        var b=Math.abs(parseInt((x/Objects.BlockW)));
        if(b > Objects.Block-1){//when over cvs_view
                b = Objects.Block-2;
        }
        var p=Objects.Pos+b;

        if ( _cvtZoom(Objects.Zoom) > 4000 ) { // When over 1k
		_drawInfoCell(id,b,y,"[]");
	} else {
		$.ajax({
			url: "./bin/"+_backendSelector("info.php"),
			type: "GET",
			cache: false,
			data: {
				"prm_Zoom":Objects.Zoom,
				"prm_Chr":Objects.Chr,
				"prm_Mode":Objects.Mode,
				"prm_Pos":p,
				"prm_QUAL":storage.getItem("_QUAL"),
				"prm_DP":storage.getItem("_DP"),
				"prm_DP4":storage.getItem("_DP4"),
				"prm_EffGrps":storage.getItem("_EffGrps"),
				"prm_Acc":id
			},
			success: function(datas) {
				_drawInfoCell(id,b,y,datas);
			}
		});
	}
}

///////////////////////////////////////////////////////////
//Ajax: Search ID
//1K zoom will setted
///////////////////////////////////////////////////////////
function _execSearch(keyword, addOffset) {
	var target=keyword.split("|");
	var cnt=0;
	for(var i in target){cnt++;}
	if(cnt>4){
		var leftPos = target[1];
		var rightPos = target[2];
		if(addOffset) {
			var offset = parseInt((target[2] - target[1] + 1) * 0.05);
			leftPos = parseInt(target[1]) - offset;
			rightPos = parseInt(target[2]) + offset;
			if(leftPos<1) leftPos = 1;
		}
		_changeAutoPosZoom(target[3], leftPos, rightPos);
		storage.setItem("_Keyword", target[0]);
/*
		if(target[0] && target[0] != DAMMY_KEYWORD) {
			if($('#cb_highlight_keyword_variant').prop('checked')) {
				storage.setItem("_HighlightVariantGene", target[0]);
				if($('#cb_hlvar_kw_exclude_updown').prop('checked')) {
					storage.setItem("_HighlightVariantExclUpDown", "1");
				} else {
					storage.setItem("_HighlightVariantExclUpDown", "");
				}
			} else {
				storage.setItem("_HighlightVariantGene", "");
				storage.setItem("_HighlightVariantExclUpDown", "");
			}
		}
*/
		if (target[0] == "all") {
			target[0] = "Target region";
		}
		// ここで設定したハイライトは、このあとで_moveVarposを経由する場合(GWAS機能など)上書きされるので注意
		setRegionHighlight({"chr":target[3], "st":target[1], "en":target[2]});	// Region Highlight
//                addRegionHighlight({"chr":target[3], "st":target[1], "en":target[2]});	// Region Highlight

		_changeChromosomeSearch(target[0]);
	}
}
function _changeAutoPosZoom(chr, st, en) {
	if(!_validateChr(chr)) {
		alert("Invalid:this chromosomeis not registered!!");
//		_messageOnScreen("Invalid:this chromosomeis not registered!!");
		return;
	}

        var block = parseInt(storage.getItem("_Block"));
/*
	var startZoom = getAdjustedZoom(st, en, block);
	zoomsize = startZoom['zoom'];
	st = startZoom['start'];
	var optblks = convZoomNum2Str(zoomsize);
	var p = Math.floor(startZoom['start'] / zoomsize);
//console.log(len + "   " + zoomsize + " => " + optblks);
*/
	var len = en - st + 1;
	var blks = Math.ceil(len / block);	// Block bp len
	var blksL = String(blks).length - 1;	// 10^n

	var zoomsize = Math.ceil(blks/Math.pow(10,blksL)) * Math.pow(10,blksL);
//	var zoomsize = Math.round(blks/Math.pow(10,blksL)) * Math.pow(10,blksL);
	var optblks;
	if (zoomsize > 900) {
		optblks = Math.ceil(zoomsize/1000) + "k";
	} else {
		optblks = parseInt(zoomsize) + "b";
	}

	// Centering
	var dispLen = block * zoomsize;	// =bp len
	if(len < dispLen) {
		var stPos = st - parseInt((dispLen - len)/2);
		if(stPos<1) stPos = 1;
		p=_checkPos_Chr(stPos,optblks,chr);
	} else {
		p=_checkPos_Chr(st,optblks,chr);
	}

	storage.setItem("_Chr", chr);
	storage.setItem("_Zoom", optblks);
	storage.setItem("_Pos", p);
}
function convZoomNum2Str(zoom) {
	zoom = parseInt(zoom);
	var optblks;
	if (zoom > 900) {
		optblks = Math.ceil(zoom/1000) + "k";
	} else {
		optblks = parseInt(zoom) + "b";
	}
	return optblks;
}
function convZoomStr2Num(zoomStr) {
	var regexp = /^(\d+)([bk])$/i;
	var arr = regexp.exec(zoomStr);
	var zoom = null;
	if(arr && arr.length >= 3) {
		if(arr[2] === 'k' || arr[2] === 'K') {
			zoom = parseInt(arr[1]) * 1000;
		} else {
			zoom = parseInt(arr[1]);
		}
	}
	return zoom;
}

///////////////////////////////////////////////////////////
//Ajax: Search ID
//for  candidates
///////////////////////////////////////////////////////////
function _preExecSearch(keyword,mode) {
	$.ajax({
		url: "./bin/"+_backendSelector("search.php"),
		type: "GET",
		cache: false,
		data: {
			"prm_chr":storage.getItem("_Chr"),
			"prm_zoom":storage.getItem("_Zoom"),
			"prm_keyword":keyword,
			"session_flg":"true"
		},
		success: function(datas) {
			if (/Invalid/.test(datas)) {
                                $('#prm_keyword_res').find('option').remove().end().append("<option value=\'\'>"+datas+"</option>");
				submit = "<input type=\"submit\" id=\"prm_keyword_res\" value=\"GO\" disabled />";
                        	$('#prm_keyword_res_sb').find('input').remove().end().append(submit);
                        } else {
			var spdatas = datas.split("~");
			var cnt=-1;
			var ls="<OPTGROUP label=\"&lt;ID&gt;&nbsp;&nbsp;&nbsp;&lt;Chromosome&gt;&nbsp;&nbsp;&nbsp;&lt;Start&#045;End&gt;&nbsp;&nbsp;&nbsp;&lt;Note&gt;\"></OPTGROUP>";
			var tc=0;
			var num="";
			var submit="";
			for(var i in spdatas){cnt++;}
			for(var t=0; t < cnt; t++){
				var a=spdatas[tc].split("|");
				var id = _delLFCR(a[0]);
				var st = _delLFCR(a[1]);
				var ed = _delLFCR(a[2]);
				var c = _delLFCR(a[4]);
				var note ="";
				var raw_note="";
				if(a[5]){
					note = _delLFCR(a[5]);
					raw_note=note;
					var all=id+""+st+""+ed+""+c+""+note;
					if (all.length > 70){
						note=note.substring(0, (70-(all.length-note.length)));
						note=note+"...";
					}
				}
				if(a[1]>0){
					var selected = "";
					if(t==0) selected = "selected";
					ls = ls+"<option value='"+id+"|"+st+"|"+ed+"|"+c+"' " + selected + " title='"+raw_note+"'>"+id+"&#009;"+c+"&#009;"+st+"&#045;"+ed+"&#009;"+note+"</option>";
					submit="<input type=\"submit\" id=\"prm_keyword_res\" value=\"GO\" onClick=\"_searchID(event)\"/>";
					num="Search&nbsp;results&nbsp;:&nbsp;"+a[3];
					$('#cb_highlight_keyword_variant').prop('disabled', false);
/*
					if(t==0){
						ls = ls+"<option value='"+id+"|"+st+"|"+ed+"|"+c+"' selected title='"+raw_note+"'>"+id+"&#009;"+c+"&#009;"+st+"&#045;"+ed+"&#009;"+note+"</option>";
						submit="<input type=\"submit\" id=\"prm_keyword_res\" value=\"GO\" onClick=\"_searchID(event)\"/>";
						num="Search&nbsp;results&nbsp;:&nbsp;"+a[3];
					}else{
						ls = ls+"<option value='"+id+"|"+st+"|"+ed+"|"+c+"' title='"+raw_note+"'>"+id+"&#009;"+c+"&#009;"+st+"&#045;"+ed+"&#009;"+note+"</option>";
						submit="<input type=\"submit\" id=\"prm_keyword_res\" value=\"GO\" onClick=\"_searchID(event)\"/>";
						num="Search&nbsp;results&nbsp;:&nbsp;"+a[3];
					}
*/
					if(a[3] >= 1000){
						num="&nbsp;<font color='red'>Too&nbsp;many&nbsp;results&nbsp;were&nbsp;found.&nbsp;(Displayed&nbsp;only&nbsp;1&nbsp;to&nbsp;1000&nbsp;of&nbsp;"+a[3]+"&nbsp;results)<br>&nbsp;Try&nbsp;it&nbsp;again&nbsp;with&nbsp;other&nbsp;keywords.</font>";
					}
				} else {
					var msgNotFound = "Not&nbsp;found";
					if(st=="false1") msgNotFound = "Note&nbsp;is&nbsp;not&nbsp;installed&nbsp;in&nbsp;TASUKE.&nbsp;";
					ls = "<option value='NF' disabled>&nbsp;" + msgNotFound + "&nbsp;</option>";
					submit = "<input type=\"submit\" id=\"prm_keyword_res\" value=\"GO\" disabled />";
					num="&nbsp;";
					$('#cb_highlight_keyword_variant').prop('disabled', true);
					break;
/*
					if(st=="false1"){ 
						ls = "<option value='NF' disabled>&nbsp;Note&nbsp;is&nbsp;not&nbsp;installed&nbsp;in&nbsp;TASUKE.&nbsp;&nbsp;</option>";
						submit = "<input type=\"submit\" id=\"prm_keyword_res\" value=\"GO\" disabled />";
						num="&nbsp;";
						break;
					}else{
						ls = "<option value='NF' disabled>&nbsp;Not&nbsp;found&nbsp;</option>";
						submit = "<input type=\"submit\" id=\"prm_keyword_res\" value=\"GO\" disabled />";
						num="&nbsp;";
						break;
					}
*/
				}
				tc++;
			}
			var cr = document.getElementById("prm_keyword_res_str");
			cr.innerHTML=num;
			$('#prm_keyword_res').find('option').remove().end().append(ls);
			$('#prm_keyword_res_sb').find('input').remove().end().append(submit);
		}
		}
	});
}

///////////////////////////////////////////////////////////
//Ajax: get environment settings
///////////////////////////////////////////////////////////
function _getphenotypeFlg() {
        var phenotypeFlg="";
        $.ajax({
                url: "./bin/"+_backendSelector("getPhenoFlg.php"),
                cache: false,
                async: false,
                success: function(data) {
                        phenotypeFlg=data;
                }
        });
        return phenotypeFlg;
}
/*
function _getNumThread() {
        var threadnum="";
        $.ajax({
                url: "./bin/"+_backendSelector("getNumThread.php"),
                cache: false,
                async: false,
                success: function(data) {
                        threadnum=data;
                }
        });
        return threadnum;
}
*/
function _getTitle() {
        var titleary=[];
        $.ajax({
                url: "./bin/"+_backendSelector("getTitle.php"),
                cache: false,
                async: false,
                success: function(data) {
                        titleary=data;
                }
        });
        return titleary;
}

function _getp3Path() {
        var primer3Path="";
        $.ajax({
                url: "./bin/"+_backendSelector("getp3Path.php"),
                cache: false,
                async: false,
                success: function(data) {
                        primer3Path=data;
                }
        });
        return primer3Path;
}
////replace LF and CR for Search
function _delLFCR(string){
	string = string.replace( /\r\n/g , "\n" );	
	string = string.replace( /^(\n+)|(\n+)$/g , "" );
	return string
}
function _getPhenolist() {
	$.ajax({
                url: "./bin/"+_backendSelector("getPhenolist.php"),
                cache: false,
                async: false,
                success: function(data) {
                        storage.setItem("_Phenolist", data);
		}
	});
}
function _getPheno($phenoname) {
        $.ajax({
                url: "./bin/"+_backendSelector("getPheno.php"),
                cache: false,
		type:'POST',
                async: false,
		data: {
			"phenoname":$phenoname
		},
                success: function(data) {
                        storage.setItem("_Phenoexp", data);
                }
        });
}
///////////////////////////////////////////////////////////
//Ajax: Get track&depth&variant and drawing
///////////////////////////////////////////////////////////
function initSystemTreeObj() {
	treeobj = new PhyloTreeCreater(document.getElementById('cvs_tree'));
	treeobj.tMargin = 0;
	treeobj.bMargin = 0;
//	treeobj.tMargin = Number($(".title2").css('padding-top').replace('px', ''));	// header space
//	treeobj.bMargin = Number($(".title2").css('padding-bottom').replace('px', ''));	// footer space
	treeobj.rMargin = 0;
//	treeobj.treeWidth = getSystemTreeWidth() - treeobj.lMargin - treeobj.rMargin;
	treeobj.auxLineColor = "rgba(255,255,255,0.35)";
//	treeobj.mouseOverColor = "#ff8c00";

	initSystreeStyle();
//	treeobj.headerString = "Whole genome tree";
//	treeobj.lineColor = "black";
	treeobj.treeWidth = parseFloat(storage.getItem("_SystemTreeW")) - treeobj.lMargin - treeobj.rMargin;
}
function clearSystemTreeCache() {
	storage.setItem("_SysTreeNewick", "");
	storage.setItem("_SystemTreeCollapsedBranch", "{}");
	storage.setItem("_SystemTreeLastLeafOrder", "[]");
}
function clearPhylipTreeCache() {
	if(treeobj != null) treeobj.initTree();
	phylipCollapsedBranch = {};
	storage.removeItem("_PhylipTreeNewick");
	storage.setItem("_SystemTreeLastLeafOrder", "[]");
}
/*
 * TODO Consider moving to dialog.js
 * storage.setItem("Lists") in advance.
 * Since the Variant Track cache is left and reused, it cannot be used for processing that involves position changes (including horizontal drag moving).
*/
function syncListsWithCancelPhylipTree(threshold) {
	syncListsWithCancelPhylipTreeCore(threshold, STR_SYSTREE_MODE_DIST);
}
function syncListsWithCancelPhylipTreeLW(threshold) {
	syncListsWithCancelPhylipTreeCore(threshold, STR_SYSTREE_MODE_NEWICK);
}
function syncListsWithCancelPhylipTreeDefault(threshold) {
	var en = JSON.parse(storage.getItem('_Env'));
	if(en.useSystemTreeLW === "1") {
		syncListsWithCancelPhylipTreeCore(threshold, STR_SYSTREE_MODE_NEWICK);
	} else {
		syncListsWithCancelPhylipTreeCore(threshold, STR_SYSTREE_MODE_DIST);
	}
}
function syncListsWithCancelPhylipTreeLast(threshold) {
	var mode = storage.getItem("_CurrentSystemTreeMode");
	if(mode === STR_SYSTREE_MODE_NEWICK) {
		syncListsWithCancelPhylipTreeCore(threshold, STR_SYSTREE_MODE_NEWICK);
	} else {
		syncListsWithCancelPhylipTreeCore(threshold, STR_SYSTREE_MODE_DIST);
	}
}
/**
 * 
 */
function syncListsWithCancelPhylipTreeCore(threshold, mode) {
	if(isPhylipTreeUsing()) {
		clearPhylipTreeCache();
		if(!systreeFlg) {
			storage.setItem("_SYSTREE","off");
			setRadioGroupValue("lstBox_grp", "sort");
			setRadioGroupValue("idlst_grp", "sort");
		}
	}
	setTimeout(function() {
		if(isTreeUsing()) {
			//TODO If it is difficult to control, use only syncListsAndSystemTree.
			var diff = true;
			var currentSystreeMode = storage.getItem("_CurrentSystemTreeMode");
			if(DEBUG_MODE) console.log(currentSystreeMode + " <=> " + mode);
			if(mode === currentSystreeMode && storage.getItem("_SysTreeNewick")) {
				// Check the differences between last "_SysTreeNewick" and current Acc members.
				if(DEBUG_MODE) console.log("Check diff")
				var localTreeObj = new PhyloTreeCreater(null);
				localTreeObj.parseNewick(storage.getItem("_SysTreeNewick"));
				convSystreeDb2Id(localTreeObj);
				var allLeafs = localTreeObj.getAllPotentialNameOrder();
				var lists = _getAccListObjArray('_Lists');
				var diffs = diffAccListsVsOrder(lists, allLeafs);
				diff = diffs[1];
				localTreeObj.initTree();
			}
			storage.setItem("_CurrentSystemTreeMode", mode);

			if(diff) {
				// Recreate SystemTree (with ajax)
				if(threshold==null) threshold = 0;
				_showLoadingDialog();
				if(mode === 'newick') {
					syncListsAndSystemTreeLW(threshold);
				} else {
					syncListsAndSystemTree(threshold);	//NOTICE!! asynchronous proc
				}
			} else {
				// Reuse last SystemTree (without ajax)
//				syncStorage2SystemTree2Lists();	// This function reflects the current tree collapse rather than the default.

				updateSystemTreeByStorageCore();	// Set "uncollapsed Tree that applies only the current sort condition".
				collapseTreeNode(treeobj, threshold);	// If threshold is empty, do nothing.
				flgUpdateTree = true;
				syncSystemTree2Lists(true);
			}
		} else {
			_showLoading();
//			storage.setItem("_ListsTgt", "");
			FROMSCROLL=true;
			var lists = _getAccListObjArray("_Lists");
			syncList2DlgMakeList(lists, {order:false, check:true, clearSelect:false});
			_execCanvas();
		}
		syncDlgMakeList();	//Add 20231026
	}, 50);
}
function updateSystemTreeByStorageCore() {
	if(!storage.getItem("_SysTreeNewick")) return;

	treeobj.parseNewick(storage.getItem("_SysTreeNewick"));	// Old TreeObj are automatically initialized.
	convSystreeDb2Id(treeobj);	// changeLeafName accDb -> accId
	initSystreeStyle();

	var type = storage.getItem("_SystemTreeSortType");
	var xscend = storage.getItem("_SystemTreeSort");
	if(xscend !== "") treeobj.sortByLength(xscend, type);
}
function updateSystemTreeByStorage() {
	if(!storage.getItem("_SysTreeNewick")) return;

	updateSystemTreeByStorageCore();
	var serialsHash = JSON.parse(storage.getItem("_SystemTreeCollapsedBranch"));
	var serialsArray = [];
	for(var key in serialsHash) serialsArray.push(key);
	var serials = treeobj.autoCollapseBySerials(serialsArray);
	storage.setItem("_SystemTreeCollapsedBranch", JSON.stringify(serials));	// It shouldn't be necessary, but just in case.
}
function syncStorage2SystemTree2Lists() {
	if(DEBUG_MODE) console.log("[using Storage] Recreate SystemTree");
	updateSystemTreeByStorage();

	flgUpdateTree = true;
	syncSystemTree2Lists();
/*
	_reset_accession_lists_byArray(treeobj.getNameOrder());
	flgUpdateTree = true;
	_drawSystemTree();	// Update Tree before loading DB.
	_execCanvas();
*/
}

/**
 * At the time of initial loading(F5), Canvas is not drawn and the Viewport cannot be obtained with getContentVisibleArea().
 * To actually recreate Tree, you need to set flgUpdateTree=true outside of this function.
 */
function syncSystemTree2Lists(flgUpdateListForm = false) {
	_reset_accession_lists_byArray(treeobj.getNameOrder());

	//TODO Should it be called in _dlg_make_list()/_dlg_make_phylist()?
	if(flgUpdateListForm && storage.getItem('_AccmanagerListType') === 'standard') {
		if(listListManager && $('#dialog_list').is(":visible")) {
			var opt1 = {order:false, using:true, check:true, clearSelect:false};
			if(getRadioGroupValue("lstBox_grp") === 'tree') opt1['order'] = true; 
			listListManager.resetOrder(treeobj.getCollapsedNameOrder(), opt1);
		}
		if(phyListManager && $('#dialog_phy').is(":visible")) {
			var opt2 = {order:false, using:true, check:true, clearSelect:false};
			if(getRadioGroupValue("idlst_grp") === 'tree') opt2['order'] = true;
			phyListManager.resetOrder(treeobj.getCollapsedNameOrder(), opt2);
		}
	}

	_windowGffClose();

	// Accs to be loaded from DB is determined by Canvas height, so change height according to Tree.
	resizeContentHeight( treeobj.getNameOrder().length * parseInt(storage.getItem("_BlockH")) );	// for _drawSystemTree(). It is executed redundantly even in _execCanvas.
	_drawSystemTree();	// Since flgUpdateTree = false in this, _drawSystemTree() not be execute again in _execCanvas().

	// The following is a high-speed process that reuses the Track cache, but there is a problem that the cache of collapsed nodes is not updated when the position is moved, and the display position shifts when expanded.
	if(RELOAD) {
		// At the time of first loading, Canvas is not drawn and its size is unknown, so getContentVisibleArea cannot be used.
		storage.removeItem("_ListsTgt");	// It's probably okay without it
		_showLoading();
		_execCanvas();
	} else {
		// Below, the canvas of VariantTrack/Title is before change, but the Canvas of SystemTree has been changed,
		// so you can get Acc list in viewport from the scroll position of "content".
		if(SCRTIMER){clearTimeout(SCRTIMER);}
		SCRTIMER = setTimeout(function() {
			var visibleArea = getContentVisibleArea();
			var topIdx = visibleArea.top - 1;
			var endIdx = topIdx + visibleArea.count;
			var loadDbs = [];
			var listsArr = _getAccListObjArray("_Lists");
			for(var i=topIdx; i <= endIdx ; i++){
				if(!listsArr[i]) continue;
				var db = listsArr[i].db;
				if(!isValidTrackRow(db)) loadDbs.push(db);
			}

			if(loadDbs.length === 0) {
				_drawCanvas();
				if(!isSetEvents()) _hideLoading();
				_closeLoadingDialog();
			} else {
				var allAccs = _getAccListObjArray("_Lists-origin");
				if(loadDbs.length < allAccs.length - 1) {	//TODO Beware of boundary values.
					storage.setItem("_ListsTgt", loadDbs.join(','));
				} else {
					storage.removeItem("_ListsTgt");
				}
				_showLoading();
				FROMSCROLL=true;
				_execCanvas();
			}
/*
			if(loadDbs.length === 0) {
				// If loadDbs.length=0, all records will be retrieved, so avoid that.
				for(var i=topIdx; i <= endIdx ; i++){
					if(!listsArr[i]) continue;
					var db = listsArr[i].db;
					loadDbs.push(db);
					break;
				}
			}
			storage.setItem("_ListsTgt", loadDbs.join(','));
			FROMSCROLL=true;
			_execCanvas();
*/
			SCRTIMER = null;
		}, 100);
	}
}

function syncPhylip2SystemTree() {
	var oriSystreNewick = storage.getItem("_SysTreeNewick");

//	clearSystemTreeCache();
//	clearPhylipTreeCache();

	try {
		var newickStr = $("#newick").val();
//		var newickStr = $("#newick").val().replace(/[^\:\(\),\_]+_[^\:\(\),\_]+/g, convFunc);
//		if(cant_convert_title != null) throw "Detect abnormal title:" + cant_convert_title;

		treeobj.initTree();
		treeobj.parseNewick(newickStr);
		treeobj.removeLeafsAndUpdate(["Reference"]);
		storage.setItem("_PhylipTreeNewick", treeobj.tree.getNewick());	// Register Unsort Newick. SampleID is "accession_db"
		convSystreeDb2Id(treeobj);	// changeLeafName accDb -> accId
//		storage.setItem("_CurrentSystemTreeMode", STR_SYSTREE_MODE_PHY);

		// Re-collapsing when the Tree is recreated by sorting.
		var serialsArray = Object.keys(phylipCollapsedBranch);
		serialsArray.sort(function (a, b) {
			return a - b;
		});	// Sort by number

		// Since collapsedBranch is a reference of the itreeobj member variable, copy it so that it will not be erased by initTree.
		phylipCollapsedBranch = Object.assign({}, treeobj.autoCollapseBySerials(serialsArray));

		var type = storage.getItem("_SystemTreeSortType");
		var xscend = storage.getItem("_SystemTreeSort");
		if(xscend !== "") treeobj.sortByLength(xscend, type);

		flgUpdateTree = true;
		_drawSystemTree();	// Unnecessary?
		syncSystemTree2Lists(true);
	} catch(e) {
		console.error(e);
		window.alert("The phylogenetic tree could not be apply to track due to an error.");
		_closeErr();

		if(systreeFlg) {
			storage.removeItem("_PhylipTreeNewick");
			storage.setItem("_SysTreeNewick", oriSystreNewick);
			initSystreeStyle();
			syncStorage2SystemTree2Lists();
		} else {
			treeobj.initTree();
			storage.setItem("_PhylipTreeNewick", "ThisIsDummy");	// Dummy operation for canceling phylip tree;
			syncListsWithCancelPhylipTreeDefault();
		}
	}
}
function convSystreeDb2Id(tree) {
	var accDb2ObjMap = _getAccDb2ObjMap();
	var idNames = [];
	for(var i=0,len=tree.order.length; i<len; i++) {
// console.log("Test:" + tree.order[i].childs + " => " + accDb2ObjMap[tree.order[i].childs].id);
		idNames.push(accDb2ObjMap[tree.order[i].childs].id);
	}
	tree.changeLeafName(idNames);
}
function convSystreeId2Db(tree) {
	var accId2ObjMap = _getAllAccId2listsObj();
	var dbNames = [];
	for(var i=0,len=tree.order.length; i<len; i++) {
		dbNames.push(accId2ObjMap[tree.order[i].childs].db);
	}
	tree.changeLeafName(dbNames);
}
function syncListsAndSystemTreeDefault(threshold) {
	var en = JSON.parse(storage.getItem('_Env'));
	if(en.useSystemTreeLW === "1") {
		syncListsAndSystemTreeLW(threshold);
	} else {
		syncListsAndSystemTree(threshold);
	}
}
function syncListsAndSystemTreeLast(threshold) {
	var mode = storage.getItem("_CurrentSystemTreeMode");
	if(mode === STR_SYSTREE_MODE_NEWICK) {
		syncListsAndSystemTreeLW(threshold);
	} else {
		syncListsAndSystemTree(threshold);
	}
}
function syncListsAndSystemTreeLW(threshold) {
	if(DEBUG_MODE) console.log("[using Newick] Recreate SystemTree");

	clearSystemTreeCache();	//Add 20231130

	var oriWholeNewick = storage.getItem("_SysTreeNewickLW");
	treeobj.parseNewick(oriWholeNewick);
	var delLists = _getAccListObjArray("_ListsDeleted");
	var delAccs = [];
	for(var i=0,len=delLists.length; i<len; i++) {
		delAccs.push(delLists[i].db);
	}
	treeobj.removeLeafsAndUpdate(delAccs);
	storage.setItem("_SysTreeNewick", treeobj.tree.getNewick());
	convSystreeDb2Id(treeobj);
	initSystreeStyle();
	treeobj.treeWidth = parseFloat(storage.getItem("_SystemTreeW")) - treeobj.lMargin - treeobj.rMargin;

	var type = storage.getItem("_SystemTreeSortType");
	var xscend = storage.getItem("_SystemTreeSort");
	if(xscend !== "") treeobj.sortByLength(xscend, type);

	collapseTreeNode(treeobj, threshold);
/*
	if(threshold && threshold !== 0) {
		var collapsed;
		if(storage.getItem("_SystemTreeAutoCollapseType") === "ratio") {
			collapsed = treeobj.autoCollapseByRatioToMaxHeight(threshold);
		} else {
			collapsed = treeobj.autoCollapseByHeight(threshold);
		}
		storage.setItem("_SystemTreeCollapsedBranch", JSON.stringify(collapsed));
	}
	storage.setItem("_CurrentSystemTreeMode", STR_SYSTREE_MODE_NEWICK);
*/

	flgUpdateTree = true;
	syncSystemTree2Lists(true);
	storage.setItem("_CurrentSystemTreeMode", STR_SYSTREE_MODE_NEWICK);
/*
	_reset_accession_lists_byArray(treeobj.getNameOrder());
	flgUpdateTree = true;
	_drawSystemTree();
	FROMSCROLL = true;
	_execCanvas();
*/
	syncDlgMakeList();
}

var jqxhrGetNewick = null;
function syncListsAndSystemTree(threshold) {
	if(DEBUG_MODE) console.log("[using Matrix] Recreate SystemTree");

//	clearSystemTreeCache();

	var lists = _getAccListObjArray("_Lists");
	var array = [];
	for(var i=0, len=lists.length; i<len; i++) {
		array.push(lists[i].db);
//		array.push(lists[i].id);
	}
	array.sort();	// Perhaps tree changes in order of Acc, so string sort for reproducibility.

	var en=new Object(JSON.parse(storage.getItem("_Env")));

	var accLen = array.length;
	var expTotalDummyBytes = accLen * en.systreeProgressCharLen;	// The length of the received dummy string must match bin/getNewick.php

	_showLoading();
	var buttonsHtml = $("#progress_error").html();
		buttonsHtml = buttonsHtml + '<button style="margin-left:5px;" type="submit" onclick="_stopSyncListsAndSystemTree();">Cancel</button>';
	_changeProgressStr("Creating system tree...", buttonsHtml);
	jqxhrGetNewick = $.ajax({
		url: "./bin/"+_backendSelector("getNewick.php"),
		type: "POST",
		async:true,
//		cache: false,
		data: {
//			"prm_Lists":JSON.stringify(array)
			"prm_Lists":array.join(',')
		},
                xhr: function () {
			var xhr = $.ajaxSettings.xhr();
//			if(accLen > dispTreeLoadProgressAccNum) {
//				xhr.upload.onprogress = function(evt) {
//					if(evt) console.log("upload.onprogress: " + evt.loaded);
//				};
				xhr.onprogress = function(evt) {
					if(evt) {
//						console.log("onprogress: " + evt.loaded);
						_updateProgress(evt.loaded / expTotalDummyBytes * 100);
					}
				};
//				xhr.onreadystatechange = function(evt) {
//					if(evt) console.log("onreadystatechange: " + xhr.readyState);
//				};
				xhr.onloadend = function(evt) {
					_updateProgress(100);
				};
//			}
                        return xhr;
                }
	}).done(function(data) {
		_defProgressStr();

		if(/Error:/.test(data)) {
			alert(data + " Check out the Phylip programs and distance matrix.");
		}

		clearSystemTreeCache();

		repRegexp = new RegExp("^[\\" + en.systreeProgressChar + "\\s]+");
		data = data.replace(repRegexp, '');
		var retObj = JSON.parse(data);
		var nwk = retObj['newick'];
		var needRooting = retObj['needrooting'];

		// Midpoint rooting.
		if(needRooting) {
			var midtree;
			try{
				var dataCnv = rootingMidpoint(nwk);
				midtree = parseNewick(dataCnv);
				nwk = midtree.tree.getNewick();
			} catch(e) {
				// If rooting fails, use original newick.
				console.error(e);
			} finally {
				clearParseNewick(midtree);
			}
		}
		storage.setItem("_SysTreeNewick", nwk);
		storage.setItem("_CurrentSystemTreeMode", STR_SYSTREE_MODE_DIST);
		if(!storage.getItem("_SysTreeNewickLW")) storage.setItem("_SysTreeNewickLW", nwk);
		treeobj.parseNewick(nwk);
		convSystreeDb2Id(treeobj);	// changeLeafName accDb -> accId
		initSystreeStyle();
		treeobj.treeWidth = parseFloat(storage.getItem("_SystemTreeW")) - treeobj.lMargin - treeobj.rMargin;

		var type = storage.getItem("_SystemTreeSortType");
		var xscend = storage.getItem("_SystemTreeSort");
		if(xscend !== "") treeobj.sortByLength(xscend, type);

		collapseTreeNode(treeobj, threshold);
/*
		if(threshold && threshold !== 0) {
			var collapsed;
			if(storage.getItem("_SystemTreeAutoCollapseType") === "ratio") {
				collapsed = treeobj.autoCollapseByRatioToMaxHeight(threshold);
			} else {
				collapsed = treeobj.autoCollapseByHeight(threshold);
			}
			storage.setItem("_SystemTreeCollapsedBranch", JSON.stringify(collapsed));
		}
*/
		storage.setItem("_CurrentSystemTreeMode", STR_SYSTREE_MODE_DIST);

		flgUpdateTree = true;
		syncSystemTree2Lists(true);
/*
		_reset_accession_lists_byArray(treeobj.getNameOrder());	// Match order of AccList with order of Tree
		flgUpdateTree = true;
		_drawSystemTree();	// Change height of the "#content" by drawing tree first.
//		FROMSCROLL=false;
		FROMSCROLL = true;
		_execCanvas();
*/
		syncDlgMakeList();
	}).fail(function() {
		//TODO no problem?
		if(!isSetEvents()) _hideLoading();
//		_hideLoading();
	}).always(function() {
		_defProgressStr();
		jqxhrGetNewick = null;
	});
}
function _stopSyncListsAndSystemTree() {
        if(jqxhrGetNewick) {
		jqxhrGetNewick.abort();    // exec $.ajax.always();
//		_hideLoading();
//		setTimeout(_closeLoadingDialog, 100);

		var en = JSON.parse(storage.getItem('_Env'));

		// Since tree creation is suspended, force hide SystemTree.
		storage.setItem('_SYSTREE', 'off');
		storage.removeItem("_ListsTgt");
		if(en.useSystemTreeLW === "1" && storage.getItem("_CurrentSystemTreeMode") === STR_SYSTREE_MODE_DIST) {
			// Since this is "Cancel" and not "Hide", _CurrentSystemTreeMode is changed to the default STR_SYSTREE_MODE_NEWICK.
			storage.setItem("_CurrentSystemTreeMode", STR_SYSTREE_MODE_NEWICK);
		}
		ROMSCROLL=false;
                if(!_isEmpty(storage.getItem("_SysTreeNewick"))) {
                        // For reload(F5). Reuse SystemTree in session storage and Reproduce hiding SystemTree.
                        updateSystemTreeByStorage();
                        var lastLeafOrder = treeobj.getNameOrder();
                        storage.setItem("_SystemTreeLastLeafOrder", JSON.stringify(lastLeafOrder));
                }
		_showLoading();

		// Updates dialogs with the current "_Lists".
		var lists = _getAccListObjArray("_Lists");
		syncList2DlgMakeList(lists, {order:false, check:true, clearSelect:false});
		syncDlgMakeList();

		_execCanvas();
	}
}
function collapseTreeNode(treeobj, threshold) {
	if(threshold && threshold !== 0) {
		var collapsed;
		if(storage.getItem("_SystemTreeAutoCollapseType") === "ratio") {
			collapsed = treeobj.autoCollapseByRatioToMaxHeight(threshold);
		} else {
			collapsed = treeobj.autoCollapseByHeight(threshold);
		}
		storage.setItem("_SystemTreeCollapsedBranch", JSON.stringify(collapsed));
	}
}
function initSystreeStyle() {
	treeobj.headerString = "Whole genome tree";
	treeobj.lineColor = 'black';
}

//TODO Consider moving to dialog.js
//var lastLeafOrder = [];
function hideSystemTreeSimple(hide) {
	if(hide) {
//		if($('#dialog_systree').is(":visible")) $("#dialog_systree").dialog('close');
		_showLoading();
		var lastLeafOrder = treeobj.getAllPotentialNameOrder();
		_reset_accession_lists_byArray(lastLeafOrder);
		storage.setItem('_SystemTreeLastLeafOrder', JSON.stringify(lastLeafOrder));
		storage.setItem('_SYSTREE', 'off');
//		_syncContentWidth();

//		storage.removeItem("_ListsTgt");	// This is because the collapsed Acc is all expanded and the Canvas size is unknown.
		_drawCanvas();
		FROMSCROLL=true;
//		SCRTIMER = 1;
		_execCanvas();
//SCRTIMER = null;
	} else {
		var lists = _getAccListObjArray('_Lists');
//		var lists = new Object(JSON.parse(storage.getItem('_Lists')));
		var listsLen = lists.length;
		if(listsLen < 3) {
			alert("Post three or more Accessions on the track. Or \"Reset\" in the header menu.");
			return;
		}

		
		var diff = false;
		var diffOrder = false;
		if(treeobj.isTreeUsing()) { 
			var lastLeafOrder = JSON.parse(storage.getItem('_SystemTreeLastLeafOrder'));
			var diffs = diffAccListsVsOrder(lists, lastLeafOrder);
			diff = diffs[1];
			diffOrder = diffs[0];
		} else {
			diff = true;
		}
		if(diff) {
			var msg = "Recreate SystemTree. ";
			if(listsLen > 1000  && _isEmpty(storage.getItem("_SysTreeNewick"))) msg += "Due to the large number of accessions, it takes several tens of seconds to several minutes. ";
			msg += "Is that OK?";
			var ok = window.confirm(msg);
//			var ok = window.confirm("Recreate SystemTree. Accession order will change. Is that OK?");
			if(ok) {
				storage.setItem('_SYSTREE', 'on');
				if(isPhylipTreeUsing()) {
//				if(flgUsingPhylipTree) {
					clearPhylipTreeCache();
				} else {
					clearSystemTreeCache();
				}
				treeobj.initTree();
				var threshold = parseFloat(storage.getItem("_SystemTreeAutoCollapseThreshold"));
				storage.setItem('_SYSTREE', 'on');
				flgUpdateTree = true;
				_showLoadingDialog();
				// Recreate the tree in the latest SystemTree mode, not the default(LW) 
				syncListsAndSystemTreeLast(threshold);
				storage.setItem('_SystemTreeLastLeafOrder', '[]');
			}
		} else {
			var ok2 = true;
			if(diffOrder) ok2 = window.confirm("It's trying to display SystemTree. Accession order will change. Is that OK?");
			if(ok2) {
				storage.setItem('_SYSTREE', 'on');
				flgUpdateTree = true;
				if(!isPhylipTreeUsing() && _isEmpty(storage.getItem("_SysTreeNewick"))) {
//				if(!flgUsingPhylipTree && _isEmpty(storage.getItem("_SysTreeNewick"))) {
					// Tree is null when reloaded(F5) with Using phylipTree+Show tree:off
					var threshold = parseFloat(storage.getItem("_SystemTreeAutoCollapseThreshold"));
					syncListsAndSystemTreeLast(threshold);
				} else {
					if(!treeobj.isTreeUsing()) {
						// Tree is null when reloaded(F5) with Show tree:off
						updateSystemTreeByStorage();
					}
					syncSystemTree2Lists(true);	// Execute _setMenu() and _initCanvas() in this.
				}
				storage.setItem('_SystemTreeLastLeafOrder', '[]');
			}
		}
	}
	syncDlgMakeList();
}
/**
 * return [orderDiff, memberDiff]
 */
function diffAccListsVsOrder(lists, order2) {
	var order1 = [];
	for(var i=0,len=lists.length; i<len; i++) {
		order1.push(lists[i].id);
	}
	return diffAccOrderVsOrder(order1, order2);
}
/**
 * return [orderDiff, memberDiff]
 */
function diffAccOrderVsOrder(preOrder1, preOrder2) {
	var order1 = [];	// If preOrder1 is null.
	if(preOrder1) order1 = preOrder1.concat();	// Deep copy

	var order2 = [];	// If preOrder2 is null.
	if(preOrder2) order2 = preOrder2.concat();	// Deep copy

	var diffs = [false, false];
	if(order1.length === order2.length) {
		var arrLen = order1.length;

		// Chech for different order.
		for(var i=0; i<arrLen; i++) {
			if(order1[i] !== order2[i]) {
				diffs[0] = true;
				break;
			}
		}

		// Check the differences between Acc members
		var sorter = function(a, b) {
			return a < b ? -1 : 1;
		};
		order1.sort(sorter);
		order2.sort(sorter);
		for(var i=0; i<arrLen; i++) {
			if(order1[i] !== order2[i]) {
				diffs[1] = true;
				break;
			}
		}
	} else {
		diffs = [true, true];
	}
	return diffs;
}

//TODO Consider moving to dialog.js
function returnPhylip2WholeGenomeTree() {
	if(!isPhylipTreeUsing()) return void(0);
//	if(!flgUsingPhylipTree) return void(0);

	_reset_accession_lists_byArray(treeobj.getAllPotentialNameOrder());
	storage.removeItem("_ListsTgt");	// add 2021/05/10
	var threshold = parseFloat(storage.getItem("_SystemTreeAutoCollapseThreshold"));
	_messageOnScreen("The phylogenetic tree by the subtool is canceled.");
	syncListsWithCancelPhylipTreeLast(threshold);
//	syncDlgMakeList();
}

function sortListsByTrackOrder(oriLists) {
	var lists = oriLists.concat();
	var id2orderMap = {};

	// Current track order: high priority
	var trackOrder = _getAccListObjArray('_Lists');
	for(var i=0,len=trackOrder.length; i<len; i++) id2orderMap[trackOrder[i].id] = i;

	// All acc order: low priority
	var accOrder = _getAccListObjArray('_Lists-origin');
	for(var i=0,len=accOrder.length; i<len; i++) {
		if( !(accOrder[i].id in id2orderMap) ) id2orderMap[accOrder[i].id] = (i+1) * 10000; 
	}

        var sorter = function(a, b) {
                if( !(a.id in id2orderMap)) {
			// this should never run.
                        return 1;       // Unused Accs are in the back order
                } else if( !(b.id in id2orderMap) ) {
			// this should never run.
                        return -1;      // Unused Accs are in the back order
                } else {
                        return id2orderMap[a.id] - id2orderMap[b.id];
                }
        }
        lists.sort(sorter);

	return lists;
}
function convListsForSystemTree(oriLists) {
	/* Make form Acc order as similar as that of Tree */

	// Copy array for sort
	var lists = oriLists.concat();

	// Sort Acc in Tree order
	var treeAccOrder = treeobj.getAllPotentialNameOrder();
	var id2orderMap = {};
	for(var i=0,len=treeAccOrder.length; i<len; i++) { id2orderMap[treeAccOrder[i]] = i; }
	var sorter = function(a, b) {
		if( !(a.id in id2orderMap)) {
			return 1;	// Unused Accs are in the back order
		} else if( !(b.id in id2orderMap) ) {
			return -1;	// Unused Accs are in the back order
		} else {
			return id2orderMap[a.id] - id2orderMap[b.id];
		}
	}
	lists.sort(sorter);

	/* If it is a collapsed Acc, set the array, otherwise set id String to listsNew. */

	// pre-scan lists
	var isListsAcc = {};
	for(var i=0,len=lists.length; i<len; i++) { isListsAcc[lists[i].id] = true; }

	var accId2ObjMap = _getAllAccId2listsObj();

	// make collapsed node => childs leaf map
	// If collapsed recursively, the smaller serial is the upstream branch. In this case, it will be skipped larger serial branch as a result.
	var altId2childObjs = {};
	var usedAccId = {};
	var collapsedBranchSerials = Object.keys(treeobj.collapsedBranchSerial);
	collapsedBranchSerials.sort(function(a, b) {
		return a - b;
	});	// sort by int.
	for(var i=0,len=collapsedBranchSerials.length; i<len; i++) {
		var collasedBranch = treeobj.serial2branch[collapsedBranchSerials[i]];
		var altAccId = collasedBranch.alternativeLeaf.childs;
		if( !(altAccId in isListsAcc) || usedAccId[altAccId] ) continue;
		altId2childObjs[altAccId] = [];	// key is AccId
		var collapsedLeafs = collasedBranch.leafs;
		for(var j=0,jLen=collapsedLeafs.length; j<jLen; j++) {
			var childAccId = collapsedLeafs[j].childs;
			if(childAccId in isListsAcc) {
				if( !(childAccId in usedAccId) ) {
					altId2childObjs[altAccId].push(accId2ObjMap[childAccId]);
				}
				usedAccId[childAccId] = true;
			}
		}
		if(altId2childObjs[altAccId].length == 0) {
			// Skip larger serial Branch.
			delete altId2childObjs[altAccId];
		}
	}

	var listsNew = [];
	for(var i=0,len=lists.length; i<len; i++) {
		if(lists[i].id in altId2childObjs) {
			listsNew.push(altId2childObjs[lists[i].id]);
		} else if( !(lists[i].id in usedAccId) ) {
			listsNew.push(lists[i]);
		}
	}
	return listsNew;
}
function getListsForSystemTree() {
	var lists = [];
	if(isTreeUsing()) {
		var allAccMap = _getAllAccId2listsObj();
		var leafs = treeobj.getAllPotentialNameOrder();
		for(var i=0,len=leafs.length; i<len; i++) {
			lists.push(allAccMap[leafs[i]]);
		}
	} else {
		lists = _getAccListObjArray('_Lists');
//		lists = Object(JSON.parse(storage.getItem('_Lists')));
	}
	return lists;
}
function _execCanvas(p,b,s) {
/*
  // For debug. Display function that called _execCanvas().
  if(_execCanvas.caller == null){
    console.log('caller : NONE');
  }else{
    console.log('caller : ', _execCanvas.caller.name + " searchAccIndex:" + searchAccIndex);
  }
*/
        var thread = DEF_TRACK_THREADNUM;
        if(!thread) thread = 4;
	var invisDatas = "";

	if(SCRTIMER) clearTimeout(SCRTIMER);
	var isScroll=false;
	if(FROMSCROLL) isScroll=true;
	FROMSCROLL=false;
/*
	var isScroll=false;	
	if(SCRTIMER && FROMSCROLL){
		isScroll=true;
		clearTimeout(SCRTIMER);
	}
	FROMSCROLL=false;
*/
	if(DEBUG_MODE) console.log("isScroll:" + isScroll);

	// Depth&Variants
	if (_isEmpty(p)) {
		p=storage.getItem("_Pos"); 
		b=storage.getItem("_Block"); 
	}
	baseobj=new Object(_getList("db"));

	var visList = [];
	if((storage.getItem("_ListsTgt") || storage.getItem("_ListsTgt")=="") && parseInt(baseobj.length/thread) != 0){
		// Get Accs of "_ListsTgt". if "_ListsTgt" is empty, get all Accs in Viewport.
		if(DEBUG_MODE) console.log("Use _ListsTgt");
		if(storage.getItem("_ListsTgt") == "") _getVisibleArea();
		visList=storage.getItem("_ListsTgt").split(","); 
	}else{
		// Executed when storage.removeItem("_ListsTgt").
		// If #content heignt is undetermined, get Accs for it's maximum height.
		if(DEBUG_MODE) console.log("Use Viewport");
		var contentVisibleArea = getContentVisibleArea();
		var bodyHeight = $(window).outerHeight(true);	//  body height
//		var bodyHeight = $(window).outerHeight(true)-document.body.clientHeight;	// Code until 202509. I don't know why body.clientHeight is being subtracted.
		if(DEBUG_MODE && document.body.clientHeight !== 0) console.error("body.clientHeight is not 0: " + document.body.clientHeight);
		height = bodyHeight - (145 + (_getTrack('view').length * 41 + 10) + 100);	// (topMenu + reference) + track + (SNP dens +  footer)
		if(storage.getItem("_GWAS") === "on") height = height - 105;	// GWAS
		// header is not considered.
		var len = Math.ceil(height/parseInt(storage.getItem("_BlockH")));
		if(len > baseobj.length){len = baseobj.length;}
		visList = _NgetList("db", contentVisibleArea.top, len+1);	// Just in case len+1
		// If canvas height becomes smaller and top changes after executing drawCanvas(),
		// scroll event will occur and redrawng.
	}
	if(DEBUG_MODE) console.log("_ListsTgt:" + visList.length);

	if(isScroll) {
		var convVisList = [];
		for(var i=0,len=visList.length; i<len; i++) {
			if(!isValidTrackRow(visList[i])) convVisList.push(visList[i]);
		}
		if(DEBUG_MODE) console.log("visList:" + visList.length + " => " + convVisList.length);
		visList = convVisList;
	}

	var prmDbs = new Array([]);	// index=0 element is empty array(dummy).
	var countaAc = parseInt(visList.length / thread);
	if(visList.length === 0) {
		// All track information for the target Accs has already been obtained.
		// After this, DB reload occurs.
		thread = 0;
	} else if(countaAc === 0) {
		prmDbs.push([].concat(visList));	// copy Array
		thread = 1;
	} else {
		var mod = (visList.length)%thread;
		var elemIndex = 0;
		for (var i = 1; i <= thread; i++) {
			var elemLen = countaAc;
			if(i <= mod) elemLen++;
			prmDbs.push(visList.slice(elemIndex, elemIndex + elemLen));
			elemIndex = elemIndex + elemLen;
		}
	}
//console.log("prmDbs:" + JSON.stringify(prmDbs));

	// Set dummy data to Accs that are "not vertically scrolling" and "out of screen".
	var listsObjs = _getAccListObjArray('_Lists');
	var notValidDbs = [];
	var en=new Object(JSON.parse(storage.getItem("_Env")));
var testArr = [];
	for(var i=0,len=listsObjs.length; i<len; i++) {
		var listsDb = listsObjs[i].db;
		if(visList.indexOf(listsDb) < 0) {
			if(isScroll && isValidTrackRow(listsDb)){
				// A valid value has already been set.
			} else {
				// set dummy data
				if(en.cstm_track=="enabled"){
					notValidDbs.push(listsDb + "|[" + times("{\"dp\":\"x\",\"rdp\":\"x\"},",b).slice(0,-1) + "]");
				} else {
					notValidDbs.push(listsDb + "|[" + times("{\"dp\":\"x\"},",b).slice(0,-1) + "]");
				}
testArr.push(listsObjs[i].id);
			}
		}
	}
if(DEBUG_MODE) console.log("Invalid:" + testArr.length);
	if(notValidDbs.length > 0) invisDatas = ';' + notValidDbs.join(';');

	var isLoadGffTrack = !isScroll || !_loadedGffTrackMap();	// Save with another name before initing isScroll
//	var isLoadGffTrack = !isScroll;
	isScroll=false;
	var prm_Gene = "";
	var prm_ExcludeUpDownVar = "";
	if(storage.getItem("_HighlightVariantGene")) {
		prm_Gene = storage.getItem("_HighlightVariantGene");
		if(storage.getItem("_HighlightVariantExclUpDown")) prm_ExcludeUpDownVar = "1";
	}

	// Dummy ajax returning success
	var ajax_dummy_response = function(response) {
		var deferred = $.Deferred().resolve(response);
		return deferred.promise();
	};
		var jqXHRList = [];
		_changeProgressStr("Loading track information...");
		_drawProgress(100,1);
		if(isLoadGffTrack) {
		if(DEBUG_MODE) console.log("Load track");
			jqXHRList.push($.ajax({
				url: "./bin/"+_backendSelector("track.php"),
				type: "POST",
				cache: false,
				data: {
					"prm_Zoom":storage.getItem("_Zoom"),
					"prm_Chr":storage.getItem("_Chr"),
					"prm_Pos":storage.getItem("_Pos"),
					"prm_Block":storage.getItem("_Block"),
					"prm_Tracks":new Object(_getTrack("list"))
				}
			}));
			if(phenotypeFlg) {
				jqXHRList.push($.ajax({
					url: "./bin/phenotype_prob.php",
					type: "GET",
					cache: false,
					data: {
						"prm_Phenotype":storage.getItem("_Phenotype"),
						"prm_Zoom":storage.getItem("_Zoom"),
						"prm_Chr":storage.getItem("_Chr"),
						"prm_Pos":storage.getItem("_Pos"),
						"prm_Block":storage.getItem("_Block"),
					}
				}));
			} else {
				jqXHRList.push(ajax_dummy_response);
			}
		} else {
			// Set dummy ajax returning success
			jqXHRList.push(ajax_dummy_response);
			jqXHRList.push(ajax_dummy_response);
		}

		for (var i = 1; i <= thread; i++) {
			jqXHRList.push($.ajax({ 
				url: "./bin/"+_backendSelector("data.php"),
				type: "POST",
				cache: false,
				data: {
					"prm_Ref":storage.getItem("_Ref"),
					"prm_width":storage.getItem("_BlockW"),
					"prm_Zoom":storage.getItem("_Zoom"),
					"prm_Chr":storage.getItem("_Chr"),
					"prm_Pos":p,
					"prm_QUAL":storage.getItem("_QUAL"),
					"prm_DP":storage.getItem("_DP"),
					"prm_DP4":storage.getItem("_DP4"),
					"prm_EffGrps":storage.getItem("_EffGrps"),
					"prm_Block":b,
					"prm_Lists":new Object(prmDbs[i]),
					"prm_ExcludeUpDownVar":prm_ExcludeUpDownVar,
					"prm_Gene":prm_Gene,
				}
			}
			));
		}
		$.when.apply($, jqXHRList).done(function () {
			var datas = [];
			var statuses = [];
//			var jqXHRResultList = [];
			if(isLoadGffTrack) {
				// Gff track
				var trdatas = [];
				var trstatuses = [];
				var trjqXHRResultList = [];
				var trresult = arguments[0];
				trdatas.push(trresult[0]);
				trstatuses.push(trresult[1]);
				trjqXHRResultList.push(trresult[3]);
				var n=trdatas[0].split("|");
				for (var i=0, trackLen=_getTrack("list").length; i<trackLen; i++){
					n[i] = n[i].replace(/---/g,"\|");
					_setGffTrackMapByJson("_Track_"+i, n[i]);
//					storage.setItem("_Track_"+i, n[i]);
				}
				if ( storage.getItem("_Zoom") == '1b' ) {
					storage.setItem("_FASTA", n[n.length-1]);
				}

				// GWAS track
				if(phenotypeFlg) {
					if(arguments[1] != null && arguments[1][0] != null) {
						var o=new Object(JSON.parse(storage.getItem("_Phenotypes")));
						for(var i=0, oLen=o.length; i<oLen; i++){
							var phenotype_prob_name = o[i].phenotype.replace(/\s+/g, "_");
							_clearPhenoProbArray("_Phenotype_Prob_" + phenotype_prob_name);
//							storage.removeItem("_Phenotype_Prob_" + phenotype_prob_name);
						}
						var n = arguments[1][0].split(";");
						for (var i = 0, nLen=n.length; i < nLen; i++) {
							var a = n[i].split("|");
							_setPhenoProbArray("_Phenotype_Prob_" + a[0], JSON.parse(a[1]));
//							storage.setItem("_Phenotype_Prob_" + a[0], a[1]);
							storage.setItem("_Min_Phenotype_Prob_" + a[0], a[2]);
						}
					}
				}
			}

			// Variant/Depth track
			for (var i=2; i<thread+2; i++) {
				var result = arguments[i];
				datas.push(result[0]);
				statuses.push(result[1]);
//				jqXHRResultList.push(result[3]);
			}

			for(var x=0; x<timerArray.length; x++){	clearInterval(timerArray.shift());} // animation

			var dvdata = datas.join(";") + invisDatas;
			var d = dvdata.replace(/^\s+|\s+$/g, "");
			if (_isEmpty(s)) {
				_setData(d);
			} else {
				_setData_p(d,s,b);
			}
			_drawCanvas();
			_hideLoading();
			DATAPFLAG=false;
			storage.setItem("_ListsTgt","");
			clearTimeout(PROGRESSTIMER);
			setTimeout("_drawProgress('100')",100);
			setTimeout(_closeLoadingDialog,500);
			if(searchAccIndex !== null) {
				setTimeout(moveToSearchAcc(), 100);	// "!=null" cannot be used because it becomes true when it is 0.
			}

//jqXHRList.push($.ajax({
//	url: "./bin/"+_backendSelector("test.php"),
//	type: "POST",
//	cache: false
//}));
		}).always(function() {
			_defProgressStr();
		});
	clearTimeout(BUSYDETECTTIMER);
}

var searchAccIndex = null;	// Set on searchAndExpandAccInTree(), Become null in moveToSearchAcc()
function getMoveToSearchAccTop(searchAccIndex) {
	if(searchAccIndex === null) return null;

	var elemContent = document.getElementById("content");
	var currentScrollTop = elemContent.scrollTop;

	var blockH = parseInt(storage.getItem("_BlockH"));
	var contentHeight = elemContent.getBoundingClientRect().height;
	var contentTop = 10 + searchAccIndex * blockH - contentHeight/2 + blockH/2;

	// check scroll area
	var contentTableHeight = document.getElementById("content_table").offsetHeight;	// Track height in scroll
	var maxScrollTop = contentTableHeight - contentHeight;
	var visibleArea = getContentVisibleArea();	// value is 1origin
	if(searchAccIndex >= visibleArea.top && searchAccIndex < visibleArea.count + visibleArea.top - 3) {
		// Same scroll area
		contentTop = currentScrollTop;
	} else if(contentTop < 0) {
		// Top of scroll 
		contentTop = 0;
	} else if(contentTop > maxScrollTop) {
		// Bottom of scroll
		contentTop = maxScrollTop;
	}
//console.log("contentTop:" + contentTop + " / " + currentScrollTop + "(" + contentHeight + "/" + contentTableHeight + ")" + " (" + visibleArea.top + "," + visibleArea.count + ")");
	return contentTop;
}
function moveToSearchAcc() {
	if(searchAccIndex === null) return;

	var contentTop = getMoveToSearchAccTop(searchAccIndex);

	var elemContent = document.getElementById("content");
	var currentScrollTop = elemContent.scrollTop;

	searchAccIndex = null;	// very important!
	if(currentScrollTop != contentTop) {
		elemContent.scrollTop = contentTop;
		_showLoading();	// remove _mouseScrollListener().
		FROMSCROLL=true;
//SCRTIMER = 1;
		_execCanvas();	// Since it scrolls Track, reload the Acc.
//SCRTIMER = null;
	} else {
		_drawCanvas();	// _drawTitle is enough to update image, but it is post-processed in _drawCanvas.
//		_drawTitle(null);
//		_closeErr();	// _execCanvas() is not executed, so close it here.
	}
}
function searchAndExpandAccInTree(accId) {
	// Deselection
	searchAccIndex = null;
//	storage.setItem("_AccHighlight", "");
//	highlightAcc = null;
	clearAccHighlight();
	clearSystreeHighlight();

	// Selection
	if(isTreeUsing()) {
		if( !(accId in treeobj.name2leaf) ) {
			_drawCanvas();	// Reflect deselection on canvas
			return;
		}
		
		var leafObj = treeobj.name2leaf[accId];
//		searchAccIndex = leafObj.leafIndex;
		storage.setItem("_AccHighlight", leafObj.childs);
//		highlightAcc = leafObj.childs;

		var branch = leafObj;
		var isChanged = false;
		while(branch !== null) {
			var parent = branch.parent;
			if(branch.alternativeLeaf != null) {
				treeobj.expandBranch(branch.alternativeLeaf);
				isChanged = true;
			}
			branch = parent;
		}

		flgUpdateTree = true;
		_messageOnScreen("Searching for " + accId);
		if(isChanged) {
			storage.setItem("_SystemTreeCollapsedBranch", JSON.stringify(treeobj.collapsedBranchSerial));
			treeobj.updateTree();	// update leafObj.leafIndex
			searchAccIndex = leafObj.leafIndex;
			syncSystemTree2Lists();
		} else {
			searchAccIndex = leafObj.leafIndex;
//			_showLoading();
//			_execCanvas();
			moveToSearchAcc();
		}
	} else {
		var lists = _getAccListObjArray("_Lists");
//		var lists = JSON.parse(storage.getItem("_Lists"));
		for(var i=0,len=lists.length; i<len; i++) {
			if(lists[i].id === accId) {
				searchAccIndex = i;
				storage.setItem("_AccHighlight", lists[i].id);
//				highlightAcc = lists[i].id;
				break;
			}
		}
		if(searchAccIndex !== null) {
			_messageOnScreen("Searching for " + accId);
//			_showLoading();
//			_execCanvas();
			moveToSearchAcc();
		} else {
			_drawCanvas();	// Reflect deselection on canvas
		}
	}
}

/////////////////////////////////////////////// Output messages and reload Canvas
function _reloadCanvas(msg) {
	_showLoading();
	_messageOnScreen(msg);
	FROMSCROLL=false;
	_execCanvas();
}

function _NgetList(str,num,count) {
	var a=new Array();
	var o = _getAccListObjArray("_Lists");
//	var o=new Object(JSON.parse(storage.getItem("_Lists")));
	var oLen = o.length;
	var acCount=0;
	var start=parseInt(num-1);
	var end=parseInt(num-1+count);
	for(var i=start; i<end; i++){
		if(i >= oLen) break;
		if(!_isUndefined(o[i])){
			if(str=="id"){
				a[acCount]=o[i].id;
			}else if(str=="db"){
				a[acCount]=o[i].db;
			}else if(str=="name"){
				a[acCount]=o[i].name;
			}else if(str=="grp"){
				a[acCount]=o[i].grp;
			}else if(str=="variety"){
				a[acCount]=o[i].variety;
			}else if(str=="origin"){
				a[acCount]=o[i].origin;
			}else if(str=="origin_2"){
				a[acCount]=o[i].origin_2;
			}else if(str=="type"){
				a[acCount]=o[i].type;
                        }else if(str=="other_1"){
                                a[acCount]=o[i].other_1;
                        }else if(str=="other_2"){
                                a[acCount]=o[i].other_2;
			}
			acCount++;
		}else{
			//console.log(i+" is undefined");
		}
	}
	return a;
}

function _sessionStart(){
	var runP3Res = document.getElementById("run_p3_res");
	var runP3Hist = document.getElementById("run_p3_hist");
	$.ajax({
		url: "./bin/session.php",
		type: "POST",
		cache: false,
		data: {
			"init":"load",
			"string":"1"
		},
		success: function(data) {
			array=data.split("---SPLIT---");
			if(array[3]=="true"){
				runP3Hist.innerHTML=array[2];
				runP3Res.innerHTML="";
			}else if(array[3]=="false"){
				var resTblStr = "<hr><table class=\"fontCourierNew\" style=\"margin-left:150px;\" cellspacing=\"0\"  width=\"60%\"><tr><td>";
				var resTblEnd = "</td></tr></table>";
				runP3Res.innerHTML=resTblStr+"<img src=\"./images/loader.gif\" alt=\"Running...\" style=\"\" />Running Primer3."+resTblEnd;
//				runP3Res.innerHTML=resTblStr+"<img src=\"./images/loader.gif\" alt=\"Running...\" style=\"\" />Running Primer3, you can close this dialog."+resTblEnd;
			}else{
				runP3Res.innerHTML="";
			}
		}
	});
}

function _sessionBlastStart(){
        var runBlastRes = document.getElementById("result");
        var runBlastHist = document.getElementById("run_blast_hist");
	if(storage.getItem("_blastTable") !== undefined) {
		runBlastHist.innerHTML = _getCompressedData("_blastTable");
//        	runBlastHist.innerHTML=storage.getItem("_blastTable");
	}
        runBlastRes.innerHTML="";

        // for tbalstx
        var en=new Object(JSON.parse(storage.getItem("_Env")));
	var useTblastx = false;
	if( 'useTblastx' in en && parseInt(en.useTblastx) ) useTblastx = true;
	var select = runBlastRes = document.getElementById("blast_program");
	var options = select.options;
	var existTblastx = false;
	for(var i=0; i<options.length; i++) {
		if(options[i].value === 'tblastx') {
			if(!useTblastx) select.removeChild(options[i]);
			existTblastx = true;
		}
	}
	if(useTblastx && !existTblastx) {
		var optTblastx = document.createElement("option");
		optTblastx.text = 'tblastx (nt)';
		optTblastx.value = 'tblastx';
		select.appendChild(optTblastx);
	}
}

function _reset_accession_lists_byArray(order) {
	var id2obj = {};
	var all = _getAccListObjArray('_Lists-origin');
//	var all = JSON.parse(storage.getItem('_Lists-origin'));
	for(var i=0,len=all.length; i<len; i++) {
		id2obj[all[i].id] = all[i];
	}

	var lists = [];
	var listsIds = {};
	for(var i=0,len=order.length; i<len; i++) {
		var id = order[i];
		lists.push(id2obj[id]);
		listsIds[id] = true;
	}
	_setAccListObjArray("_Lists", lists);
//	storage.setItem("_Lists", JSON.stringify(lists));

	var dels = [];
	for(var i=0,len=all.length; i<len; i++) {
		if( !(all[i].id in listsIds) ) dels.push(id2obj[all[i].id]);
	}
	_setAccListObjArray("_ListsDeleted", dels);
//	storage.setItem("_ListsDeleted", JSON.stringify(dels));
}

///////////////////////////////////////////////////////////
// Interface group for set/get GFF Track
///////////////////////////////////////////////////////////
var gffTrackMap = {};	// Do not use this object directly outside these interface group.
function _setGffTrackMapByJson(name, json) {
	if(/\d$/.test(name)) { 
		gffTrackMap[name] = JSON.parse(json);
	} else {
		storage.setItem(name, json);
	}
}
function _getGffTrackMap(name) {
	if(/\d$/.test(name)) {
		return gffTrackMap[name];
	} else {
		return JSON.parse(storage.getItem(name));
	}
}
function _clearGffTrackMap() {
	gffTrackMap = {};
	// Primer3 and Blast result will be  deleted separately by storage.clear().
}
function _loadedGffTrackMap() {
	if(Object.keys(gffTrackMap).length > 0) {
		return true;
	} else {
		return false;
	}
}

///////////////////////////////////////////////////////////
// Interface group for set/get Variant+Depth
///////////////////////////////////////////////////////////
var variantDepthMap = {};	// Do not use this object directly outside these interface group.
function _setVariantDepthMap(accdb, objArray) {
	if( !(objArray instanceof Array) ) {
		console.error("This object is not an Array");
		return;
	}
	variantDepthMap[accdb] = objArray;
//	_setCompressedData(accdb, value);
}
function _getVariantDepthMap(accdb) {
	return variantDepthMap[accdb];
//	return _getCompressedData(accdb)
}
function _clearVariantDepthMap() {
	variantDepthMap = {};
}
function isValidTrackRow(db) {
	var array = _getVariantDepthMap(db);
	if(array == null || array.length === 0) return false;

	var valid = true;
	for(var i=0,len=array.length; i<len; i++) {
		if(array[i].dp === 'x') {
			valid = false;
			break;
		}
	}
	return valid;
}
function setInvalidTrackRow(db) {
	// Dummy data (It is determined to be invalid within _execCanvas and is overwritten with valid data)
	_setVariantDepthMap(db, [{dp:"x"}]);
}

///////////////////////////////////////////////////////////
// Interface group for set/get GWAS phenotype prob
///////////////////////////////////////////////////////////
var phenoProbArray = [];	// Do not use this object directly outside these interface group.
function _setPhenoProbArray(key, objArray) {
//	storage.setItem(key, JSON.stringify(objArray));

	if( !(objArray instanceof Array) ) {
		console.error("This object is not an Array");
		return;
	}
	phenoProbArray = objArray;
}
function _getPhenoProbArray(key) {
//	return JSON.parse(storage.getItem(key));
	return phenoProbArray;
}
function _clearPhenoProbArray(key) {
//	storage.removeItem(key);
	phenoProbArray = [];
}


///////////////////////////////////////////////////////////
// Interface group for set/get accession list of Web Storage.
///////////////////////////////////////////////////////////
// [!!!Notice!!!] Objects below should not be changed after initialization by setter.
// Do not use these objects directly outside these interface group.
var accListObjArray = null; 
var accListObjMap = null;	// Share ListsObj with accListObjArray to save memory.
function _setAccListObjArray(key, accObjArray) {
	if( !(accObjArray instanceof Array) ) {
		console.error("This object is not an Array");
		return;
	}

	if(key === "_Lists-origin") {
		var accObjArrayStr = JSON.stringify(accObjArray);
		accListObjArray = JSON.parse(accObjArrayStr);	// Deep copy of accObjArray
		accListObjMap = null;
		_setCompressedData(key, accObjArrayStr);
	} else {
		var dbArray = [];
		for(var i=0, len=accObjArray.length; i<len; i++) {
			var accdb = accObjArray[i].db;
			dbArray.push(accdb);
			if(key === '_ListsDeleted')  setInvalidTrackRow(accdb);
		}
//console.log("Test:" + key + " => " +  dbArray.join(','));
		storage.setItem(key, dbArray.join(','));
	}
}
function _getAccListObjArray(key) {
	var accObjArray = [];
	if(key === "_Lists-origin") {
		if(accListObjArray === null) {
			// For reload(F5)
//console.log("_getAccListObjArray: decompress");
			var decompData = _getCompressedData(key);
			accListObjArray = JSON.parse(decompData);
			accListObjMap = null;
		}
		accObjArray = accListObjArray;	// [Notice] Shallow copy!!
	} else {
		var data = storage.getItem(key);
//console.log("key:" + key)
//console.log(data);
//		if(data !== "") {
		if(data) {
			var accDb2ObjMap = _getAccDb2ObjMap();
			var dbArray = data.split(',');
			for(var i=0, len=dbArray.length; i<len; i++) {
				accObjArray.push(accDb2ObjMap[dbArray[i]]);
			}
		}
	}
	return accObjArray;
}
function _clearAccListObjArray() {
	accListObjArray = null;
	accListObjMap = null;
}
function _getAllAccId2listsObj() {
	if(accListObjMap !== null) return accListObjMap;

	if(accListObjArray === null) {
		if(DEBUG_MODE) console.log("_getAllAccId2listsObj: renew accListObjArray");
		var dummyHash = _getAccListObjArray("_Lists-origin");	// set accListObjArray
	}
	accListObjMap = {};
	for(var i=0,len=accListObjArray.length; i<len; i++) { accListObjMap[accListObjArray[i].id] = accListObjArray[i]; }
/*
	var allAccs = _getAccListObjArray('_Lists-origin');
	accListObjMap = {};
	for(var i=0,len=allAccs.length; i<len; i++) { accListObjMap[allAccs[i].id] = allAccs[i]; }
*/
	return accListObjMap;
}
function _getAccDb2ObjMap() {
	var accDb2ObjMap = {};
	if(accListObjArray === null) {
		if(DEBUG_MODE) console.log("_getAccDb2ObjMap: renew accListObjArray");
		var dummyMap = _getAccListObjArray("_Lists-origin");	// set accListObjArray
	}
	for(var i=0,len=accListObjArray.length; i<len; i++) {
		accDb2ObjMap[accListObjArray[i].db] = accListObjArray[i];
	}
/*
	var accId2ObjMap = _getAllAccId2listsObj();
	var ids = Object.keys(accId2ObjMap);
	var dbs = [];
	var accDb2ObjMap = {};
	for(var i=0,len=ids.length; i<len; i++) {
		var db = accId2ObjMap[ids[i]].db;
		dbs.push(db);
		accDb2ObjMap[db] = accId2ObjMap[ids[i]];
	}
*/
	return accDb2ObjMap;
}
/*
function getAccObjArrayCopy() {
	var array = _getAccListObjArray("_Lists-origin");
	return JSON.parse(JSON.stringify(array));	// return deeply copied object
}
*/

///////////////////////////////////////////////////////////
//Exporting/importing Accession list
///////////////////////////////////////////////////////////
//TODO Consider moving to dialog.js
function _downloadAccList(){
	var l = getListsForSystemTree();
//	var l = new Object(JSON.parse(storage.getItem('_Lists')));
	var str = "";
	var Time = new Date();
	var timePrint = Time.getFullYear()+"_"+(Time.getMonth()+1)+"_"+Time.getDate();
	var fileName="AccessionList_"+timePrint+".txt";

	for (var i=0;i<l.length;i++){
		if ( Objects.Name == "id" ) {
			str += l[i].id;
		} else {
			str += l[i].name;
		}
		if(i != (l.length-1)){str += "\n";}
	}
	_download(str,fileName);
}

//TODO Consider moving to dialog.js
var extAccList = new Array();
function _validateAccList(files){
	var elm = document.getElementById("list_upfile_msg");
//	var lists = new Object(JSON.parse(storage.getItem('_Lists-origin')));
	var limit = 10000000;
	var accArray = new Array();
	var reader = new FileReader();
	document.getElementById("prm_list_up").disabled = true;

	if(!_isUndefined(files[0])){
		if(files[0].type != "text/plain"){
			elm.innerHTML="<font color='red'>Invalid file</font>"
				files[0].value = '';
			return;
		}
		if(files[0].size > limit){
			elm.innerHTML="<font color='red'>Too large!</font>"
				files[0].value = '';
			return;
		}

		reader.readAsText(files[0],"utf-8");
		reader.onload = function(ev){
                        var reg = /\r\n/;
                        if (reg.test(reader.result)) {
                                accArray = reader.result.split("\r\n");
                        } else {
                                accArray = reader.result.split("\n");
                        }
			var accId2ObjMap = _getAllAccId2listsObj();
			var ids = Object.keys(accId2ObjMap);
			var assName2ObjMap = {};
			for(var i=0,len=ids.length; i<len; i++) {
				assName2ObjMap[accId2ObjMap[ids[i]].name] = accId2ObjMap[ids[i]];
			}

			var used = {};
			var validated = new Array();
			for(var i=0,len=accArray.length; i<len; i++) {
				var id = null;
				if(accArray[i] in accId2ObjMap) {
					id = accId2ObjMap[accArray[i]].id;
				} else if(accArray[i] in assName2ObjMap) {
					id = assName2ObjMap[accArray[i]].id;
				}
				if(id === null || id in used) continue; 

				validated.push(id);
				used[id] = true;
			}
			extAccList = validated;
			document.getElementById("prm_list_up").disabled = false;
		}
	}
}

//TODO Consider moving to dialog.js  
function _uploadAccList(){
	var elm = document.getElementById("list_upfile_msg");
	if(extAccList.length != 0){
		if(extAccList.length < 3 && isTreeUsing()) {
//			storage.setItem("_SysTreeNewick", "");
			storage.setItem('_SYSTREE', 'off');
		}

		lists = [];
		var accId2ObjMap = _getAllAccId2listsObj();
		for(var i=0,len=extAccList.length; i<len; i++) {
			lists.push(accId2ObjMap[extAccList[i]]);
		}
		_setAccListObjArray("_Lists", lists);
		_setAccListObjArray("_ListsDeleted", getDeletedLists(lists));
		elm.innerHTML="";
		storage.removeItem("_ListsTgt");
//		FROMSCROLL=false;
		var threshold = parseFloat(storage.getItem("_SystemTreeAutoCollapseThreshold"));
		_messageOnScreen("Applying Accession list.");
		syncListsWithCancelPhylipTreeDefault(threshold);	//TODO check:Should I use "~Last"?
	} else {
		elm.innerHTML="<font color='red'>Valid accessions were not found.</font>";
	}
}

function _checkID(id) {
	$.ajax({
        	url: "./bin/"+_backendSelector("isExistID.php"),
                type: "POST",
		async: false,
                cache: false,
                data: {
                	"id":id,
                },
                success: function(data) {
			if(data == 0) {
				result = "Error";
			} else {
				result = "";
			}
        	}
       	});
	return result;
}
function _convPhylipTreeName(newick) {
        var convNewick = newick;

        var subType2key = {
                'variety':'variety',
                'subvariety':'grp',
                'origin':'origin',
                'origin_2':'origin_2',
                'type':'type',
                'other_1':'other_1',
                'other_2':'other_2',
		'id':'id',
		'name':'name'
        };

	var accDb2ObjMap = _getAccDb2ObjMap();
	var dbs = Object.keys(accDb2ObjMap);
	dbs.sort(function(a, b) {return b.length - a.length;});	// String length order, desc
	for(var i=0,len=dbs.length; i<len; i++) {
		var db = dbs[i];
		var accObj = accDb2ObjMap[db];
		var dispName = accObj.id;
		if(currentPhyloTarget.name !== 'id') dispName = accObj.name;
/*
		var subType = currentPhyloTarget.namesub;
		var subVal = accObj[subType2key[subType]];
		var label = dispName + '_' + subVal;
*/
		var label = dispName;
		if(currentPhyloTarget.namesub) {
			var subType = currentPhyloTarget.namesub;
			var subVal = accObj[subType2key[subType]];
			label = label + '_' + subVal;
		}
		label = label.replace(/[\(\)\,\:]/g, '_');
		var pat = new RegExp('([\\W^])' + db + '([\\W$])');
		convNewick = convNewick.replace(pat, '$1' + label + '$2');
//		convNewick = convNewick.replace(db, label);
	}

/*
	var accId2ObjMap = _getAllAccId2listsObj();
        var ids = Object.keys(accId2ObjMap);
        ids.sort(function(a, b) {return b.length - a.length;}); // String length order, desc
        for(var i=0,len=ids.length; i<len; i++) {
                var id = accId2ObjMap[ids[i]].id;
                var dispName = id;
                if(currentPhyloTarget.name !== 'id') dispName = accId2ObjMap[id].name;

                var subType = currentPhyloTarget.namesub;
                var subVal = accId2ObjMap[id][subType2key[subType]];
		var label = dispName + '_' + subVal;
			label = label.replace(/\(([^:\(\)]*)\)/g, '$1');
                convNewick = convNewick.replace(id, label);
        }
*/
        return convNewick;
}
//var DLDATA = "";
//var DLNAME = "";
function _genPhyResult(data,fileName, phy_method){
	var retString = "";
	var phyResult = "";
	var selectbox = "";
	var name = storage.getItem("_Name");
	var ret = data.split("|");	// [0]:Acc List(order by tree) [1]:Newick [2]:Fasta [3]:
	var accessions = ret[0].split(",");
	accessions.reverse();
	var DLDATA = ret[1];
		DLDATA = DLDATA.replace(/\(([^:\(\)]*)\)/g, '$1');	// Excludes parentheses in the ACC name because it conflicts with the Newick format.
	var phylipTreeobj = new PhyloTreeCreater(null);
	try {
		// Reflect sort settings of SystemTree.
		phylipTreeobj.parseNewick(DLDATA);
		var type = storage.getItem("_SystemTreeSortType");
		var xscend = storage.getItem("_SystemTreeSort");
		if(xscend !== "") phylipTreeobj.sortByLength(xscend, type);
		DLDATA = phylipTreeobj.tree.getNewick();
	} catch(error) {
		console.error(error);
	} finally {
		phylipTreeobj.initTree();	//If not executed, a memory leak will occur intensely.
	}
	var DLFASTA = ret[2];
	var DLNAME = fileName + ".nwk";
	var DLFNAME = fileName + ".fasta";
	//boxH = 8 * accessions.length +100;
	boxH = 10 * accessions.length +100;
	for(var i=0; i<accessions.length; i++){
		var idname = accessions[i].split(":");
		var acc_name = idname[0];
		var acc_id = idname[1];
		if(name == "name") {
			selectbox += "<option value="+acc_id+">"+acc_name+"</option>";
		} else if (name == "id") {
			selectbox += "<option value="+acc_id+">"+acc_id+"</option>";
		}
	}

	var btn_dlFasta_attr = "";
	if(phy_method === 'bin') btn_dlFasta_attr = 'disabled';

	retString +=  "<hr>"+
	"<div height='100%' width='100%' style='text-align:left;'>"+
	"<font color='#008000'>The analysis has been finished!</font>"+
	"<table><tr>"+
	"<td width='25%' align='left' style='padding-right:20px;'>"+
	"Sorting accessions in main panel by the order of the reconstructed phylogeny."+
	"<div style=\"display:none\">"+
        "<select size='15' id='phy_acc_order' style='width:100%;font-family:Courier;'>"+
        selectbox+
        "</select>"+
	"</div>"+
	"</td></tr>"+
	"<tr><td>"+
	"<button id='phy_sorted' type='submit' onclick='_sortAccByPhylip();'>Apply now</>"+
	"</td></tr></table>";
	phyResult = "<table width='100%'>"+
	"<tr>"+
	"<td width='75%'>"+
	"Style of phyrogram&nbsp"+
	"<select id='style'>"+
	"<option value='phylogram' selected='true'>Rectangular</option>"+
	"<option value='circlephylogram'>Circular</option>"+
	"<option value='cladogram'>Linear</option>"+
	"</select>"+
	"<button onclick=\"showtree('newick','phy_svg')\">Show</button>"+
	"</td>"+
        "</tr>"+
        "<tr>"+
        "<td>"+
        "Downloads:&nbsp;Phylogeny&nbsp;"+
        "<button type='submit' onClick='_dlNewick();'>newick</button>"+
        "<button type='submit' onClick='_dlPic();'>png</button>"+
        "<button type='submit' onClick='_dlSVG();'>SVG</button>"+
        "&nbsp;&nbsp;&nbsp;Sequences&nbsp;"+
        "<button type='submit' onClick='_dlFasta();' " + btn_dlFasta_attr + ">fasta</button>"+
	"<div id='phy_tree_res' style='height:525;background-color:white; border:1px solid #cccccc;'>"+
	"<svg id='phy_svg' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' version='1.1' height='525' width='525'>"+
	"<script src='./lib/SVGPan2/SVGPan.js' type='text/javascript'></script>"+
	"<g id='viewport' transform='translate(200,200)'></g>"+
	"</svg>"+
	"</div>"+
        "</td>"+
        "</tr>"+
        "</table>";

	$("#newick").val(DLDATA);
//	$("#newick").val(_convPhylipTreeName(DLDATA));	// Since the currentPhyloTarget cannot be referenced from the tree window, create a converted newick.
	$("#fasta").val(DLFASTA);
	$("#nname").val(DLNAME);
	$("#fname").val(DLFNAME);

	var returns = new Object();
	returns.retString = retString;
	returns.phyResult = phyResult;
/*
	returns.newickOri = DLDATA;
	returns.newick = _convPhylipTreeName(DLDATA);
	returns.fasta = DLFASTA;
	returns.nname = DLNAME;
	returns.fname = DLFNAME
*/
	return returns;
}

function _dlPic() {
/*
	var filenames = DLNAME.split('.');
	var ext = filenames.pop();
	var picname = filenames.pop();
*/
	var picname = $("#filename").val();

//	var width = $("#phy_svg").width();
//	var height = $("#phy_svg").height();
	var bBox = document.getElementById('phy_svg').getBBox();
	var width = bBox.width + bBox.x;
	var height = bBox.height + bBox.y;

	// Temporarily change the inline size to draw the entire phylogenetic tree. (Return automatically)
	$("#phy_svg").attr('width', width);
	$("#phy_svg").attr('height', height);

	$("body").append("<canvas id='canvas1' class='hidden' width="
                                  + width + " height=" + height +"></canvas>");
	var canvas = $("#canvas1")[0];
	var ctx = canvas.getContext("2d");

	var svg = $("#phy_svg");
//	svg.attr("viewBox", "0 0 " + width + " " + height);
	var svgData = new XMLSerializer().serializeToString(svg[0]);
	svg2base64 = btoa(unescape(encodeURIComponent(svgData)));
	var imgsrc = "data:image/svg+xml;charset=utf-8;base64,"+svg2base64;
	var image = new Image();
        image.onload = function(){
            ctx.drawImage( image, 0, 0 );
	    if (window.navigator.msSaveBlob) {
		var dataurl = canvas.toDataURL("image/png");
		var bin = atob(dataurl.split(',')[1]);
		var buffer = new Uint8Array(bin.length);
		for (var i = 0; i < bin.length; i++) {
 		    buffer[i] = bin.charCodeAt(i);
		}
		var blob = new Blob([buffer.buffer], {type:"image/png"});
		window.navigator.msSaveBlob(blob, picname+".png");
		window.navigator.msSaveOrOpenBlob(blob, picname+".png");
		$("#canvas1").remove();
	    } else {
    	    	$("body").append("<a id='image-file' type='application/octet-stream' href='"
            	+ canvas.toDataURL("image/png") + "' download=\'"+picname+".png'></a>");
    	    	$("#image-file")[0].click();
    	    	$("#canvas1").remove();
    	    	$("#image-file").remove();
	    }
	}
	image.src = imgsrc;
}

function _dlSVG() {
	/*
        var filenames = DLNAME.split('.');
        var ext = filenames.pop();
        var picname = filenames.pop();
	*/
	var picname = $("#filename").val();
//        var width = $("#phy_svg").width();
//        var height = $("#phy_svg").height();
	var bBox = document.getElementById('phy_svg').getBBox();
	var width = bBox.width + bBox.x;
	var height = bBox.height + bBox.y;

	// Temporarily change the inline size to draw the entire phylogenetic tree. (Return automatically)
	$("#phy_svg").attr('width', width);
	$("#phy_svg").attr('height', height);
	$("#phy_svg").css('width', width + 'px');
	$("#phy_svg").css('height', height + 'px');

        var svg = $("#phy_svg");
//        svg.attr("viewBox", "0 0 " + width + " " + height);
        var svgData = new XMLSerializer().serializeToString(svg[0]);
//console.log("Test:" + svgData);
	var blob = new Blob([svgData], {"type":"image/svg+xml"});
	if (window.navigator.msSaveBlob) { 
        	window.navigator.msSaveBlob(blob, picname+".svg"); 
	 	// msSaveOrOpenBlobの場合はファイルを保存せずに開ける
                window.navigator.msSaveOrOpenBlob(blob, picname+".svg"); 
        } else {
	    var append_word = "<a id=\"download\" href=\"#\" download=\""+picname+".svg\">ダウンロード</a>";
            $("body").append(append_word);
	    document.getElementById("download").href = window.URL.createObjectURL(blob);
            $("#download")[0].click();
            $("#download").remove();
	}
}

function _sortAccByPhylip(){
	// Notice: Phylip trees will be erased when reloaded and the SystemTree will be drawn. 
	var headerString = "";
	if(currentPhyloTarget.cri === "1") {
		headerString = "" + currentPhyloTarget.objid + "";
	} else {
		headerString = "" + currentPhyloTarget.chr + ":" + currentPhyloTarget.s + "-" + currentPhyloTarget.e + "";
	}
	treeobj.headerString = headerString;

	storage.setItem("_SYSTREE", "on");
	treeobj.treeWidth = getSystemTreeWidth() - treeobj.lMargin - treeobj.rMargin;

	_messageOnScreen("Apply phylogenetic tree");
	setTimeout(function() {
		syncPhylip2SystemTree();
//		syncDlgMakeList();	//20250220 Commentout
	}, 20);
}

///////////////////////////////////////////////////////////
//Exporting FASTA
///////////////////////////////////////////////////////////
var jqxhrGenFasta = null;
function _genFasta(){
	var chr = document.getElementById("prm_fa_chr");
	var st = document.getElementById("prm_fa_s");
	var ed = document.getElementById("prm_fa_e");
	var sub = document.getElementById("fa_submit");
        var stop = document.getElementById("fa_stop");
//	var numthread = JSON.parse(storage.getItem('_Env')).threadnum;
//        var numthread = _getNumThread();
	var ajaxloader = document.getElementById("fa_ajaxloader");

	var cri = document.getElementById("prm_fa_cri").value;
	var cds = document.getElementById("prm_fa_gene").value;	// genome/mrna/cds/aa
	var objid = "";
	if(parseInt(cri) === 1) objid = document.getElementById("prm_fa_objid").value;
//	if(parseInt(cri) === 1 && cds !== 'genome') objid = document.getElementById("prm_fa_objid").value;
	var reverse = 0;
	if(document.getElementById("prm_fa_reverse").checked) reverse = document.getElementById("prm_fa_reverse").value;
	var rep_n = 0;
	if(document.getElementById("prm_fa_rep_n").checked) rep_n = document.getElementById("prm_fa_rep_n").value;

	//ajaxloader.innerHTML="<img src=\"./images/loader.gif\" alt=\"Exporting...\" style=\"\" />Exporting...";
	ajaxloader.innerHTML="<img src=\"./images/loader.gif\" alt=\"Exporting...\" style=\"\" />Exporting...(It may take several minutes)";
	sub.disabled = true;
        stop.disabled = false;
	jqxhrGenFasta = $.ajax({
		//url: "./bin/"+_backendSelector("fasta.php"),
		url: "./bin/"+_backendSelector("get_fasta_multi.php"),
		type: "POST",
		cache: false,
		data: {
			"prm_fa_chr":chr.value,
			"prm_fa_s":st.value,
			"prm_fa_e":ed.value,
			"prm_fa_flk":"",
			"prm_fa_tgt":document.getElementById("prm_fa_tgt").value,
			"prm_fa_var":"",
			"prm_fa_qual":document.getElementById("prm_fa_qual").value,
			"prm_fa_dp":document.getElementById("prm_fa_dp").value,
			"prm_fa_list": _getList("db").join(","),
//			"prm_fa_list":document.getElementById("prm_fa_list").value,
			"prm_fa_name":document.getElementById("prm_fa_name").value,
			"prm_fa_nameS":document.getElementById("prm_fa_nameS").value,
			"prm_fa_ref":document.getElementById("prm_fa_ref").value,
			"prm_fa_width":document.getElementById("prm_fa_width").value,
			"prm_fa_avd":document.getElementById("prm_fa_avd").value,
			"prm_fa_p3prm":"",
                        "prm_fa_DN":"",
                        "prm_fa_DNnum":"",
			"prm_fa_Ns":document.getElementById("prm_fa_Ns").value,
			"prm_type":"a",
			"prm_epcrprms":"",
			"prm_obj_id":objid,
			"prm_fa_gene":cds,
			"prm_fa_reverse":reverse,
			"prm_fa_rep_n": rep_n
//			,"prm_numthread":numthread
		}
	}).fail(function (XMLHttpRequest, textStatus, errorThrown) {
            if(textStatus === 'abort') {
                ajaxloader.innerHTML = "Processing aborted";
            } else {
                ajaxloader.innerHTML = XMLHttpRequest.status + " Error";
            }
	}).done(function (data) {
		data = data.replace(/^\s+/, '');	// Remove leading spaces sent for abort detection.
		ajaxloader.innerHTML="";
		if (data.match(/<font/) || data.match(/Invalid/)) {
			ajaxloader.innerHTML = data;
		} else {
			seqArr = JSON.parse(data);
			var res = "";
			for(var i=0, len=seqArr.length; i<len; i++) {
				if(seqArr[i]) res = res + seqArr[i].replace(/Error/g,'');
			}
			var Time = new Date();
			var timePrint = Time.getFullYear()+"_"+(Time.getMonth()+1)+"_"+Time.getDate();
			var fileName = "";
			if(objid !== "") {
				fileName = escape_filename(objid) + "_" + timePrint + "_" + cds + ".fasta";
			} else {
				fileName = escape_filename(chr.value) + "_" + st.value + "b-" + ed.value + "b_" + timePrint + ".fasta";
			}
			_download(res, fileName);
		}
/*
            ajaxloader.innerHTML="";
            data = data.replace(/Error/g,'');
            var res = JSON.stringify(data);
            res = res.replace(/\\\\n/g,'\n');
            res = res.replace(/\"\[\\\"/g,'');
            res = res.replace(/\\\",\\\"/g,'\n');
            res = res.replace(/\\\"\]\"/g,'\n');
            if (data.match(/<font/) || data.match(/Invalid/)) {
                ajaxloader.innerHTML=data;
             } else {
                //data = data.replace(/Error/g,'');
                var Time = new Date();
                var timePrint = Time.getFullYear()+"_"+(Time.getMonth()+1)+"_"+Time.getDate();
                var fileName=_escapeHTML(chr.value)+"_"+st.value+"b-"+ed.value+"b_"+timePrint+".fasta";
                //_download(data,fileName);
                _download(res,fileName);
             }
*/
	}).always(function() {
            sub.disabled = false;
            stop.disabled = true;
            jqxhrGenFasta = null;
        });
}
function _stopGenFasta() {
	if(jqxhrGenFasta) jqxhrGenFasta.abort();	// exec $.ajax.always();
}

///////////////////////////////////////////////////////////
//Exporting CSV
///////////////////////////////////////////////////////////
var jqxhrGenCSV = null;
function _genCSV(mode){
	var chr = document.getElementById("prm_csv_chr");
	var st = document.getElementById("prm_csv_s");
	var ed = document.getElementById("prm_csv_e");
	var pos = document.getElementById("choose_pos");
        var id = document.getElementById("choose_id");
        var sub = document.getElementById("csv_submit");
	var stop = document.getElementById("csv_stop");
        if(pos.checked) {
                choose_flag = "1";
        } else if (id.checked) {
                choose_flag = "2";
        }
	var ajaxloader = document.getElementById("csv_ajaxloader");
	var idflag = 1;
	if(choose_flag == 2) {
		var kwd = document.getElementsByName("prm_csv_keyword")[0].value;
		var result = _checkID(kwd);
        	if(result == "Error") {
        		idflag = 0;
        	}
	}
	if (isNaN(parseInt(st.value)) || isNaN(parseInt(ed.value))) {
                ajaxloader.innerHTML="Invalid value: Position";
                return;
	} else if (idflag == 0) {
            	ajaxloader.innerHTML = "<font style=\"font-size:18px;color:red;\">Error : Invalid value in ID!</font>";
		return;
        } else {
		var usegtrow = '';
		if(mode === 'gtrow') usegtrow = 1;

		ajaxloader.innerHTML="<img src=\"./images/loader.gif\" alt=\"Exporting...(It may take several minutes)\" style=\"\" />Exporting...";
	        sub.disabled = true;
		stop.disabled = false;
		jqxhrGenCSV = $.ajax({
			url: "./bin/"+_backendSelector("csv.php"),
			type: "POST",
			cache: false,
			data: {
				"prm_csv_chr":chr.value,
				"prm_csv_s":st.value,
				"prm_csv_e":ed.value,
				"prm_pos_id":document.getElementsByName("prm_pos_id")[0].value,
				"prm_csv_qual":document.getElementById("prm_csv_qual").value,
				"prm_csv_dp":document.getElementById("prm_csv_dp").value,
				"prm_csv_list": _getList("db").join(","),
//				"prm_csv_list":document.getElementById("prm_csv_list").value,
				"prm_csv_keyword":document.getElementsByName("prm_csv_keyword")[0].value,
//				"prm_csv_effgrps":JSON.stringify(_getEffGrpArray("expfilter_effgrp")),
				"prm_csv_usegtrow":usegtrow,
				"choose_flag":choose_flag
			}
		}).fail(function (XMLHttpRequest, textStatus, errorThrown) {
//			console.log("x");
			if(textStatus === 'abort') {
				ajaxloader.innerHTML = "Processing aborted";
			} else {
				ajaxloader.innerHTML=XMLHttpRequest.status + " Error";
			}
		}).done(function (data) {
			ajaxloader.innerHTML="";
			if (data.match(/Error/)) {
				ajaxloader.innerHTML=data;
			} else {
				//ajaxloader.innerHTML="";
				var Time = new Date();
				var timePrint = Time.getFullYear()+"_"+(Time.getMonth()+1)+"_"+Time.getDate();
				var fileName = "";
				if (choose_flag == "1") {
					fileName=_escapeHTML(chr.value)+"_"+parseInt(st.value)+"b-"+parseInt(ed.value)+"b_"+timePrint+".tsv";
				} else if (choose_flag == "2") {
					fileName=document.getElementsByName("prm_csv_keyword")[0].value+"_"+timePrint+".tsv";
				}
				_download(data,fileName);
			}
		}).always(function () {
			sub.disabled = false;
			stop.disabled = true;
			jqxhrGenCSV = null;
		});
	}
}
function _stopGenCSV() {
	if(jqxhrGenCSV) jqxhrGenCSV.abort();	// exec $.ajax.always();
}

///////////////////////////////////////////////////////////
//Gen p3
///////////////////////////////////////////////////////////
var jqxhrGenPrimer3Query = null;
function _genPrimer3Query(){
	var chr = document.getElementById("prm_p3_chr");
	var flk = document.getElementById("prm_p3_flk");
	var st = document.getElementById("prm_p3_s");
	var ed = document.getElementById("prm_p3_e");
	var tgt = document.getElementById("prm_p3_tgt");
	var dp = document.getElementById("prm_p3_dp");
	var q = document.getElementById("prm_p3_qual");
	var variant = document.getElementById("prm_p3_var");
	var tgte = document.getElementById("prm_p3_tgt_e");
	//var li = document.getElementById("prm_p3_list");
	var avd = document.getElementById("prm_p3_avd");
	var res = document.getElementById("p3_query_res");
	//var p3Ns = document.getElementById("prm_p3_Ns");
	var sub = document.getElementById("p3_submit");
	var stop = document.getElementById("p3_stop");
        var form = document.forms.prm_rp3_Ns2;
        var p3Ns = form.Ns2_selection.value;
	var chrv = _escapeHTML(chr.value);
	var tgtv = parseInt(tgt.value);
	var tgtev = parseInt(tgte.value);
	//accession[0] = li.value; //for genarate each accession-based sequence. (disabled)
	var fileName = "";

	sub.disabled = true;
	stop.disabled = false;
	jqxhrGenPrimer3Query = $.ajax({
//		url: "./bin/"+_backendSelector("fasta.php.multi"),
		url: "./bin/"+_backendSelector("fasta.php"),
		type: "POST",
		cache: false,
		data: {
			"prm_fa_chr":chrv,
			"prm_fa_s":parseInt(st.value),
			"prm_fa_e":parseInt(ed.value),
			"prm_fa_flk":parseInt(flk.value),
			"prm_fa_tgt":parseInt(tgt.value)+"-"+parseInt(tgte.value),
			"prm_fa_qual":q.value,
			"prm_fa_dp":dp.value,
			"prm_fa_var":variant.value,
			//"prm_fa_list":accession[0],
			"prm_fa_list":_getList("db").toString(),
			"prm_fa_name":storage.getItem("_Name"),
			"prm_fa_nameS":storage.getItem("_NameSub"),
			"prm_fa_ref":"REFERENCE",
			"prm_fa_width":"80",
			"prm_fa_avd":parseInt(avd.value),
			"prm_fa_p3prm":"",
			"prm_fa_Ns":p3Ns,
			//"prm_fa_DN":p3DN,
			"prm_type":"b"
		}
	}).fail(function(XMLHttpRequest, textStatus, errorThrown) {
		if(textStatus === 'abort') {
			res.innerHTML = "<span style=\"margin-left:150px;\">Processing aborted</span>";
		} else {
			res.innerHTML = XMLHttpRequest.status + " Error";
		}
	}).done(function(data) {
		data = data.replace(/Error/g,'');
		res.innerHTML="<hr><br>"+data;
	}).always(function() {
		sub.disabled = false;
		stop.disabled = true;
		jqxhrGenPrimer3Query = null;
	});
}
function _stopGenPrimer3Query() {
	if(jqxhrGenPrimer3Query) jqxhrGenPrimer3Query.abort();	// exec $.ajax.always();
}

///////////////////////////////////////////////////////////
// Run BLAST
///////////////////////////////////////////////////////////
var jqxhrRunBlast = null;
function _runBlast(){
  var query = document.getElementById("blast_qryarea").value;
  var program = document.getElementById("blast_program").value;
  var evalue = document.getElementById("blast_eval").value;
  var wordSize = document.getElementById("blast_word_size").value;
  var max_target_seqs = document.getElementById("max_target_seqs").value;
  //var max_matches = document.getElementById("max_matches").value;
  var match_scores = document.getElementById("match_scores").value.split(",");
  var match_scr = match_scores[0];
  var mismatch_scr = match_scores[1];
  var gap_costs = document.getElementById("gap_costs").value.split(",");
  var gap_open = gap_costs[0];
  var gap_extend = gap_costs[1];
  //var scoreMatrix = document.getElementById("blast_score_matrix").value;
  var sub = document.getElementById("blast_submit");
  var stop = document.getElementById("blast_stop");	// The button is currently hidden.
  var blastHit = true;
  query = query.replace(/<script>.*<\/script>/,"");
  escQuery = _escapeHTML(query);

  var ajaxloader = document.getElementById("result");
  ajaxloader.innerHTML="<img src=\"./images/loader.gif\" alt=\"BLAST running\" style=\"\" />Running...";

  sub.disabled = true;
  stop.disabled = false;
  jqxhrRunBlast = $.ajax({
    //url: '../bin/blast.php',
    url: './bin/blast.php',
    type: "POST",
    data: {
        params:{
                blast_qryarea: escQuery,
		blast_program: program,
                blast_eval: evalue,
                blast_word_size: wordSize,
                max_target_seqs: max_target_seqs,
                match_scr: match_scr,
                mismatch_scr: mismatch_scr,
                gap_open: gap_open,
                gap_extend: gap_extend
                //"blast_score_matrix" : scoreMatrix
        }
   }
   })
   .done(function (response) {
//	console.log(response);
        if (response instanceof Array) {
//		var hitsAndOrder = parseBlastXmlByArray(response);
		var hitsAndOrder = parseBlastPairwiseByArray(response);
		var hits = hitsAndOrder[0];
		var sortEval = hitsAndOrder[1];

                var alignSum = "";
                var blastResult = "";
		var blastTable;
                var alignResult="";
                var idCount = 0;
		var queCount = 0;
		var htmlstr = "";
		function ObjArraySort(ary, key, order) {
    			var reverse = 1;
    			if(order && order.toLowerCase() == "desc") 
        			reverse = -1;
    				ary.sort(function(a, b) {
        			if(parseFloat(a[key]) < parseFloat(b[key]))
            				return -1 * reverse;
        			else if(parseFloat(a[key]) == parseFloat(b[key]))
            				return 0;
        			else
            				return 1 * reverse;
    			});
		}
		ObjArraySort(sortEval,'evalue','asc');
		var messageStart = "<table style=\"text-align:center;width:530px;\" border=\"1\">\
                                        <tr>\
                                        <th>query</th>\
                                        <th>chr</th>\
                                        <th>hsp</th>\
                                        <th>qStrand</th>\
                                        <th>qStart</th>\
                                        <th>qEnd</th>\
                                        <th>sStrand</th>\
                                        <th>sStart</th>\
                                        <th>sEnd</th>\
                                        <th>Coverage</th>\
                                        <th>Evalue</th>\
                                        <th>Identity</th>\
                                        <th>Bit score</th>\
					<th>Frame</th>\
					<th> </th>\
                                        </tr><tr>";
		var messageEnd ="</table>";
		var p3qinfo = document.getElementById("p3result").value;
		var p3qinfos = [];
		if(p3qinfo != "undefined") {
			p3qinfos = p3qinfo.split(":");
		}
                for (key in hits) {
			if(key == "qlen") continue;
			queCount++;
			blastResult = "";
                        qname = key;
			for(i in sortEval) {
				if(!sortEval[i]["name"]) continue;	// for IE. (In IE, the contents of Array.prototype.remove are added to sortEval)
				var evals = sortEval[i]["name"].split("---SEv---");
				var quename = evals[0];
				var chr = evals[1];
				var hsp_num = evals[2];
				var bitscr;
                                var eval;
                                var q_from;
                                var q_to;
				var qstrand;
                                var s_from;
                                var s_to;
				var alignstr;
                                var alignlen;
				var qcover;
				var frame;
				if(quename == qname) {
					idCount++;
                                        for (key4 in (hits[qname][chr][hsp_num])) {
                                                if (key4 == 'bitscr') {
                                                        bitscr = hits[qname][chr][hsp_num][key4];
                                                } else if (key4 == 'eval') {
                                                        eval = hits[qname][chr][hsp_num][key4];
                                                } else if (key4 == 'qfrom') {
                                                        q_from = hits[qname][chr][hsp_num][key4];
                                                } else if (key4 == 'qto') {
                                                        q_to = hits[qname][chr][hsp_num][key4];
                                                } else if (key4 == 'qstrand') {
                                                        q_strand = hits[qname][chr][hsp_num][key4];
                                                } else if (key4 == 'sfrom') {
                                                        s_from = hits[qname][chr][hsp_num][key4];
                                                } else if (key4 == 'sto') {
                                                        s_to = hits[qname][chr][hsp_num][key4];
                                                } else if (key4 == 'sstrand') {
                                                        s_strand = hits[qname][chr][hsp_num][key4];
                                                } else if (key4 == 'alignlen') {
                                                        alignlen = hits[qname][chr][hsp_num][key4];
                                                        if(typeof alignlen == 'string') alignlen=alignlen.trim();
                                                } else if (key4 == 'identity') {
                                                        identity = hits[qname][chr][hsp_num][key4];
                                                        if(typeof identity == 'string') identity=identity.trim();
                                                } else if (key4 == 'gaps') {
                                                        gaps = hits[qname][chr][hsp_num][key4];
                                                        if(typeof gaps == 'string') gaps=gaps.trim();
						} else if (key4 == 'alignstr') {
							alignstr = hits[qname][chr][hsp_num][key4];
                                                } else if (key4 == 'qcover') {
							qcover = hits[qname][chr][hsp_num][key4];
						} else if (key4 == 'frame') {
							frame = hits[qname][chr][hsp_num][key4];
						}
                                        }
                                        var ident =Math.round(identity/alignlen*100);
                                        var gaprate = Math.round(gaps/alignlen*100);
					var p3result = document.getElementById("p3result").value;

					var blstSt = s_from;
					var blstEn = s_to;
					if(s_from > s_to) {
						blstSt = s_to;
						blstEn = s_from;
					} 
					var blstTrack = ['all', blstSt, blstEn, chr].join('---TRK---');
					var blstButtonHtml  = "<button style=\"padding:0px;margin:-1px;\" onclick=\"_callDrawBLAST(\'"+ blstTrack + "\')\">Jump</button>";

					var trStyle = "";
					if(p3result != "undefined") {
						var p3results = p3result.split(":");
						var left = p3results[0];
						var leftinfo = left.split("---BLS---");
						var right = p3results[1];
						var rightinfo = right.split("---BLS---");
						if (leftinfo[0] == qname && leftinfo[1] == s_from && leftinfo[2] == s_to && leftinfo[3] == chr) {
							trStyle = "style=\"background-color:#ff6699;\"";
						} else if ( rightinfo[0] == qname && rightinfo[1] == s_to && rightinfo[2] == s_from && rightinfo[3] == chr) {
							trStyle = "style=\"background-color:#0099ff;\"";
						}
					} 
					blastResult = blastResult + "<tr " + trStyle + "><td align=\"center\">" + "<a href=#"+idCount + ">" + _escapeHTML(qname) + "</td>" +
						"<td align=\"center\">" + _escapeHTML(chr) + "</td>" + "<td align=\"center\">" + _escapeHTML(hsp_num) + "</td>" +
						"<td align=\"center\">" + _escapeHTML(q_strand) + "</td>" + "<td align=\"center\">" + _escapeHTML(q_from) + "</td>" +
						"<td align=\"center\">" + _escapeHTML(q_to) + "</td>" + "<td align=\"center\">" + _escapeHTML(s_strand) + "</td>" +
						"<td align=\"center\">" + _escapeHTML(s_from) + "</td>" + "<td align=\"center\">" + _escapeHTML(s_to) + "</td>" +
						"<td align=\"center\">" + Math.round(qcover) + "%" + "</td>" + "<td align=\"center\">" + _escapeHTML(eval) + "</td>" +
						"<td align=\"center\">" + _escapeHTML(ident.toString(10)) + "%</td>" + "<td align=\"center\">" + _escapeHTML(bitscr) + "</td>" +
						"<td align=\"center\">" + _escapeHTML(frame) + "</td>" +
						"<td>" + blstButtonHtml + "</td></tr>";
					var strandStr = q_strand + "/" + s_strand;
					if(frame) strandStr = frame
                                        alignResult="<div id="+idCount+">Query  : "+_escapeHTML(qname)+"<br>Subject: "+_escapeHTML(chr)+
						"<div style=\"border-top: 1px solid silver; border-bottom: 1px solid silver;\">" +
						"<table><tbody>" +
						"<tr><th align=\"center\">hsp    </th><th align=\"center\">bitscore    </th><th align=\"center\">expect    </th><th align=\"center\">identity    </th><th align=\"center\">gaps    </th><th align=\"center\">Strand    </th></tr>" +
						"<tr><td align=\"center\">"+_escapeHTML(hsp_num)+"</td><td align=\"center\">"+_escapeHTML(bitscr)+"</td><td align=\"center\">"+_escapeHTML(eval)+"</td><td align=\"center\">"+_escapeHTML(identity)+"/"+_escapeHTML(alignlen)+"("+ident+"%)"+"</td><td align=\"center\">"+_escapeHTML(gaps)+"/"+_escapeHTML(alignlen)+"("+gaprate+"%)"+"<td align=\"center\">"+_escapeHTML(strandStr) + "</td></tr>" +
						"</tbody></table></div>";
					alignResult += "<div><pre>" + alignstr + "</pre></div>";
                                        alignSum = alignSum+alignResult+"</div><br><br>";
                                }
                        }
			if(blastResult !== "") {
				if ( blastTable === undefined) {
                        		blastTable= "<font size=\"4\"><b>Query "+queCount+":"+qname+"</b></font><br>"+messageStart+blastResult+messageEnd;
				} else {
                        		blastTable= blastTable + "<font size=\"4\"><b>Query "+queCount+":"+qname+"</b></font><br>"+messageStart+blastResult+messageEnd;
				}
			}
		}
		var alignStart="<br><font size=\"4\"><b>Alignment</b></font><br><br>";
		blastTable = blastTable +alignStart+alignSum;
		var runBlastRes = document.getElementById("result");
        	var runBlastHist = document.getElementById("run_blast_hist");
                $('#result').html(blastTable);
		try {
			_setCompressedData("_blastTable", blastTable);
//			storage.setItem("_blastTable",blastTable);
		} catch(error) {
			console.error(error);
			alert("An error has occurred Maybe the blast result is too big to register the history in webstorage.");
		}
                runBlastHist.innerHTML="<hr><div align=\"center\"><p><strong>Previous result was overwritten with latest one.</align></strong></p></div>";

		storage.setItem("_runBlast",1);
		storage.setItem("_blstHistFlg",1);
        } else {
                 errMsg="<font size=\"4\" color=\"red\"><b>"+response+"</b></font><br><br>";
                 $('#result').html(errMsg);
        }
        collapseBlastDialog(false);
   }).fail(function (XMLHttpRequest, textStatus, errorThrown) {
	if(textStatus === 'abort') {
		$('#result').val('Blast aborted');
	} else {
	        $('#result').val('Blast failure');
	}
   }).always(function() {
        sub.disabled = false;
	stop.disabled = true;
	jqxhrRunBlast = null;
   });
}
function _stopRunBlast() {
	if(jqxhrRunBlast) jqxhrRunBlast.abort();	// exec $.ajax.always();
}

function collapseBlastDialog(toCollapse) {
        if(toCollapse) {
                // Make the dialog smaller only if all content is collapsed.
                if(!$('#result').html() && $("#blst_opt").hasClass("close") && $('#blst_hist').hasClass("close")) {
                        $(".blast_window").css('max-height', '372px');
                        $(".blast_content").css('max-height', '329px');

                        $(".blast_window").css('max-height', '372px');
                        $(".blast_content").css('max-height', '329px');
                }
        } else {
                var defDialogHeight = 1240;
		var dialogHeight = defDialogHeight;
		if(parseInt($(".blast_window").css('top')) + dialogHeight - 1 > parseInt($("#tasuke").css('height'))) {
			dialogHeight = parseInt($("#tasuke").height()) - parseInt($(".blast_window").css('top')) + 1;
		}
                $(".blast_window").css('height', dialogHeight + 'px');
                $(".blast_content").css('height', (dialogHeight - 43) + 'px');

                $(".blast_window").css('max-height', defDialogHeight + 'px');
                $(".blast_content").css('max-height', (defDialogHeight - 43) +'px');
        }
}

///////////////////////////////////////////////////////////
//Run Primer3 (Supports v2.3.x)
///////////////////////////////////////////////////////////
var jqxhrRunPrimer3 = null;
function _runPrimer3(){
        var chr = document.getElementById("prm_rp3_chr").value;
        var flk = document.getElementById("prm_rp3_flk").value;
        var st = document.getElementById("prm_rp3_s").value;
        var ed = document.getElementById("prm_rp3_e").value;
        var tgt = document.getElementById("prm_rp3_tgt").value;
        var dp = document.getElementById("prm_rp3_dp").value;
        var q = document.getElementById("prm_rp3_qual").value;
        var variant = document.getElementById("prm_rp3_var").value;
        var tgte = document.getElementById("prm_rp3_tgt_e").value;
        var avd = document.getElementById("prm_rp3_avd").value;
        var prdmi = document.getElementById("prm_rp3_prdmi").value;
        var prdmx = document.getElementById("prm_rp3_prdmx").value;
        var sizeopt = document.getElementById("prm_rp3_sizopt").value;
        var sizmax = document.getElementById("prm_rp3_sizmax").value;
        var sizmin = document.getElementById("prm_rp3_sizmin").value;
        var tmopt = document.getElementById("prm_rp3_tmopt").value;
        var tmmx = document.getElementById("prm_rp3_tmmx").value;
        var tmmi = document.getElementById("prm_rp3_tmmi").value;
        var tmdif = document.getElementById("prm_rp3_tmdif").value;
        var lowmsk = document.getElementById("prm_rp3_lowmsk").value;
        //var p3Ns = document.getElementById("prm_rp3_Ns").value;
	//var form1 = document.forms.prm_rp3_Ns;
        //var p3Ns = form1.Ns_selection.value;
        var p3Ns = $("input[name='Ns_selection']:checked").val();
        //var form2 = document.forms.prm_rp3_DN;
        //var p3DN = form2.DN_selection.value;
        var p3DN = $("input[name='DN_selection']:checked").val();
	var p3DNnum = document.getElementById("prm_NA_num").value;
        var runP3Res = document.getElementById("run_p3_res");
        var runP3Hist = document.getElementById("run_p3_hist");
	var sub = document.getElementById("rp3_submit");
	var stop = document.getElementById("rp3_stop");
        var chrv = chr;
        var tgtv = parseInt(tgt);
        var tgtev = parseInt(tgte);

        //var doMFE = parseInt(document.forms.prm_epcr_onoff.epcr_selection.value);
        var doMFE = parseInt($("input[name='epcr_selection']:checked").val());
        epcr_prdmi = document.getElementById("prm_epcr_prdmi").value;
        epcr_prdmx = document.getElementById("prm_epcr_prdmx").value;
        epcr_tmmx = document.getElementById("prm_epcr_tmmx").value;
        epcr_tmmi = document.getElementById("prm_epcr_tmmi").value;
        epcr_monoconc = document.getElementById("prm_epcr_KCl").value;
        epcr_divaconc = document.getElementById("prm_epcr_MgCl2").value;
        epcr_dNTP = document.getElementById("prm_epcr_dNTP").value;
        epcr_anneal = document.getElementById("prm_epcr_annealing").value;
        var fileName = "";
        var p3Params = prdmi+","+prdmx+","+sizeopt+","+sizmax+","+sizmin+","
                        +tmopt+","+tmmx+","+tmmi+","+tmdif+","+lowmsk;
        var epcrParams = doMFE+","+epcr_prdmi+","+epcr_prdmx+","+epcr_tmmx+","+epcr_tmmi
                        +","+epcr_monoconc+","+epcr_divaconc+","+epcr_dNTP+","+epcr_anneal;
        var resTblStr = "<hr><table class=\"fontCourierNew\" style=\"margin-left:150px;\" cellspacing=\"0\"  width=\"60%\"><tr><td>";
        var resTblEnd = "</td></tr></table>";
	runP3Res.innerHTML = resTblStr+"<img src=\"./images/loader.gif\" alt=\"Running...\" style=\"\" />Running Primer3."+resTblEnd;
//        runP3Res.innerHTML = resTblStr+"<img src=\"./images/loader.gif\" alt=\"Running...\" style=\"\" />Running Primer3, you can close this dialog."+resTblEnd;
	sub.disabled = true;
	stop.disabled = false;
	jqxhrRunPrimer3 = $.ajax({
		url: "./bin/"+_backendSelector("fasta.php"),
		type: "POST",
		cache: false,
		data: {
                        	"prm_fa_chr":chrv,
                        	"prm_fa_s":parseInt(st),
                        	"prm_fa_e":parseInt(ed),
                        	"prm_fa_flk":parseInt(flk),
                        	"prm_fa_tgt":parseInt(tgt)+"-"+parseInt(tgte),
                        	"prm_fa_qual":q,
                        	"prm_fa_dp":dp,
                        	"prm_fa_var":variant,
                        	"prm_fa_list":_getList("db").toString(),
                        	"prm_fa_name":storage.getItem("_Name"),
                        	"prm_fa_nameS":storage.getItem("_NameSub"),
                        	"prm_fa_ref":"REFERENCE",
                        	"prm_fa_width":"80",
                        	"prm_fa_avd":parseInt(avd),
                        	"prm_fa_p3prm":p3Params,
                        	"prm_fa_Ns":p3Ns,
                        	"prm_fa_DN":p3DN,
                        	"prm_fa_DNnum":p3DNnum,
                        	"prm_type":"c",
                        	"prm_epcrprms":epcrParams
		}
	}).done(function(data) {
                        if (data.match(/^PRIMER/)) {
				if(p3DN == 2) {
					var resTblStr = "<hr><table class=\"fontCourierNew\" style=\"margin-left:150px;\" cellspacing=\"0\"  width=\"60%\"><tr><td>";
                                	var resTblEnd = "</td></tr></table>";
					runP3Res.innerHTML=resTblStr+"<img src=\"./images/loader.gif\" alt=\"Running...\" style=\"\" />Running Primer3."+resTblEnd;
//                                runP3Res.innerHTML=resTblStr+"<img src=\"./images/loader.gif\" alt=\"Running...\" style=\"\" />Running Primer3, you can close this dialog."+resTblEnd;
				}
                                data = data;
                                var rtn = "";
                                var resTblStr = "<table class=\"fontCourierNew\" style=\"margin-left:75px;\" cellspacing=\"0\"  width=\"80%\"><tr><td>";
                                var rtnTblStr = "<table class=\"fontCourierNew\" width=\"585px\"style=\"margin-left:60px;\" cellspacing=\"0\" border=\"1\" ><tr><td>";
                                var resTblEnd = "</td></tr></table>";
                                var rtnTblEnd = "</td></tr></table><br>";
                                        var resCont = "You can download the result from this button ->\
                                        <button type=\"submit\" name=\"prm_rp3_submit\" onclick=\"_getP3Result();\">Download</button>";
                                var array = [];
//                                var MFEresult = "";
                                var lNsseqs = [];
                                var rNsseqs = [];
				if(p3DN == 2) {
                                       var array=data.split("---SPLIT---");
					if(!(array[0].match(/NO PRIMERS FOUND/))) {
                                        	var rtnP3Array = array[1].split("--split--");
                                        	var lPrmList = rtnP3Array[1].split("-");
                                        	var rPrmList = rtnP3Array[2].split("-");
                                        	var lPrm = lPrmList[0].split(":");
                                        	var rPrm = rPrmList[0].split(":");
                                        	var rtnSeqArray = rtnP3Array[0].split("");
                                        	var t = lPrmList.length;
                                        	var prmCand="";
                                        	for(var i=0; i<t; i++){
                                                	var eachLPrm = lPrmList[i].split(":");
                                                	var eachRPrm = rPrmList[i].split(":");
							// !!! PRIMER_FIRST_BASE_INDEX=0(default) !!!
                                                	lprm_from=parseInt(tgt)-parseInt(flk)+parseInt(eachLPrm[0]);
                                                	lprm_to = parseInt(lprm_from)+parseInt(eachLPrm[1])-1;
                                                	rprm_to = parseInt(tgt)-parseInt(flk)+parseInt(eachRPrm[0]);
                                                	rprm_from = parseInt(rprm_to)-parseInt(eachRPrm[1])+1;
                                                	resultNs = _checkNs(lprm_from,lprm_to,rprm_from,rprm_to,chrv);
                                                	resultNspos = resultNs.split("|");
                                                	lNspos = resultNspos[0];
                                                	rNspos = resultNspos[1];
                                                	var lNsseq = "";
                                                	var rNsseq = "";
                                                	leftp3=_escapeHTML(eachLPrm[2]);
                                                	rightp3=_escapeHTML(eachRPrm[2]);
                                                	for ($j=0;$j<leftp3.length;$j++) {
                                                	        pos = lprm_from + $j;
                                                	        if(lNspos.match(pos)) {
                                                                	lNsseq = lNsseq + "<font color=\"orange\">"+leftp3[$j]+"</font>";
                                                        	} else {	
                                                                	lNsseq = lNsseq + leftp3[$j];
                                                        	}	
                                                	}
                                                	lNsseqs[i] = lNsseq;
                                                	for ($j=0;$j<rightp3.length;$j++) {
                                                        	pos = rprm_from + $j;
                                                        	if(rNspos.match(pos)) {
                                                        	        rNsseq = rNsseq + "<font color=\"orange\">"+rightp3[$j]+"</font>";
                                                        	} else {
                                                                	rNsseq = rNsseq + rightp3[$j];
                                                        	}
                                                	}
							rNsseqs[i] = rNsseq;
                                        	}
					}
                                }
				if(doMFE==1) {
					var twodata = data.split("---MFESPLIT---");
					array=twodata[0].split("---SPLIT---");
					var MFEResObj = parseMFEprimerResult(data);
					var rtn = _p3Table(data,chrv,tgt,tgte,flk,runP3Res,p3DN,lNsseqs,rNsseqs, MFEResObj);
				} else {
					array=data.split("---SPLIT---");
					var rtn = _p3Table(data,chrv,tgt,tgte,flk,runP3Res,p3DN,lNsseqs,rNsseqs, null);
				}
/*
                                if(doMFE==1) {
                                        twodata = data.split("---MFESPLIT---");
                                        array=twodata[0].split("---SPLIT---");
                                        MFEresult = twodata[1].replace(/---QUERY---/g,"\n").replace(/---MFERES---/g,"\n");
                                        var rtn = _MFETable(data,chrv,tgt,tgte,flk,runP3Res,p3DN,lNsseqs,rNsseqs);
                                } else if (doMFE==0) {
                                        array=data.split("---SPLIT---");
                                        var rtn = _p3Table(data,chrv,tgt,tgte,flk,runP3Res,p3DN,lNsseqs,rNsseqs);
                                }
*/
                                var rtnArray = rtn.split("--RTNSPLIT--");
                                var prmCand = rtnArray[0];
                                var rtnSeqArray = rtnArray[1].split("");
                                var lPrmRtn = rtnArray[2];
                                var lPrm = lPrmRtn.split("--lPrm--");
                                var rPrmRtn = rtnArray[3];
                                var rPrm = rPrmRtn.split("--rPrm--");
                                var message = rtnArray[4];
                                var fileName = rtnArray[5];
                                var tableFunc = rtnArray[6];
                                var y = rtnSeqArray.length;
                                var strCount = 0;
                                var strRealCount = 0;
                                var pointer = 0;
                                var tag = "false";
                                for(var x=0; x<y; x++){
                                        strRealCount++;
                                        if(rtnSeqArray[x].match(/</)){
                                                tag = "true";
                                        }
                                        if(tag == "true"){
                                                if(rtnSeqArray[x].match(/>/)){
                                                        tag = "false";
                                                }
                                        }
                                        else{
                                                if(rtnSeqArray[x].match(/[ATGCNWSMKRYBDHVatgcnwsmkrybdhv]/)){
                                                        strCount++;
                                                        pointer=0;
                                                        if(rtnSeqArray[x+1]=="<" && rtnSeqArray[x+2]=="/"){pointer=7;}//</font> +7
                                                        if(strCount == lPrm[0]){
                                                                rtnSeqArray[x+pointer]=rtnSeqArray[x+pointer]+"<font color='#ff6699'>";
                                                        }else if(strCount == parseInt(lPrm[0])+parseInt(lPrm[1])){
                                                                rtnSeqArray[x+pointer]=rtnSeqArray[x+pointer]+"</font>";
                                                        }
                                                        else if(strCount == parseInt(rPrm[0])-parseInt(rPrm[1])+1){
                                                                rtnSeqArray[x+pointer]=rtnSeqArray[x+pointer]+"<font color='#0099ff'>";
                                                        }
                                                        else if(strCount == parseInt(rPrm[0])+1){
                                                                rtnSeqArray[x+pointer]=rtnSeqArray[x+pointer]+"</font>";
                                                        }
                                                }else{
                                                        console.log("Unexpected char");
                                                }
                                        }
                                }
                                var rtnP3 = rtnTblStr+"<span id=\"resSeq\"><!--:-->"+rtnSeqArray.join("")+"<!--:--></span>"+rtnTblEnd;
                                //runP3Res.innerHTML="<hr>"+resTblStr+message+prmCand+resTblEnd+rtnP3+resTblStr+resCont+resTblEnd;
                                runP3Res.innerHTML="<hr>"+resTblStr+message+prmCand+resTblEnd+rtnP3+resTblStr+resCont+resTblEnd;
                                if(doMFE==0) {
                                        _storeP3Res(fileName+"---SPLIT---"+array[0]+"---SPLIT---"+"<hr>"+resTblStr+message+prmCand+resTblEnd+""+rtnP3+""+resTblStr+resCont+resTblEnd);
                                } else {
					var twodata = data.split("---MFESPLIT---");
					var MFEresult = twodata[1].replace(/---QUERY---/g,"\n").replace(/---MFERES---/g,"\n");
                                        _storeP3Res(fileName+"---SPLIT---"+"Primer3Result\n\n"+array[0]+"------------------------------\n\nMFEprimerResult\n\n"+MFEresult+"---SPLIT---"+"<hr>"+resTblStr+message+prmCand+resTblEnd+""+rtnP3+""+resTblStr+resCont+resTblEnd);
                                }
                                runP3Hist.innerHTML="<hr><div align=\"center\"><p><strong>Previous result was overwritten with latest one.</align></strong></p></div>";
                        } else {
                                errMsg="<font size=\"4\" color=\"red\"><b>"+data+"</b></font><br><br>";
                                runP3Res.innerHTML=errMsg;
                        }
        }).fail(function(XMLHttpRequest, textStatus, errorThrown) {
		if(textStatus === 'abort') {
			runP3Res.innerHTML = "<span style=\"margin-left:150px;\">Processing aborted</span>";
		} else {
			ajaxloader.innerHTML = XMLHttpRequest.status + " Error";
		}
	}).always(function() {
		sub.disabled = false;
		stop.disabled = true;
		jqxhrRunPrimer3 = null;
	});
}
function _stopRunPrimer3() {
	if(jqxhrRunPrimer3) jqxhrRunPrimer3.abort();	// exec $.ajax.always();
}

///////////////////////////////////////////////////////////
// create Primer3 result
///////////////////////////////////////////////////////////
function _p3Table(data,chrv,tgt,tgte,flk,runP3Res,p3DN,lNsseq,rNsseq, MFEResult) {
        var date = new Date();
        var array=data.split("---SPLIT---");
        var resTblStr = "<table class=\"fontCourierNew\" style=\"margin-left:75px;\" cellspacing=\"0\"  width=\"80%\"><tr><td>";
        var resTblEnd = "</td></tr></table>";
        var fileName=chrv+"_"+parseInt(tgt)+"-"+parseInt(tgte)+"_"+date.getFullYear()+"-"+(date.getMonth()+1)+"-"+date.getDate();
        var target = fileName.split("_");
	var message = "<font style=\"font-size:18px\"><b>Result</b></font><br><strong>Your request: "+_escapeHTML(target[0])+" "+_escapeHTML(target[1])+"</strong><br><font color='#008000'>Primer designing has been finished!</font>";
        var message = "<font style=\"font-size:18px\"><b>Result</b></font><br><strong>Your request: "+_escapeHTML(target[0])+" "+_escapeHTML(target[1])+"</strong><br><font color='#008000'>Primer designing has been finished!</font>";
	if(MFEResult != null) message = message + "<br><font color=red>the results PPC value is under 0 is predicted with the same query pairs(left-left or right-right).</font>";
	if (p3DN == 2) {
		message = message + "<br><font color=orange>the strings colored orange explain the position with DEPTH is NA.</font><br><br>";
	} else {
		message = message + "<br><br>";
	}
        var resCont = "You can download the result from this button ->\
                  <button type=\"submit\" name=\"prm_rp3_submit\" onclick=\"_getP3Result();\">Download</button>";
        runP3Res.innerHTML="";
        if(array[0].match(/^Error/)){
                runP3Res.innerHTML=array[0]+"<br>";
                return;
        }
        if(array[1]=="Cookies"){resCont="Cookies Required: Cookies are not enabled on your browser.";}
        var rtnP3Array = array[1].split("--split--");
        var rtnTblStr = "<table class=\"fontCourierNew\" width=\"585px\"style=\"margin-left:60px;\" cellspacing=\"0\" border=\"1\" ><tr><td>";
        var rtnTblEnd = "</td></tr></table><br>";
        var lPrmList = rtnP3Array[1].split("-");
        var rPrmList = rtnP3Array[2].split("-");
        var lPrm = lPrmList[0].split(":");
        var rPrm = rPrmList[0].split(":");
        var rtnSeqArray = rtnP3Array[0].split("");
        var t = lPrmList.length;
        var prmCand="";
        var mfepParams = ['amp', 'lseq', 'rseq', 'hitchr', 'start', 'end', 'len', 'ltm', 'rtm', 'ppc', 'gc'];
        for(var i=0; i<t; i++){
                var eachLPrm = lPrmList[i].split(":");
                var eachRPrm = rPrmList[i].split(":");
                if(!eachLPrm[0]){
                        prmCand="<strong>NO PRIMERS FOUND</strong><br>";
                        break;
                }
		// !!! PRIMER_FIRST_BASE_INDEX=0(default) !!!
                lprm_from=parseInt(tgt)-parseInt(flk)+parseInt(eachLPrm[0]);
                lprm_to = lprm_from + parseInt(eachLPrm[1]) - 1;
		rprm_to = parseInt(tgt)-parseInt(flk)+parseInt(eachRPrm[0]);
		rprm_from = rprm_to - parseInt(eachRPrm[1]) + 1;
//                lprm_from=parseInt(tgt)-parseInt(flk)+parseInt(eachLPrm[0]);
//                lprm_to = parseInt(lprm_from)+parseInt(eachLPrm[1])-1;
//                rprm_to = parseInt(tgt)-parseInt(flk)+parseInt(eachRPrm[0]);
//                rprm_from = parseInt(rprm_to)-parseInt(eachRPrm[1])+1;
                s_from = parseInt(lprm_from);
                s_to = parseInt(rprm_to);
		var p3_track="all---TRK---"+s_from+"---TRK---"+s_to+"---TRK---"+chrv+"---SPL---lPrm---TRK---"+lprm_from+"---TRK---"+lprm_to+"---TRK---"+chrv+"---SPL---rPrm---TRK---"+rprm_from+"---TRK---"+rprm_to+"---TRK---"+chrv+"---SPL---target---TRK---"+tgt+"---TRK---"+tgte+"---TRK---"+chrv;
                p3blast="left---BLS---"+lprm_from+"---BLS---"+lprm_to+"---BLS---"+chrv+":Right---BLS---"+rprm_from+"---BLS---"+rprm_to+"---BLS---"+chrv;
                primer3ArrayForBLASTLeft = "left\n"+_escapeHTML(eachLPrm[2]);
                primer3ArrayForBLASTRight = "Right\n"+_escapeHTML(eachRPrm[2]);

		var leftSeq = "";
		var rightSeq = "";
		var isEssRes = false;
		if(p3DN==2) {
			leftSeq = lNsseq[i];
			rightSeq = rNsseq[i];
			if(lNsseq[i] != "" && rNsseq[i] != "") isEssRes = true;
		} else {
			leftSeq = _escapeHTML(eachLPrm[2]);
			rightSeq = _escapeHTML(eachRPrm[2]);
			isEssRes = true;
		}
		if(isEssRes) {
			var radioVal = [_escapeHTML(eachLPrm[0]), _escapeHTML(eachLPrm[1]), _escapeHTML(eachRPrm[0]), _escapeHTML(eachRPrm[1]), i].join(':');
			var checked = '';
			if(i==0) checked = 'checked';
			var prmCand = prmCand + "<input type=\"radio\" name=\"chPrimer\" value=\"" + radioVal +"\" " + checked + " onclick=\"_switchP3Result();\" />" +
				"&nbsp;Left:&nbsp;" + leftSeq +"&nbsp;&nbsp;&nbsp;Right:&nbsp;" + rightSeq + "&nbsp;&nbsp;" + 
				"<input type=\"button\" value=\"BLAST\" class=\"blast\" onclick=\"_dialog_blast(\'"+_escapeHTML(eachLPrm[2])+"\',\'"+_escapeHTML(eachRPrm[2])+"\',\'"+_escapeHTML(p3blast)+"\')\">&nbsp;&nbsp;" +
				"<button onclick=\"_callDrawBLAST(\'"+p3_track+"\')\">Jump</button>";

			// Add MFEprimer Result
			var primer3ArrayForBLASTLeft = ">left\n"+_escapeHTML(eachLPrm[2]);
			var primer3ArrayForBLASTRight = ">right\n"+_escapeHTML(eachRPrm[2]);
			var primerpair = primer3ArrayForBLASTLeft+"\n"+primer3ArrayForBLASTRight;
			if(MFEResult != null && primerpair in MFEResult) {
				var table = "<table align=\"center\" border=\"1\" width=\"840px\" style=\"margin-left:16px;\">"+
					"<tr><th>AmpID</th>"+
					"<th>Left Seq</th>"+
					"<th>Right Seq</th>"+
					"<th>Hit chr</th>"+
					"<th>Start</th>"+
					"<th>End</th>"+
					"<th>Length</th>"+
					"<th>Left Tm</th>"+
					"<th>Right Tm</th>"+
					"<th>PPC</th>"+
					"<th>GCcontent</th>"+
					"<th></th>"+
					"</tr><tr>";
				var hit = 0;
				var psets = MFEResult[primerpair];
				for(var j=0, psetsLen=psets.length; j<psetsLen; j++) {
					hit++;
					var obj = MFEResult[primerpair][j];
					table = table + "<tr>";
//					for(var v of ['amp', 'lseq', 'rseq', 'hitchr', 'start', 'end', 'len', 'ltm', 'rtm', 'ppc', 'gc']) {
					for(var k=0,mfepParamsLen=mfepParams.length; k<mfepParamsLen; k++) {
						var v = mfepParams[k];
						table = table + "<td align=center>" + obj[v]+ "</td>";
					}
					var mfe_p3_track="all---TRK---" + obj['start'] + "---TRK---" + obj['end'] + "---TRK---" + obj['hitchr'] +  
						"---SPL---lPrm---TRK---" + parseInt(obj['start']) + "---TRK---" + (parseInt(obj['start']) + obj['lseqm'].length - 1) + "---TRK---" + obj['hitchr'] + 
						"---SPL---rPrm---TRK---" + (parseInt(obj['end']) - obj['rseqm'].length + 1) + "---TRK---" + obj['end'] + "---TRK---" + obj['hitchr'] + 
						"---SPL---target---TRK---" + (parseInt(obj['start']) + obj['lseqm'].length) + "---TRK---" + (parseInt(obj['end']) - obj['rseqm'].length) + "---TRK---" + obj['hitchr'];
					table = table + "<td><button style=\"padding:0px;margin:-1px;\" onclick=\"_callDrawBLAST(\'" + mfe_p3_track + "\')\">Jump</button></td>";
					table = table + "</tr>";
				}
				table = table+"</table><br>";
				prmCand = prmCand + "&nbsp;<br><span style=\"margin-left:16px;\"><div style=\"display: inline-block\" ><span id=\"cond_multi_triangle" + i + "\" class=\"ui-icon ui-icon-triangle-1-e\" onClick=\"_slideePCRTable(" + i + ")\" style=\"cursor:pointer;\"></span></div>" +
					"<span onClick=\"_slideePCRTable(" + i + ")\" style=\"cursor:pointer;\">estimated amplified products&nbsp;:&nbsp;" + hit  + "</span><br>" + 
					"<div id=\"epcrTable" + i + "\" style=\"display:none\">" + table + "</div></span>";
//				prmCand = prmCand + "&nbsp;<br><span><div style=\"display: inline-block\" ><span id=\"cond_multi_triangle\" class=\"ui-icon ui-icon-triangle-1-e\"></span></div><span onClick=\"_slideePCRTable(" + i + ")\">estimated amplified products&nbsp;:&nbsp;" + hit  + "</span><br>" + "<div id=\"epcrTable" + i + "\" style=\"display:none\">" + table + "</div></span>";
			} else {
				prmCand = prmCand+"<br>";
			}
		}

        	if(prmCand != "") {
                	var lPrmRtn = lPrm[0]+"--lPrm--"+lPrm[1]+"--lPrm--"+lPrm[2];
                	var rPrmRtn = rPrm[0]+"--rPrm--"+rPrm[1]+"--rPrm--"+rPrm[2];
        	}
	}
        var rtn = prmCand+"--RTNSPLIT--"+rtnP3Array[0]+"--RTNSPLIT--"+lPrmRtn+"--RTNSPLIT--"+rPrmRtn+"--RTNSPLIT--"+message+"--RTNSPLIT--"+fileName;
        return(rtn);
}

///////////////////////////////////////////////////////////
// parse MFEprimer result
///////////////////////////////////////////////////////////
function parseMFEprimerResult(data) {
	var revConvTable = {A:'T', T:'A', G:'C', C:'G', a:'t', t:'a', g:'c', c:'g'};
	function revSeq(seq) {
		var rightRevArray = seq.split("").reverse();
		for(var k=0,rightRevArrayLen=rightRevArray.length; k<rightRevArrayLen; k++) {
			var base = rightRevArray[k];
			rightRevArray[k] = revConvTable[base];
		}
		return rightRevArray.join('');
	}

	var twodata = data.split("---MFESPLIT---");
	var mfedata = twodata[1].split("---MFERES---");

	var result = {};
	var m = mfedata.length-1;
	for (var i=0;i<m;i++) {
		var mfeque = mfedata[i].split("---QUERY---");
		var primerpair = mfeque[0];

		result[primerpair] = [];
		MFEresult=mfeque[1].split("\n");
		lenres = MFEresult.length;
		for (var j=0;j<lenres;j++) {
			if(MFEresult[j].match(/^AmpID/)) continue;

			MFEinfo = MFEresult[j].split("\t");
			if(MFEinfo.length > 14) MFEinfo.splice(4, MFEinfo.length - 14); //Tab is used in Fasta header, so delete it

			var mferesPat = /^([atgc]*)([ATCG].*[ATCG])[a-z]+([ATCG].*[ATCG])([atgc]*)$/;
			var productArray = [];
			if(mferesPat.test(MFEinfo[13])) productArray = MFEinfo[13].match(mferesPat);    // (agg)(ATtCGaGCG)cgatgnca...taycgtacg(CGTCaGCTaC)(gctt);

			var leftDisp = productArray[1] + productArray[2];
			var leftMatch = productArray[2];
			var rightDisp = revSeq(productArray[3] + productArray[4]);
			var rightMatch = revSeq(productArray[3]);
/*
			var leftArray = MFEinfo[13].match(/^([atgc]*)([ATCG]+?)[atgc]/);
			var rightArray = MFEinfo[13].match(/[atgc]([ATCG]+)([atgc]*)$/);
			var leftDisp = leftArray[1] + leftArray[2];
			var leftMatch = leftArray[2];
			var rightDisp = revSeq(rightArray[1] + rightArray[2]);
			var rightMatch = revSeq(rightArray[1]);
*/
			var onerowHash = {
				amp:	MFEinfo[0],
				hitchr:	MFEinfo[3],
				ppc:	MFEinfo[4],
				len:	MFEinfo[5],
				gc:	MFEinfo[6],
				ltm:	MFEinfo[7],
				rtm:	MFEinfo[8],
				start:	MFEinfo[11],
				end:	MFEinfo[12],
				lseq:	leftDisp,
				rseq:	rightDisp,
				lseqm:	leftMatch,
				rseqm:	rightMatch
			};
			result[primerpair].push(onerowHash);
		}
	}
	return result;
}

///////////////////////////////////////////////////////////
//store primer3 result with $_SESSION
///////////////////////////////////////////////////////////
function _storeP3Res(string){
	var runP3Res = document.getElementById("run_p3_res");
	$.ajax({
		url: "./bin/session.php",
		type: "POST",
		async: false,
		cache: false,
		data: {
			"init":"storeP3Res",
			"string":string
		},
		success: function(data) {
			if(data.match(/Invalid/)){
				runP3Res.innerHTML = data;
			} 
			//console.log("stored:"+data);
		}
	});
}



function _getP3Result(){
	var chr = document.getElementById("prm_rp3_chr");
	var tgt = document.getElementById("prm_rp3_tgt");
	$.ajax({
		url: "./bin/session.php",
		type: "POST",
		async: false,
		cache: false,
		data: {
			"init":"load",
			"string":"1"
		},
		success: function(data) {
			array=data.split("---SPLIT---");
			if(array[3]=="true"){
				fileName=array[0];
				_download(array[1],fileName);
			}
		}
	});
}

///////////////////////////////////////////////////////////
//Switching primer position
///////////////////////////////////////////////////////////
function _switchP3Result(){
	var resSeq = document.getElementById("resSeq");
	var radioList = document.getElementsByName("chPrimer");
	var radioListLen = radioList.length;
	var primerPos = "";
	for(var i=0; i<t; i++){
		if (radioList[i].checked) {
			primerPos = radioList[i].value;
			break;
		}
	}
	var primerPosArray = primerPos.split(":");
	$.ajax({
		url: "./bin/session.php",
		type: "POST",
		cache: false,
		data: {
			"init":"load",
			"string":"1"
		},
		success: function(data) {
			array=data.split("---SPLIT---");
			if(array[3]=="true"){
				var splitedArray = array[2].split("<!--:-->");
				var seqarray = splitedArray[1].split("");
				var seq = seqarray.join("");
				seq = seq.replace(/<br>/g, "@");
				seq = seq.replace(/(.*)<font color='#ff6699'>([@\s\n\rATGCNWSMKRYBDHVatgcnwsmkrybdhv]*)<\/font>(.*)/, "$1$2$3");
				seq = seq.replace(/(.*)<font color='#0099ff'>([@\s\n\rATGCNWSMKRYBDHVatgcnwsmkrybdhv]*)<\/font>(.*)/, "$1$2$3");
				seq = seq.replace(/@/g, "<br>");
				var rtnSeqArray = seq.split("");
				var y = rtnSeqArray.length;
				var strCount = 0;
				var strRealCount = 0;
				var pointer = 0;
				var tag = "false";
				for(var x=0; x<y; x++){
					strRealCount++;
					if(rtnSeqArray[x].match(/</)){
						tag = "true";
					}
					if(tag == "true"){
						if(rtnSeqArray[x].match(/>/)){
							tag = "false";
						}
					}else{
						if(rtnSeqArray[x].match(/[ATGCNWSMKRYBDHVatgcnwsmkrybdhv]/)){
							strCount++;
							pointer=0;
							if(rtnSeqArray[x+1]=="<" && rtnSeqArray[x+2]=="/"){pointer=7;}//</font> +7
							if(strCount == primerPosArray[0]){
								rtnSeqArray[x+pointer]=rtnSeqArray[x+pointer]+"<font color='#ff6699'>";
							}else if(strCount == parseInt(primerPosArray[0])+parseInt(primerPosArray[1])){
								rtnSeqArray[x+pointer]=rtnSeqArray[x+pointer]+"</font>";
							}
							else if(strCount == parseInt(primerPosArray[2])-parseInt(primerPosArray[3])+1){
								rtnSeqArray[x+pointer]=rtnSeqArray[x+pointer]+"<font color='#0099ff'>";
							}
							else if(strCount == parseInt(primerPosArray[2])+1){
								rtnSeqArray[x+pointer]=rtnSeqArray[x+pointer]+"</font>";
							}
						}else{
							console.log("Unexpected char");
						}
					}	
				}
				resSeq.innerHTML=rtnSeqArray.join("");
			}else if(array[3]=="false"){
				resSeq.innerHTML="";
			}else{
				//pass
			}
		}
	});
}

///////////////////////////////////////////////////////////
//File download
///////////////////////////////////////////////////////////
function _download(content,name){
	dlTarget=new Blob([content],{type:"text/plain"});
	if (window.navigator.msSaveBlob) {
		// IE, Edge
		window.navigator.msSaveOrOpenBlob(dlTarget, name); 
	} else {
		var a = document.createElement("a");
		a.download = name;
		a.href = window.URL.createObjectURL(dlTarget);
		e = document.createEvent('MouseEvent');
		e.initEvent("click",true,true);
		a.dispatchEvent(e);
	}
}

function _indirDownload(data,name){
	_download(data,name);
}

function _dlFasta() {
	var content = $("#fasta").val();
	var name = $("#fname").val();	
	dlTarget=new Blob([content],{type:"text/plain"});
        var a = document.createElement("a");
        a.download = name;
        a.href = window.URL.createObjectURL(dlTarget);
        e = document.createEvent('MouseEvent');
        e.initEvent("click",true,true);
        a.dispatchEvent(e);
}

function _dlNewick() {
        var content = $("#newick").val();
        var name = $("#nname").val();
        dlTarget=new Blob([content],{type:"text/plain"});
        var a = document.createElement("a");
        a.download = name;
        a.href = window.URL.createObjectURL(dlTarget);
        e = document.createEvent('MouseEvent');
        e.initEvent("click",true,true);
        a.dispatchEvent(e);
}
///////////////////////////////////////////////////////////
//Double click for zoom in
///////////////////////////////////////////////////////////
function _execDblClick(x) {
	if(_cvtZoom(Objects.Zoom)>1){
		var t=parseInt(x/Objects.BlockW);
		if (t==0) t=1;
		var b=(parseInt(Objects.Pos)+t)*_cvtZoom(Objects.Zoom);
		var p=_checkPos(parseInt(b/_cvtZoom(_cvtZoomDown(Objects.Zoom)))-(Objects.Block/2)+1,_cvtZoomDown(Objects.Zoom));
		storage.setItem("_Pos", new String(p));
		storage.setItem("_Zoom", _cvtZoomDown(Objects.Zoom));
		_showLoading();
		_drawMessageOnScreen("zoomInPos",x);
		_messageOnScreen("Zoom in "+Objects.Zoom+" to "+_cvtZoomDown(Objects.Zoom)+" per block");
		FROMSCROLL=false;
		_execCanvas();
	} else {
		_messageOnScreen("Minimum zoom scale");
	}
	// Unlink cell information
	if($("#dialog_infocell").hasClass("ui-dialog-content")){
		$("#dialog_infocell").dialog("close");
	}
}

///////////////////////////////////////////// Get chromosome
function _getChr(id) {
	var a=new Object();
	var o=new Object(JSON.parse(storage.getItem("_Chrs")));
	if (_isEmpty(id)) {
		a.id=o[0].id;
		a.size=o[0].size;
		a.centromere=o[0].centromere;
	} else if (id == "max") {
		a.size=0;
		for(i=0;i<o.length;i++){
			if(parseInt(o[i].size)>parseInt(a.size)){
				a.size=o[i].size;
			}
		}
	} else {
		for(i=0;i<o.length;i++){
			if(o[i].id==id){
				a.id=o[i].id;
				a.size=o[i].size;
				a.centromere=o[i].centromere;
				break;
			}
		}
	}
	return a;
}
///////////////////////////////////////////// Get list of accession by mode
function _getList(str) {
	var a=new Array();
	var o = _getAccListObjArray("_Lists");
//	var o=new Object(JSON.parse(storage.getItem("_Lists")));
	for(var i=0;i<o.length;i++){
		if(str=="id"){
			a[i]=o[i].id;
		}else if(str=="db"){
			a[i]=o[i].db;
		}else if(str=="name"){
			a[i]=o[i].name;
		}else if(str=="grp"){
			a[i]=o[i].grp;
		}else if(str=="variety"){
			a[i]=o[i].variety;
		}else if(str=="origin"){
			a[i]=o[i].origin;
		}else if(str=="origin_2"){
			a[i]=o[i].origin_2;
		}else if(str=="type"){
			a[i]=o[i].type;
                }else if(str=="other_1"){
                        a[i]=o[i].other_1;
                }else if(str=="other_2"){
                        a[i]=o[i].other_2;
                }
		/*
		else if(str=="pheno"){
                        a[i]=o[i].pheno;
                }
		*/
		else {
			a[i] = "";
		}
	}
	return a;
}

///////////////////////////////////////////// Get list of tracks
function _getTrack(str) {
	var s=0;
	var a=new Array();
	var o=new Object(JSON.parse(storage.getItem("_Tracks")));
	if (str=="list") {
		for(var i=0;i<o.length;i++){
			a[i]=o[i].track;
		}
		return a;
	}
	if ( str=="view" ) {
		for(var i=0;i<o.length;i++){
			if (o[i].p==1){
				a.push(o[i].track);
			}
		}
		return a;
	}
}

///////////////////////////// Set accession data to localStorage
function _setData(str) {
	var n=str.split(";");
	for (var i=0, nLen=n.length; i<nLen; i++) {
		if(!n[i]) continue;	//TODO Sometimes n[0] is blank. The condition is unknown.

		var a=n[i].split("|");
		_setVariantDepthMap(a[0], JSON.parse(a[1]));
	}
}

///////////////////////////// Hide loading 
function _hideLoading() {
	document.body.style.cursor = "default";
	_initEvents();
}

///////////////////////////// Show loading 
function _showLoading(opt) {
	document.body.style.cursor = "wait";
	_removeEvents(opt);
}

///////////////////////////// Moving head or tail
function _moveEdge(pos) {
	if ( pos == "s" ) {
		storage.setItem("_Pos", "1");
		msg="head";
	} else { 
		storage.setItem("_Pos",new String(_last(Objects.Zoom)-Objects.Block+1));
		msg="last";
	} 
	_showLoading();
	_messageOnScreen("Moving "+msg+" of "+Objects.Chr);
	FROMSCROLL=false;
	_execCanvas();
}

///////////////////////////// Moving page
function _movePage(str) {
	var p=Objects.Pos;
	var b=Objects.Block;
	var msg;
	if (str == "+") {
		var c=0;
		if ((p+b+b-1)>_last(Objects.Zoom)) {
			storage.setItem("_Pos",new String(_last(Objects.Zoom)-b+1));
		} else {
			storage.setItem("_Pos", new String(p+b));
		}
		msg="right";
	} else {
		if (p-b<1) {
			storage.setItem("_Pos", new String(1));
		} else {
			storage.setItem("_Pos", new String(p-b));
		}
		msg="left";
	}
	//_setHistory("position,"+Objects.Chr+","+p+","+Objects.Zoom);
	_drawMessageOnScreen(msg);
	_showLoading();
	FROMSCROLL=false;
	_execCanvas();
}

///////////////////////////// Initialize canvas with size
function _initCanvas() {
	_syncContentWidth();

	cvs0.width=Objects.titleWidth + getSystemTreeWidth();
	cvs0.height=Objects.TrackH;
	ctx0.fillRect(0,0,cvs0.width, cvs0.height);
	ctx0.setTransform(1, 0, 0, 1, 0, 0);
	ctx0.font="11px 'Courier'";

	cvs1.width=Objects.canvasWidth;
	cvs1.height=Objects.TrackH;
	ctx1.fillRect(0,0,cvs1.width, cvs1.height);
	ctx1.setTransform(1, 0, 0, 1, 0, 0);
	ctx1.font="11px 'Courier'";

	cvs2.width=Objects.canvasWidth;
	cvs2.height=Objects.NavH+5;
	ctx2.fillRect(0,0,cvs2.width, cvs2.height);
	ctx2.setTransform(1, 0, 0, 1, 0, 0);
	ctx2.font="11px 'Century'";

	cvs3.width=Objects.titleWidth + 12;
	cvs3.height=Objects.canvasHeight;
	ctx3.fillStyle="#dcdcdc";
	ctx3.fillRect(0,0,cvs3.width,cvs3.height);
	ctx3.setTransform(1, 0, 0, 1, 0, 0);
	ctx3.font="11px 'Courier'";

	cvs4.width=Objects.canvasWidth;
	cvs4.height=Objects.canvasHeight;
	ctx4.fillStyle="#ffffff";
	ctx4.fillRect(0,0,cvs4.width,cvs4.height);
	ctx4.setTransform(1, 0, 0, 1, 0, 0);
	ctx4.font="10px 'Courier'";

	cvs5.width=Objects.titleWidth + getSystemTreeWidth();
	cvs5.height=20;
	//ctx5.fillStyle=_setColor().bgcolor;
	ctx5.fillStyle="#dcdcdc";
	ctx5.fillRect(0,0,cvs5.width,cvs5.height);
	ctx5.setTransform(1, 0, 0, 1, 0, 0);
	ctx5.font="12px 'Courier'";

	cvs6.width=Objects.canvasWidth;
	cvs6.height=20;
	ctx6.fillStyle=_setColor().bgcolor;
	ctx6.fillRect(0,0,cvs6.width,cvs6.height);
	ctx6.setTransform(1, 0, 0, 1, 0, 0);
	ctx6.font="11px 'Courier'";
	
	if(phenotypeFlg){
		cvs12.width=Objects.canvasWidth;
		//cvs12.width="1000";
		//cvs12.height="120";
		cvs12.height="80";
		ctx12.fillStyle="#ffffff";
		ctx12.fillRect(0,0,cvs12.width,cvs12.height);
		ctx12.setTransform(1, 0, 0, 1, 0, 0);
		ctx12.font="10px 'Courier'";
	
		//cvs13.width=Objects.titleWidth +11;
		cvs13.width=Objects.titleWidth + 3  + getSystemTreeWidth();
		//cvs13.height="120";
		cvs13.height="80";
		ctx13.fillRect(0,0,cvs13.width,cvs13.height);
		ctx13.setTransform(1, 0, 0, 1, 0, 0);
		ctx13.font="11px 'Courier'";
		cvs19.width=Objects.titleWidth +11;
                cvs19.height="80";
                ctx19.fillRect(0,0,cvs13.width,cvs13.height);
                ctx19.setTransform(1, 0, 0, 1, 0, 0);
                ctx19.font="11px 'Courier'";

	}

	document.getElementById('cvs_tree').width = getSystemTreeWidth();
	if(storage.getItem("_SYSTREE") === "on") {
		document.getElementById('cvs_tree').style.display="block";
		document.getElementById('div_tree_header').style.display="block";
		document.getElementById('div_tree_footer').style.display="block";
//		document.getElementById('div_tree_footer').style.backgroundColor = "#e8e8e8";
	} else {
		document.getElementById('cvs_tree').style.display="none";
		document.getElementById('div_tree_header').style.display="none";
		if(isTreeAvailable()) {
			document.getElementById('div_tree_footer').style.display="block";	// Display unhide icon
		} else {
			document.getElementById('div_tree_footer').style.display="none";
		}
	}

	cvs14.width=1;
        cvs14.height=1;
        cvs15.width=1;
        cvs15.height=1;

        cvs16.width=cvs4.width;
        cvs16.height=cvs4.height;
        ctx16.fillStyle="#fff";
        ctx16.fillRect(0,0,cvs16.width,cvs16.height);

        cvs17.width=Objects.titleWidth+2;
        cvs17.height=20;
        //ctx5.fillStyle=_setColor().bgcolor;
        ctx17.fillStyle="#dcdcdc";
        ctx17.fillRect(0,0,cvs17.width,cvs17.height);
        ctx17.setTransform(1, 0, 0, 1, 0, 0);
        ctx17.font="12px 'Courier'";

        cvs18.width=Objects.canvasWidth;
        cvs18.height=20;
        ctx18.fillStyle=_setColor().bgcolor;
        ctx18.fillRect(0,0,cvs18.width,cvs18.height);
        ctx18.setTransform(1, 0, 0, 1, 0, 0);
        ctx18.font="11px 'Courier'";


	if(Objects.canvasHeight < 130){
		var elementind = document.getElementById("ind"); 
		var indmode=storage.getItem("_Mode");
		if(indmode == "s" || indmode == "i" || indmode == "dp"){
			elementind.style.marginTop = ((-150)+(75-Objects.canvasHeight))+"px"; 
		}else if(indmode == "dp+s" || indmode == "dp+i" || indmode == "si"){
			elementind.style.marginTop = ((-150)+(113-Objects.canvasHeight))+"px"; 
		}else if(indmode == "dp+a"){
			elementind.style.marginTop = ((-150)+(130-Objects.canvasHeight))+"px"; 
		}
	}
	cvs7.width=150;
	cvs7.height=135;
	ctx7.fillStyle='rgba(0,0,0,0)';
	ctx7.fillRect(0,0,cvs7.width,cvs7.height);
	ctx7.fillStyle='rgba(255,255,255,0.6)';
	ctx7.fillRect(4,cvs7.height-28,cvs7.width-8,23);
	ctx7.strokeStyle="#acacb3";
	ctx7.lineWidth=1;
	ctx7.strokeRect(4,cvs7.height-28,cvs7.width-8,23);
	ctx7.setTransform(1, 0, 0, 1, 0, 0);
	ctx7.font="10px 'Courier'";

	cvs8.width=Objects.canvasWidth;
	cvs8.height=1;
	ctx8.fillStyle='rgba(0,0,0,0)';
	ctx8.fillRect(0,0,cvs8.width,1);
	ctx8.setTransform(1, 0, 0, 1, 0, 0);
	ctx8.font="10px 'Courier'";

//	pre-drawing:required
	
	cvs9.width=Objects.canvasWidth;
	cvs9.height=75;
	//ctx9.fillStyle=_setColor().bgcolor;
	ctx9.fillStyle="#302833";
	ctx9.fillRect(0,0,cvs9.width,cvs9.height);
	ctx9.strokeStyle="#302833";
	ctx9.lineWidth=30;
	ctx9.beginPath();
	ctx9.moveTo(3,49);
	ctx9.lineTo(591,49);
	ctx9.stroke();
	ctx9.closePath();
	ctx9.lineWidth=23;
	ctx9.beginPath();
	ctx9.lineCap = "round";
	ctx9.moveTo(14,55);
	ctx9.lineTo(580,55);
	ctx9.stroke();
	ctx9.closePath();
	ctx9.beginPath();
	ctx9.lineCap = "round";
	ctx9.moveTo(14,45);
	ctx9.lineTo(580,45);
	ctx9.stroke();
	ctx9.closePath();
	ctx9.shadowOffsetX = 0;
	ctx9.shadowOffsetY = 0;
	ctx9.shadowBlur = 0;
/*
	ctx9.strokeStyle="#999999";
	ctx9.lineWidth=3;
	ctx9.beginPath();
	ctx9.arc(384, 19, 9, 0, Math.PI*2, false);
	ctx9.stroke();
	ctx9.beginPath();
	ctx9.arc(419, 19, 9, 0, Math.PI*2, false)
	ctx9.stroke();
	ctx9.lineWidth=4;
	ctx9.beginPath();
	ctx9.moveTo(392,26);
	ctx9.lineTo(405,37);
	ctx9.closePath();
	ctx9.stroke();
	ctx9.beginPath();
	ctx9.moveTo(425,26);
	ctx9.lineTo(438,37);
	ctx9.closePath();
*/
	
	ctx9.stroke();
	ctx9.fillStyle=_setColor().zoombar;
	ctx9.fillRect(384,13,6,18);
	ctx9.fillRect(378,19,18,6);
	ctx9.fillRect(413,19,18,6);
	ctx9.setTransform(1, 0, 0, 1, 0, 0);
	ctx9.font="10px 'Courier'";
	frameZoomb=ctx9.getImageData(0, 0, cvs9.width, cvs9.height);
	var elementcell = document.getElementById("cellinf"); 
	elementcell.style.top = '1px'; 
	elementcell.style.left = '1px';

	cvs10.width=1;
	cvs10.height=1;
	ctx10.fillStyle='rgba(0,0,0,0)';
	ctx10.fillRect(0,0,cvs10.width,cvs10.height);
	ctx10.setTransform(1, 0, 0, 1, 0, 0);
	ctx10.font="10px 'Courier'";

	cvs11.width=Objects.titleWidth;
	cvs11.height=parseInt(Objects.NavH/3);
	//ctx11.fillStyle=_setColor().bgcolor;
	ctx11.fillStyle="#dcdcdc";
	ctx11.fillRect(0,0,cvs11.width, cvs11.height);
	ctx11.setTransform(1, 0, 0, 1, 0, 0);
	ctx11.font="16px 'Courier'";

	// Set to main canvas height
	resizeContentHeight(Objects.canvasHeight);
/*
	var offset = 20;
	var divHeight = getContentHeight(offset);
	if ( Objects.canvasHeight < divHeight ) {
		divHeight = Objects.canvasHeight + offset;
	}
	$('#content').css("height", divHeight);
*/
	// Changing height during resize
	$(window).bind("resize", resizeWindow);
	function resizeWindow( e ) {
		resizeContentHeight(Objects.canvasHeight);
/*
		divHeight = getContentHeight(offset);
		if ( Objects.canvasHeight < divHeight ) {
			divHeight=Objects.canvasHeight + offset
		} 
		$('#content').css("height", divHeight);
*/

		// Erase TreeHeader and TreeFooter when #content is very small
		positioningTreeHeader();
		positioningTreeFooter();
	}
}
function resizeContentHeight(heightByAccs, offset) {
	var trackH = heightByAccs + 24;
	var viewportH = getContentHeight(0);
	if (viewportH > trackH) {
		viewportH = trackH;
	} else {
		// "-3" offset is a solution to the problem that some browser measure the page height as larger than it actually is,
		// causing scroll bars to appear.
		viewportH = viewportH - 3;
	}
	$('#content').css("height", viewportH);
/*
	if(offset == null) offset = 20;
	var height = getContentHeight(offset);	// height by page rayout
	if ( height > heightByAccs ) {
		height = heightByAccs + offset
	}
	$('#content').css("height", height);
*/
}

///////////////////////////// Print area
function _printArea(area) {
	t=area*_cvtZoom(Objects.Zoom);
	if (t<1000) {
		return String(t)+" bp";
	} else if (t>=1000 && t<1000000) {
		return String(t/1000)+" kbp";
	} else if (t>=1000000) {
		return String(t/1000000)+" mbp";
	}
}

///////////////////////////// Print pos by zoom
function _printPos(pos) {
	z=_cvtZoom(Objects.Zoom);
	t=parseInt(pos*z);
	if (z<1000) {
		return String(t)+" b";
	} else if (z>=1000 && z<1000000) {
		return String((t/1000))+" k";
	} else if (z>=1000000) {
		return String((t/1000000))+" m";
	}
}

///////////////////////////// Drawing Snpblock: Estimation of SNP "blocks"
function _getSnpblock(str) {
	var o=new Object(JSON.parse(storage.getItem('_Snpblock')));
	for (var x=0, oLen=o.length; x<oLen; x++) {
		var pattern=new RegExp(str);
		if(o[x].id.match(pattern)) {
			return o[x].rate;
		}
	}
}

/////////////////////////////////////////////// Stop drag when mouse up
function _getData_p(d) {
	var s;
	var t=0;
	var p=0
	var b=Math.abs(parseInt(d/Objects.BlockW));
	var setP;
	if (d>0){
		s="right";
		t=Objects.BlockW-d%Objects.BlockW;
		n=d+t;
		b=parseInt(n/Objects.BlockW);
		if(Objects.Pos-b<1){
			n=0;
			b=Objects.Pos-1;
			p=1;
		} else {
			p=Objects.Pos-b;
		}
		setP=p;
	} else {
		s="left";
		t=Objects.BlockW+d%Objects.BlockW;
		n=d-t;
		b=Math.abs(n/Objects.BlockW);
		max=_last(Objects.Zoom);
		p=Objects.Pos+Objects.Block;
		if(p+b-1>max){
			p=max-(max-p);
			n=-((max-p+1)*Objects.BlockW);
			b=(max-p+1);
		}
		setP=p-Objects.Block+b;
	}
	// Set canvas by block width
	ctx2.clearRect(0, 30, cvs2.width, 30);
	ctx4.clearRect(0, 0, Objects.canvasWidth, Objects.canvasHeight);
//	ctx4.putImageData(frameCellwoI['data'], n, frameCellwoI['y']);
	ctx4.putImageData(frameCellwoI, n, 0);
	if(phenotypeFlg){
		ctx12.clearRect(0, 0, Objects.canvasWidth, Objects.canvasHeight);
		ctx12.putImageData(framePlot1, n, 0);
		_drawRulesforPlot();
	}
	ctx1.clearRect(0, 0, cvs1.width, cvs1.height);
	ctx1.putImageData(frameTrack, n, 0);
	ctx0.clearRect(0, 0, cvs0.width, cvs0.height);
	ctx0.putImageData(frameTrackTitle, 0, 0);
	ctx6.putImageData(frameSNP, n, 0);
	_drawMeter(setP,null);
	_drawRules();
	if (Objects.Indicator=="on") {
		_drawIndicator();
		_drawDirection();
	}
	// If occured gap
	if (b>0) {
		_showLoading();
		storage.setItem("_Pos", setP);  // need load, first position
		//_setHistory("position,"+Objects.Chr+","+setP+","+Objects.Zoom);
		FROMSCROLL=false;
		_execCanvas(p,b,s);   // Load part of datas
	}
}

///////////////////////////// Stringfy of array data
function _mergeObject(o){
	var str;
	str="{\"dp\":\"";
	if(o.dp == null){
		str=str+"";
	} else {
		str=str+o.dp;
	}
	str=str+"\"";
	if(o.rdp != undefined){
		str=str+",\"rdp\":\"";
		if(o.rdp == null){
			str=str+"";
		} else {
			str=str+o.rdp;
		}
		str=str+"\"";
	}
	if(o.s != undefined){
		str=str+",\"s\":\""+o.s+"\"";
	}
	if(o.i != undefined){
		str=str+",\"i\":\""+o.i+"\"";
	}
	if(o.d != undefined){
		str=str+",\"d\":\""+o.d+"\"";
	}
	if(o.hs != undefined){
		str=str+",\"hs\":\""+o.hs+"\"";
	}
	if(o.hi != undefined){
		str=str+",\"hi\":\""+o.hi+"\"";
	}
	if(o.hd != undefined){
		str=str+",\"hd\":\""+o.hd+"\"";
	}
	str=str+"}";
	return str; 
}

///////////////////////////// Set part of data
function _setData_p(datas,s,b) {
	var n=datas.split(";");
	for (var i=0,len=n.length; i<len; i++) {
		var a=n[i].split("|");
		var o = _getVariantDepthMap(a[0]);
		if(!a[1]) continue;
		var j=new Object(JSON.parse(a[1]));
		var tArray = [];
		if(s=="left"){
			for(var k=0, oLen=o.length-b; k<oLen; k++) {
				tArray.push(_mergeObject(o[k+b]));
			}
			for(var k=0; k<b; k++) {
				tArray.push(_mergeObject(j[k]));
			}
		} else {
			for(var k=0; k<b; k++) {
				tArray.push(_mergeObject(j[k]));
			}
			for(var k=0, oLen=o.length-b; k<oLen; k++) {
				tArray.push(_mergeObject(o[k]));
			}
		}
		var t = "[" + tArray.join(",") + "]";
		_setVariantDepthMap(a[0], JSON.parse(t));
	}
}

Array.prototype.remove = function(from, to) {
	var rest = this.slice((to || from) + 1 || this.length);
	this.length = from < 0 ? this.length + from : from;
	return this.push.apply(this, rest);
};

/////////////////////////////////////////////// Change display mode
function _changeMode(str){
	if ( Objects.Snpblock == "off" ) {
		var mode = storage.getItem("_Mode"); //get drawing mode
		if (str == "s") {
			if (storage.getItem("_sFlg") == "1") { // if already selected
        			if(mode.match(/dp/)) { //if with depth
					if(mode.match(/a/)) { //if with snp and indel
						mode = mode.replace('a','is'); // a to is
                                		mode = mode.replace('s',''); //remove s -> dp+i
                        		} else {
                                		mode = mode.replace('+s',''); //remove s -> dp
                        		} 
				} else { //if not depth
					mode = mode.replace('s','');
				}
				storage.setItem("_sFlg","0"); //set off-snpFlg
			} else if (storage.getItem("_sFlg") == "0") { //if not selected
        			if(mode.match(/dp/)) { //if with depth
					if(mode.match(/i/)) { //if with indel
						mode = mode.replace(/i/,''); //dp +
						mode = mode+'a'; // dp+a(indel+snp)
					} else {
						mode = mode+'+s'; //with snp(dp+s)
					}
				} else {
					mode = 's'+mode; // a to si
				}
				storage.setItem("_sFlg","1"); //set off-snpFlg
			}
			storage.setItem("_Mode", mode);
		}
		else if (str == "i") {
                        if (storage.getItem("_iFlg") == "1") { // if already selected
                                if(mode.match(/dp/)) { //if with depth
                                        if(mode.match(/a/)) { //if with snp and indel
                                                mode = mode.replace('a','is'); // a to is
                                                mode = mode.replace('i',''); //remove s -> dp+i
                                        } else {
                                                mode = mode.replace('+i',''); //remove s -> dp
                                        }
                                } else { //if not depth
                                        mode = mode.replace('i','');
                                }
                                storage.setItem("_iFlg","0"); //set off-snpFlg
                        } else if (storage.getItem("_iFlg") == "0") { //if not selected
                                if(mode.match(/dp/)) { //if with depth
                                        if(mode.match(/s/)) { //if with indel
                                                mode = mode.replace(/s/,''); //dp +
                                                mode = mode+'a'; // dp+a(indel+snp)
                                        } else {
                                                mode = mode+'+i'; //with snp(dp+s)
                                        }
                                } else {
                                        mode = mode+'i'; // a to si
                                }
                                storage.setItem("_iFlg","1"); //set off-snpFlg
                        }
                        storage.setItem("_Mode", mode);
		}
		else if (str == "dp") {
                        if (storage.getItem("_dpFlg") == "1") { // if already selected
                                mode = mode.replace('dp',''); // remove dp+
                                mode = mode.replace('+',''); // remove dp+
                        	if(mode == "a") { // with snp and indel
                                        mode = mode.replace('a','si'); // a -> si
                                }
                                storage.setItem("_dpFlg","0"); //set off-snpFlg
                        } else if (storage.getItem("_dpFlg") == "0") { //if not selected
                        	if(mode == "si") { //if with snp and indel
                                	mode = mode.replace('si','a');
                                } 
				if (mode == "") {
					mode = 'dp';
				} else {
					mode = 'dp+'+mode;
				}
                                storage.setItem("_dpFlg","1"); //set off-snpFlg
                        }
                        storage.setItem("_Mode", mode);
		}
		_drawCanvas();
	} else {
		_messageOnScreen("Mode is fixed reason why 'Snpblock' is on.");
	}
}

/////////////////////////////////////////////// Change display mode(switch)
/*
function _changeModeSW(str){
	if ( Objects.Snpblock == "off" ) {
		if (storage.getItem("_Mode") == str){
			storage.setItem("_Mode", "dp");
		} else {
			storage.setItem("_Mode", str);
		}
		_drawCanvas();
	} else {
		_messageOnScreen("Mode is fixed reason why 'Snpblock' is on.");
	}
}
*/

/////////////////////////////////////////////// Change direction of reference
function _changeDirRef(){
	if ( storage.getItem("_DirRef") == "+" ) {
		storage.setItem("_DirRef", "-");
	} else {
		storage.setItem("_DirRef", "+");
	}
}

/////////////////////////////////////////////// Change select chromosome for search ID
function _changeChromosomeSearch(kwd){
	var chr=$('#prm_chr').val();
	$('#prm_chr').blur(); // focus out from select box
	_showLoading();
	_messageOnScreen("Moving to "+kwd);
	FROMSCROLL=false;
	_execCanvas();
	// Set chromosome option on dialog 'Search'
	$('#prm_position_chr').val(chr);
}

/////////////////////////////////////////////// Change select chromosome 
function _changeChromosome(){
	var chr=$('#prm_chr').val();
	storage.setItem('_Chr', chr);
	storage.setItem('_Pos', '1');
	storage.setItem('_chrFlg', '1');
	$('#prm_chr').blur(); // focus out from select box
	_showLoading();
	_messageOnScreen("Loading "+chr);
	FROMSCROLL=false;
	_execCanvas();
	// Set chromosome option on dialog 'Search'
	$('#prm_position_chr').val(chr);
}
/*
function _changeChromosomeByDialog() {
	if(!storage.getItem("_Chrs")) return;

	var chrs = new Object(JSON.parse(storage.getItem("_Chrs")));
	var minChrSwitchToSearchForm = parseInt(JSON.parse(storage.getItem("_Env")).min_chr_switch_to_search_form);
	if(minChrSwitchToSearchForm > chrs.length) return;

	_dialog_changechr();
}
*/

/////////////////////////////////////////////// Change zoom
function _changeZoomS(zoom){
	var msg;
	var flag;
	var cZoom=_cvtZoom(Objects.Zoom);
	var tZoom=_cvtZoom(zoom);
	var scrMsg="";
	var toZoom="";
	var o = _getChr(Objects.Chr);

	// Zoom in when over 1b
	if(zoom=='+') {
		if ( _cvtZoom(Objects.Zoom) > 1 ){
			var b=(parseInt(Objects.Pos)+(Objects.Block/2))*_cvtZoom(Objects.Zoom);
			var p=_checkPos(parseInt(b/_cvtZoom(_cvtZoomDown(Objects.Zoom)))-(Objects.Block/2)-1,_cvtZoomDown(Objects.Zoom));
			storage.setItem("_Pos", new String(p));
			storage.setItem("_Zoom", _cvtZoomDown(Objects.Zoom));
			msg="zoomIn";
			flag=true;
		} else {
			msg="Minimum zoom scale";
			flag=false;
		}
	}
	// Zoom out when under 100k
	if(zoom=='-') {
		if (_cvtZoom(Objects.Zoom) < 100000 && (_cvtZoom(_cvtZoomUp(Objects.Zoom))*Objects.Block <= o.size) ){
			if(_cvtZoom(Objects.Zoom) === 1) storage.removeItem("_ListsTgt");

			var b=(parseInt(Objects.Pos)+(Objects.Block/2))*_cvtZoom(Objects.Zoom);
			var p=_checkPos(parseInt(b/_cvtZoom(_cvtZoomUp(Objects.Zoom)))-(Objects.Block/2)+1,_cvtZoomUp(Objects.Zoom));
			storage.setItem("_Pos", new String(p));
			storage.setItem("_Zoom", _cvtZoomUp(Objects.Zoom));
			flag=true;
			msg="zoomOut";
		} else {
			msg="Maximum zoom scale";
			flag=false;
		}
	}
	if(msg=="zoomIn"){
		_drawMessageOnScreen(msg);
		scrMsg="Zoom in "+Objects.Zoom+" to "+_cvtZoomDown(Objects.Zoom)+" per block";
		_messageOnScreen(scrMsg);
		toZoom=_cvtZoomDown(Objects.Zoom);
	} else if ( msg=="zoomOut") {
		scrMsg="Zoom out "+Objects.Zoom+" to "+_cvtZoomUp(Objects.Zoom)+" per block";
		_messageOnScreen(scrMsg);
		toZoom=_cvtZoomUp(Objects.Zoom);
	} else {
		_messageOnScreen(msg);
	}
	if(flag){
		drCnt=0;
		timerArray.push(setInterval(function(){_trfMain(scrMsg,Objects.Zoom,toZoom);},50));
		_showLoading();
		FROMSCROLL=false;
		_execCanvas();
	}
}

////////////////////////////////////////animation
function _trfMain(m,czoom,zoom){
	var scale=_cvtZoom(zoom)/_cvtZoom(czoom);
	if(scale <= 1){
		scale=Math.pow(1-(1-scale), 1/10);
		ctx4.putImageData(frameCell, 0, 0);
		ctx4.drawImage(cvs4,parseInt((Objects.canvasWidth-(Objects.canvasWidth*scale))/2) ,0 ,parseInt(Objects.canvasWidth*scale) ,Objects.canvasHeight ,0,0 ,Objects.canvasWidth ,Objects.canvasHeight );
		frameCell=ctx4.getImageData(0, 0, cvs4.width, cvs4.height);
		_messageOnScreen(m);
		drCnt++;
		if( drCnt > 9 ){
			for(var x=0; x<timerArray.length; x++){
				clearInterval(timerArray.shift());
			}
		}
	}else{
		scale=Math.pow(scale, 1/10);  
		ctx4.putImageData(frameCell, 0, 0);
		ctx4.drawImage(cvs4,0 ,0 ,Objects.canvasWidth ,Objects.canvasHeight ,parseInt((Objects.canvasWidth/2)-Objects.canvasWidth/2/scale),0 ,parseInt(Objects.canvasWidth/scale) ,Objects.canvasHeight );
		frameCell=ctx4.getImageData(0, 0, Objects.canvasWidth , cvs4.height);
		ctx4.fillStyle="#ffffff";
		ctx4.fillRect(0, 0, parseInt((Objects.canvasWidth/2)-Objects.canvasWidth/2/(scale*Math.pow(scale, drCnt+1))), Objects.canvasHeight);
		ctx4.fillRect(parseInt((Objects.canvasWidth/2)+Objects.canvasWidth/2/(scale*Math.pow(scale, drCnt+1))), 0, parseInt((Objects.canvasWidth/2)-Objects.canvasWidth/2/(scale*Math.pow(scale, drCnt+1))), Objects.canvasHeight);
		_messageOnScreen(m);
		drCnt++;
		if( drCnt > 9){
			for(var x=0; x<timerArray.length; x++){
				clearInterval(timerArray.shift());
			}
		}
	}
}

/////////////////////////////////////////////// Change zoom
function _changeZoom(zoom){
	var msg;
	var flag;
	var cZoom=_cvtZoom(Objects.Zoom);
	var tZoom=_cvtZoom(zoom);
	var scrMsg="";
	var o = _getChr(Objects.Chr);

	if(zoom != Objects.Zoom){
		if(tZoom*Objects.Block > o.size){
			console.log("!");
			msg="This window size will be larger than ["+o.id+"].";
			flag = false;
		}else{
			if(_cvtZoom(Objects.Zoom) === 1) storage.removeItem("_ListsTgt");

			var b=(parseInt(Objects.Pos)+(Objects.Block/2))*_cvtZoom(Objects.Zoom);
			var p=_checkPos(parseInt(b/_cvtZoom(zoom))-(Objects.Block/2)+1,zoom);
			storage.setItem('_Pos', new String(p));
			storage.setItem('_Zoom', zoom);
			if ( cZoom > tZoom ) { msg="zoomInC" }
			else { msg="zoomOut"; }
			flag=true;
		}
	} else {
		msg="Currently zoom scale is "+Objects.Zoom+" per block";
		flag=false;
	}
	if(msg=="zoomInC"){
		_drawMessageOnScreen(msg,tZoom,cZoom);
		scrMsg="Zoom in "+Objects.Zoom+" to "+zoom+" per block";
		_messageOnScreen(scrMsg);
	} else if ( msg=="zoomOut" ) {
		scrMsg="Zoom in "+Objects.Zoom+" to "+zoom+" per block";
		_messageOnScreen(scrMsg);
	} else {
		_messageOnScreen(msg);
	}
	if(flag){
		drCnt=0;
		timerArray.push(setInterval(function(){_trfMain(scrMsg,Objects.Zoom,zoom);},50));
		_showLoading();
		FROMSCROLL=false;
		_execCanvas();
	}
	// Set zoom option on dialog 'Search'
	$('#prm_position_zoom').val(zoom);
}

/////////////////////////////////////////////// Details accession
function _changeRef(){
	var i=document.getElementById("prm_chref").value;
	var o = _getAccListObjArray('_Lists');
//	var o=new Object(JSON.parse(storage.getItem('_Lists')));
	if(Objects.Onebase!="off"){
		_dlg_chref_cancel();
		return;
	}

	if ( storage.getItem("_Ref") != o[i].db ) {
		_changeEff('off');
		_changeOnebase('off');
		storage.setItem("_Ref", o[i].db);
		msg="Changing reference "+o[i].id;
	} else {
		storage.setItem("_Ref", "Reference");
		msg="Reset reference";
	}
	// Estimation of SNP 'blocks' in changing reference
	if (storage.getItem("_Snpblock") != "off") {
		_execSnpblock(storage.getItem("_Ref"));
	}
//	_changeNull();
//	_changeNull();//require
	_showLoading();
	_messageOnScreen(msg);
	FROMSCROLL=false;
	_execCanvas();
	_dlg_chref_cancel();
}

/////////////////////////////////////////////// Message on screen
function _messageOnScreen(str){
	ctx4.textAlign="left";
	ctx4.fillStyle="#ffffff";
	if(cvs4.height < 37){
		ctx4.fillRect(((cvs4.width-350)/2),1,350,11);
		ctx4.strokeStyle="#b0c4de";
		ctx4.lineWidth=2;
		ctx4.strokeRect(((cvs4.width-350)/2),1,350,11);
		ctx4.font="Bold 8px 'Century'";
		ctx4.fillStyle="#000000";
		ctx4.fillText(str,((cvs4.width-350)/2)+20,1+9);
	}else if(cvs4.height < 74){
		ctx4.fillRect(((cvs4.width-350)/2),cvs4.height/6,350,35);
		ctx4.strokeStyle="#b0c4de";
		ctx4.lineWidth=5;
		ctx4.strokeRect(((cvs4.width-350)/2),cvs4.height/6,350,35);
		ctx4.font="Bold 13px 'Century'";
		ctx4.fillStyle="#000000";
		ctx4.fillText(str,((cvs4.width-350)/2)+20,cvs4.height/6+20);
	}else{
		var errstrs = str.split("<br>");
		cvs14.width = 640;
		cvs14.height=20 + 25*errstrs.length;
		ctx14.fillStyle = "#ffffff";
		ctx14.fillRect(0,0,cvs14.width,cvs14.height);
		ctx14.strokeStyle="#b0c4de";
		ctx14.lineWidth=7;
		ctx14.strokeRect(0,0,cvs14.width,cvs14.height);
                ctx14.font="Bold 20px 'Arial'";
		if (errstrs.length > 1) {
                	ctx14.fillStyle="red";
		} else {
			if (str.match(/Invalid/)) {
				ctx14.fillStyle="red";
			} else {
                		ctx14.fillStyle="black";
			}
		}
                ctx14.textAlign="center";
		
		for (var i=0;i<errstrs.length;i++) {
			var errstr = errstrs[i];
			if (errstrs.length == 1) {
				ctx14.fillText(errstr,cvs14.width*0.5,cvs14.height*0.6-22*i);
			} else if (errstrs.length == 2) {
				
				ctx14.fillText(errstr,cvs14.width*0.5,cvs14.height*0.8-6-22*i);
			} else if (errstrs.length == 3) {
				ctx14.fillText(errstr,cvs14.width*0.5,cvs14.height*0.8-22*i);
			}
		}
                cvs15.width = 20;
                cvs15.height=20;
		ctx15.fillStyle = "gray";
		ctx15.fillRect(cvs14.width-23,3,cvs15.width,cvs15.height);
		ctx15.fillStyle="white";
		ctx15.font="Bold 20px 'Arial'";
		ctx15.fillText("x",cvs14.width-13,18)
	}
}

/////////////////////////////////////////////// view each variants
function _changeOnebase(base){
	var en=new Object(JSON.parse(storage.getItem("_Env")));
	var zm = _cvtZoom(en.nuc_max);
	if(!zm){zm=4000;}
	if ( storage.getItem("_Ref") == "Reference") {
		if (storage.getItem('_Onebase')=="on" || base == "off"){
			storage.setItem('_Onebase', "off");
		}else{
			if (_cvtZoom(Objects.Zoom) > zm){
				storage.setItem("_Onebase", "off");
			}else{
				storage.setItem('_Onebase', "on");
			}
		}
		if ( storage.getItem("_Snpblock") != "off" && storage.getItem('_Onebase') == "on" ) {
			storage.setItem('_Onebase', "off");
		}
		_drawCanvas();
	} else {
		var accDb2ObjMap = _getAccDb2ObjMap();
		var accId = accDb2ObjMap[storage.getItem("_Ref")].id;
		alert("The reference sequence has been changed to " + accId + ". Reset this to change Block mode.");
	}
//	_drawCanvas();
}

/////////////////////////////////////////////// WGS or Custom track
function _changeDepth(ctrl){
	var en=new Object(JSON.parse(storage.getItem("_Env")));
	if(en.cstm_track == "enabled"){
		if (storage.getItem("_CSTM") == "on" || ctrl == "off"){
			storage.setItem('_CSTM', "off");
		}else{
			storage.setItem('_CSTM', "on");
		}
		_drawCanvas();
	}
}

/////////////////////////////////////////////// Change variant Effect
/*
var forceSnpEffColor = false;
function setForceSnpEffColor(flg) {
	forceSnpEffColor = flg;
}
function getNonBlockColorMode() {
	if(forceSnpEffColor) return 'eff';

	if (Objects.Eff==="on" && Objects.ColorMode==="") {
		return 'eff';
	} else if(Objects.ColorMode==="gt") {
		return 'gt';
	} else {
		return '';	// Default
	}
}
*/
function _changeEff(eff){
	if ( storage.getItem("_Ref") == "Reference") {
		if (storage.getItem('_Eff')=="on" || eff == "off") {
			storage.setItem('_Eff', "off");
//			setForceSnpEffColor(false);			
		} else {
			storage.setItem('_Eff', "on");
//			setForceSnpEffColor(true);
		}
		if ( storage.getItem("_Snpblock") != "off" && storage.getItem('_Eff') == "on" ) {
			storage.setItem('_Snpblock', "off");
		}
	}
	_drawCanvas();
}
function _changeToDefault() {
	if(Objects.Eff==="on") {
		return void(0);
	} else {
		if ( storage.getItem("_Ref") == "Reference") {
			if (storage.getItem('_ColorMode') !== "") {
				storage.setItem('_ColorMode', "");
				_drawCanvas();
			}
		}
//		setForceSnpEffColor(false);
	}
}
/*
function _changeToEff() {
	if ( storage.getItem("_Ref") == "Reference") {
		if (storage.getItem('__ColorMode') !== "eff") {
			storage.setItem('__ColorMode', "eff");
			_drawCanvas();
		}
	}
}
*/
function _changeToGt() {
	if(Objects.Eff==="on") {
		return void(0);
	} else {
		if ( storage.getItem("_Ref") == "Reference") {
			if (storage.getItem('_ColorMode') !== "gt") {
				storage.setItem('_ColorMode', "gt");
				_drawCanvas();
			}
		}
//		setForceSnpEffColor(false);
	}
}

function _changeSystreeType() {
	var type = document.getElementById("prm_systree_type").value;
	if(!type || storage.getItem("_SystemTreeMode") === type) return;

	if(type === 'phylogram') {
		storage.setItem("_SystemTreeMode", type);
		document.getElementById("prm_systree_correct").disabled = false;
	} else {
		// cladogram
		storage.setItem("_SystemTreeMode", 'cladogram');
		document.getElementById("prm_systree_correct").disabled = true;
	}
	flgUpdateTree = true;
//	_drawSystemTree();

	_drawCanvas();
}
function _changeSystreeCorrect() {
	var correct = document.getElementById("prm_systree_correct").value;
	if(storage.getItem("_SystemTreeCorrect") === correct) return;
	if(!correct || correct === 'none') {
		storage.setItem("_SystemTreeCorrect", '');
	} else {
		storage.setItem("_SystemTreeCorrect", correct);
	}
	flgUpdateTree = true;
//	_drawSystemTree();

	_drawCanvas();
}
function _resetAutoCollapse() {
	var oriThreshold = Number(document.getElementById("prm_systree_collapseHeight").value);
	var type = document.getElementById("prm_systree_collapseType").value;
	var threshold = oriThreshold;
	if(type === "ratio") threshold = oriThreshold * treeobj.oriMaxHeight;
	_messageOnScreen("Reset SystemTree auto collapse by threshold=" + getFormattedNumberString(threshold, 6));
	treeobj.expandAllBranch();
//	var collapsedBranch = treeobj.autoCollapseByHeight(threshold);
	var collapsedBranch;
	if(type === "ratio") {
		collapsedBranch = treeobj.autoCollapseByRatioToMaxHeight(oriThreshold);
	} else {
		collapsedBranch = treeobj.autoCollapseByHeight(oriThreshold);
	}
	storage.setItem("_SystemTreeCollapsedBranch", JSON.stringify(collapsedBranch));
	storage.setItem("_SystemTreeAutoCollapseThreshold", oriThreshold);
	storage.setItem("_SystemTreeAutoCollapseType", type);
	flgUpdateTree = true;
	syncSystemTree2Lists();
	syncDlgMakeList();
}
function _defaultAutoCollapse() {
	var en = new Object(JSON.parse(storage.getItem("_Env")));
	var oriThreshold = Number(en['systreeAutoCollapseThreshold']);
	var type = en['systreeAutoCollapseType'];

	_messageOnScreen("Return to default SystemTree");
	treeobj.expandAllBranch();
	var collapsedBranch;
	if(type === "ratio") {
		collapsedBranch = treeobj.autoCollapseByRatioToMaxHeight(oriThreshold);
	} else {
		collapsedBranch = treeobj.autoCollapseByHeight(oriThreshold);
	}
/*
	var threshold = oriThreshold;
	if(type === "ratio") threshold = oriThreshold * treeobj.oriMaxHeight;
	_messageOnScreen("Return to default SystemTree");
	treeobj.expandAllBranch();
	var collapsedBranch = treeobj.autoCollapseByHeight(threshold);
*/
	storage.setItem("_SystemTreeCollapsedBranch", JSON.stringify(collapsedBranch));
	storage.setItem("_SystemTreeAutoCollapseType", type);
	storage.setItem("_SystemTreeAutoCollapseThreshold", oriThreshold);
	document.getElementById("prm_systree_collapseType").value = type;
	document.getElementById("prm_systree_collapseHeight").value = oriThreshold;
	_changeSysTreeThresholdInfo();
	flgUpdateTree = true;
	syncSystemTree2Lists();

	syncDlgMakeList();
}
var systreeLeafCountTimeoutId = null; 
function _changeSysTreeThresholdInfo() {
	var span = document.getElementById("span_tree_threshold");
	var type = document.getElementById("prm_systree_collapseType").value;
	var threshold = Number(document.getElementById("prm_systree_collapseHeight").value);
	if(threshold == null || !treeobj.isTreeUsing()) return;
	var ratio = threshold;
	if(type === "ratio") {
		threshold = threshold * treeobj.oriMaxHeight;
	} else {
		ratio = threshold / treeobj.oriMaxHeight;
	}
	span.innerHTML = getFormattedNumberString(threshold, 4) + ' / ' + getFormattedNumberString(treeobj.oriMaxHeight, 4) + " (" + getFormattedNumberString(ratio, 4) + "&middot;)";

	// Display Leaves count.
	var spanLeafs = document.getElementById("span_tree_leafs");
	if(isNaN(threshold)) {
		spanLeafs.innerHTML = "";
//console.log("Threshold is NaN:" + threshold);
		return;
	}
	spanLeafs.innerHTML = "Calculating...";
	if(systreeLeafCountTimeoutId !== null) {
//console.log("clearTimeout:" + systreeLeafCountTimeoutId);
		clearTimeout(systreeLeafCountTimeoutId);
	}
	systreeLeafCountTimeoutId = setTimeout(function() {
		var bgTree = new PhyloTreeCreater(null);
		try{
			if(isPhylipTreeUsing()) {
				bgTree.parseNewick(storage.getItem("_PhylipTreeNewick"));
//				bgTree.removeLeafsAndUpdate(["Reference"]);
			} else {
				var newick = storage.getItem("_SysTreeNewick");
				if(newick) bgTree.parseNewick(newick);
			}
			if(bgTree.isTreeUsing()) {
				var collapsed = bgTree.autoCollapseByHeight(threshold);
				spanLeafs.innerHTML = "Leaves: " + String(bgTree.order.length) + " / " + String(bgTree.tree.leafs.length);
			}
		} catch(error) {
			spanLeafs.innerHTML = "";
			console.log(error);
		} finally {
			bgTree.initTree();	//If not executed, a memory leak will occur intensely.
			systreeLeafCountTimeoutId = null;
		}
	}, 300);
}
function _getSystreeThresholdByLeafCount(count) {
	var treeLeafs = treeobj.tree.leafs.length;
	if(count>treeLeafs) return;
	if(count<=1) count = 2;

	var res = null;
	var bgTree = new PhyloTreeCreater(null);
	var newick = "";
	if(isPhylipTreeUsing()) {
		newick = storage.getItem("_PhylipTreeNewick");
	} else {
		newick = storage.getItem("_SysTreeNewick");
	}
	try {
		bgTree.parseNewick(newick);
		var threshold = treeobj.oriMaxHeight / 2;
		var unit = threshold / 2;
		var minUnit = treeobj.oriMaxHeight/1000;
		while(true) {
			if(unit < minUnit) {
//console.log("Break: unit:" + unit + " < " + minUnit);
				res = threshold;
				break;
			}
			bgTree.expandAllBranch();
			var collapsed = bgTree.autoCollapseByHeight(threshold);
//console.log("Test:" + threshold + "," + unit + " => " + bgTree.order.length);
			if(bgTree.order.length === count) {
				res = threshold;
				break;
			} else if(bgTree.order.length < count) {
				threshold += unit;	// next threshold
			} else {
				threshold -= unit;	// next threshold
			}
			unit = unit / 2;
		}
	} catch(error) {
		console.log(error);
	} finally {
		bgTree.initTree();	//If not executed, a memory leak will occur intensely.
	}
	return res;
}
function _expandAllSystree() {
	_messageOnScreen("Expand all collapsed nodes");
	var collapsedBranch = treeobj.expandAllBranch();	// Return value is always empty hash
	storage.setItem("_SystemTreeCollapsedBranch", JSON.stringify(collapsedBranch));

	flgUpdateTree = true;
	syncSystemTree2Lists();

	syncDlgMakeList();
}
function _downloadCurentNewick() {
	if(!isTreeAvailable()) return void(0);

	var leafs = treeobj.tree.appearanceLeafs;
	var accId2ObjMap = _getAllAccId2listsObj();
	var leafNames = [];
	for(var i=0,len=leafs.length; i<len; i++) {
		var accObj = accId2ObjMap[leafs[i].childs];
		if(accObj != null) {
			var leafName = "";
			if(storage.getItem("_Name") === "id") {
				leafName = accObj.id;
			} else {
				leafName = accObj.name;
			}
			var subKey = storage.getItem('_NameSub');
			if(subKey === "subvariety") subKey = "grp";
			if(accObj[subKey] != null && accObj[subKey] !== "") {
				leafName += "_";
				leafName += accObj[subKey];
			}
			leafName = leafName.replace(/[\(\)\:,]/g, '_');
			leafNames.push(leafName);
		}
	}
	var newickStr = treeobj.tree.getNewick(leafNames);

//	var newickStr = treeobj.tree.getNewick();
//	console.log("Newick:" + newickStr);
	var Time = new Date();
	var timePrint = Time.getFullYear()+"_"+(Time.getMonth()+1)+"_"+Time.getDate();
	var headerStr = treeobj.headerString;
	headerStr = headerStr.replace(/\s+/g, "_");
	var fileName = _escapeHTML(headerStr) + "_newick_" + timePrint+".txt";
	_download(newickStr, fileName);
}
function _changeSystreeW() {
	var width = document.getElementById("prm_systreeW").value;
	treeobj.treeWidth = width - treeobj.lMargin - treeobj.rMargin;
	storage.setItem("_SystemTreeW", width);

/*
	flgUpdateTree = true;
	_execCanvas();	// exec _syncContentWidth() in this.
*/

	flgUpdateTree = true;
	_drawCanvas();
}
var lastXscend = null;
var lastTreeSortType = null;
function _changeSystreeSort() {
	var xscend = document.getElementById("prm_systree_sort").value;
	var type = document.getElementById("prm_systree_sorttype").value;
	storage.setItem("_SystemTreeSort", xscend);
	storage.setItem("_SystemTreeSortType", type);

	syncStyleSystreeSortType();
	if(xscend === "" && lastXscend === xscend) return;	// Unsort

	_messageOnScreen("Change SystemTree sort");
	if(xscend) {
		// asc/desc
		treeobj.sortByLength(xscend, type);
		flgUpdateTree = true;
		syncSystemTree2Lists();
/*
		syncSystemTree2Lists();
		flgUpdateTree = true;
		_execCanvas();
*/
	} else {
		// unsort
		if(isPhylipTreeUsing()) {
//		if(flgUsingPhylipTree) {
			syncPhylip2SystemTree()
		} else {
			syncStorage2SystemTree2Lists();
		}
	}
	lastXscend = xscend;
	lastTreeSortType = type;
}
function syncStyleSystreeSortType() {
	var xscend = document.getElementById("prm_systree_sort").value;
	if(xscend === "") {
		document.getElementById("prm_systree_sorttype").style.color = '#aaaaaa';
//		document.getElementById("prm_systree_sorttype").disabled = false;
	} else {
		document.getElementById("prm_systree_sorttype").style.color = 'black';
//		document.getElementById("prm_systree_sorttype").disabled = false;
	}
}

/////////////////////////////////////////////// Change snpblock
/*
function _changeSnpblock(){
	if ( storage.getItem("_Snpblock")=="off" ) {
		storage.setItem('_Eff', "off");
		storage.setItem('_Mode', storage.getItem("_Mode"));
		_execSnpblock(storage.getItem("_Ref"));
	} else {
		storage.setItem("_Snpblock", "off");
	}
	_drawCanvas();
	if ( storage.getItem('_Snpblock') == "[]" ) {
		_messageOnScreen("Snpblock data is not found");
	}
}
*/

/////////////////////////////////////////////// Change NULL on/off
function _changeNull(){
	if (storage.getItem("_Null")=="false"){
		storage.setItem("_Null", "true");
	} else {
		storage.setItem("_Null", "false");
	}
	_drawCanvas();
}

/////////////////////////////////////////////// Change color gradient from color manager
function _changeColorGradient(){
	var en=new Object(JSON.parse(storage.getItem("_Env")));
	var colorObjects=["#manager_snp_max","#manager_snp_min","#manager_indel_max","#manager_indel_min","#manager_depth_max","#manager_depth_min","#manager_cstm_max","#manager_cstm_min"];
	for(var i=0; i<colorObjects.length; i++){
		var array = colorObjects[i].split("_");
		en[array[1]+"_"+array[2]+"_col"]=$(colorObjects[i]).val();
	}
	storage.setItem("_Env",JSON.stringify(en));
	grad_DP = gra_hexcolor(en.depth_min_col,en.depth_max_col);
	grad_S = gra_hexcolor(en.snp_min_col,en.snp_max_col);
	grad_INDEL = gra_hexcolor(en.indel_min_col,en.indel_max_col);
	grad_CSTM_array[0] = gra_hexcolor(en.cstm_min_col,en.cstm_max_col);
	_drawCanvas();
}

function _changeCondColorGradient(){
	var en=new Object(JSON.parse(storage.getItem("_Env")));
	var colorObjects=["#manager_cstm_max_para0","#manager_cstm_min_para0","#manager_cstm_max_para1","#manager_cstm_min_para1","#manager_cstm_max_para2","#manager_cstm_min_para2","#manager_cstm_max_para3","#manager_cstm_min_para3"];
	for(var i=0; i<colorObjects.length; i++){
		var array = colorObjects[i].split("_");
		if(array[3] == "para0"){
			en[array[1]+"_"+array[2]+"_col"] = $(colorObjects[i]).val();
		}else{
			en[array[1]+"_"+array[2]+"_col_"+array[3]] = $(colorObjects[i]).val();
		}
	}
	storage.setItem("_Env",JSON.stringify(en));
	grad_CSTM_array[0] = gra_hexcolor(en.cstm_min_col,en.cstm_max_col);
	grad_CSTM_array[1] = gra_hexcolor(en.cstm_min_col_para1,en.cstm_max_col_para1);
	grad_CSTM_array[2] = gra_hexcolor(en.cstm_min_col_para2,en.cstm_max_col_para2);
	grad_CSTM_array[3] = gra_hexcolor(en.cstm_min_col_para3,en.cstm_max_col_para3);
	_drawCanvas();
}

/////////////////////////////////////////////// Change range of gradient from color manager
function _changeRangeOfGrad(dest){
	var en=new Object(JSON.parse(storage.getItem("_Env")));
	var colorObjects=[ dest+"_slider_max", dest+"_slider_min"];
	for(var i=0; i<colorObjects.length; i++){
		var array = colorObjects[i].split("_");
		if(((array[0]=="depth" || array[0]=="cstm"))){
			en[array[0]+"_"+array[2]]=$("#"+colorObjects[i]).val();
		}else{
			var keys = Object.keys(en);
			for (var a=0; a<keys.length; a++) {
				var regexp = new RegExp(array[0]+"_.*[kb]");
				if(keys[a].match(regexp)){
					var keySp = keys[a].split("_");
					var percentage = $("#"+colorObjects[i]).val();
					var value = parseInt(_cvtZoom(keySp[1])*(percentage/100));
					if(value < 1 ){value=1;}
					if(array[0]==dest && array[2]=="min"){
						Objects[array[0]+"_"+array[2]+"_rate"]=percentage/100;
						en[array[0]+"_"+array[2]]=value;
					}else{
						en[keys[a]]=value;
					}
				}
			}
		}
	}
	storage.setItem("_Env",JSON.stringify(en));
	_drawCanvas();
}

function _setMinColor(dest){
	var en=new Object(JSON.parse(storage.getItem("_Env")));
	if(dest+"_min_rate" in Objects){
		en[dest+"_min"]=parseInt(_cvtZoom(storage.getItem("_Zoom"))*Objects[dest+"_min_rate"]);
		if(en[dest+"_min"]<1){en[dest+"_min"]=1;}
		storage.setItem("_Env",JSON.stringify(en));
	}else{
		//pass
	}
}

////////////////////////////////////////////////view object id on each track
function _viewObjectID(){
	var isConflict=false;
	if (storage.getItem("_TrackID")!="on"){
		isConflict = _trackConflict();
		if(!isConflict){storage.setItem("_TrackID", "on");}
	}else{
		storage.setItem("_TrackID", "off");
	}
	_drawCanvas();
	if(isConflict){_messageOnScreen("No space for viewing the feature ID");}
	var evt = document.createEvent("HTMLEvents");//reloading main canvas by track resizing
	evt.initEvent("scroll", true, true);
	content.dispatchEvent(evt);
}

////////////////////////////////////////////////Check confliction of feature ID on tracks.
function _trackConflict(){
	var to=new Object(JSON.parse(storage.getItem("_Tracks")));
	var track2Index = {};
	for ( var j=0, toLen=to.length; j<toLen; j++) {
		track2Index[to[j].track] = j;
	}

	var ta=_getTrack("view");
	var ret=false;
	for ( var i=0, taLen=ta.length; i<taLen; i++) {
//		for ( var j=0, toLen=to.length; j<toLen; j++) {
//			if ( ta[i] == to[j].track ) {
				var j = track2Index[to[i].track];
				var prevRow = new Array(0,0,0,0,0);
				var prevEnd=0;
				var o = _getGffTrackMap("_Track_" + j);
//				var o=new Object(JSON.parse(storage.getItem("_Track_"+j)));
				for (var k=0, oLen=o.length; k<oLen; k++){
                                        if(parseInt(o[k].pos) < prevRow[o[k].h] && prevRow[o[k].h] != 0 && o[k].id != ""){
                                            ret=true;
                                            break;
                                        }
                                        prevRow[o[k].h] = parseInt(o[k].pos) + 100;
/*
					var end=(parseInt(o[k].rs)*Objects.BlockW)+100;
					if(((o[k].rs*Objects.BlockW) < prevRow[o[k].h]) && prevRow[o[k].h] != 0 && o[k].id != ""){
						ret=true;
					}
					prevRow[o[k].h]=end;
*/
				}
				if(ret) break;
//			}
//		}
	}
	return ret;
}

/////////////////////////////////////////////// escape HTML
function _escapeHTML(str) {
	if(typeof str != 'string') str = String(str);
	if(str == null) {
		return "";
	} else {
		return str.replace(/&/g, '&amp;')
			.replace(/</g, '&lt;')
			.replace(/>/g, '&gt;')
			.replace(/"/g, '&quot;')
			.replace(/'/g, '&#039;');
	}
}

/////////////////////////////////////////////// 
function _getVisibleArea(mode){
	var ONDIALOG=false;
/*
	if ($('#dialog_csv').is(":visible")) ONDIALOG=true;
	if ($('#dialog_fa').is(":visible")) ONDIALOG=true;
	if ($('#dialog_p3').is(":visible")) ONDIALOG=true;
	if ($('#dialog_track').is(":visible")) ONDIALOG=true;
	if ($('#dialog_reset').is(":visible")) ONDIALOG=true;
*/
	if(!ONDIALOG){
		var visibleArea = getContentVisibleArea();
		var skipTop = visibleArea.top;
		var visibleCont = visibleArea.count;
//		VIEWSTART=skipTop;
//		VIEWLEN=visibleCont;
		var str="";
		var array = new Array;
		array = _NgetList("db", skipTop, visibleCont+1);
		storage.setItem("_ListsTgt", array.join(','));
	}
}

function _isUndefined(value){
	var a;
	if(value === a){
		return 1;
	}else{
		return 0;
	}
}

function times(str, n) {
	var	i;
	var part = str;
	var res = '';
	for (var i = 1; i <= n; i <<= 1, part += part) {
		if (n & i) res += part;
	}
	return res;
}

function _overWriteColorFromEnv(){
	var en=new Object(JSON.parse(storage.getItem("_Env")));
	grad_DP = gra_hexcolor(en.depth_min_col,en.depth_max_col);
	grad_S = gra_hexcolor(en.snp_min_col,en.snp_max_col);
	grad_INDEL = gra_hexcolor(en.indel_min_col,en.indel_max_col);
	grad_CSTM_array[0] = gra_hexcolor(en.cstm_min_col,en.cstm_max_col);
	grad_CSTM_array[1] = gra_hexcolor(en.cstm_min_col_para1,en.cstm_max_col_para1);
	grad_CSTM_array[2] = gra_hexcolor(en.cstm_min_col_para2,en.cstm_max_col_para2);
	grad_CSTM_array[3] = gra_hexcolor(en.cstm_min_col_para3,en.cstm_max_col_para3);
}

function _resetMultiCondEnv(str){
	if(parseInt(str) == 0){
		var condArray = storage.getItem("_CrtCondition").split("|");
		for(var i=0; i<condArray.length; i++){
			var tgt = 'select[name=cond_select_row'+i+']';
			if(i==0){
				$(tgt).val(0);
			}else{
				$(tgt).val("");
			}
		}
		_setMultiCond();
	}else{
		var org = "";
		$.ajax({
			url: "./bin/env.php",
			cache: false,
			async: false,
			success: function(data) {
				org = data;
			}
		});
		var orgen=new Object(JSON.parse(org));
		var en=new Object(JSON.parse(storage.getItem("_Env")));
		var colorObjects=["cstm_max_col","cstm_min_col","cstm_max_col_para1","cstm_min_col_para1","cstm_max_col_para2","cstm_min_col_para2","cstm_max_col_para3","cstm_min_col_para3"];
		for(var i=0; i<colorObjects.length; i++){
			en[colorObjects[i]] = orgen[colorObjects[i]];
		}
		storage.setItem("_Env",JSON.stringify(en));
		grad_CSTM_array[0] = gra_hexcolor(en.cstm_min_col,en.cstm_max_col);
		grad_CSTM_array[1] = gra_hexcolor(en.cstm_min_col_para1,en.cstm_max_col_para1);
		grad_CSTM_array[2] = gra_hexcolor(en.cstm_min_col_para2,en.cstm_max_col_para2);
		grad_CSTM_array[3] = gra_hexcolor(en.cstm_min_col_para3,en.cstm_max_col_para3);
		_drawCanvas();
		_dialog_cond();
	}
}

function _externalParser(){
	var url = location.search;
	var query = url.split("?");
	if(query.length < 2) return false;

	var prm = query[1].split("&");
	var object = new Object();
	var windowSize=100;

	//  e.g.) http://yourserver/index.html?id=AAA&st=111&en=222&chr=BBB
	//  id: If you set transcript id to this parameter, the transcript object is highlighted on track. (Not required)
	//  st: Target start position
	//  en: Target end position
	//  chr: Name of taget sequence
	//  acc: Comma separated accessions if(!_isUndefined(o[i])){

	for(var i=0, prmLen=prm.length; i<prmLen; i++){
		var keyVal = prm[i].split("=");
		object[keyVal[0]]=keyVal[1];
	}

	// Accessions
	if('acc' in object || 'cdb' in object) {
		var accs = [];
		if('acc' in object) {
			accs = object["acc"].split(",");
		} else {
			var dbArr = tasukeCompAccArray.decodeUrlSafe(object["cdb"], {compress:true});
			var db2accInfo = _getAccDb2ObjMap();
			for(var i=0,len=dbArr.length; i<len; i++) {
				accs.push(db2accInfo[dbArr[i]].id);
			}
		}
		storage.setItem("_Ext_accessions", accs.join(","));
		_setAccListObjArray("_Lists", []);	// To re-execute list.php at the reloaded destinatin.
		storage.setItem("_SysTreeNewick", "");

		if(accs.length < 3 && isTreeUsing()) {
			storage.setItem('_SYSTREE', 'off');
		}
	}

	//Position
	if(!_isUndefined(object["chr"]) && !_isUndefined(object["st"]) && !_isUndefined(object["en"])){
                if (!_isEmpty(storage.getItem("_Block"))) windowSize=storage.getItem("_Block");
                storage.setItem("_Block", windowSize);

		_changeAutoPosZoom(object["chr"], object["st"], object["en"]);
		if(!_isUndefined(object["id"])){storage.setItem("_Keyword", object["id"]);}

		setRegionHighlight({"chr":object["chr"], "st":object["st"], "en":object["en"]});	// Region Highlight
//		addRegionHighlight({"chr":object["chr"], "st":object["st"], "en":object["en"]});	// Region Highlight
	}

	location.replace('./');	// [Notice!!] Even if replace(), the process proceeds until the page is loaded.

	return true;
}

function _backendSelector(str){
	var en = new Object(JSON.parse(storage.getItem("_Env")));
	var script = str.split("\.");
	var ret = "";
	switch (en.backend) {
	case "oracle":
		ret = "oracle/"+script[0]+"_oracle."+script[1];
		break;
	default: 
		ret = str;
	break;
	}
	return ret;
}

/*
var overflowObject = new Object();
var compressedStorage = true;
//var compressedStorage = false;
function _setCompressedData(key,val){
	if(compressedStorage == true){
		try{
			storage.setItem(key,LZString.compressToUTF16(val));
		}catch(e){
			// alert("The LocalStorage has overflowed. The TASUKE will be reset after 10 second.");
			console.log(e.message);
			setTimeout(_dlg_reset_confirm(),5000);
			//overflowObject[key] = val;
		}
	}else{
		storage.setItem(key,val);
	}
}

function _getCompressedData(key){
	var val = "";
	if(compressedStorage == true){
		if (storage.getItem(key) === null) {
			if(key in overflowObject){
				//alert("Invalid key was found. The TASUKE will be reset after 10 second.");
				console.log(e.message);
				//setTimeout(_dlg_reset_confirm(),5000);
				return;
			}else{
				//val = overflowObject[key];
			}
		}else{
			val = LZString.decompressFromUTF16(storage.getItem(key));
		}
	}else{
		val = storage.getItem(key);
	}
	return val;
}
*/
function _getTitleColor(str){
	var col = new Object(JSON.parse(storage.getItem("_GrpCol")));
	return col[str];
}

function _changeTitleColor(){
	var i = $("select[name=prm_grpcol_switch]").val();
	if(i==1){
		storage.setItem('_ColorCode',"on");
	}else{
		storage.setItem('_ColorCode',"off");
	}
	_drawCanvas();
}

function _drawTitleColor(){
	_setTitleColor();
	_drawCanvas();
}

function tasuke_version(){
	var version = "1.4.0";
	return version;
}


function _callDrawBLAST(str){
	var p3StrSplit = str.split("---SPL---");
	var len = p3StrSplit.length;
  	var allary = p3StrSplit[0].split("---TRK---");
  	var start = allary[1];
  	var end = allary[2];
        var chr = allary[3];
	if(!_validateChr(chr)) {
		_messageOnScreen("Invalid:this chromosomeis not registered!!");
		return;
	}
	var p3Zoom = p3StrSplit[0].replace(/---TRK---/g,"|");
	_zoomFromGffWindow(p3Zoom);

  	var blocksize = _cvtZoom(storage.getItem("_Zoom"));
  	var StartBlock=(start/blocksize)-(storage.getItem("_Pos"))+1;
  	var EndBlock=(end/blocksize)-(storage.getItem("_Pos"))+1;
  	if(StartBlock<=EndBlock){EndBlock++;}
  	rangestart = (storage.getItem("_Pos")-1) * blocksize + 1;
  	rangeend = rangestart + blocksize*100-1;
	var type = '';
	for(var i=0, arrLen=p3StrSplit.length; i<arrLen; i++) {
		if(p3StrSplit[i].match(/^lPrm\W/i) || p3StrSplit[i].match(/^rPrm\W/i)) {
			type = 'primer3';
		}
	}
	if(type == 'primer3') {
		_addPrimer3Track(str);
	} else {
		_addBlastTrack(str);
	}
}
function _validateChr(chr) {
	var validated = false;
	try {
		var chrs = JSON.parse(storage.getItem('_Chrs'));
		for(var i=0, chrsLen=chrs.length; i<chrsLen; i++) {
			if(chrs[i].id == chr) {
				validated = true;
				break;
			}
		}
	} catch(e) { }
	return validated;
}

function _addPrimer3Track(str){
  if(str) {
	var prm_Zoom = storage.getItem("_Zoom");	// '1k' '100b' etc
	var prm_Chr = storage.getItem("_Chr");
	var prm_Pos = parseInt(storage.getItem("_Pos"));
	var prm_Block = parseInt(storage.getItem("_Block"));

	var numZoom = _cvtZoom(prm_Zoom);
	var db_range_start = prm_Pos * numZoom - numZoom;
	var db_range_end = (prm_Pos + prm_Block) * numZoom;
	var prm_Tracks = str.split('---SPL---');

	var start;
	var end;
	var secstart;
	var secend;
	var idsArr = [];
	var arrStr = "";
        for(var i=0, tracksLen=prm_Tracks.length; i<tracksLen; i++) {
		var prminfos = prm_Tracks[i].split('---TRK---');
		if(prminfos[0] === "all") {
			start = parseInt(prminfos[1]);
			end = parseInt(prminfos[2]);
			var rtnArr = [];
			var rs = (start / numZoom) - prm_Pos;
			var re = (end / numZoom) - prm_Pos;
			var p1 = (start / numZoom) - prm_Pos;
			var p;
			if (end % numZoom){
				p = parseInt(end / numZoom) - prm_Pos + 1;
			} else {
				p = parseInt(end / numZoom) - prm_Pos;
			}
			if (prm_Zoom !== "1b") { 
				rs++; re++; p1++; p++;
			}
			var a1 = 0;
			var a2 = 0;
			var a3 = 0;
			var h;
			if ( p1 > a1 || a1 == null ) {
				h=1;
				a1=p;
			} else if (p1 > a2 || a2 == null ) {
				h=2;
				a2=p;
			} else if ( p1 > a3 || a3 == null ) {
				h=3;
				a3=p;
			} else {
				h=4;
			}
			arrStr = "[{\"id\":\"Primer3 Result\",\"name\":\"Primer3 Result\",\"pos\":\"" + start + "\",\"length\":\"" + (end-start+1) + "\",\"strand\":\"\",\"s\":\"" + p1 + "\",\"e\":\"" + p + "\",\"h\":\"" + h + "\",\"rs\":\"" + rs + "\",\"re\":\"" + re + "\",\"ln\":\"\"";
		} else {
			secstart = parseInt(prminfos[1]);
			secend = parseInt(prminfos[2]);
			var s = (secstart - start) / (end - start + 1) * 100;
			var l = (secend - secstart + 1) / (end - start + 1) * 100;
			idsArr.push(prminfos[0] + "-" + s + "-" + l);
		}
	}
	var data = arrStr + ",\"t\":\"" + idsArr.join(";") + "\"}]";

	var trcs = new Object(JSON.parse(storage.getItem("_Tracks")));
//	var str1 = "{\"track\":\"Primer3 Result\",\"p\":\"1\",\"h\":\"4\",\"c\":\"#0099ff\",\"s\":\"1\",\"t\":\"general\"}";
	var existRes = false;
	for (var a=0, trcslen=trcs.length; a<trcslen; a++){
		if(trcs[a].track == "Primer3 Result") {
			existRes = true;
			break;
		}
	}
	if(!existRes) trcs.push( new Object({track:"Primer3 Result", p:"1", h:"4", c:"#0099ff", s:"1", t:"general"}) );

	storage.setItem("_Tracks", JSON.stringify(trcs));
	_setGffTrackMapByJson("_Track_prm", data);
//	storage.setItem("_Track_prm", data);
	storage.setItem("_Prm_str", str);
/*
    $.ajax({
	url: "./bin/"+_backendSelector("drawPrimer3.php"),
	type: "GET",
	cache: false,
	data: {
		"prm_Zoom":storage.getItem("_Zoom"),
		"prm_Chr":storage.getItem("_Chr"),
		"prm_Pos":storage.getItem("_Pos"),
		"prm_Block":storage.getItem("_Block"),
		"prm_Track": str
	},
	success: function(data) {
		var ret1="";
    		var str1="";
    		var register=1;
    		var trc = new Object(JSON.parse(storage.getItem("_Tracks")));
        	str1="{\"track\":\"Primer3 Result\",\"p\":\"1\",\"h\":\"4\",\"c\":\"#0099ff\",\"s\":\"1\",\"t\":\"general\"}";

    		var ret1="[";
    		for (var a=0;a<trc.length;a++){
      			if(trc[a].track=="Primer3 Result"){register=0;}
      			if(register == 1) {
        			ret1 += JSON.stringify(trc[a])+",";
        			if(a==trc.length-1){ret1+=str1;}
      			}
    		}
    		ret1+="]";
    		if(register==1){storage.setItem("_Tracks",ret1);}
		_setGffTrackMapByJson("_Track_prm",data);
//    		storage.setItem("_Track_prm",data);
    		storage.setItem("_Prm_str",str);	
	}
    });
*/
  }
}
function _addBlastTrack(str){
  if(str) {
        var prm_Zoom = storage.getItem("_Zoom");        // '1k' '100b' etc
        var prm_Chr = storage.getItem("_Chr");
        var prm_Pos = parseInt(storage.getItem("_Pos"));
        var prm_Block = parseInt(storage.getItem("_Block"));

        var numZoom = _cvtZoom(prm_Zoom);
        var db_range_start = prm_Pos * numZoom - numZoom;
        var db_range_end = (prm_Pos + prm_Block) * numZoom;
	var blst_Tracks = str.split('---SPL---');

	var idsArr = [];
        for(var i=0, tracksLen=blst_Tracks.length; i<tracksLen; i++) {
		var blstinfos = blst_Tracks[i].split('---TRK---');
                        var start = parseInt(blstinfos[1]);
                        var end = parseInt(blstinfos[2]);
                        var rs = (start / numZoom) - prm_Pos;
                        var re = (end / numZoom) - prm_Pos;
                        var p1 = (start / numZoom) - prm_Pos;
                        var p;
                        if (end % numZoom){
                                p = parseInt(end / numZoom) - prm_Pos + 1;
                        } else {
                                p = parseInt(end / numZoom) - prm_Pos;
                        }
                        if (prm_Zoom != "1b") {
                                rs++; re++; p1++; p++;
                        }

                        var a1 = 0;
                        var a2 = 0;
                        var a3 = 0;
                        var h;
                        if ( p1 > a1 || a1 == null ) {
                                h=1;
                                a1=p;
                        } else if (p1 > a2 || a2 == null ) {
                                h=2;
                                a2=p;
                        } else if ( p1 > a3 || a3 == null ) {
                                h=3;
                                a3=p;
                        } else {
                                h=4;
                        }

                        idsArr.push(
				"{\"id\":\"Blast Result\",\"name\":\"Blast Result\",\"pos\":\"" + start + "\",\"length\":\"" + (end-start+1) + "\",\"strand\":\"\",\"s\":\"" + p1 + "\",\"e\":\"" + p + "\",\"h\":\"" + h + "\",\"rs\":\"" + rs + "\",\"re\":\"" + re + "\",\"ln\":\"\",\"t\":\"hsp-0-100\"}"
			);
        }
        var data =  "[" + idsArr.join(",") + "]";

        var trcs = new Object(JSON.parse(storage.getItem("_Tracks")));
//      var str1 = "{\"track\":\"Primer3 Result\",\"p\":\"1\",\"h\":\"4\",\"c\":\"#0099ff\",\"s\":\"1\",\"t\":\"general\"}";
        var existRes = false;
        for (var a=0, trcslen=trcs.length; a<trcslen; a++){
                if(trcs[a].track == "Blast Result") {
                        existRes = true;
                        break;
                }
        }
        if(!existRes) trcs.push( new Object({track:"Blast Result", p:"1", h:"4", c:"#0000ff", s:"2", t:"general"}));

        storage.setItem("_Tracks", JSON.stringify(trcs));
	_setGffTrackMapByJson("_Track_blst", data);
//        storage.setItem("_Track_blst",data);
        storage.setItem("_Blst_str",str);
    }
}
function _execPhenotype() {
	$.ajax({
		url: "./bin/phenotype.php",
		cache: false,
		async: false,
		success: function(data) {
			storage.setItem("_Phenotypes", data);
		}
	});
}

function _getPhenotype(id) {
	var o=new Object(JSON.parse(storage.getItem("_Phenotypes")));
	if(!o || !(o instanceof Array) || o.length==0) return "";
	if (!(_isEmpty(id))) {
		return o[id].phenotype;
	}

	return o[0].phenotype;
}

function _getPhenotypeExpressions() {
	var a=new Array();
	var o=new Object(JSON.parse(storage.getItem("_PhenotypeExpressions")));
	for(var i=0;i<o.length;i++){
		if(!a[o[i].id]){
			a[o[i].id]=new Array();
		}
		if(o[i].expression == 1){
			a[o[i].id][o[i].phenotype] = true;
		}else{
			a[o[i].id][o[i].phenotype] = false;
		}
	}
	return a;
}

function _getPhenotypePapers(id, phenotype) {
	var a=new Array();
	var o=new Object(JSON.parse(storage.getItem("_PhenotypePapers")));
	for(var i=0;i<o.length;i++){
		if(o[i].id == id && o[i].phenotype == phenotype){
			a = o[i].paper;
			break;
		}
	}

	return a;
}

function _getTotalChrsSize(){
	var o = new Object(JSON.parse(storage.getItem("_Chrs")));
	var totalChrsSize = 0;
	for(var i=0;i<o.length;i++){
		totalChrsSize += parseInt(o[i].size);
	}
//
	return totalChrsSize;
}

function _getChrBeginPosOnAll(){
	var a = new Object();
	var o = new Object(JSON.parse(storage.getItem("_Chrs")));
	var size = 1;
	for(var i=0;i<o.length;i++){
		a[o[i].id] = size;
		size += parseInt(o[i].size);
	}

	return a;
}

function _showGWAS() {
        if(phenotypeFlg) {
                if(storage.getItem("_GWAS") == "on") {
			var color = _setColor().tracktitle;
                	$("#GWAS_plot").css('display','none');
                	$("#show_phenotype").css('display','inline');
			$("#track").css('border-bottom','1px #c3c3c3 solid');
			storage.setItem("_GWAS","off");
		} else if(storage.getItem("_GWAS") == "off") {
			$("#GWAS_plot").css('display','block');
//			$("#GWAS_plot").css('display','inline');
                	$("#show_phenotype").css('display','none');
			$("#track").css('border-bottom','');
			storage.setItem("_GWAS","on");
			/*
			$("#show_phenotype").empty();
			ctx14.clearRect(0, 0, cvs14.width-20, cvs14.height);
			var ongwas = $("#content").height() - $("#GWAS_plot").height();
			$("#content").css("height",ongwas);
			*/
		}
		_showLoading();
		storage.removeItem("_ListsTgt");
		FROMSCROLL=false;
		_execCanvas();
	} else {
		// This may not make sense.
		_setMenu();
	}
}

function _showTree() {
	if(!isTreeAvailable()) {
		return void(0);
	} else if(storage.getItem("_SYSTREE") === "on") {
		hideSystemTreeSimple(true);
	} else {
		hideSystemTreeSimple(false);
	}
}
function _changeCursorLines(e) {
	if(storage.getItem("_CursorLines") === "on") {
		storage.setItem("_CursorLines", "off");
		_clearCursorLines(e);
	} else {
		storage.setItem("_CursorLines", "on");
	}
//	_setMenu();
	_drawCanvas();
}

function getRegionHighlightArray() {
  var array = [];
  var regHighlights = storage.getItem("_RegHighlights");        // ex. [{"st":20000,"en":21000,"chr":"chr01"},{"st":110000,"en":120000,"chr":"chr01"}]
  if(regHighlights != null &&  regHighlights != '') {
    try {
      var ary = JSON.parse(regHighlights);
      if(ary instanceof Array) array = ary;
    } catch(e) { }
  }
  return array;
}
function setRegionHighlightArray(array) {
  if( !(array instanceof Array) ) {
    storage.setItem("_RegHighlights", "[]");
    return;
  }
  try {
    var str = JSON.stringify(array);
    storage.setItem("_RegHighlights", str);
  } catch(e) { }
  // To reflect on Canvas, execute _drawCanvas () separately.
}
function setRegionHighlight(ref) {
  setRegionHighlightArray([ref]);
}
function addRegionHighlight(ref) {
  if("chr" in ref && "st" in ref && !isNaN(ref["st"]) && "en" in ref && !isNaN(ref["en"])) {
    var st = ref["st"];
    var en = ref["en"];
    var array = getRegionHighlightArray();
    array.push(ref);
    setRegionHighlightArray(array);
  }
  // necessary to execute _drawCanvas()
}
function clearRegionHighlight() {
	setRegionHighlightArray(new Array());
	storage.setItem("_Keyword", "");
	// necessary to execute _drawCanvas()
}
function clearAccHighlight() {
	storage.setItem("_AccHighlight", "");
	// necessary to execute "flgUpdateTree = true;", _drawCanvas()
}
function clearSystreeHighlight() {
	treeobj.lastChangedBranch = null;
	// necessary to "flgUpdateTree = true;" and execute _drawCanvas()
}
function changeDialogZindex(className) {
	if(className == lastClickDialogName) return;
	lastClickDialogName = className;

        maxDialogZindex++;
        $(className).css('z-index', maxDialogZindex);
}
// for JQuery dialog only
function setClickEventToDialog(dialog, className) {
	dialog.on('mousedown',function(e1){
		changeDialogZindex(className);
	}).parent().find('.ui-dialog-titlebar').on('mousedown',function(e1){
		changeDialogZindex(className);
	});
}

////////////////////////////////////////////////////////
// Set menu bar
////////////////////////////////////////////////////////
function _setMenu(){
  // Set chromosome on main page
  var o=new Object(JSON.parse(storage.getItem("_Chrs")));
  var en=new Object(JSON.parse(storage.getItem("_Env")));
  var mode_name = "";

  var o=new Object(JSON.parse(storage.getItem("_Chrs")));

/*
  $("#prm_chr").off("change");
  $("#prm_chr").find('option').remove();
  for (var i=0;i<o.length;i++){
    var selected = "";
    if(o[i].id === storage.getItem('_Chr')) selected = "selected"
    $('#prm_chr').append("<option value='" + o[i].id + "' " + selected + ">" + en.chromosome_name + o[i].id + "</option>");
  }
  $("#prm_chr").on("change", function() {_changeChromosome();});
*/
  var ld="";
  for (var i=0;i<o.length;i++){
    ld=ld+"<option value='"+o[i].id+"'>"+en.chromosome_name+o[i].id+"</option>";
  }
  $('#prm_chr').find('option').remove().end().append(ld);
  $('#prm_chr').val(storage.getItem('_Chr'));

  $('#menu .zoom').text("Block size "+storage.getItem('_Zoom'));
  if(!_isUndefined(Objects.Conditions)){
    if(Objects.Conditions.length > 1){
      var condArray = storage.getItem("_CrtCondition").split("|");
      var cond = parseInt(condArray[0]);
      mode_name = en.cstm_name.substr(0, 10)+" : "+Objects.Conditions[cond].id.substr(0, 10);
      //mode_name = $.format("%30s",mode_name);
    }else{
      mode_name = en.cstm_name;
    }
  }else{
    mode_name = en.cstm_name;
  }

  ///Available within 4k///
  $('#menu .one').css("color", "black");

  var onchk = "<i class=\"fa fa-circle\" aria-hidden=\"true\"></i> ";
  var offchk = "<i class=\"fa fa-circle-o\" aria-hidden=\"true\"></i> ";

  if (storage.getItem('_sFlg') == "1"){
    $('#menu .menuLisSnp').empty()
    $('#menu .menuLisSnp').append(onchk+"<i id=\"effbox\" style=\"background-color:#00ffff;width:10px;height:12px;display:inline-block;\"></i>SNP : ON (s)")
    $('#menu .menuLisSnp').css("color", "black");
  } else {
    $('#menu .menuLisSnp').empty()
    $('#menu .menuLisSnp').append(offchk+" <i id=\"effbox\" style=\"background-color:#00ffff;width:10px;height:12px;display:inline-block;\"></i>SNP : OFF (s)")
    $('#menu .menuLisSnp').css("color", "black");
  }
  if (storage.getItem('_iFlg') == "1"){
    $('#menu .menuLisIndel').empty()
    $('#menu .menuLisIndel').append(onchk+" <i id=\"effbox\" style=\"background-color:#A52A2A;width:10px;height:12px;display:inline-block;\"></i>INDEL : ON (i)")
    $('#menu .menuLisIndel').css("color", "black");
  } else {
    $('#menu .menuLisIndel').empty()
    $('#menu .menuLisIndel').append(offchk+" <i id=\"effbox\" style=\"background-color:#A52A2A;width:10px;height:12px;display:inline-block;\"></i>INDEL : OFF (i)")
    $('#menu .menuLisIndel').css("color", "black");
  }
  if (storage.getItem('_dpFlg') == "1"){
    $('#menu .menuLisDP').empty()
    $('#menu .menuLisDP').append(onchk+" <i id=\"effbox\" style=\"background-color:#b2b2b2;width:10px;height:12px;display:inline-block;\"></i>DEPTH : ON (p)")
    $('#menu .menuLisDP').css("color", "black");
  } else {
    $('#menu .menuLisDP').empty()
    $('#menu .menuLisDP').append(offchk+" <i id=\"effbox\" style=\"background-color:#b2b2b2;width:10px;height:12px;display:inline-block;\"></i>DEPTH : OFF (p)")
    $('#menu .menuLisDP').css("color", "black");
  }

  if (storage.getItem('_Eff') === "on"){
    // SnpEff
    $('#menu_eff_i').removeClass('fa-circle-o').addClass('fa-circle');
    $('#menu .SnpEffModeState').html('ON');
  } else {
    $('#menu_eff_i').removeClass('fa-circle').addClass('fa-circle-o');
    $('#menu .SnpEffModeState').html('Off');
  }

  if (storage.getItem('_Snpblock') == "off"){
    $('#menu .snpblock').empty()
    $('#menu .snpblock').append(offchk+"Snpblock : OFF (b)")
    $('#menu .snpblock').css("color", "black");
  } else {
    $('#menu .snpblock').empty()
    $('#menu .snpblock').append(onchk+"Snpblock : ON (b)")
    $('#menu .snpblock').css("color", "black");
  }
  if (storage.getItem('_Null') == "true"){
    //$('#menu .null').text("Highlight DEPTH=NA ON (n)")
    $('#menu .null').empty()
    $('#menu .null').append(onchk+"Highlight DEPTH=NA : ON (n)")
    //$('#menu .null').css("color", "yellow");
    $('#menu .null').css("color", "black");
  } else {
    //$('#menu .null').text("Highlight DEPTH=NA OFF (n)")
    $('#menu .null').empty()
    $('#menu .null').append(offchk+"Highlight DEPTH=NA : OFF (n)")
    //$('#menu .null').css("color", "white");
    $('#menu .null').css("color", "black");
  }
  if (storage.getItem('_Amino') == "off"){
    //$('#menu .amino').text("Amino acids OFF")
    $('#menu .amino').empty()
    $('#menu .amino').append(offchk+"Amino acids : OFF")
    //$('#menu .amino').css("color", "white");
    $('#menu .amino').css("color", "black");
  } else {
    //$('#menu .amino').text("Amino acids ON")
    $('#menu .amino').empty()
    $('#menu .amino').append(onchk+"Amino acids : ON")
    //$('#menu .amino').css("color", "yellow");
    $('#menu .amino').css("color", "black");
  }
  if (storage.getItem('_Indicator') == "off"){
    //$('#menu .indicator').text("Indicator : OFF (d)")
    $('#menu .indicator').empty()
    $('#menu .indicator').append(offchk+"Indicator : OFF (d)")
    //$('#menu .indicator').css("color", "white");
    $('#menu .indicator').css("color", "black");
  } else {
    //$('#menu .indicator').text("Indicator : ON (d)")
    $('#menu .indicator').empty()
    $('#menu .indicator').append(onchk+"Indicator : ON (d)")
    //$('#menu .indicator').css("color", "yellow");
    $('#menu .indicator').css("color", "black");
  }

  $('#menu .GWAS').empty();
  if (storage.getItem('_GWAS') == "off"){
    $('#menu .GWAS').append(offchk+"Show GWAS : OFF (g)");
    $('#menu .GWAS').css("color", "black");
  } else {
    $('#menu .GWAS').append(onchk+"Show GWAS : ON (g)");
    $('#menu .GWAS').css("color", "black");
  }

  $('#systree_mode').empty();
  $('#systree_subul').empty();
  $('#menu .SYSTREE').empty();
  if(isTreeAvailable()) {
    $('#menu .SYSTREE').css("color", "black");
    if(isTreeUsing()) {
      $('#menu .SYSTREE').append(onchk + "Show Tree : ON (r)");
      $('#systree_subul').append('<li><a href=\"javascript:returnPhylip2WholeGenomeTree()\" class=\"return_wgtree\">Return WholeGenomeTree</a></li>');
	changeColor($('#menu .return_wgtree'), isPhylipTreeUsing());
//      changeColor($('#menu .return_wgtree'), flgUsingPhylipTree);
    } else {
      $('#menu .SYSTREE').append(offchk + "Show Tree : OFF (r)");
    }

    $('#menu .export_systree').css("color", "black");
  } else {
    $('#menu .SYSTREE').append(offchk + "Show Tree : OFF (r)");
    $('#menu .SYSTREE').css("color", "#aaaaaa");
    $('#menu .export_systree').css("color", "#aaaaaa");
  }

  if (storage.getItem('_Onebase') == "off"){
    $('#frqmode_subul').empty();
    if(storage.getItem("_Ref") == "Reference"){
      $('#menu .one').empty()
      $('#menu .one').append(onchk+"Block mode : ON (b)")
    }else{
      $('#menu .one').empty()
      $('#menu .one').append(onchk+"Block mode : ON (b)")
    }
  } else {
    $('#frqmode_subul').empty();
    if(storage.getItem("_Ref") == "Reference"){
      $('#menu .one').empty()
      $('#menu .one').append(offchk+"Block mode : OFF (b)")

      $('#frqmode_subul').append('<li><a href=\"javascript:_changeToDefault()\" class=\"def\"><i class="fa fa-circle-o" aria-hidden="true"> Allele</a></li>');
      $('#frqmode_subul').append('<li><a href=\"javascript:_changeToGt()\" class=\"gt\"><i class="fa fa-circle-o" aria-hidden="true"> GT(Homo/Hetero)</a></li>');
      
      if(Objects.Eff === "on") {
        $('#menu .def').css("color", "#aaaaaa");
	$('#menu .gt').css("color", "#aaaaaa");

	var msgAlleleGt = 'Turn SnpEff:Off to enable this menu.';
	$('#frqmode_subul .def').prop("title", msgAlleleGt);
	$('#frqmode_subul .gt').prop("title", msgAlleleGt);
      } else {
        $('#menu .def').css("color", "black");
        $('#menu .gt').css("color", "black");

	$('#frqmode_subul .def').prop("title", "");
	$('#frqmode_subul .gt').prop("title", "");
      }

      if(storage.getItem('_ColorMode') === "") $('#menu .def i').removeClass('fa-circle-o').addClass('fa-circle');
      if(storage.getItem('_ColorMode') === "gt") $('#menu .gt i').removeClass('fa-circle-o').addClass('fa-circle');
    }else{
      $('#menu .one').empty()
      $('#menu .one').append(offchk+"Block mode : OFF (b)")
    }
  }

  if (storage.getItem('_CSTM') == "on"){
    $('#menu .cstm').text("View "+en.cstm_name+" : ON (c)");
    $('#menu .cstm').css("color", "yellow");
    if(Objects.Conditions.length > 1){
      $('#menu .condSelect').css("color", "white");
      $("#menu .condSelect").attr({href: "javascript:_dialog_cond()"});
    }else{
      $('#menu .condSelect').css("color", "gray");
      $("#menu .condSelect").attr({href: "javascript:void(0)"});
    }
    $('#menu .color_cstm').text("Color manager");
    //$('#menu .color_cstm').css("color", "white");
    $('#menu .color_cstm').css("color", "black");
  }
  if(_trackConflict()){
    $('#menu .viewObjId').empty();
    $('#menu .viewObjId').append(offchk+"Feature IDs : ON (t)")
    $('#menu .viewObjId').css("color", "#aaaaaa");
  }else if (storage.getItem('_TrackID') == "on"){
    $('#menu .viewObjId').empty();
    $('#menu .viewObjId').append(onchk+"Feature IDs : ON (t)");
    $('#menu .viewObjId').css("color", "black");
  } else {
    $('#menu .viewObjId').empty();
    $('#menu .viewObjId').append(offchk+"Feature IDs : OFF (t)");
    $('#menu .viewObjId').css("color", "black");
  }

  // Coursor lines
  $('#menu .cursorLines').empty(); 
  if(storage.getItem("_CursorLines") === "on") {
    $('#menu .cursorLines').append(onchk + "Cursor lines : ON (l)");
  } else {
    $('#menu .cursorLines').append(offchk + "Cursor lines : OFF (l)");
  }

  // MacroView menu
  if(en['validMacroViewerMenu'] == 0) {
    $('#menu #macrogenome').parent().remove();
  }

  // Acc/Region highlight
  changeColor($('#menu .allHighlight'), isAnythingHighlighted());
  changeColor($('#menu .regHighlight'), isRegionHighlighted());
  changeColor($('#menu .accHighlight'), isAccHighlighted());
  changeColor($('#menu .systreeHighlight'), isSystreeHighlighted());
  // Variant filter/highlight
  changeColor($('#menu .variantFilterAndHighlight'), isVariantHighlightGene() || isVariantFiltered());
  changeColor($('#menu .variantHighlight'), isVariantHighlightGene());
  changeColor($('#menu .variantFilter'), isVariantFiltered());

  function changeColor(elem, isValid) {
	if(isValid) {
		elem.css("color", "black");
	} else {
		elem.css("color", "#aaaaaa");
	}
  }
}
function isAnythingHighlighted() {
	return isRegionHighlighted() || isAccHighlighted() || isSystreeHighlighted();
}
function isRegionHighlighted() {
	return (storage.getItem("_RegHighlights") && JSON.parse(storage.getItem("_RegHighlights")).length > 0);
}
function isAccHighlighted() {
	var accHighlighted = storage.getItem("_AccHighlight");
	return (storage.getItem("_AccHighlight") !== '' && accHighlighted != null);
}
function isSystreeHighlighted() {
	return treeobj.lastChangedBranch !== null;
}
function isVariantFiltered() {
	return (isFilteredVariantDepth() || isFilteredVariantQual() || isFilteredVariantSnpEff());
}
function isVariantHighlightGene() {
	return storage.getItem("_HighlightVariantGene");
}
function isFilteredVariantDepth() {
	var dp = parseInt(storage.getItem("_DP"));
	var dp4 = parseInt(storage.getItem("_DP4"));
        return (dp !== DEF_DP) || (dp4 !== DEF_DP4);
}
function isFilteredVariantQual() {
	var qual = parseInt(storage.getItem("_QUAL"));
        return qual !== DEF_QUAL;
}
function isFilteredVariantSnpEff() {
        var effgrpsStr = storage.getItem("_EffGrps");
        var effgrps = [];
        try {
                if(effgrpsStr) effgrps = JSON.parse(effgrpsStr);
                if(effgrps.length < _getEffNoFilterArray().length) return true;
        } catch (error) {
                console.error(error);
        }
        return false;
}

