Index: binary-improvements/webserver/js/map.js
===================================================================
--- binary-improvements/webserver/js/map.js	(revision 299)
+++ binary-improvements/webserver/js/map.js	(revision 306)
@@ -93,4 +93,14 @@
 	});
 
+	var densityMismatchMarkerGroupAir = L.markerClusterGroup({
+		maxClusterRadius: function(zoom) { return zoom == mapinfo.maxzoom ? 10 : 50; }
+	});
+	var densityMismatchMarkerGroupTerrain = L.markerClusterGroup({
+		maxClusterRadius: function(zoom) { return zoom == mapinfo.maxzoom ? 10 : 50; }
+	});
+	var densityMismatchMarkerGroupNonTerrain = L.markerClusterGroup({
+		maxClusterRadius: function(zoom) { return zoom == mapinfo.maxzoom ? 10 : 50; }
+	});
+
 
 	var layerControl = L.control.layers({
@@ -117,4 +127,5 @@
 	
 	layerControl.addOverlay (GetRegionLayer (mapinfo), "Region files");
+	layerCount++;
 	
 	var miniMap = new L.Control.MiniMap(tileLayerMiniMap, {
@@ -166,5 +177,5 @@
 		layerCount++;
 	}
-
+	
 	if (layerCount > 0) {
 		layerControl.addTo(map);
@@ -430,4 +441,119 @@
 	}
 
+	
+	
+	
+	
+	
+	
+	
+	
+	// ===============================================================================================
+	// Density markers
+
+	var setDensityMarkers = function(data) {
+		var densityCountAir = 0;
+		var densityCountTerrain = 0;
+		var densityCountNonTerrain = 0;
+
+		densityMismatchMarkerGroupAir.clearLayers();
+		densityMismatchMarkerGroupTerrain.clearLayers();
+		densityMismatchMarkerGroupNonTerrain.clearLayers();
+		
+		
+		var downloadCsv = true;
+		var downloadJson = false;
+		
+		if (downloadJson) {
+			var jsonAir = [];
+			var jsonTerrain = [];
+			var jsonNonTerrain = [];
+		}
+		if (downloadCsv) {
+			var csvAir = "x;y;z;Density;IsTerrain;BvType\r\n";
+			var csvTerrain = "x;y;z;Density;IsTerrain;BvType\r\n";
+			var csvNonTerrain = "x;y;z;Density;IsTerrain;BvType\r\n";
+		}
+		
+		$.each( data, function( key, val ) {
+			if (val.bvtype == 0) {
+				marker = L.marker([val.x, val.z]).bindPopup(
+					"Density Mismatch: <br>Position: " + val.x + " " + val.y + " " + val.z + "<br>Density: " + val.density + "<br>isTerrain: " + val.terrain + "<br>bv.type: " + val.bvtype
+				);
+				densityMismatchMarkerGroupAir.addLayer(marker);
+				densityCountAir++;
+				if (downloadJson) {
+					jsonAir.push (val);
+				}
+				if (downloadCsv) {
+					csvAir += val.x + ";" + val.y + ";" + val.z + ";" + val.density + ";" + val.terrain + ";" + val.bvtype + "\r\n";
+				}
+			} else if (val.terrain) {
+				marker = L.marker([val.x, val.z]).bindPopup(
+					"Density Mismatch: <br>Position: " + val.x + " " + val.y + " " + val.z + "<br>Density: " + val.density + "<br>isTerrain: " + val.terrain + "<br>bv.type: " + val.bvtype
+				);
+				densityMismatchMarkerGroupTerrain.addLayer(marker);
+				densityCountTerrain++;
+				if (downloadJson) {
+					jsonTerrain.push (val);
+				}
+				if (downloadCsv) {
+					csvTerrain += val.x + ";" + val.y + ";" + val.z + ";" + val.density + ";" + val.terrain + ";" + val.bvtype + "\r\n";
+				}
+			} else {
+				marker = L.marker([val.x, val.z]).bindPopup(
+					"Density Mismatch: <br>Position: " + val.x + " " + val.y + " " + val.z + "<br>Density: " + val.density + "<br>isTerrain: " + val.terrain + "<br>bv.type: " + val.bvtype
+				);
+				densityMismatchMarkerGroupNonTerrain.addLayer(marker);
+				densityCountNonTerrain++;
+				if (downloadJson) {
+					jsonNonTerrain.push (val);
+				}
+				if (downloadCsv) {
+					csvNonTerrain += val.x + ";" + val.y + ";" + val.z + ";" + val.density + ";" + val.terrain + ";" + val.bvtype + "\r\n";
+				}
+			}
+		});
+
+		layerControl.addOverlay (densityMismatchMarkerGroupAir, "Density Mismatches Air (<span id='mapControlDensityCountAir'>0</span>)");
+		layerControl.addOverlay (densityMismatchMarkerGroupTerrain, "Density Mismatches Terrain (<span id='mapControlDensityCountTerrain'>0</span>)");
+		layerControl.addOverlay (densityMismatchMarkerGroupNonTerrain, "Density Mismatches NonTerrain (<span id='mapControlDensityCountNonTerrain'>0</span>)");
+
+		$( "#mapControlDensityCountAir" ).text( densityCountAir );
+		$( "#mapControlDensityCountTerrain" ).text( densityCountTerrain );
+		$( "#mapControlDensityCountNonTerrain" ).text( densityCountNonTerrain );
+		
+		if (downloadJson) {
+			download ("air-negative-density.json", JSON.stringify(jsonAir, null, '\t'));
+			download ("terrain-positive-density.json", JSON.stringify(jsonTerrain, null, '\t'));
+			download ("nonterrain-negative-density.json", JSON.stringify(jsonNonTerrain, null, '\t'));
+		}
+		if (downloadCsv) {
+			download ("air-negative-density.csv", csvAir);
+			download ("terrain-positive-density.csv", csvTerrain);
+			download ("nonterrain-negative-density.csv", csvNonTerrain);
+		}
+		
+		function download(filename, text) {
+			var element = document.createElement('a');
+			var file = new Blob([text], {type: 'text/plain'});
+			element.href = URL.createObjectURL(file);
+			element.download = filename;
+
+			element.style.display = 'none';
+			document.body.appendChild(element);
+
+			element.click();
+
+			document.body.removeChild(element);
+		}
+	}
+
+	$.getJSON("densitymismatch.json")
+	.done(setDensityMarkers)
+	.fail(function(jqxhr, textStatus, error) {
+		console.log("Error fetching density mismatch list");
+	});
+
 }
 
