User:Magicpiano/NRBot/NRHPstats.js

From Wikipedia, the free encyclopedia
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
/* jshint maxerr: 3000 */

//
// addPortletLink wrapper for invoking Javascript function instead of navigating
//
function addPortlet( portletId, text, id, tooltip, fn) {
	//console.log('NRHPstats: add portlet '+text);
	var node = mw.util.addPortletLink(portletId,'#', text,id, tooltip);
	$( node ).on('click', fn );
	return node;
}

var NRHPstats_portlet=null;
//switch portlet button from gathering stats to toggling display
function changePortletButton() {
	if (NRHPstats_portlet===null) return;
	$(NRHPstats_portlet).off('click',LoadNRHPstats);
    $(NRHPstats_portlet).on('click',ToggleDisp);
    NRHPstats_portlet.getElementsByTagName('a')[0].innerHTML="Show/hide NRHP stats";
}

var ShellInvoked=false; //interlock to prevent multiple runs
var AutoRunStats=true;
function Shell() {
	if (ShellInvoked) return;
	ShellInvoked=true;
    if (typeof(NRHPstatsAuto)!='undefined') {
        if (NRHPstatsAuto=='false' || NRHPstatsAuto===false) {
        	AutoRunStats=false;
        	console.log('NRHPstats: do not run automatically');
        }
    }

    if ((mw.config.get('wgPageName').search("National_Register_of_Historic_Places_listings") !== -1||mw.config.get('wgPageName').search("National_Historic_Landmarks_in") !== -1) && mw.config.get('wgNamespaceNumber')===0 && location.href.indexOf('action')===-1    && mw.config.get('wgArticleId')!==0) {
    	// if on NRHP list
        if (AutoRunStats) {
            LoadNRHPstats(null);
        } else {
        	NRHPstats_portlet = addPortlet('p-tb','NRHP Progress stats','t-NRHP','NRHP Progress stats',LoadNRHPstats);
        }
    } else if (mw.config.get('wgPageName') == "Wikipedia:WikiProject_National_Register_of_Historic_Places/Progress") {
    	// if on Progress page
        if (AutoRunStats) {
            NRHPTotals(null);
        } else {
        	NRHPstats_portlet = addPortlet('p-tb','Gather NRHP stats','t-NRHP','Gather NRHP stats',NRHPTotals);
        }
    } else {
	    // if on some other article
        return;
    }
}

function ToggleDisp(evt) {
	if (evt !== null) evt.preventDefault();
    var Disps = document.getElementsByClassName('NRHPdisp');
    var i;
    if (Disps.length === 0) return;
    if (Disps[0].style.display === '') {
        for (i=0; i<Disps.length; i++) {
            Disps[i].style.display='none';
        }
    } else {
        for (i=0; i<Disps.length; i++) {
            Disps[i].style.display='';
        }
    }
}

/*
   The following function only works on NRHP list articles; it calculates how many listings in the page's table(s)
   have articles, how many have images, and a host of other statistics useful for gauging "completeness" of a list.
   For more information, including a compilation of these statistics nationwide, see WP:NRHPPROGRESS.
*/


// global variables
var NRHPstats_HTMLTables=[];
var NRHPstats_HTMLRows = [];
var NRHPstats_Rows = [];
var TableStructure = [];
var TotalToQuery = 0;
var TotalQueried = 0;

var NRHPstatsrunning=false;
function LoadNRHPstats(evt) {
	if (evt !== null) evt.preventDefault();
	changePortletButton();
    console.log('NRHPstats starting');

	if (NRHPstatsrunning) {
		console.log('NRHPstats double invocation, aborting second call');
		return;
	}
	NRHPstatsrunning=true;
	// reset state in case we get run again
	NRHPstats_HTMLTables=[];
	NRHPstats_HTMLRows = [];
	NRHPstats_Rows = [];
	TableStructure = [];
	TotalToQuery = 0;
	TotalQueried = 0;
    getNRHPstatsWikitext(mw.config.get('wgPageName'));
}

