            var rowheaders = 2;
            var groupsize = 3;
            var groups = 4;
            var grouped = { 0: [], 1: [], 2: [], 3: [] };
            var groupcheck = { 0: "", 1: "", 2: "", 3: "" };
            var topheaders = ["AGILE","IMPORTANT","APPLIED","AGILE vs. IMPORTANT vs. APPLIED"];
            var headers = [];
            $(function() {
                // columns
                var headerels = $("#tbaps thead tr:last th");
                headers = headerels.map(function(){
                    return $(this).text().replace(/[ \.]/g,"");
                });
                $.each(topheaders,function(i,s) {
                    $("#columns .calced").append("<span class='groupspan'><input type='checkbox' checked='checked' class='grc' name='g" + i + "c' id='g" + i + "c' /> <label for='g" + i + "c'>" + s + "</label></span><div id='group" + i + "' class='group'></div>");
                });
                headerels.each(function(i){
                    if ( i > (rowheaders-1) ) {
                        var groupno = Math.floor((i-rowheaders)/groupsize);
                        var group = grouped[groupno];
                        group[group.length] = headers[i];
                        $(this).addClass(headers[i]);
                        $("#columns .calced #group" + groupno).append("<span class='columnspan'><input type='checkbox' checked='checked' name='" + headers[i] + "' id='" + headers[i] + "'/> <label for='" + headers[i] + "'>" + $(this).text() + "</label></span>");
                    }
                });

                $("#tbaps tbody tr").each(function() {
                    $(this).addClass($(this).find("th:first").text());
                    
                    $(this).find("td").each(function(i) {
                       $(this).addClass(headers[i+rowheaders]);
                    });
                });

                $("#tbaps").tablesorter();
                
                $("#tbaps thead").prepend('<tr id="theader"><th scope="colgroup" colspan="2">The Big Agile Practices Survey (www.noop.nl)</th><th id="g0" scope="colgroup" colspan="3">AGILE</th><th id="g1" scope="colgroup" colspan="3">IMPORTANT</th><th id="g2" scope="colgroup" colspan="3">APPLIED</th><th id="g3" scope="colgroup" colspan="3">AGILE vs. IMPORTANT vs. APPLIED</th></tr>');

                for (var k = 0; k < groups; k++ ) {
                    groupcheck[k] = $.map(grouped[k],function(s){ return "#columns th." + s + ":visible"; }).join(", ");
                }

                // hook up
                $("#columns .calced .group input").click(function(){
                    checkChanged(this);
                    checkGroups();
                    tidyUp();
                });
                $("#columns .calced input.grc").click(function(){
                    $("#" + this.id.slice(0,2).replace("g","group") + " input").attr("checked",this.checked).each(function(){
                        checkChanged(this);
                    });
                    checkGroups();
                    tidyUp();
                });


                // areas
                var areas = [];
                $("#tbaps tbody tr").find("th:first").each(function(){
                    var area = $(this).text();
                    if ( $.inArray(area,areas) == -1 ) {
                        areas[areas.length] = area;
                        $("#areas .calced").append("<input type='checkbox' checked='checked' name='" + area + "' id='" + area + "'/> <label for='" + area + "'>" + area + "</label>");
                    }
                });
                $("#areas .fixed").append("<a href='javascript:flipAreas(true)'>all</a> <a href='javascript:flipAreas(false)'>none</a>");

                // highlighting percentage ranges
                $("#colours").append("<input type='checkbox' name='colours' id='colourbypercentage'/> <label for='colourbypercentage'>percentage ranges:</label> <div id='percentageranges'></div>");
                
                var colourgroups = ["colourbyarea","colourbypercentage"];
                var percentageranges = [];
                $("#tbaps tbody td").each(function(){
                    var pr = Math.floor(parseInt($(this).text().replace("%",""))/10)*10;
                    if ($.inArray( pr, percentageranges ) == -1) {
                        percentageranges[percentageranges.length]=pr;
                    }
                    $(this).addClass("p" + pr);
                });

                $.each(percentageranges.sort(function(a,b){return a==b?0:(a<b?-1:1);}),function(i,pr){
                    var prlabel = "" + pr + "%" + ((pr==100)?"":"...");    //("-" + (pr+9.9) + "%"));
                
                    $("#percentageranges").append("<span id='spr"+ pr + "'><input type='checkbox' name='pr" +  pr + "' id='pr" + pr + "'/> <label for='pr" + pr + "'>" + prlabel + "</label></span>");
                });

                $("#colourbypercentage").click(function(){
                    var tchecked = this.checked;
                    $("#percentageranges input").each(function(){
                        this.checked = tchecked;
                        updatePercentageRangeClass(!this.checked,this.id);
                    });
                    tidyUp();
                });

                $("#percentageranges input").click(function() {
                    updatePercentageRangeClass(!this.checked,this.id);
                    $("#colourbypercentage").attr("checked", ($("#percentageranges input:checked").length > 0?"checked":""));
                    tidyUp();
                });
                
                $("#colourbypercentage")[0].click();
                
                // hook up
                $("#areas .calced input").click(function(){
                    checkChanged(this);
                    tidyUp();
                });
                
                tidyUp();
                $("#filters").css("display","block");

                if ( $("body").width() < $("#tbaps").width() ) {
                    $("#notenoughwidth").css("display","block");
                }
            }); 
            
            function updatePercentageRangeClass(remove,className){
                if ( remove ) {
                    $("#tbaps").removeClass(className);
                } else {
                    $("#tbaps").addClass(className);
                }
            }
            
            function checkGroups() {
                for (var k=0; k < groups; k++ ) {
                    var colspan = $(groupcheck[k]).length;
                    if (colspan == 0) {
                        $("#g" + k).hide(); //.attr("colSpan",0);
                        $("#g" + k + "c").attr("checked",false);
                    } else {
                        $("#g" + k).show().attr("colSpan",colspan);
                        $("#g" + k + "c").attr("checked",true);
                    }
                }
            }
            
            function tidyUp() {
                $("form input").each(function(){
                    $("label[for='" + this.id + "']").css("font-weight",this.checked?"bold":"normal")
                });
            }
            
            function checkChanged(t) {
                if (t.checked) {
                    $("." + t.id).show();
                } else {
                    $("." + t.id).hide();
                }
            }
            
            function flipAreas(checked) {
                $("#areas .calced input").each(function(){
                    this.checked = checked;
                    checkChanged(this);
                });
                tidyUp();
            }
            
            function showColumns(showAll,changeShowAll,prefix,prefixShow) {
                var all = $("#columns .calced .group input");
                if ( changeShowAll ) {
                    all.attr("checked", (showAll?"checked":"") );
                }
                if ( prefix != "" ) {
                    $("#columns .calced .group input[id^='" + prefix + "']").attr("checked",(prefixShow?"checked":""));
                }
                all.each(function(){
                    checkChanged(this);
                });
                checkGroups();
                tidyUp();
            }

            function levelOnly(show) {
                showColumns(false,true,"level",show);
            }
            function agreementOnly(show) {
                showColumns(false,true,"agreement",show);
            }
            function confidenceOnly(show) {
                showColumns(false,true,"confidence",show);
            }
            function levelNone(show) {
                showColumns(true,false,"level",show);
            }
            function agreementNone(show) {
                showColumns(true,false,"agreement",show);
            }
            function confidenceNone(show) {
                showColumns(true,false,"confidence",show);
            }
            function showAllColumns(show) {
                showColumns(show,true,"",true);
            }

