graph.js
function readAscendantUnitsAfterTakingOffMc(conn, objEarlierUnitProps, arrLaterUnitProps, handleUnits){
	var arrLaterUnits = arrLaterUnitProps.map(function(objLaterUnitProps){ return objLaterUnitProps.unit; });
	var max_later_limci = Math.max.apply(null, arrLaterUnitProps.map(function(objLaterUnitProps){ return objLaterUnitProps.latest_included_mc_index; }));
	var arrLandedUnits = []; // units that took off MC after earlier unit's MCI, they already include the earlier unit
	var arrUnlandedUnits = []; // direct shoots from earlier units, without touching the MC
	
	arrLaterUnitProps.forEach(function(objUnitProps){
		if (objUnitProps.latest_included_mc_index >= objEarlierUnitProps.main_chain_index)
			arrLandedUnits.push(objUnitProps.unit);
		else
			arrUnlandedUnits.push(objUnitProps.unit);
	});
	
	function goUp(arrStartUnits){
		conn.query(
			"SELECT unit, level, latest_included_mc_index, main_chain_index, is_on_main_chain \n\
			FROM parenthoods JOIN units ON parent_unit=unit \n\
			WHERE child_unit IN(?) AND (main_chain_index>? OR main_chain_index IS NULL) AND level>=?",
			[arrStartUnits, max_later_limci, objEarlierUnitProps.level],
			function(rows){
				var arrNewStartUnits = [];
				for (var i=0; i<rows.length; i++){
					var objUnitProps = rows[i];
					//if (objUnitProps.main_chain_index <= max_later_limci)
					//    continue;
					//if (objUnitProps.level < objEarlierUnitProps.level)
					//    continue;
					arrNewStartUnits.push(objUnitProps.unit);
					if (objUnitProps.latest_included_mc_index >= objEarlierUnitProps.main_chain_index)
						arrLandedUnits.push(objUnitProps.unit);
					else
						arrUnlandedUnits.push(objUnitProps.unit);
				}
				(arrNewStartUnits.length > 0) ? goUp(arrNewStartUnits) : handleUnits(arrLandedUnits, arrUnlandedUnits);
			}
		);
	}
	
	goUp(arrLaterUnits);
}
function readAscendantUnitsAfterTakingOffMc(conn, objEarlierUnitProps, arrLaterUnitProps, handleUnits){
	var arrLaterUnits = arrLaterUnitProps.map(function(objLaterUnitProps){ return objLaterUnitProps.unit; });
	var max_later_limci = Math.max.apply(null, arrLaterUnitProps.map(function(objLaterUnitProps){ return objLaterUnitProps.latest_included_mc_index; }));
	var arrLandedUnits = []; // units that took off MC after earlier unit's MCI, they already include the earlier unit
	var arrUnlandedUnits = []; // direct shoots from earlier units, without touching the MC
	
	arrLaterUnitProps.forEach(function(objUnitProps){
		if (objUnitProps.latest_included_mc_index >= objEarlierUnitProps.main_chain_index)
			arrLandedUnits.push(objUnitProps.unit);
		else
			arrUnlandedUnits.push(objUnitProps.unit);
	});
	
	function goUp(arrStartUnits){
		conn.query(
			"SELECT unit, level, latest_included_mc_index, main_chain_index, is_on_main_chain \n\
			FROM parenthoods JOIN units ON parent_unit=unit \n\
			WHERE child_unit IN(?) AND (main_chain_index>? OR main_chain_index IS NULL) AND level>=?",
			[arrStartUnits, max_later_limci, objEarlierUnitProps.level],
			function(rows){
				var arrNewStartUnits = [];
				for (var i=0; i<rows.length; i++){
					var objUnitProps = rows[i];
					//if (objUnitProps.main_chain_index <= max_later_limci)
					//    continue;
					//if (objUnitProps.level < objEarlierUnitProps.level)
					//    continue;
					arrNewStartUnits.push(objUnitProps.unit);
					if (objUnitProps.latest_included_mc_index >= objEarlierUnitProps.main_chain_index)
						arrLandedUnits.push(objUnitProps.unit);
					else
						arrUnlandedUnits.push(objUnitProps.unit);
				}
				(arrNewStartUnits.length > 0) ? goUp(arrNewStartUnits) : handleUnits(arrLandedUnits, arrUnlandedUnits);
			}
		);
	}
	
	goUp(arrLaterUnits);
}
function readAscendantUnitsAfterTakingOffMc ( conn , objEarlierUnitProps , arrLaterUnitProps , handleUnits ) { var arrLaterUnits = arrLaterUnitProps . map ( function ( objLaterUnitProps ) { return objLaterUnitProps . unit ; } ) ; var max_later_limci = Math . max . apply ( null , arrLaterUnitProps . map ( function ( objLaterUnitProps ) { return objLaterUnitProps . latest_included_mc_index ; } ) ) ; var arrLandedUnits = [ ] ; // units that took off MC after earlier unit's MCI, they already include the earlier unit var arrUnlandedUnits = [ ] ; // direct shoots from earlier units, without touching the MC arrLaterUnitProps . forEach ( function ( objUnitProps ) { if ( objUnitProps . latest_included_mc_index >= objEarlierUnitProps . main_chain_index ) arrLandedUnits . push ( objUnitProps . unit ) ; else arrUnlandedUnits . push ( objUnitProps . unit ) ; } ) ; function goUp ( arrStartUnits ) { conn . query ( "SELECT unit, level, latest_included_mc_index, main_chain_index, is_on_main_chain \n\
			FROM parenthoods JOIN units ON parent_unit=unit \n\
			WHERE child_unit IN(?) AND (main_chain_index>? OR main_chain_index IS NULL) AND level>=?" , [ arrStartUnits , max_later_limci , objEarlierUnitProps . level ] , function ( rows ) { var arrNewStartUnits = [ ] ; for ( var i = 0 ; i < rows . length ; i ++ ) { var objUnitProps = rows [ i ] ; //if (objUnitProps.main_chain_index <= max_later_limci) //    continue; //if (objUnitProps.level < objEarlierUnitProps.level) //    continue; arrNewStartUnits . push ( objUnitProps . unit ) ; if ( objUnitProps . latest_included_mc_index >= objEarlierUnitProps . main_chain_index ) arrLandedUnits . push ( objUnitProps . unit ) ; else arrUnlandedUnits . push ( objUnitProps . unit ) ; } ( arrNewStartUnits . length > 0 ) ? goUp ( arrNewStartUnits ) : handleUnits ( arrLandedUnits , arrUnlandedUnits ) ; } ) ; } goUp ( arrLaterUnits ) ; }
includes later units
includes later units