function FetchedNRHPstatsWikitext(wikitext) {
    if (wikitext=="error") {
        alert("Could not retrieve wikitext! NRHPstats script aborted!");
        NRHPstatsrunning=false;
        return;
    }

    var table=document.getElementsByClassName('wikitable sortable');
    var i;
    
    if (table === null) return;
    for (i=0; i<table.length; i++) {   // get rid of non-NRHP tables
        var tr=table[i].getElementsByTagName("tr");
        if (tr[0].getElementsByTagName("th").length >= 5) {
        	var disp = table[i].previousSibling;
        	var needYellowBox = true;
        	if (disp !== null && (disp.nodeName === 'div' || disp.nodeName==='DIV')) {
        		if (!disp.hasAttributes || !disp.hasAttribute('class') || disp.getAttribute('class') !== 'NRHPdisp') {
        			// DIV found, but it's not ours, so disp is wrong
	        		//console.log('NRHPStats: DIV found, does not have NRHPdisp class');
        			needYellowBox = true;
        		} else {
        			// our DIV found, disp is set to it
	        		//console.log('NRHPStats: DIV found');
        			needYellowBox = false;
        		}
        	} else {
        		// DIV not found, so disp is wrong
        		//if (disp !== null) {
        		//	console.log('NRHPStats: Node found, nodeName='+disp.nodeName);
        		//}
        		//console.log('NRHPStats: DIV not found');
        		needYellowBox = true;
        	}
        	if (needYellowBox) {
        		//console.log('NRHPStats: Creating NRHPdisp DIV');
            	disp = document.createElement( 'div' );
	        	disp.setAttribute('style', 'font-size:125%; background-color:yellow; width:400px; padding:5px; text-align:center');
    	    	disp.setAttribute('class', 'NRHPdisp');
        		table[i].parentNode.insertBefore(disp , table[i]);
	            disp.innerHTML="<br><br><br>Loading statistics...<br><br><br><br>";

	            NRHPstats_HTMLTables.push(table[i]);
	            NRHPstats_HTMLRows[NRHPstats_HTMLRows.length]=[];
	            TableStructure[TableStructure.length]=[];
	            for (var j=1; j<tr.length; j++) {
	                NRHPstats_HTMLRows[NRHPstats_HTMLRows.length-1].push(tr[j]);
	                TableStructure[TableStructure.length-1][j-1]=["unknown", false, false, false, false, false, false, false];
	                // 0=title, 1=illustrated, 2=articled, 3=stub, 4=NRIS-only, 5=Start+, 6=unassessed, 7=untagged
	            }
        	//} else {
        	//	console.log('NRHPStats: Not rerunning');
        	}

        }
    }

	if (NRHPstats_HTMLTables.length === 0) {
		NRHPstatsrunning=false;
		return; // nothing to do
	}
	
    // get rows from wikitext
    var TableStartIndex=0;
    while (true) {
        TableStartIndex=wikitext.search(/{{[ ]*NRHP (former )?header/);  // find next table
        if (TableStartIndex==-1) {
            break;
        }
        NRHPstats_Rows[NRHPstats_Rows.length]=[];
        wikitext=wikitext.substr(TableStartIndex+1,wikitext.length-TableStartIndex);  // get rid everything before current table

        var tabletext=wikitext.substr(0,wikitext.indexOf("\n|}"));

        var str = "{{";
        var start=0;
        var commentstart=0;
        var regex;
        while (true) {
            commentstart=tabletext.indexOf("<!--",start);
            start=tabletext.indexOf(str,start);
            if (start==-1) break;
            while (commentstart<start&&commentstart!=-1) {
                start=tabletext.indexOf("-->",commentstart);
                commentstart=tabletext.indexOf("<!--",start);
                start=tabletext.indexOf(str,start);
            }
            if (start==-1) break;
            var open=1;
            var index=start+str.length;
            while (open!==0 && index<tabletext.length) {
                if (tabletext.substr(index,2)=="}}") {
                    open--;
                    index++;
                } else if (tabletext.substr(index,2)=="{{") {
                    open++;
                    index++;
                }
                index++;
            }
            var template=tabletext.substr(start,index-start);
            regex = new RegExp("{{[\\s]*NRHP row(\\s)*\\|", "g");
            if (template.match(regex)!==null) NRHPstats_Rows[NRHPstats_Rows.length-1].push(template);
            start++;
        }
        for (i=0; i<NRHPstats_Rows[NRHPstats_Rows.length-1].length; i++) { // get rid of false positives inside nowiki or pre tags
            regex=new RegExp("<[ ]*?(nowiki|pre)[ ]*?>((?!<[ ]*?/[ ]*?(nowiki|pre)[ ]*?>)(.|\\n))*?"+NRHPstats_Rows[NRHPstats_Rows.length-1][i].replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&")+"(.|\\n)*?<[ ]*?/[ ]*?(nowiki|pre)[ ]*?>", "g");
            if (tabletext.match(regex)!==null) {NRHPstats_Rows[NRHPstats_Rows.length-1].splice(i,1); i--}
        }
    }
    TotalToQuery=0;
    for (i=0; i<NRHPstats_Rows.length; i++) {
        TotalToQuery+=NRHPstats_Rows[i].length;
    }
    //console.log('Total number of rows to query: '+TotalToQuery);
    TotalQueried=0;
    var currentRow=0, currentTable=0;
    for (i=0;i<TotalToQuery; i++) {
    	try {
	    	NRHPstats_NextRow(currentTable, currentRow);
    	}
    	catch (e) {
    		console.log('Error processing table '+currentTable+' row '+currentRow);
    	}
    	currentRow++;
	    if (currentRow>NRHPstats_Rows[currentTable].length-1) {
	        currentRow=0;
	        currentTable++;
	    }
    }
}

function NRHPstats_NextRow(NRHPstats_currentTable,NRHPstats_currentRow) {
    // check if there are no more tables (should not happen)
    if (NRHPstats_currentTable>NRHPstats_Rows.length-1) return;

    var ThisRow=NRHPstats_Rows[NRHPstats_currentTable][NRHPstats_currentRow];
    var test=ThisRow.match(/\|[ ]*?image[ ]*?=.*?(\n|\||}})/g);
    if (test!==null) {
        test=test[0].replace(/\|[ ]*?image[ ]*?=/g,"").replace(/(\n|\||}})/g,"").replace(/<\!\-\-(.|[\r\n])*?\-\-\>/g,"").trim();
        if (test!=="") {
        	// console.log('NRHPstats: found image in row '+NRHPstats_currentRow+': '+test);
        	var test2 = test.match(/Address restricted/gi);
        	if (test2!==null && test2!=="") {
        		console.log('NRHPstats: image on row '+NRHPstats_currentRow+' appears to be address restricted image (ignoring): '+test);
        	} else {
	            TableStructure[NRHPstats_currentTable][NRHPstats_currentRow][1]=true;  // only true if image param there and non-blank
	            //console.log('NRHPstats: currentTable='+NRHPstats_currentTable+' currentRow='+NRHPstats_currentRow);
    	        NRHPstats_HTMLRows[NRHPstats_currentTable][NRHPstats_currentRow].className+=" NRHPstats-illustrated";
        	}
        }
    }
    var article=ThisRow.match(/\|[ ]*?article[ ]*?=[ ]*?.*?[\n|\|]/g);
    var blank=ThisRow.match(/\|[ ]*?article[ ]*?=[ ]*?[\n|\|]/g);                               // default to name param if article
    if (article===null||blank!==null) article=ThisRow.match(/\|[ ]*?name[ ]*?=[ ]*?.*?[\n|\|]/g); // blank or missing

    // strip param name, comments, final line break
    article=article[0].replace(/\|[ ]*?(article|name)[ ]*?=[ ]*?/g,"").replace(/[\n|\|]/g,"").replace(/<\!\-\-(.|[\r\n])*?\-\-\>/g,"").trim();
    article=decodeURIComponent(article.split("#")[0].trim());     // corrections for weird titles
    TableStructure[NRHPstats_currentTable][NRHPstats_currentRow][0]=article;

    $.ajax({
        dataType: "json",
        url: mw.util.wikiScript('api'),
        data: {
            format: 'json',
            action: 'query',
            prop: 'categories',
            clcategories: 'Category:All disambiguation pages|Category:All articles sourced only to NRIS',
            cllimit: 'max',
            titles: article,
            redirects: 'true'
        },
        success: function(ArticlejsonObject) {
        	ArticleChecked(ArticlejsonObject,NRHPstats_currentTable,NRHPstats_currentRow);
        },
        error: function(ArticlejsonObject) {
        	console.log('NRHPstats: error fetching article: '+article);
        }
    });
    return;
}

function ArticleChecked(ArticlejsonObject,NRHPstats_currentTable,NRHPstats_currentRow) {
    if (ArticlejsonObject.query.normalized) { // normalize any weird titles
        for (var n in ArticlejsonObject.query.normalized) {
            TableStructure[NRHPstats_currentTable][NRHPstats_currentRow][0]=ArticlejsonObject.query.normalized[n].to;
        }
    }
    if (ArticlejsonObject.query.redirects) { // resolve any redirects
        for (var r in ArticlejsonObject.query.redirects) {
            TableStructure[NRHPstats_currentTable][NRHPstats_currentRow][0]=ArticlejsonObject.query.redirects[r].to;
        }
    }

    TableStructure[NRHPstats_currentTable][NRHPstats_currentRow][2]=true; // default to articled
    NRHPstats_HTMLRows[NRHPstats_currentTable][NRHPstats_currentRow].className+=" NRHPstats-articled";
    for (var page in ArticlejsonObject.query.pages) {
        if (typeof ArticlejsonObject.query.pages[page].missing!="undefined") {
            // redlink=unarticled
            TableStructure[NRHPstats_currentTable][NRHPstats_currentRow][2]=false;
            NRHPstats_HTMLRows[NRHPstats_currentTable][NRHPstats_currentRow].className=NRHPstats_HTMLRows[NRHPstats_currentTable][NRHPstats_currentRow].className.replace(" NRHPstats-articled","");
        }
        if (ArticlejsonObject.query.pages[page].categories) {
            for (var category in ArticlejsonObject.query.pages[page].categories) {
                if (ArticlejsonObject.query.pages[page].categories[category].title=="Category:All disambiguation pages") {
                    // dab=unarticled
                    TableStructure[NRHPstats_currentTable][NRHPstats_currentRow][2]=false;
                    NRHPstats_HTMLRows[NRHPstats_currentTable][NRHPstats_currentRow].className=NRHPstats_HTMLRows[NRHPstats_currentTable][NRHPstats_currentRow].className.replace(" NRHPstats-articled","");
                }
                if (ArticlejsonObject.query.pages[page].categories[category].title.indexOf("sourced only to NRIS")!=-1) {
                    // mark as NRIS-only
                    TableStructure[NRHPstats_currentTable][NRHPstats_currentRow][4]=true;
                    NRHPstats_HTMLRows[NRHPstats_currentTable][NRHPstats_currentRow].className+=" NRHPstats-NRIS";
                }
            }
        }
    }

    if (TableStructure[NRHPstats_currentTable][NRHPstats_currentRow][2]) { // if articled, check talk page
        var catlist='Category:FA-Class National Register of Historic Places articles';
        catlist+='|Category:A-Class National Register of Historic Places articles';
        catlist+='|Category:GA-Class National Register of Historic Places articles';
        catlist+='|Category:B-Class National Register of Historic Places articles';
        catlist+='|Category:C-Class National Register of Historic Places articles';
        catlist+='|Category:Start-Class National Register of Historic Places articles';
        catlist+='|Category:Stub-Class National Register of Historic Places articles';
        catlist+='|Category:Unassessed National Register of Historic Places articles';
        catlist+='|Category:FL-Class National Register of Historic Places articles';
        catlist+='|Category:List-Class National Register of Historic Places articles';
        catlist+='|Category:Redirect-Class National Register of Historic Places articles';

        $.ajax({
            dataType: "json",
            url: mw.util.wikiScript('api'),
            //async: true,
            data: {
                format: 'json',
                action: 'query',
                prop: 'categories',
                clcategories: catlist,
                cllimit: 'max',
                titles: "Talk:"+TableStructure[NRHPstats_currentTable][NRHPstats_currentRow][0]
            },
            success: function(TalkjsonObject) {TalkChecked(TalkjsonObject,NRHPstats_currentTable,NRHPstats_currentRow)},
            error: function(TalkjsonObject) {
	        	console.log('NRHPstats: error fetching talk page for article: '+TableStructure[NRHPstats_currentTable][NRHPstats_currentRow][0]);
            }
        });
    } else { // if unarticled, no need to check talk page; send empty jsonObject
        TalkChecked({"query":{"pages":[]}},NRHPstats_currentTable,NRHPstats_currentRow);
    }
    return;
}

