<commit_before>// ****************************************
// get the year(s) for each metric
// ****************************************
function getYear(m) {
    switch(metricConfig[m].type) {
        case 'sum': case 'normalize':
        	// console.log('metricConfig[m].metric = '+JSON.stringify(metricConfig[m].metric));
        	// console.log("theData['r' + metricConfig[m].metric][0] = "+JSON.stringify(theData['r' + metricConfig[m].metric][0]));
            // console.log(m +" "+"metricConfig[m].type = "+metricConfig[m].type);
            // console.log("_.without(_.keys(theData['r' + metricConfig[m].metric][0]), 'id' = "+_.without(_.keys(theData['r' + metricConfig[m].metric][0]), 'id'));
            return _.without(_.keys(theData['r' + metricConfig[m].metric][0]), 'id');
            break;
        case 'mean':
            //console.log(m +" "+"metricConfig[m].type = "+metricConfig[m].type);
            return _.without(_.keys(theData['n' + metricConfig[m].metric][0]), 'id');
            break;
    }
}

// ****************************************
// set model variable as needed from data type
// ****************************************
function setModel(m) {
    model.metricId = m;
    if (!(m in metricConfig)) {
        console.log("Error: metricConfig is undefined for " + m);
        return;
    }
    switch(metricConfig[m].type) {
        case 'sum':
            model.metric = theData['r' + metricConfig[m].metric];
            break;
        case 'mean':
            model.metric = theData['n' + metricConfig[m].metric];
            if (metricConfig[m].raw_label) {
                model.metricRaw = theData['r' + metricConfig[m].metric];
            }
            break;
        case 'normalize':
            model.metricRaw = theData['r' + metricConfig[m].metric];
            model.metricDenominator = theData['d' + metricConfig[m].metric];
            if (model.metricRaw.length != model.metricDenominator.length) {
            	console.log("Error: Misconfigured metric " + metricConfig[m].metric + ". Length mismatch between r and d arrays.");
            	return;
            }

            var calcMetric = $.extend(true, {}, model.metricRaw);
            var keys = _.without(_.keys(model.metricRaw[0]), "id");

            // this next bit can get taken out when the normalize capabilities are complete
             _.each(calcMetric, function(theval, i) {
                _.each(keys, function(key) {
                    theRaw = model.metricRaw[i][key];
                    theDemoninator = model.metricDenominator[i][key];
                    theval[key] = theRaw / theDemoninator;
                });
            });
            //console.log("calcMetric = "+JSON.stringify(calcMetric));
            model.metric = calcMetric;
            // end bit

            break;
    }
}

// ****************************************
// Return the nth instance of a substring
// ****************************************
function GetSubstringIndex(str, substring, n) {
    var times = 0, index = null;
    while (times < n && index !== -1) {
        index = str.indexOf(substring, index+1);
        times++;
    }
    return index;
}