function TalkChecked(TalkjsonObject,NRHPstats_currentTable,NRHPstats_currentRow) {
	//console.log('NRHPstats: TalkChecked table='+NRHPstats_currentTable+' row='+NRHPstats_currentRow);
    for (var page in TalkjsonObject.query.pages) {
        TableStructure[NRHPstats_currentTable][NRHPstats_currentRow][7]=true; // default to untagged
        if (TalkjsonObject.query.pages[page].categories) {
            TableStructure[NRHPstats_currentTable][NRHPstats_currentRow][7]=false; // if cat hit, mark as tagged
            for (var category in TalkjsonObject.query.pages[page].categories) {
                var CatTitle=TalkjsonObject.query.pages[page].categories[category].title;
		        //console.log('NRHPstats: Category found='+CatTitle);
                if (CatTitle.indexOf("Stub")!=-1) {
                    TableStructure[NRHPstats_currentTable][NRHPstats_currentRow][3]=true; // mark as stub
                    NRHPstats_HTMLRows[NRHPstats_currentTable][NRHPstats_currentRow].className+=" NRHPstats-stub";
                }
                if (CatTitle.indexOf("Unassessed")!=-1 || CatTitle.indexOf("Redirect")!=-1) {
                    TableStructure[NRHPstats_currentTable][NRHPstats_currentRow][6]=true; // mark as unassessed
                    NRHPstats_HTMLRows[NRHPstats_currentTable][NRHPstats_currentRow].className+=" NRHPstats-unassessed";
                }
                if  (CatTitle.indexOf("List")!=-1 || CatTitle.indexOf("FL-Class")!=-1) { // count links to other county/MPS lists as unarticled; other list-class as stubs
                    if (TalkjsonObject.query.pages[page].title.indexOf("National Register of Historic Places")!=-1){
                        TableStructure[NRHPstats_currentTable][NRHPstats_currentRow][2]=false;
                        NRHPstats_HTMLRows[NRHPstats_currentTable][NRHPstats_currentRow].className=NRHPstats_HTMLRows[NRHPstats_currentTable][NRHPstats_currentRow].className.replace(" NRHPstats-articled","");
                    } else {
                        TableStructure[NRHPstats_currentTable][NRHPstats_currentRow][3]=true;
                        NRHPstats_HTMLRows[NRHPstats_currentTable][NRHPstats_currentRow].className+=" NRHPstats-stub";
                    }
                }
            }
        }
        if (TableStructure[NRHPstats_currentTable][NRHPstats_currentRow][7]===true) { // if no category hits, mark as untagged
            NRHPstats_HTMLRows[NRHPstats_currentTable][NRHPstats_currentRow].className+=" NRHPstats-untagged";
        }

        var temp=TableStructure[NRHPstats_currentTable][NRHPstats_currentRow];
        if (temp[2]&&!temp[3]&&!temp[6]&&!temp[7]) { // if articled but not stub, unassessed, or untagged, must be Start+
            TableStructure[NRHPstats_currentTable][NRHPstats_currentRow][5]=true;
            NRHPstats_HTMLRows[NRHPstats_currentTable][NRHPstats_currentRow].className+=" NRHPstats-Start+";
        }
    }

    TotalQueried++;
    // if we've queried all rows, add up statistics and display them
    //console.log('Total queried: '+TotalQueried+'/'+TotalToQuery);
    if (TotalQueried==TotalToQuery) CalculateNRHPStatistics();
    return;
}

function CalculateNRHPStatistics() {
    for (var NRHPstats_currentTable=0; NRHPstats_currentTable<TableStructure.length; NRHPstats_currentTable++) {
        var listings=TableStructure[NRHPstats_currentTable].length;
        var articled=0;
        var illustrated=0;
        var stubs=0;
        var NRIS=0;
        var start=0;
        var unassessed=0;
        var untagged=0;
        var temp=TableStructure[NRHPstats_currentTable];
        for (var i=0; i<listings; i++) {
            if (temp[i][1]) illustrated++;
            if (temp[i][2]) articled++;
            if (temp[i][3]) stubs++;
            if (temp[i][4]) NRIS++;
            if (temp[i][5]) start++;
            if (temp[i][6]) unassessed++;
            if (temp[i][7]) untagged++;
        }
        var percentIllustrated=Math.round(illustrated/listings*1000)/10;
        var percentArticled=Math.round(articled/listings*1000)/10;
        var percentStartPlus=Math.round(start/listings*1000)/10;
        var netQuality = (start+0.5*stubs+0.5*unassessed-0.5*untagged-0.75*NRIS)/listings;
            netQuality = Math.round((0.75*netQuality+0.25*illustrated/listings)*1000)/10;
        if (netQuality<0) netQuality = 0;

        // update yellow box
        var disp=NRHPstats_HTMLTables[NRHPstats_currentTable].previousSibling;
        var str1 = "<b>Total Listings:</b> " + listings;
        var str2 = "<br /><b>No. Illustrated:</b> " + illustrated + " (" + percentIllustrated + "%)";
        var str3 = "<br /><b>No. Articled:</b> " + articled + " (" + percentArticled + "%)";
        var str4 = "<br /><b>No. Stubs:</b> " + stubs;
        var str5 = "<br /><b>No. NRIS-only:</b> "+ NRIS;
        var str6 = "<br /><b>No. Start+:</b> " + start + " (" + percentStartPlus + "%)";
        var str7 = "<br /><b>No. Unassessed:</b> " + unassessed;
        var str8 = "<br /><b>No. Untagged:</b> " + untagged;
        var str9 = "<br /><b>Net Quality Rating:</b> " + netQuality + "%";

        disp.setAttribute('style', 'font-size:125%; background-color:yellow; width:400px; padding:5px');
        disp.innerHTML = str1 + "&nbsp;<small><a onclick='ToggleRows(\"all\","+NRHPstats_currentTable+")'>(Show all)</a></small>";
        var Span2 = document.createElement('span');
        Span2.innerHTML = str2 + "&nbsp;<small><a onclick='ToggleRows(\"illustrated\","+NRHPstats_currentTable+")'>(Show only unillustrated)</a></small>";
        disp.appendChild(Span2);
        var Span3 = document.createElement('span');
        Span3.innerHTML = str3 + "&nbsp;<small><a onclick='ToggleRows(\"articled\","+NRHPstats_currentTable+")'>(Show only unarticled)</a></small>";
        disp.appendChild(Span3);
        var Span4 = document.createElement('span');
        Span4.innerHTML = str4 + "&nbsp;<small><a onclick='ToggleRows(\"stub\","+NRHPstats_currentTable+")'>(Show only stubs)</a></small>";
        disp.appendChild(Span4);
        if (NRIS > 0) {
            var Span5 = document.createElement('span');
            Span5.innerHTML = str5 + "&nbsp;<small><a onclick='ToggleRows(\"NRIS\","+NRHPstats_currentTable+")'>(Show only NRIS-only)</a></small>";
            disp.appendChild(Span5);
            Span5.style.color = 'red';
        }
        var Span6 = document.createElement('span');
        Span6.innerHTML = str6 + "&nbsp;<small><a onclick='ToggleRows(\"Start+\","+NRHPstats_currentTable+")'>(Show only Start+)</a></small>";
        disp.appendChild(Span6);
        if (unassessed > 0) {
            var Span7 = document.createElement('span');
            Span7.innerHTML = str7 + "&nbsp;<small><a onclick='ToggleRows(\"unassessed\","+NRHPstats_currentTable+")'>(Show only unassessed)</a></small>";
            disp.appendChild(Span7);
            Span7.style.color = 'red';
        }
        if (untagged > 0) {
            var Span8 = document.createElement('span');
            Span8.innerHTML = str8 + "&nbsp;<small><a onclick='ToggleRows(\"untagged\","+NRHPstats_currentTable+")'>(Show only untagged)</a></small>";
            disp.appendChild(Span8);
            Span8.style.color = 'red';
        }
        var Span9 = document.createElement('span');
        Span9.innerHTML = str9;
        disp.appendChild(Span9);
    }
    NRHPstatsrunning=false;
}

function ToggleRows(show,tableNumber) {
    var HTMLTables=[];
    var i, tr;
    var table=document.getElementsByClassName('wikitable sortable');
    if (table === null) return;
    for (i=0; i<table.length; i++) {   // get rid of non-NRHP tables
        tr=table[i].getElementsByTagName("tr");
        if (tr[0].getElementsByTagName("th").length >= 5) {
            HTMLTables.push(table[i]);
        }
    }
    tr=HTMLTables[tableNumber].getElementsByTagName("tr");
    switch (show) {
        case "all":
            for (i=1; i<tr.length; i++) {tr[i].style.display=""}
            break;
        case "illustrated":
        case "articled":
            for (i=1; i<tr.length; i++) {
                if (tr[i].className.indexOf("NRHPstats-"+show)!=-1) {
                    tr[i].style.display="none";
                } else {
                    tr[i].style.display="";
                }
            }
            break;
        case "stub":
        case "NRIS":
        case "Start+":
        case "unassessed":
        case "untagged":
            for (i=1; i<tr.length; i++) {
                if (tr[i].className.indexOf("NRHPstats-"+show)==-1) {
                    tr[i].style.display="none";
                } else {
                    tr[i].style.display="";
                }
            }
            break;
    }
}


/*
   The following function only triggers on the NRHP Progress page; it adds up totals for each state table
   as well as for the national table at the top of the page. It outputs a yellow box similar to LoadNRHPstats()
*/