// ****************************************
// Create the metric blocks and table values
// ****************************************
function createData(featureSet) {
	var template = _.template($("script.template-metric").html()), categories = _.uniq(_.pluck(metricConfig, 'category'));
	model.selected = featureSet;
    _.each(featureSet, function(featureRaw) {
	    var feature = featureRaw.replace(/ /g,'-');
		_.each(categories, function(dim) {
			var theTable = $(".table-" + feature + "-" + dim.toLowerCase().replace(/\s+/g, "-") + " tbody");
			var theMetrics = _.filter(metricConfig, function(el) {
				return el.category.toLowerCase() === dim.toLowerCase();
			});
			_.each(theMetrics, function(val) {
			    // Check that metric is in data file before continuing.
                if (!('r' + val.metric in theData)) {
                    return;
                }
				var m = 'm' + val.metric;
				var lineChartObject = {
					"id" : m,
					"feature" : feature,
					"prefix": getPrefix(m),
					"suffix": getSuffix(m),
					"years" : "",
					"featurevalues" : "",
					"selectedvalues" : "",
					"countyvalues" : ""
				};
				setModel(m);
				var aboutHTML;
				var importance;
				var metricTitle;
				var additionalResourcesLinks;
				var additionalResourcesHTML;
				$.ajax({
					url : 'data/meta/' + m + '.html',
					type : 'GET',
					dataType : 'text',
					success : function(data) {
						metricTitle = data.substring(GetSubstringIndex(data, '</p>', 1), GetSubstringIndex(data, '<p', 1) + 3);
						aboutHTML = data.substring(GetSubstringIndex(data, '</h3>', 2) + 5, GetSubstringIndex(data, '<h3', 3));
						importance = data.substring(GetSubstringIndex(data, '</p>', 2), GetSubstringIndex(data, '<p', 2) + 3);
						var additionalResourcesHTML = "<table><thead></thead>" + data.substring(GetSubstringIndex(data, '</tbody>', 1) + 8, GetSubstringIndex(data, '<tbody', 1)) + "</body>";
						var parser = new DOMParser();
						var parserDoc = parser.parseFromString(additionalResourcesHTML, "text/html");
						//var table = parserDoc.getElementsByTagName('table');
						var tableTRs = parserDoc.getElementsByTagName("tr");
						var trTDs;
                        var additionalResourcesLinks = "";
						for (var i = 0; i < tableTRs.length; i++) {
							parserDoc = parser.parseFromString("<table><tr>" + tableTRs[i].innerHTML + "</tr></table>", "text/html");
							trTDs = parserDoc.getElementsByTagName("td");
							additionalResourcesLinks += "<div>" + [trTDs[0].innerHTML.slice(0, 3), 'title="' + trTDs[1].innerHTML + '"', trTDs[0].innerHTML.slice(3)].join('') + "</div>";;
						}
					},
					error : function(error, status, desc) {
					},
					complete : function() {
                        if (!(m in metricConfig)) {
                            console.log("Error: metricConfig is undefined for " + m);
                            return;
                        }

						var tdata = {
							"id" : m,
							"feature" : feature,
							"title" : metricTitle,
							"year" : "",
							"typeValues" : "",
							"about" : aboutHTML,
							"important" : importance,
							"additionalResources" : additionalResourcesLinks,
							"selectedVal" : "",
							"selectedRaw" : "",
							"selectedNVal" : "",
							"countyVal" : "",
							"countyRaw" : "",
							"countyNVal" : ""
						};
                        setModel(m);
                        model.metricID = m;
                        model.prefix = getPrefix(m);
                        model.suffix = getSuffix(m);

                        var keys = getYear(m);
						var year = keys[keys.length - 1];
						var yearTDs = "";
						var types = [];
                        var theYear;
						var yeariii;
						var iii;
						var years = [];
						var featureValue;
						var featureNValue;
						var featureValues = [];
						var selectedValues = [];
						var countyValues = [];
                        var lineCharts = [];
                        for (iii = 0; iii < keys.length; iii++) {
							theYear = keys[iii];
							model.years = keys;
							featureNValue = metricValuesByIDYear(model.metric, feature.replace(/-/g,' '), theYear, m);
							featureValue = dataPretty(featureNValue, m);
							yeariii = keys[iii].replace('y_', '');
							tdata.countyNVal = dataCrunch('y_' + yeariii);
							tdata.selectedNVal = dataCrunch('y_' + yeariii, theFilter);
							model.suffix = val.suffix;
							if (model.suffix == "%") {
								featureValue = dataPretty(featureNValue * 100, m);
								featureNValue = featureNValue * 100;
								tdata.selectedNVal = tdata.selectedNVal * 100;
								tdata.countyNVal = tdata.countyNVal * 100;
							}
							tdata.selectedVal = dataPretty(tdata.selectedNVal, m);
							tdata.countyVal = dataPretty(tdata.countyNVal, m);
							years.push(yeariii);
							featureValues.push(dataRound(featureNValue, metricConfig[m].decimals));
							selectedValues.push(dataRound(tdata.selectedNVal, metricConfig[m].decimals));
							countyValues.push(dataRound(tdata.countyNVal, metricConfig[m].decimals));
							types.push([featureValue, yeariii, tdata.selectedVal, tdata.countyVal]);
							tdata.typeValues = types;
							$(".dataValues").innerHTML = yearTDs;
							if (metricConfig[m].raw_label) {
								tdata.countyRaw = '<br>' + dataSum(model.metricRaw, year).toFixed(0).commafy();
								theStat = dataSum(model.metricRaw, year, theFilter);
								if ($.isNumeric(theStat)) {
									theStat = theStat.toFixed(0).commafy();
								}
								tdata.selectedRaw = '<br>' + theStat;
							}
							// front page

							if ($('[data-metric="' + m + '"]').length > 0) {
								$('[data-metric="' + m + '"]').text(tdata.selectedVal);
							}
							if ($('[data-metric="r' + val.metric + '"]').length > 0) {
								$('[data-metric="r' + val.metric + '"]').text(tdata.selectedRaw.replace('<br>', ''));
							}
						}
						if (years.length > 1) {
							lineChartObject.years = years;
							lineChartObject.featurevalues = featureValues;
                            if (theFilter.length > 1) {
							    lineChartObject.selectedvalues = selectedValues;
                            }
							lineChartObject.countyvalues = countyValues;
							lineCharts.push(lineChartObject);
						}

						// Write out stuff
						theTable.append(template(tdata));

                        // Hide "Selected features" if there is only one feature selected.
                        if (theFilter.length == 1) {
                            _.each(document.querySelectorAll(".metric-table__selection-average"), function (el, i) {
                                el.style.display = "none";
                            });
                        }

                        // Create line charts if they exist.
						if (lineCharts.length > 0) {
						    console.log("Creating line chart for " + m)
							lineChartCreate(lineCharts);
						}

						// Otherwise hide the linechart div.
						else {
						    document.getElementById("lineChart"+lineChartObject.id+lineChartObject.feature).style.display = "none";
                        }
					}
				});
			});
		});
	});
}

// ****************************************
// Initialize the map
// Neighborhoods labled with leaflet.label
// ****************************************
function createMap(data){
    // set up map
    L.Icon.Default.imagePath = './images';
    var smallMap = L.map("smallmap", {
            attributionControl: false,
            zoomControl: false,
            touchZoom: false
        }).setView(mapGeography.center, mapGeography.defaultZoom - 1);

    // Disable drag and zoom handlers.
    smallMap.dragging.disable();
    smallMap.touchZoom.disable();
    smallMap.doubleClickZoom.disable();
    smallMap.scrollWheelZoom.disable();
    var selectedFeatures = [],
    selectedIDs = [];
    // add data filtering by passed neighborhood id's
    geom = L.geoJson(topojson.feature(data, data.objects[neighborhoods]), {
        style: {
            "color": "#FFA400",
            "fillColor": "#FFA400",<commit_msg>Fix additional resources links<commit_after>// ****************************************
// get the year(s) for each metric
// ****************************************
function getYear(m) {
    switch(metricConfig[m].type) {
        case 'sum': case 'normalize':
        	// console.log('metricConfig[m].metric = '+JSON.stringify(metricConfig[m].metric));
        	// console.log("theData['r' + metricConfig[m].metric][0] = "+JSON.stringify(theData['r' + metricConfig[m].metric][0]));
            // console.log(m +" "+"metricConfig[m].type = "+metricConfig[m].type);
            // console.log("_.without(_.keys(theData['r' + metricConfig[m].metric][0]), 'id' = "+_.without(_.keys(theData['r' + metricConfig[m].metric][0]), 'id'));
            return _.without(_.keys(theData['r' + metricConfig[m].metric][0]), 'id');
            break;
        case 'mean':
            //console.log(m +" "+"metricConfig[m].type = "+metricConfig[m].type);
            return _.without(_.keys(theData['n' + metricConfig[m].metric][0]), 'id');
            break;
    }
}

// ****************************************
// set model variable as needed from data type
// ****************************************
function setModel(m) {
    model.metricId = m;
    if (!(m in metricConfig)) {
        console.log("Error: metricConfig is undefined for " + m);
        return;
    }
    switch(metricConfig[m].type) {
        case 'sum':
            model.metric = theData['r' + metricConfig[m].metric];
            break;
        case 'mean':
            model.metric = theData['n' + metricConfig[m].metric];
            if (metricConfig[m].raw_label) {
                model.metricRaw = theData['r' + metricConfig[m].metric];
            }
            break;
        case 'normalize':
            model.metricRaw = theData['r' + metricConfig[m].metric];
            model.metricDenominator = theData['d' + metricConfig[m].metric];
            if (model.metricRaw.length != model.metricDenominator.length) {
            	console.log("Error: Misconfigured metric " + metricConfig[m].metric + ". Length mismatch between r and d arrays.");
            	return;
            }

            var calcMetric = $.extend(true, {}, model.metricRaw);
            var keys = _.without(_.keys(model.metricRaw[0]), "id");

            // this next bit can get taken out when the normalize capabilities are complete
             _.each(calcMetric, function(theval, i) {
                _.each(keys, function(key) {
                    theRaw = model.metricRaw[i][key];
                    theDemoninator = model.metricDenominator[i][key];
                    theval[key] = theRaw / theDemoninator;
                });
            });
            //console.log("calcMetric = "+JSON.stringify(calcMetric));
            model.metric = calcMetric;
            // end bit

            break;
    }
}

// ****************************************
// Return the nth instance of a substring
// ****************************************
function GetSubstringIndex(str, substring, n) {
    var times = 0, index = null;
    while (times < n && index !== -1) {
        index = str.indexOf(substring, index+1);
        times++;
    }
    return index;
}

// ****************************************
// Create the metric blocks and table values
// ****************************************
function createData(featureSet) {
	var template = _.template($("script.template-metric").html()), categories = _.uniq(_.pluck(metricConfig, 'category'));
	model.selected = featureSet;
    _.each(featureSet, function(featureRaw) {
	    var feature = featureRaw.replace(/ /g,'-');
		_.each(categories, function(dim) {
			var theTable = $(".table-" + feature + "-" + dim.toLowerCase().replace(/\s+/g, "-") + " tbody");
			var theMetrics = _.filter(metricConfig, function(el) {
				return el.category.toLowerCase() === dim.toLowerCase();
			});
			_.each(theMetrics, function(val) {
			    // Check that metric is in data file before continuing.
                if (!('r' + val.metric in theData)) {
                    return;
                }
				var m = 'm' + val.metric;
				var lineChartObject = {
					"id" : m,
					"feature" : feature,
					"prefix": getPrefix(m),
					"suffix": getSuffix(m),
					"years" : "",
					"featurevalues" : "",
					"selectedvalues" : "",
					"countyvalues" : ""
				};
				setModel(m);
				var aboutHTML;
				var importance;
				var metricTitle;
				var additionalResourcesLinks;
				var additionalResourcesHTML;
				$.ajax({
					url : 'data/meta/' + m + '.html',
					type : 'GET',
					dataType : 'text',
					success : function(data) {
                        if (!(m in metricConfig)) {
                            console.log("Error: metricConfig is undefined for " + m);
                            return;
                        }

                        setModel(m);
                        model.metricID = m;
                        model.prefix = getPrefix(m);
                        model.suffix = getSuffix(m);

                        var keys = getYear(m);
                        var year = keys[keys.length - 1];
                        var yearTDs = "";
                        var types = [];
                        var theYear;
                        var yeariii;
                        var iii;
                        var years = [];
                        var featureValue;
                        var featureNValue;
                        var featureValues = [];
                        var selectedValues = [];
                        var countyValues = [];
                        var lineCharts = [];

                        // Get metric metadata from metadata HTML file.
                        var metricTitle = data.substring(GetSubstringIndex(data, '</p>', 1), GetSubstringIndex(data, '<p', 1) + 3);
						var aboutHTML = data.substring(GetSubstringIndex(data, '</h3>', 2) + 5, GetSubstringIndex(data, '<h3', 3));
						var importance = data.substring(GetSubstringIndex(data, '</p>', 2), GetSubstringIndex(data, '<p', 2) + 3);
						var additionalResourcesHTML = "<table><thead></thead>" + data.substring(GetSubstringIndex(data, '</tbody>', 1) + 8, GetSubstringIndex(data, '<tbody', 1)) + "</body>";
						var parser = new DOMParser();
						var parserDoc = parser.parseFromString(additionalResourcesHTML, "text/html");
						var tableTRs = parserDoc.getElementsByTagName("tr");
						var trTDs;
                        var additionalResourcesLinks = "";
						for (var i = 0; i < tableTRs.length; i++) {
							parserDoc = parser.parseFromString("<table><tr>" + tableTRs[i].innerHTML + "</tr></table>", "text/html");
							trTDs = parserDoc.getElementsByTagName("td");
							var linkTitle = "";
							if (trTDs.length == 2) {
								linkTitle = trTDs[1].innerHTML;
							}
							additionalResourcesLinks += "<div>" + [trTDs[0].innerHTML.slice(0, 3), 'title="' + linkTitle + '"', trTDs[0].innerHTML.slice(3)].join('') + "</div>";;
						}

                        var tdata = {
                            "id" : m,
                            "feature" : feature,
                            "title" : metricTitle,
                            "year" : "",
                            "typeValues" : "",
                            "about" : aboutHTML,
                            "important" : importance,
                            "additionalResources" : additionalResourcesLinks,
                            "selectedVal" : "",
                            "selectedRaw" : "",
                            "selectedNVal" : "",
                            "countyVal" : "",
                            "countyRaw" : "",
                            "countyNVal" : ""
                        };

                        for (iii = 0; iii < keys.length; iii++) {
                            theYear = keys[iii];
                            model.years = keys;
                            featureNValue = metricValuesByIDYear(model.metric, feature.replace(/-/g,' '), theYear, m);
                            featureValue = dataPretty(featureNValue, m);
                            yeariii = keys[iii].replace('y_', '');
                            tdata.countyNVal = dataCrunch('y_' + yeariii);
                            tdata.selectedNVal = dataCrunch('y_' + yeariii, theFilter);
                            model.suffix = val.suffix;
                            if (model.suffix == "%") {
                                featureValue = dataPretty(featureNValue * 100, m);
                                featureNValue = featureNValue * 100;
                                tdata.selectedNVal = tdata.selectedNVal * 100;
                                tdata.countyNVal = tdata.countyNVal * 100;
                            }
                            tdata.selectedVal = dataPretty(tdata.selectedNVal, m);
                            tdata.countyVal = dataPretty(tdata.countyNVal, m);
                            years.push(yeariii);
                            featureValues.push(dataRound(featureNValue, metricConfig[m].decimals));
                            selectedValues.push(dataRound(tdata.selectedNVal, metricConfig[m].decimals));
                            countyValues.push(dataRound(tdata.countyNVal, metricConfig[m].decimals));
                            types.push([featureValue, yeariii, tdata.selectedVal, tdata.countyVal]);
                            tdata.typeValues = types;
                            $(".dataValues").innerHTML = yearTDs;
                            if (metricConfig[m].raw_label) {
                                tdata.countyRaw = '<br>' + dataSum(model.metricRaw, year).toFixed(0).commafy();
                                theStat = dataSum(model.metricRaw, year, theFilter);
                                if ($.isNumeric(theStat)) {
                                    theStat = theStat.toFixed(0).commafy();
                                }
                                tdata.selectedRaw = '<br>' + theStat;
                            }
                            // front page

                            if ($('[data-metric="' + m + '"]').length > 0) {
                                $('[data-metric="' + m + '"]').text(tdata.selectedVal);
                            }
                            if ($('[data-metric="r' + val.metric + '"]').length > 0) {
                                $('[data-metric="r' + val.metric + '"]').text(tdata.selectedRaw.replace('<br>', ''));
                            }
                        }
                        if (years.length > 1) {
                            lineChartObject.years = years;
                            lineChartObject.featurevalues = featureValues;
                            if (theFilter.length > 1) {
                                lineChartObject.selectedvalues = selectedValues;
                            }
                            lineChartObject.countyvalues = countyValues;
                            lineCharts.push(lineChartObject);
                        }

                        // Write out stuff
                        theTable.append(template(tdata));

                        // Hide "Selected features" if there is only one feature selected.
                        if (theFilter.length == 1) {
                            _.each(document.querySelectorAll(".metric-table__selection-average"), function (el, i) {
                                el.style.display = "none";
                            });
                        }

                        // Create line charts if they exist.
                        if (lineCharts.length > 0) {
                            console.log("Creating line chart for " + m)
                            lineChartCreate(lineCharts);
                        }

                        // Otherwise hide the linechart div.
                        else {
                            document.getElementById("lineChart"+lineChartObject.id+lineChartObject.feature).style.display = "none";
                        }
					},
					error : function(error, status, desc) {
					},
				});
			});
		});
	});
}

// ****************************************
// Initialize the map
// Neighborhoods labled with leaflet.label
// ****************************************
function createMap(data){
    // set up map
    L.Icon.Default.imagePath = './images';
    var smallMap = L.map("smallmap", {
            attributionControl: false,
            zoomControl: false,
            touchZoom: false
        }).setView(mapGeography.center, mapGeography.defaultZoom - 1);

    // Disable drag and zoom handlers.
    smallMap.dragging.disable();
    smallMap.touchZoom.disable();
    smallMap.doubleClickZoom.disable();
    smallMap.scrollWheelZoom.disable();
    var selectedFeatures = [],
    selectedIDs = [];
    // add data filtering by passed neighborhood id's
    geom = L.geoJson(topojson.feature(data, data.objects[neighborhoods]), {
        style: {
            "color": "#FFA400",
            "fillColor": "#FFA400",
{'fraction_non_alphanumeric': 0.16955031589379363, 'fraction_numerical': 0.0049964900689598215, 'mean_word_length': 1.7820792647903503, 'pattern_counts': {'":': 8, '<': 51, '<?xml version=': 0, '>': 47, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4081797', 'n_tokens_mistral': 7553, 'n_tokens_neox': 6392, 'n_words': 1286}