function NRHPTotals(evt) {
	if (evt !== null) evt.preventDefault();
	changePortletButton();

    console.log('NRHPtotals starting');
    var table=document.getElementsByClassName('wikitable sortable');

	var EnteredPercentIllustrated;
	var EnteredPercentArticled;
	var EnteredPercentStartPlus;
	var EnteredNetQuality;

    for (var i=0; i<table.length; i++){
        var rows=table[i].getElementsByTagName('tr');
        var Total = 0;
        var TotalIllustrated = 0;
        var TotalArticled = 0;
        var TotalStubs = 0;
        var TotalNRISOnly = 0;
        var TotalStartPlus = 0;
        var TotalUnassessed = 0;
        var TotalUntagged = 0;
        var CountySub = 0;
        var CountyIllustratedSub = 0;
        var CountyArticledSub = 0;
        var CountyStubsSub = 0;
        var CountyNRISOnlySub = 0;
        var CountyStartPlusSub = 0;
        var CountyUnassessedSub = 0;
        var CountyUntaggedSub = 0;

        for (var j=1; j<rows.length-1; j++) {
            var tds=rows[j].getElementsByTagName('td');

            // if on a duplicate row, alert user if no info; subtract if numbers there
            if (j == rows.length-2) {
                if (isNaN(parseFloat(tds[0].innerHTML))) {
                    tds[0].style.backgroundColor="#FF9999";
                    tds[0].title="Duplicate information needed!";
                } else {
                    Total = Total - parseFloat(tds[0].innerHTML.replace(/,/g,''));   // replace ignores commas in numbers>999
                }
                if (isNaN(parseFloat(tds[1].innerHTML))) {
                    tds[1].style.backgroundColor="#FF9999";
                    tds[1].title="Duplicate information needed!";
                } else {
                    TotalIllustrated = TotalIllustrated - parseFloat(tds[1].innerHTML.replace(/,/g,''));
                }
                if (isNaN(parseFloat(tds[3].innerHTML))) {
                    tds[3].style.backgroundColor="#FF9999";
                    tds[3].title="Duplicate information needed!";
                } else {
                    TotalArticled = TotalArticled - parseFloat(tds[3].innerHTML.replace(/,/g,''));
                }
                if (isNaN(parseFloat(tds[5].innerHTML))) {
                    tds[5].style.backgroundColor="#FF9999";
                    tds[5].title="Duplicate information needed!";
                } else {
                    TotalStubs = TotalStubs - parseFloat(tds[5].innerHTML.replace(/,/g,''));
                }
                if (isNaN(parseFloat(tds[6].innerHTML))) {
                    tds[6].style.backgroundColor="#FF9999";
                    tds[6].title="Duplicate information needed!";
                } else {
                    TotalNRISOnly = TotalNRISOnly - parseFloat(tds[6].innerHTML.replace(/,/g,''));
                }
                if (isNaN(parseFloat(tds[7].innerHTML))) {
                    tds[7].style.backgroundColor="#FF9999";
                    tds[7].title="Duplicate information needed!";
                } else {
                    TotalStartPlus = TotalStartPlus - parseFloat(tds[7].innerHTML.replace(/,/g,''));
                }
                if (isNaN(parseFloat(tds[9].innerHTML))) {
                    tds[9].style.backgroundColor="#FF9999";
                    tds[9].title="Duplicate information needed!";
                } else {
                    TotalUnassessed = TotalUnassessed - parseFloat(tds[9].innerHTML.replace(/,/g,''));
                }
                if (isNaN(parseFloat(tds[10].innerHTML))) {
                    tds[10].style.backgroundColor="#FF9999";
                    tds[10].title="Duplicate information needed!";
                } else {
                    TotalUntagged = TotalUntagged - parseFloat(tds[10].innerHTML.replace(/,/g,''));
                }
            }
            else {
                if (CountySub !== 0) {    // if inside county sublists, add to subtotal or subtract if duplicates
                    if (isNaN(parseFloat(tds[0].innerHTML))) {
                        if (tds[0].innerHTML.search("ddddd") != -1) {
                            if (isNaN(parseFloat(tds[3].innerHTML))) { // alert if no duplicates there
                                tds[3].style.backgroundColor="#FF9999";
                                tds[3].title="Duplicate information needed!";
                            } else {
                                CountySub = CountySub - parseFloat(tds[3].innerHTML.replace(/,/g,''));
                            }
                            if (isNaN(parseFloat(tds[4].innerHTML))) {
                                tds[4].style.backgroundColor="#FF9999";
                                tds[4].title="Duplicate information needed!";
                            } else {
                                CountyIllustratedSub = CountyIllustratedSub - parseFloat(tds[4].innerHTML.replace(/,/g,''));
                            }
                            if (isNaN(parseFloat(tds[6].innerHTML))) {
                                tds[6].style.backgroundColor="#FF9999";
                                tds[6].title="Duplicate information needed!";
                            } else {
                                CountyArticledSub = CountyArticledSub - parseFloat(tds[6].innerHTML.replace(/,/g,''));
                            }
                            if (isNaN(parseFloat(tds[8].innerHTML))) {
                                tds[8].style.backgroundColor="#FF9999";
                                tds[8].title="Duplicate information needed!";
                            } else {
                                CountyStubsSub = CountyStubsSub - parseFloat(tds[8].innerHTML.replace(/,/g,''));
                            }
                            if (isNaN(parseFloat(tds[9].innerHTML))) {
                                tds[9].style.backgroundColor="#FF9999";
                                tds[9].title="Duplicate information needed!";
                            } else {
                                CountyNRISOnlySub = CountyNRISOnlySub - parseFloat(tds[9].innerHTML.replace(/,/g,''));
                            }
                            if (isNaN(parseFloat(tds[10].innerHTML))) {
                                tds[10].style.backgroundColor="#FF9999";
                                tds[10].title="Duplicate information needed!";
                            } else {
                                CountyStartPlusSub = CountyStartPlusSub - parseFloat(tds[10].innerHTML.replace(/,/g,''));
                            }
                            if (isNaN(parseFloat(tds[12].innerHTML))) {
                                tds[12].style.backgroundColor="#FF9999";
                                tds[12].title="Duplicate information needed!";
                            } else {
                                CountyUnassessedSub = CountyUnassessedSub - parseFloat(tds[12].innerHTML.replace(/,/g,''));
                            }
                            if (isNaN(parseFloat(tds[13].innerHTML))) {
                                tds[13].style.backgroundColor="#FF9999";
                                tds[13].title="Duplicate information needed!";
                            } else {
                                CountyUntaggedSub = CountyUntaggedSub - parseFloat(tds[13].innerHTML.replace(/,/g,''));
                            }
                        }
                        else {
                            if (!isNaN(parseFloat(tds[3].innerHTML))) { // skip if blank
                                CountySub = CountySub + parseFloat(tds[3].innerHTML.replace(/,/g,''));
                            }
                            if (!isNaN(parseFloat(tds[4].innerHTML))) {
                                CountyIllustratedSub = CountyIllustratedSub + parseFloat(tds[4].innerHTML.replace(/,/g,''));
                            }
                            if (!isNaN(parseFloat(tds[6].innerHTML))) {
                                CountyArticledSub = CountyArticledSub + parseFloat(tds[6].innerHTML.replace(/,/g,''));
                            }
                            if (!isNaN(parseFloat(tds[8].innerHTML))) {
                                CountyStubsSub = CountyStubsSub + parseFloat(tds[8].innerHTML.replace(/,/g,''));
                            }
                            if (!isNaN(parseFloat(tds[9].innerHTML))) {
                                CountyNRISOnlySub = CountyNRISOnlySub + parseFloat(tds[9].innerHTML.replace(/,/g,''));
                            }
                            if (!isNaN(parseFloat(tds[10].innerHTML))) {
                                CountyStartPlusSub = CountyStartPlusSub + parseFloat(tds[10].innerHTML.replace(/,/g,''));
                            }
                            if (!isNaN(parseFloat(tds[12].innerHTML))) {
                                CountyUnassessedSub = CountyUnassessedSub + parseFloat(tds[12].innerHTML.replace(/,/g,''));
                            }
                            if (!isNaN(parseFloat(tds[13].innerHTML))) {
                                CountyUntaggedSub = CountyUntaggedSub + parseFloat(tds[13].innerHTML.replace(/,/g,''));
                            }
                        }
                    }
                    else {    // if now at end of county sublists, total up everything
                        var ScriptCountyPercentIllus = Math.round (CountyIllustratedSub/CountySub * 1000) / 10;
                        var ScriptCountyPercentArt = Math.round (CountyArticledSub/CountySub * 1000) / 10;
                        var ScriptCountyPercentStartPlus = Math.round (CountyStartPlusSub/CountySub * 1000) / 10;
                        var ScriptCountyNetQuality = CountyStartPlusSub+0.5*CountyStubsSub+0.5*CountyUnassessedSub;
                            ScriptCountyNetQuality = ScriptCountyNetQuality-0.5*CountyUntaggedSub-0.75*CountyNRISOnlySub;
                            ScriptCountyNetQuality = 0.75*ScriptCountyNetQuality/CountySub+0.25*CountyIllustratedSub/CountySub;
                            ScriptCountyNetQuality = Math.round(ScriptCountyNetQuality*1000)/10;
                        if (ScriptCountyNetQuality<0) ScriptCountyNetQuality = 0;

                        // check script output against what's entered
                        var EnteredCountyTotal = parseFloat(tds[3].innerHTML.replace(/,/g,''));
                        var EnteredCountyIllusTotal = parseFloat(tds[4].innerHTML.replace(/,/g,''));
                        var EnteredCountyPercentIllus = parseFloat(tds[5].innerHTML.replace(/,/g,''));
                        var EnteredCountyArtTotal = parseFloat(tds[6].innerHTML.replace(/,/g,''));
                        var EnteredCountyPercentArt = parseFloat(tds[7].innerHTML.replace(/,/g,''));
                        var EnteredCountyStubs = parseFloat(tds[8].innerHTML.replace(/,/g,''));
                        var EnteredCountyNRISOnly = parseFloat(tds[9].innerHTML.replace(/,/g,''));
                        var EnteredCountyStartPlus = parseFloat(tds[10].innerHTML.replace(/,/g,''));
                        var EnteredCountyPercentStartP = parseFloat(tds[11].innerHTML.replace(/,/g,''));
                        var EnteredCountyUnass = parseFloat(tds[12].innerHTML.replace(/,/g,''));
                        var EnteredCountyUntag = parseFloat(tds[13].innerHTML.replace(/,/g,''));
                        var EnteredCountyNetQuality = parseFloat(tds[14].innerHTML.replace(/,/g,''));

                        if (EnteredCountyTotal != CountySub && !isNaN(CountySub)) {
                           tds[3].style.backgroundColor="#FF9999";
                           tds[3].title="Script output: " + CountySub;
                        }
                        if (EnteredCountyIllusTotal != CountyIllustratedSub && !isNaN(CountyIllustratedSub)) {
                           tds[4].style.backgroundColor="#FF9999";
                           tds[4].title="Script output: " + CountyIllustratedSub;
                        }
                        if (EnteredCountyPercentIllus != ScriptCountyPercentIllus && !isNaN(ScriptCountyPercentIllus)) {
                           tds[5].style.backgroundColor="#FF9999";
                           tds[5].title="Script output: " + ScriptCountyPercentIllus + "%";
                        }
                        if (EnteredCountyArtTotal != CountyArticledSub && !isNaN(CountyArticledSub)) {
                           tds[6].style.backgroundColor="#FF9999";
                           tds[6].title="Script output: " + CountyArticledSub;
                        }
                        if (EnteredCountyPercentArt != ScriptCountyPercentArt && !isNaN(ScriptCountyPercentArt)) {
                           tds[7].style.backgroundColor="#FF9999";
                           tds[7].title="Script output: " + ScriptCountyPercentArt + "%";
                        }
                        if (EnteredCountyStubs != CountyStubsSub && !isNaN(CountyStubsSub)) {
                           tds[8].style.backgroundColor="#FF9999";
                           tds[8].title="Script output: " + CountyStubsSub;
                        }
                        if (EnteredCountyNRISOnly != CountyNRISOnlySub && !isNaN(CountyNRISOnlySub)) {
                           tds[9].style.backgroundColor="#FF9999";
                           tds[9].title="Script output: " + CountyNRISOnlySub;
                        }
                        if (EnteredCountyStartPlus != CountyStartPlusSub && !isNaN(CountyStartPlusSub)) {
                           tds[10].style.backgroundColor="#FF9999";
                           tds[10].title="Script output: " + CountyStartPlusSub;
                        }
                        if (EnteredCountyPercentStartP != ScriptCountyPercentStartPlus && !isNaN(ScriptCountyPercentStartPlus)) {
                           tds[11].style.backgroundColor="#FF9999";
                           tds[11].title="Script output: " + ScriptCountyPercentStartPlus + "%";
                        }
                        if (EnteredCountyUnass != CountyUnassessedSub && !isNaN(CountyUnassessedSub)) {
                           tds[12].style.backgroundColor="#FF9999";
                           tds[12].title="Script output: " + CountyUnassessedSub;
                        }
                        if (EnteredCountyUntag != CountyUntaggedSub && !isNaN(CountyUntaggedSub)) {
                           tds[13].style.backgroundColor="#FF9999";
                           tds[13].title="Script output: " + CountyUntaggedSub;
                        }
                        if (EnteredCountyNetQuality != ScriptCountyNetQuality && !isNaN(ScriptCountyNetQuality)) {
                           tds[14].style.backgroundColor="#FF9999";
                           tds[14].title="Script output: " + CountyUntaggedSub;
                        }

                        // update total then reset subtotals
                        Total = Total + CountySub;
                        TotalIllustrated = TotalIllustrated + CountyIllustratedSub;
                        TotalArticled = TotalArticled + CountyArticledSub;
                        TotalStubs = TotalStubs + CountyStubsSub;
                        TotalNRISOnly = TotalNRISOnly + CountyNRISOnlySub;
                        TotalStartPlus = TotalStartPlus + CountyStartPlusSub;
                        TotalUnassessed = TotalUnassessed + CountyUnassessedSub;
                        TotalUntagged = TotalUntagged + CountyUntaggedSub;

                        CountySub = 0;
                        CountyIllustratedSub = 0;
                        CountyArticledSub = 0;
                        CountyStubsSub = 0;
                        CountyNRISOnlySub = 0;
                        CountyStartPlusSub = 0;
                        CountyUnassessedSub = 0;
                        CountyUntaggedSub = 0;
                    }
                }
                else {   // regular counties
                    if (isNaN(parseFloat(tds[0].innerHTML)) && tds.length == 15) { // if first in line of sublists, begin subtotal
                        if (!isNaN(parseFloat(tds[tds.length-12].innerHTML))) {
                            CountySub = parseFloat(tds[tds.length-12].innerHTML.replace(/,/g,''));
                        }
                        if (!isNaN(parseFloat(tds[tds.length-11].innerHTML))) {
                            CountyIllustratedSub = parseFloat(tds[tds.length-11].innerHTML.replace(/,/g,''));
                        }
                        if (!isNaN(parseFloat(tds[tds.length-9].innerHTML))) {
                            CountyArticledSub = parseFloat(tds[tds.length-9].innerHTML.replace(/,/g,''));
                        }
                        if (!isNaN(parseFloat(tds[tds.length-7].innerHTML))) {
                            CountyStubsSub = parseFloat(tds[tds.length-7].innerHTML.replace(/,/g,''));
                        }
                        if (!isNaN(parseFloat(tds[tds.length-6].innerHTML))) {
                            CountyNRISOnlySub = parseFloat(tds[tds.length-6].innerHTML.replace(/,/g,''));
                        }
                        if (!isNaN(parseFloat(tds[tds.length-5].innerHTML))) {
                            CountyStartPlusSub = parseFloat(tds[tds.length-5].innerHTML.replace(/,/g,''));
                        }
                        if (!isNaN(parseFloat(tds[tds.length-3].innerHTML))) {
                            CountyUnassessedSub = parseFloat(tds[tds.length-3].innerHTML.replace(/,/g,''));
                        }
                        if (!isNaN(parseFloat(tds[tds.length-2].innerHTML))) {
                            CountyUntaggedSub = parseFloat(tds[tds.length-2].innerHTML.replace(/,/g,''));
                        }
                    }
                    else {
                        var RowTotal = parseFloat(tds[tds.length-12].innerHTML.replace(/,/g,''));
                        if (!isNaN(RowTotal)) Total = Total + RowTotal;                                    // skip if blank
                        var RowIllustrated = parseFloat(tds[tds.length-11].innerHTML.replace(/,/g,''));
                        if (!isNaN(RowIllustrated)) TotalIllustrated = TotalIllustrated + RowIllustrated;
                        var RowArticled = parseFloat(tds[tds.length-9].innerHTML.replace(/,/g,''));
                        if (!isNaN(RowArticled)) TotalArticled = TotalArticled + RowArticled;
                        var RowStubs = parseFloat(tds[tds.length-7].innerHTML.replace(/,/g,''));
                        if (!isNaN(RowStubs)) TotalStubs = TotalStubs + RowStubs;
                        var RowNRISOnly = parseFloat(tds[tds.length-6].innerHTML.replace(/,/g,''));
                        if (!isNaN(RowNRISOnly)) TotalNRISOnly = TotalNRISOnly + RowNRISOnly;
                        var RowStartPlus = parseFloat(tds[tds.length-5].innerHTML.replace(/,/g,''));
                        if (!isNaN(RowStartPlus)) TotalStartPlus = TotalStartPlus + RowStartPlus;
                        var RowUnassessed = parseFloat(tds[tds.length-3].innerHTML.replace(/,/g,''));
                        if (!isNaN(RowUnassessed)) TotalUnassessed = TotalUnassessed + RowUnassessed;
                        var RowUntagged = parseFloat(tds[tds.length-2].innerHTML.replace(/,/g,''));
                        if (!isNaN(RowUntagged)) TotalUntagged = TotalUntagged + RowUntagged;

                        // check script against what's entered
                        EnteredPercentIllustrated = parseFloat(tds[tds.length-10].innerHTML.replace(/,/g,''));
                        var ScriptPercentIllustrated = Math.round(RowIllustrated/RowTotal*1000)/10;
                        EnteredPercentArticled = parseFloat(tds[tds.length-8].innerHTML.replace(/,/g,''));
                        var ScriptPercentArticled = Math.round(RowArticled/RowTotal*1000)/10;
                        EnteredPercentStartPlus = parseFloat(tds[tds.length-4].innerHTML.replace(/,/g,''));
                        var ScriptPercentStartPlus = Math.round(RowStartPlus/RowTotal*1000)/10;
                        EnteredNetQuality = parseFloat(tds[tds.length-1].innerHTML.replace(/,/g,''));
                        var ScriptNetQuality = RowStartPlus+0.5*RowStubs+0.5*RowUnassessed-0.5*RowUntagged-0.75*RowNRISOnly;
                            ScriptNetQuality = Math.round((0.75*ScriptNetQuality/RowTotal+0.25*RowIllustrated/RowTotal)*1000)/10;
                        if (ScriptNetQuality<0) ScriptNetQuality=0;

                        if (EnteredPercentIllustrated != ScriptPercentIllustrated && !isNaN(ScriptPercentIllustrated)) {
                            tds[tds.length-8].style.backgroundColor="#FF9999";
                            tds[tds.length-8].title="Script output: " + ScriptPercentIllustrated + "%";
                        }
                        if (EnteredPercentArticled != ScriptPercentArticled && !isNaN(ScriptPercentArticled)) {
                            tds[tds.length-6].style.backgroundColor="#FF9999";
                            tds[tds.length-6].title="Script output: " + ScriptPercentArticled + "%";
                        }
                        if (EnteredPercentStartPlus != ScriptPercentStartPlus && !isNaN(ScriptPercentStartPlus)) {
                            tds[tds.length-3].style.backgroundColor="#FF9999";
                            tds[tds.length-3].title="Script output: " + ScriptPercentStartPlus + "%";
                        }
                        if (EnteredNetQuality != ScriptNetQuality && !isNaN(ScriptNetQuality)) {
                            tds[tds.length-1].style.backgroundColor="#FF9999";
                            tds[tds.length-1].title="Script output: " + ScriptNetQuality + "%";
                        }
                    }
                }
            }
        }

        // output totals for each state in yellow box
        var ScriptTotalPercentIllustrated = Math.round(TotalIllustrated/Total*1000)/10;
        var ScriptTotalPercentArticled = Math.round(TotalArticled/Total*1000)/10;
        var ScriptTotalPercentStartPlus = Math.round(TotalStartPlus/Total*1000)/10;
        var ScriptTotalNetQuality = TotalStartPlus+0.5*TotalStubs+0.5*TotalUnassessed-0.5*TotalUntagged-0.75*TotalNRISOnly;
            ScriptTotalNetQuality = Math.round((0.75*ScriptTotalNetQuality/Total+0.25*TotalIllustrated/Total)*1000)/10;
        if (ScriptTotalNetQuality<0) ScriptTotalNetQuality = 0;

        var str = "<b>Total Listings:</b> " + Total;
            str = str + "<br /><b>No. Illustrated:</b> " + TotalIllustrated + " (" + ScriptTotalPercentIllustrated;
            str = str + "%)<br /><b>No. Articled:</b> " + TotalArticled + " (" + ScriptTotalPercentArticled + "%)";
            str = str + "<br /><b>No. Stubs:</b> " + TotalStubs + "<br /><b>No. NRIS-only:</b> "+TotalNRISOnly;
            str = str + "<br /><b>No. Start+:</b> " + TotalStartPlus + " (" + ScriptTotalPercentStartPlus;
            str = str + "%)<br /><b>No. Unassessed:</b> " + TotalUnassessed + "<br /><b>No. Untagged:</b> " + TotalUntagged;
            str = str + "<br /><b>Net Quality Rating:</b> " + ScriptTotalNetQuality + "%";

		var disp = table[i].previousSibling;
    	var needYellowBox = true;
    	if (disp !== null && (disp.nodeName === 'div' || disp.nodeName==='DIV')) {
    		if (!disp.hasAttributes || !disp.hasAttribute('class') || disp.getAttribute('class') !== 'NRHPdisp') {
    			// DIV found, but it's not ours, so disp is wrong
        		//console.log('NRHPStats: DIV found, does not have NRHPdisp class');
    			needYellowBox = true;
    		} else {
    			// our DIV found, disp is set to it
        		//console.log('NRHPStats: DIV found');
    			needYellowBox = false;
    		}
    	} else {
    		// DIV not found, so disp is wrong
    		//if (disp !== null) {
    		//	console.log('NRHPStats: Node found, nodeName='+disp.nodeName);
    		//}
    		//console.log('NRHPStats: DIV not found');
    		needYellowBox = true;
    	}
		if (needYellowBox) {
	        disp = document.createElement( 'div' );

    	    disp.setAttribute('style', 'font-size:125%; background-color:yellow; width:240px; padding:5px');
        	disp.setAttribute('class', 'NRHPdisp');
        	table[i].parentNode.insertBefore(disp , table[i]);
		}
        disp.innerHTML = str;

        // check script totals against what's entered
        var Totaltds=rows[rows.length-1].getElementsByTagName('th');
        var EnteredTotal = parseFloat(Totaltds[1].innerHTML.replace(/,/g,''));
        var EnteredTotalIllustrated = parseFloat(Totaltds[2].innerHTML.replace(/,/g,''));
        EnteredPercentIllustrated = parseFloat(Totaltds[3].innerHTML.replace(/,/g,''));
        var EnteredTotalArticled = parseFloat(Totaltds[4].innerHTML.replace(/,/g,''));
        EnteredPercentArticled = parseFloat(Totaltds[5].innerHTML.replace(/,/g,''));
        var EnteredStubs = parseFloat(Totaltds[6].innerHTML.replace(/,/g,''));
        var EnteredNRISOnly = parseFloat(Totaltds[7].innerHTML.replace(/,/g,''));
        var EnteredStartPlus = parseFloat(Totaltds[8].innerHTML.replace(/,/g,''));
        EnteredPercentStartPlus = parseFloat(Totaltds[9].innerHTML.replace(/,/g,''));
        var EnteredUnassessed = parseFloat(Totaltds[10].innerHTML.replace(/,/g,''));
        var EnteredUntagged = parseFloat(Totaltds[11].innerHTML.replace(/,/g,''));
        EnteredNetQuality = parseFloat(Totaltds[12].innerHTML.replace(/,/g,''));

        if (EnteredTotal != Total && !isNaN(Total)) {
           Totaltds[1].style.backgroundColor="#FF9999";
           Totaltds[1].title="Script output: " + Total;
        }
        if (EnteredTotalIllustrated != TotalIllustrated && !isNaN(TotalIllustrated)) {
           Totaltds[2].style.backgroundColor="#FF9999";
           Totaltds[2].title="Script output: " + TotalIllustrated;
        }
        if (EnteredPercentIllustrated != ScriptTotalPercentIllustrated && !isNaN(ScriptTotalPercentIllustrated)) {
           Totaltds[3].style.backgroundColor="#FF9999";
           Totaltds[3].title="Script output: " + ScriptTotalPercentIllustrated + "%";
        }
        if (EnteredTotalArticled != TotalArticled && !isNaN(TotalArticled)) {
           Totaltds[4].style.backgroundColor="#FF9999";
           Totaltds[4].title="Script output: " + TotalArticled;
        }
        if (EnteredPercentArticled != ScriptTotalPercentArticled && !isNaN(ScriptTotalPercentArticled)) {
           Totaltds[5].style.backgroundColor="#FF9999";
           Totaltds[5].title="Script output: " + ScriptTotalPercentArticled + "%";
        }
        if (EnteredStubs != TotalStubs && !isNaN(TotalStubs)) {
           Totaltds[6].style.backgroundColor="#FF9999";
           Totaltds[6].title="Script output: " + TotalStubs;
        }
        if (EnteredNRISOnly != TotalNRISOnly && !isNaN(TotalNRISOnly)) {
           Totaltds[7].style.backgroundColor="#FF9999";
           Totaltds[7].title="Script output: " + TotalNRISOnly;
        }
        if (EnteredStartPlus != TotalStartPlus && !isNaN(TotalStartPlus)) {
           Totaltds[8].style.backgroundColor="#FF9999";
           Totaltds[8].title="Script output: " + TotalStartPlus;
        }
        if (EnteredPercentStartPlus != ScriptTotalPercentStartPlus && !isNaN(ScriptTotalPercentStartPlus)) {
           Totaltds[9].style.backgroundColor="#FF9999";
           Totaltds[9].title="Script output: " + ScriptTotalPercentStartPlus + "%";
        }
        if (EnteredUnassessed != TotalUnassessed && !isNaN(TotalUnassessed)) {
           Totaltds[10].style.backgroundColor="#FF9999";
           Totaltds[10].title="Script output: " + TotalUnassessed;
        }
        if (EnteredUntagged != TotalUntagged && !isNaN(TotalUntagged)) {
           Totaltds[11].style.backgroundColor="#FF9999";
           Totaltds[11].title="Script output: " + TotalUntagged;
        }
        if (EnteredNetQuality != ScriptTotalNetQuality && !isNaN(ScriptTotalNetQuality)) {
           Totaltds[12].style.backgroundColor="#FF9999";
           Totaltds[12].title="Script output: " + ScriptTotalNetQuality + "%";
        }

        // check national table against what's entered in each state table
        if (i !== 0) {
            var StateRows = table[0].getElementsByTagName('tr');
            var ThisStateRow = StateRows[i].getElementsByTagName('td');

            var StateTableTotal = parseFloat(ThisStateRow[1].innerHTML.replace(/,/g,''));
            var StateTableIllustrated = parseFloat(ThisStateRow[2].innerHTML.replace(/,/g,''));
            var StateTablePercentIllustrated = parseFloat(ThisStateRow[3].innerHTML.replace(/,/g,''));
            var StateTableArticled = parseFloat(ThisStateRow[4].innerHTML.replace(/,/g,''));
            var StateTablePercentArticled = parseFloat(ThisStateRow[5].innerHTML.replace(/,/g,''));
            var StateTableStubs = parseFloat(ThisStateRow[6].innerHTML.replace(/,/g,''));
            var StateTableNRISOnly = parseFloat(ThisStateRow[7].innerHTML.replace(/,/g,''));
            var StateTableStartPlus = parseFloat(ThisStateRow[8].innerHTML.replace(/,/g,''));
            var StateTablePercentStartPlus = parseFloat(ThisStateRow[9].innerHTML.replace(/,/g,''));
            var StateTableUnassessed = parseFloat(ThisStateRow[10].innerHTML.replace(/,/g,''));
            var StateTableUntagged = parseFloat(ThisStateRow[11].innerHTML.replace(/,/g,''));
            var StateTableNetQuality = parseFloat(ThisStateRow[12].innerHTML.replace(/,/g,''));

            if (EnteredTotal != StateTableTotal) {
               ThisStateRow[1].style.backgroundColor="#FF9999";
               ThisStateRow[1].title="Does not match table below! (" + EnteredTotal + ")";
            }
            if (EnteredTotalIllustrated != StateTableIllustrated) {
               ThisStateRow[2].style.backgroundColor="#FF9999";
               ThisStateRow[2].title="Does not match table below! (" + EnteredTotalIllustrated + ")";
            }
            if (EnteredPercentIllustrated != StateTablePercentIllustrated) {
               ThisStateRow[3].style.backgroundColor="#FF9999";
               ThisStateRow[3].title="Does not match table below! (" + EnteredPercentIllustrated + "%)";
            }
            if (EnteredTotalArticled != StateTableArticled) {
               ThisStateRow[4].style.backgroundColor="#FF9999";
               ThisStateRow[4].title="Does not match table below! (" + EnteredTotalArticled + ")";
            }
            if (EnteredPercentArticled != StateTablePercentArticled) {
               ThisStateRow[5].style.backgroundColor="#FF9999";
               ThisStateRow[5].title="Does not match table below! (" + EnteredPercentArticled + "%)";
            }
            if (EnteredStubs != StateTableStubs) {
               ThisStateRow[6].style.backgroundColor="#FF9999";
               ThisStateRow[6].title="Does not match table below! (" + EnteredStubs + ")";
            }
            if (EnteredNRISOnly != StateTableNRISOnly) {
               ThisStateRow[7].style.backgroundColor="#FF9999";
               ThisStateRow[7].title="Does not match table below! (" + EnteredNRISOnly + ")";
            }
            if (EnteredStartPlus != StateTableStartPlus) {
               ThisStateRow[8].style.backgroundColor="#FF9999";
               ThisStateRow[8].title="Does not match table below! (" + EnteredStartPlus + ")";
            }
            if (EnteredPercentStartPlus != StateTablePercentStartPlus) {
               ThisStateRow[9].style.backgroundColor="#FF9999";
               ThisStateRow[9].title="Does not match table below! (" + EnteredPercentStartPlus + "%)";
            }
            if (EnteredUnassessed != StateTableUnassessed) {
               ThisStateRow[10].style.backgroundColor="#FF9999";
               ThisStateRow[10].title="Does not match table below! (" + EnteredUnassessed + ")";
            }
            if (EnteredUntagged != StateTableUntagged) {
               ThisStateRow[11].style.backgroundColor="#FF9999";
               ThisStateRow[11].title="Does not match table below! (" + EnteredUntagged + ")";
            }
            if (EnteredNetQuality != StateTableNetQuality) {
               ThisStateRow[12].style.backgroundColor="#FF9999";
               ThisStateRow[12].title="Does not match table below! (" + EnteredNetQuality + ")";
            }
        }
    }
}

function getNRHPstatsWikitext(title) {
    $.ajax({
        dataType: "json",
        url: mw.util.wikiScript('api'),
        data: {
            format: 'json',
            action: 'query',
            prop: 'revisions',
            rvprop: 'content',
            rvslots: 'main',
            titles: title,
            indexpageids: true,
            redirects: 'true'
        },
        success: function (data, status, xhr) {
        	var response = xhr.responseText;
        	//console.log("NRHPstats: response to initial fetch: "+response);
        	var output = JSON.parse(response);
        	var wikitext = "error";
        	var id;
		    for (var page in output.query.pageids) {
		    	id = output.query.pageids[page];
	        	//console.log('NRHPstats: response pageid = '+id);
		        wikitext = output.query.pages[id].revisions[0].slots.main['*'];
		    }
		    FetchedNRHPstatsWikitext(wikitext);
        },
        error: function(ArticlejsonObject) {
        	console.log('NRHPstats: Error fetching title '+title);
			FetchedNRHPstatsWikitext("error");
        }
    });
}

// activate when document is ready
$.when($.ready).then(Shell);