Scouts Membership System (UK) Tweaks

Provide a few tweaks including a role compliance report to the Scouts Website

当前为 2025-06-13 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Scouts Membership System (UK) Tweaks
// @description  Provide a few tweaks including a role compliance report to the Scouts Website
// @namespace    http://tampermonkey.net/
// @version      100000035
// @author       David Breakwell
// @match        https://membership.scouts.org.uk/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=scouts.org.uk
// @grant  GM_xmlhttpRequest
// @grant GM_getResourceURL
// @grant GM_getResourceText
// @grant GM_addStyle
// @grant GM_notification
// @grant GM_log
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_getResourceURL
// @run-at      document-idle
// @require     http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js
// @require     http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/jquery-ui.min.js
// @require     https://cdnjs.cloudflare.com/ajax/libs/gojs/3.0.17/go.js
// @require     https://unpkg.com/[email protected]/dist/leaflet.js
// @require     https://cdn.jsdelivr.net/npm/[email protected]/dist/xlsx.min.js

// @require     https://unpkg.com/[email protected]/dist/js/tabulator.min.js
// @require     https://cdn.jsdelivr.net/npm/[email protected]/build/global/luxon.min.js
// @resource    jqUI_CSS  http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/jquery-ui.css
// @resource    leaf https://unpkg.com/[email protected]/dist/leaflet.css
// @resource    IconSet1  http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/images/ui-icons_222222_256x240.png
// @resource    IconSet2  http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/images/ui-icons_454545_256x240.png
// @resource    LeafletPin  https://unpkg.com/[email protected]/dist/images/marker-icon.png
// @resource    LeafletShadow   https://unpkg.com/[email protected]/dist/images/marker-shadow.png
// @resource    tabulator https://unpkg.com/[email protected]/dist/css/tabulator.min.css
// @connect tsa-memportal-prod-fun01.azurewebsites.net
// @connect tsauksprodasa001.blob.core.windows.net
// @connect tsauksprodasa001.table.core.windows.net
// @connect api.postcodes.io
// @connect learn.scouts.org.uk
// @license MIT
// ==/UserScript==
//     https://cdn.sheetjs.com/xlsx-0.20.3/package/dist/xlsx.full.min.js
var code_version = "100000035";
var mem = [{}];
var mems= [];
var mapmems= [];
var memsunique = [];
var roles = [];
var role_detail = [];
var dbs_detail = [];
var mem_learning= [];
var learn = [];
var mem_lcount;
var role_max_count;
var respond = false;
var end = false;
var un="";
var debug = false;
var keepalive = null;
var orgcounter = 0;
var myDiagram;
var postcode_regex = new RegExp("[A-Za-z]{1,2}[0-9Rr][0-9A-Za-z]? ?[0-9][ABD-HJLNP-UW-Zabd-hjlnp-uw-z]{2}")
var mappin = {};
var map = {};
var mapunits = [];
var postcodes = [];
var defcolors=['#fafad2','#ffe4b5','#ffa07a','#ff6347'];
var defcolorsT=['#000000','#000000','#000000','#000000'];
var colors=['#fafad2','#ffe4b5','#ffa07a','#ff6347'];
var colorsT=['#000000','#000000','#000000','#000000'];
var colormeanings = ["90 Days","60 Days","30 Days","Expired"];
var daylimits = [90,60,30,0,-9999999];
var tabletabulator
var added_css = false;
var added_default = false;

(function() {
    'use strict';
    function do_move() {
        console.log(document.getElementById("member-nav").value);
    }
    function dopage() {
        //    if(window.location.href.indexOf("subunitsau")!=-1) {

        setTimeout(function() {
            console.log("After Wait");
            console.log(window.location.href );
            if ((window.location.href == "https://membership.scouts.org.uk/")||(window.location.href == "https://membership.scouts.org.uk/#/")) {
                console.log("Homepage");
                if (document.getElementById("member-nav-list")==null){
                    var gotolist="<datalist id='member-nav-list'><option value='Add a New Member'></option>";
                    gotolist+="<option value='My Units'></option>";
                    gotolist+="</datalist>";

                    gotolist ='<label for="member-nav" style="font-size: 1.5em;font-weight: 600">What do you want to do?&nbsp;</label>' + gotolist;
                    gotolist += '<input style="width: 50%; font-size: 1.5em "list="member-nav-list" id="member-nav" name="member-nav-choice" onchange="do_move"/>';
                    if( document.getElementById("title")!=null) {

                        if (document.getElementById("quick_nav")==null) {
                            gotolist = '<div id="quick_nav">'+gotolist+'</div>';
                            //      document.getElementById("title").outerHTML += (gotolist);

                        } else
                        {
                            //      document.getElementById("quick_nav").innerHTML = (gotolist);
                        }
                    } // title

                } // already dispalyed
            }
            if (window.location.href.indexOf("subunitsau") != -1) {
                //document.body.appendChild(button);
                var htmlToInsert;
                htmlToInsert = '<span id="DavesnewText"><p>There are <a href="';
                htmlToInsert += window.location.href.substring(0, window.location.href.indexOf("subunitsau"));
                htmlToInsert += 'teamsau"><span id="teamcounter"></span></a> Teams at this level</p><span><span id="DavesList"><span>';
                //console.log(document.getElementById("header-main-title-all-units-grid"));

                GM_xmlhttpRequest({
                    method: "POST",
                    url: "https://tsa-memportal-prod-fun01.azurewebsites.net/api/UnitTeamsAndRolesListingAsync",
                    data: '{"unitId" : "' + window.location.href.substring(window.location.href.indexOf("allunits/") + 9, window.location.href.indexOf("subunitsau") - 1) + '", "type" : "team"}',
                    headers: {
                        "Content-Type": "application/json",
                        "Authorization": "Bearer " + JSON.parse(localStorage.getItem("authInfo")).idToken,
                        "Accept": "application/json, text/plain, */*"
                    },
                    onload: function(response) {
                        //    console.log("gut response");
                        //    console.log(response.responseText);
                        //    console.log(JSON.parse(response.responseText));
                        if (JSON.parse(response.responseText).teams.length > 1) {
                            document.getElementById("teamcounter").innerHTML = JSON.parse(response.responseText).teams.length;
                        } else {
                            htmlToInsert = '<p>There is <a href="';
                            htmlToInsert += window.location.href.substring(0, window.location.href.indexOf("subunitsau"));
                            htmlToInsert += 'teamsau/' + JSON.parse(response.responseText).teams[0].teamId + "/teamdashboardaut";
                            htmlToInsert += '"><span id="teamcounter">1</span></a> Team at this level</p>';
                            document.getElementById("DavesnewText").innerHTML = (htmlToInsert);
                        }
                        var elements = document.querySelectorAll('[id^=grid-unit]');
                        var elements2 = document.querySelectorAll('[id^=grid-parentUnit]');
                        for (var loop = 0; loop < elements.length; loop++) {
                            var htmlToInsert2 = '<a href="';
                            htmlToInsert2 += elements[loop].href.substring(0, elements[loop].href.indexOf("subunitsau"));
                            htmlToInsert2 += 'teamsau">&nbsp;&nbsp;&nbsp;<strong style=" display: inline-block;  width: 40px; height: 40px;line-height: 40px;text-align: center; background-color: #007bff;  cursor:pointer; color: white; border-color: #007bff; border-radius: 50%;font-size: 20px;font-weight: bold;">T</strong></a>';
                            elements2[loop].outerHTML += htmlToInsert2;
                        }
                    }
                }); // End of request
                document.getElementById("header-main-title-all-units-grid").innerHTML += (htmlToInsert);
                var button = document.createElement("Button");
                button.innerHTML = "Add a Member";
                button.onclick = () => {

                    window.open(window.location.href.substring(0, window.location.href.indexOf("subunitsau")) + "unitdetailsau/addmemberau", "_self");
                };
                button.style = "background: rgb(0, 97, 205);font-weight: 700;font-family: 'Nunito Sans';font-size: 20px;line-height: 1.5;color: white;min-height: 46px;max-width: 215px; cursor:pointer;vertical-align: middle;padding: 8px 24px;border-color: #007bff;";
                document.getElementById("header-main-title-all-units-grid").appendChild(button);

            }
        })

        if (window.location.href.indexOf("teamdashboardaut") != -1) {
            setTimeout(function() {
                var button = document.createElement("Button");
                button.innerHTML = "Add a Member";
                button.onclick = () => {

                    window.open(window.location.href.substring(0, window.location.href.indexOf("teamsau")) + "unitdetailsau/addmemberau", "_self");
                };
                button.style = "background: rgb(0, 97, 205);font-weight: 700;font-family: 'Nunito Sans';font-size: 20px;line-height: 1.5;color: white;min-height: 46px;max-width: 215px;vertical-align: middle;padding: 8px 24px;border: none; cursor:pointer;";
                document.getElementById("header-button-wrapper-action-list").appendChild(button);
            }, 1000);
        }

    } // dopage

    function addButton(text, onclick, cssObj,pos) {
        if (pos=="T") {
            cssObj = cssObj || {position: 'absolute', top: '63px', left:'50%', 'z-index': 3}
        }
        if (pos=="B") {
            cssObj = cssObj || {position: 'absolute', top: '30px', left:'50%', 'z-index': 3}
        }
        if (pos=="C") {
            cssObj = cssObj || {position: 'absolute', top: '30px', left:'40%', 'z-index': 3}
        }
        if (pos=="D") {
            cssObj = cssObj || {position: 'absolute', top: '63px', left:'40%', 'z-index': 3}
        }
        let button = document.createElement('button'), btnStyle = button.style
        document.body.appendChild(button)
        button.innerHTML = text
        button.onclick = onclick
        btnStyle.position = 'absolute'
        Object.keys(cssObj).forEach(key => btnStyle[key] = cssObj[key])
        return button
    }
    function get_data(count){
        var datapass;
        var max = 50;
        un = document.getElementById("gmunitname").value;
        document.getElementById("gmUnit").innerHTML = un;
        $("#gmState")[0].innerText = "Requesting Members for "+un+" ("+count+")"+"Total read "+mems.length;
        if (debug) {GM_log("get_data :Version "+code_version);}
        if (debug) {GM_log("get_data : Collection for Report");}
        if (debug) {GM_log("Unit Request for "+un+" Count "+count);}
        if (debug) {
            GM_log("Unit Request for "+un+" :"+ JSON.parse(localStorage.getItem("authInfo")).idToken.substring(1,50));
            var tokexpDate = new Date( JSON.parse(localStorage.getItem("authInfo")).account.idTokenClaims.exp *1000);
            GM_log("Token expires :"+ tokexpDate.toGMTString());
        }
        //  document.getElementById("gmState").innerText = "Hello World";
        datapass = '{"pagesize":'+max+',"nexttoken":'+count+',"filter":{"global":"","globaland":false,"fieldand":true,"filterfields":[{"field":"unitName","value":"'+un+'"}]},"isSuspended":false}';
        //       console.log(datapass);
        if (debug) {GM_log("Counter for get_data "+count);}
        GM_xmlhttpRequest({
            method: "POST",
            context: count,
            url: "https://tsa-memportal-prod-fun01.azurewebsites.net/api/MemberListingAsync",
            data: datapass,
            //            synchronous:    true,
            headers: {
                "Content-Type": "application/json",
                "Authorization": "Bearer " + JSON.parse(localStorage.getItem("authInfo")).idToken,
                "Accept": "application/json, text/plain, */*"
            },

            onload: function(response) { //  console.log(response);console.log(count);
                if (debug) {GM_log("Counter Recieved "+response.context)}
                // console.log(JSON.parse(response.responseText).data[1]);
                var mem = null;
                try { mem=JSON.parse(response.responseText).data} catch {console.log("JSON Error "+response.responseText);}
                //   mem =(JSON.parse(response.responseText).data);
                if (mem!=null) {
                    if (debug) {
                        for (var debugloop=0;debugloop<mem.length;debugloop++){
                            GM_log("Member "+mem[debugloop].firstname+" "+mem[debugloop].unitName+mem[debugloop].Role);
                        }
                    }
                }
                if ((mem==null)&&(debug)) {
                    GM_log("GetData: We got an error collecting data for mems page"+response.context);
                }
                if (mem!=null) {
                    mems = mems.concat(mem);
                }
                if (debug) {GM_log("mems now has length "+mems.length);}

                //      console.log(mem.length);
                //      console.log(JSON.parse(response.responseText).data);
                if (response.status!=200) {GM_log("HTTP error "+response.status); GM_log(JSON.stringify(response));}
                //     console.log(mem);
                //    console.log(JSON.parse(response.responseText).data.length);
                $("#gmState")[0].innerText = "Reading Members for "+un+" ("+response.context+") "+"Total read "+mems.length+"("+mem.length+")";
                if ( JSON.parse(response.responseText).data.length ==50) {get_data(count+1); } else {report2()};},
            onerror:   function(response) { GM_log("ON Error");GM_log(JSON.stringify(response))},
            onabort:  function(response) { GM_log("ON Abort");GM_log(JSON.stringify(response))}
        });

    }

    function clear_mems(){
        //if (1!=1){
        if (debug) {GM_log("Clear Mems entry: mems now has length "+mems.length);}
        if(document.getElementById("gmmissing").checked) {
            var onlymems = [];
            var onlymemsu = [];
            var act = ['managerDisclosureCheck','dataProtectionTrainingComplete','signDeclaration','updateMemberProfile','referenceRequest','safeguardconfidentialEnquiryCheck','managerWelcomeConversation','coreLearning','managerTrusteeCheck'];

            for (var i = 0; i < role_detail.length; i++) {
                var displine=true;

                if (document.getElementById("gmmissing").checked) {
                    var any_missing = false;
                    for (var j = 0; j < act.length; j++) {
                        if (role_detail[i].actions.find((element)=>element.typeid==act[j])) {
                            var value = role_detail[i].actions.find((element)=>element.typeid==act[j]).status;
                            if ((value!="Satisfactory")&&(value!="Completed")&&(value!="Held - Satisfactory")){ any_missing=true;}
                        }
                    }
                    if (any_missing==false) {displine=false}
                }
                if (displine) {
                    var memobj = new Object();
                    memobj = mems.find((element) => element.id == roles.find((element) => element.Id==role_detail[i].roleApprovalMemberShipId).ContactId);
                    onlymems.push(memobj);
                }
            }
            //roles.find((element) => element.Id==role_detail[i].roleApprovalMemberShipId).RoleName)
            // mems = mems.filter( function(v) {return v.id == onlymems.find((element)=>element.id== v.id)})
            mems = onlymems;
            for(i=0;i<memsunique.length;i++) {
                if (mems.findIndex(e=>e.id==memsunique[i].id)>-1) {
                    onlymemsu.push(memsunique[i]);
                }
            }
            memsunique = onlymemsu;
            if (debug) {GM_log("Clear Mems exit: mems now has length "+mems.length);}
        }
        //       }
        if (mems.length==0) { alert('The report will not be generated as your filters have resulted in no members being selected')}
    }


    function report2() {
        //  console.log(mem[1]);
        //      console.log(mems);

        if (debug) {GM_log("report2 : Collection for Report");}
        if (debug) {GM_log("report2 : Number of Members"+mems.length);}
        if (document.getElementById("gmwelcome").checked) {
            if (document.getElementById("gmhelper").checked) {
                mems = mems.filter( function(v) {return v.Role!="Non Member - Needs disclosure";})
                mems = mems.filter( function(v) {return v.Role!="Holding";})
                if (debug) {GM_log("Report 2: Remove Helpers roles now has length "+roles.length);}
            }

        }
        if (debug) {GM_log("mems now has length "+mems.length);}
        if (document.getElementById("gmteamname").value !=""){
            if (debug) {GM_log("Match team "+document.getElementById("gmteamname").value);}
            mems = mems.filter( function(v) {return v.Team.includes(document.getElementById("gmteamname").value);})
            if (debug) {GM_log("mems now has length "+mems.length);}

        }
        if(document.getElementById("gmexact").checked) { //gmexact
            if (debug) {GM_log("Match team "+document.getElementById("gmteamname").value);}
            mems = mems.filter( function(v) {return v.unitName == document.getElementById("gmunitname").value;})
            if (debug) {GM_log("mems now has length "+mems.length);}
        }
        if (document.getElementById("gmpersonname").value !=""){
            if (debug) {GM_log("Match Names "+document.getElementById("gmpersonname").value);}
            mems = mems.filter( function(v) {return v.fullname.toLowerCase().includes(document.getElementById("gmpersonname").value.toLowerCase());})
            if (debug) {GM_log("mems now has length "+mems.length);}

        }
        if (mems.length==0) { alert('The report will not be generated as your filters have resulted in no members being selected')}
        if (debug) {GM_log("Check for Duplicates ");}
        var seen = {};
        var out = [];
        var len = mems.length;
        var j = 0;
        for(var i = 0; i < len; i++) {
            var item = mems[i];
            if(seen[item.id] !== 1) {
                seen[item.id] = 1;
                out[j++] = item;
            }
        }
        if (!document.getElementById("gmwelcome").checked) {
            mems = out;
        }
        memsunique = out;
        if (document.getElementById("gmwelcome").checked) {
            if (document.getElementById("gmhelper").checked) {
                mems = mems.filter( function(v) {return v.Role!="Non Member - Needs disclosure";})
                mems = mems.filter( function(v) {return v.Role!="Holding";})
                if (debug) {GM_log("Report 2: Remove Helpers roles now has length "+roles.length);}
            }
            mem_lcount = 0;
            clear_mems();
            report5()
        } else {



            if (mems.length==0) { alert('The report will not be generated as your filters have resulted in no members being selected')}
            $("#gmState")[0].innerText = "Number of Members "+mems.length;
            for(var loop = 0;loop<memsunique.length; loop++) {
                if (debug) {GM_log("Request Roles for "+loop+" "+memsunique[loop].firstname+" "+memsunique[loop].unitName);}

                GM_xmlhttpRequest({
                    method: "POST",
                    context: loop+1,
                    url: "https://tsa-memportal-prod-fun01.azurewebsites.net/api/GetMemberRolesAsync",
                    data: '{"contactId": "'+memsunique[loop].id+'"}',
                    headers: {
                        "Content-Type": "application/json",
                        "Authorization": "Bearer " + JSON.parse(localStorage.getItem("authInfo")).idToken,
                        "Accept": "application/json, text/plain, */*"
                    },
                    onload: function(response) {//console.log(response.context);
                        $("#gmState")[0].innerText = "Number of Members "+memsunique.length+" reading roles for number "+response.context;
                        //     console.log(mems.length);
                        if (response.status!=200) {GM_log("HTTP error "+response.status); GM_log(JSON.stringify(response));}
                        if (debug) {GM_log("Request Roles recieved for "+response.context+" "+memsunique[response.context-1].firstname+" "+memsunique[response.context-1].unitName);}
                        var jrole= null;
                        try { jrole=JSON.parse(response.responseText).data} catch {console.log("JSON Error "+response.responseText);}
                        if (jrole!=null) {
                            roles=roles.concat(jrole);
                        }
                        if ((jrole==null)&&(debug)) {
                            GM_log("GetData: We got an error collecting roles for member "+response.context+mems[response.context-1].firstname);
                        }
                        if (debug) {GM_log("Context "+response.context+" mems length"+mems.length+" roles length"+roles.length);}
                        // console.log(JSON.parse(response.responseText));
                        if (response.context-1==mems.length-1){console.log(roles);console.log(mems);report3();} },
                    onerror:   function(response) { GM_log("ON Error");GM_log(JSON.stringify(response))},
                    onabort:  function(response) { GM_log("ON Abort");GM_log(JSON.stringify(response))}
                });
            };
        }
    }


    function report3() {
        console.log(roles);
        if (debug) {GM_log("Report 3: mems now has length "+mems.length);}
        if (debug) {GM_log("Report 3: roles now has length "+roles.length);}
        if (document.getElementById("gmhelper").checked) {

            roles = roles.filter( function(v) {return !v.RoleName.includes("Non Member - Needs disclosure");})
            roles = roles.filter( function(v) {return !v.RoleName.includes("Holding");})
            if (debug) {GM_log("Report 3: Remove Helpers roles now has length "+roles.length);}
        }
        if (document.getElementById("gmclosed").checked) {
            roles = roles.filter( function(v) {return v.Closed});
            roles = roles.filter( function(v) {return v.EndDate==null});
            roles = roles.filter( function(v) {return !v.IsSecondaryLevel});
            if (debug) {GM_log("Report 3: Remove Closed roles now has length "+roles.length);}
            console.log(roles);

        }
        if (document.getElementById("gmteamname").value !=""){
            roles = roles.filter( function(v) {if( v.Team==null){return false} else {return v.Team.includes(document.getElementById("gmteamname").value);}})
            if (roles.length==0) { alert('There were no roles in Units matching the Unit Name maybe check you have a % at the end to get all the sub Units')}
            if (debug) {GM_log("Report 3: Filter by Team roles now has length "+roles.length);}
        }
        if (document.getElementById("gmteamonly").checked){
            var  filter = document.getElementById("gmunitname").value.replaceAll("%", "*");
            let w = filter.replace(/[.+^${}()|[\]\\]/g, '\\$&'); // regexp escape
            const re = new RegExp(`^${w.replace(/\*/g,'.*').replace(/\?/g,'.')}$`,'i');
            roles = roles.filter( function(v) {return re.test(v.UnitId)});
            if (debug) {GM_log("Report 3: Filter by for Unit only roles now has length "+roles.length);}
        }

        var xml = 0;
        var nullc=0;

        if (roles.length==0) { alert('The report will not be generated as your filters have resulted in no roles being selected')}

        for(var loop=0;loop<roles.length;loop++) {
            if (debug) {GM_log("Report 3: Roles Loop request for "+roles[loop].RoleName+" "+roles[loop].Team)+" "+loop;}
            //  console.log(roles[loop].EndDate);
            $("#gmState")[0].innerText = "Checking Role "+loop+" of "+roles.length;
            if ((roles[loop].EndDate==null)||(roles[loop].Status!=null)) {
                //   console.log("OK");
                role_max_count = loop;
                GM_xmlhttpRequest({
                    method: "POST",

                    context: loop+1,
                    url: "https://tsa-memportal-prod-fun01.azurewebsites.net/api/GenerateSASTokenAsync",
                    data: '{container: "contacts", permissions: "R", file: "'+roles[loop].ContactId+'/membership/'+roles[loop].Id+'/audit/data.json"}',
                    //                  synchronous:    true,
                    headers: {
                        "Content-Type": "application/json",
                        "Authorization": "Bearer " + JSON.parse(localStorage.getItem("authInfo")).idToken,
                        "Accept": "application/json, text/plain, */*"
                    },
                    onload: function(response) {
                        if (debug) {GM_log("Report 3: Roles Blob request for "+response.context+" ")}
                        $("#gmState")[0].innerText = "Fetching Role "+response.context+" of "+roles.length;
                        GM_xmlhttpRequest({
                            method: "GET",
                            Accept: "application/json;odata=minimalmetadata",
                            context: response.context+1,
                            url: JSON.parse(response.responseText).token,

                            onload: function(response) { // console.log(response.responseText);
                                // console.log(JSON.parse(response.responseText));
                                // console.log("Total"+(role_detail.length + nullc + xml));
                                //  console.log("Aim"+(roles.length-1));
                                if (debug) {GM_log("Report 3: Roles Loop received for "+(response.context-1));}
                                if (response.status!=200) {GM_log("HTTP error "+response.status); GM_log(JSON.stringify(response));}
                                $("#gmState")[0].innerText = "Checking Role "+response.context;
                                if(!response.responseText.includes("xml")) { role_detail.push(JSON.parse(response.responseText));} else {xml++; console.log("XML for "+response.context)};
                                if (debug) {GM_log("Report 3: role_detail.length : " +role_detail.length+" XML "+xml+" nullc "+nullc + " roles "+roles.length);}
                                if ((role_detail.length+nullc+xml)>=roles.length){console.log("Finish REport 3");console.log(role_detail); mem_lcount = 0;clear_mems();report5()}},
                            onerror:   function(response) { GM_log("Report 3 ON Error");GM_log(JSON.stringify(response))},
                            onabort:  function(response) { GM_log("Report ON Abort");GM_log(JSON.stringify(response))}

                        })

                    },
                    onerror:   function(response) { GM_log("Report 3 Outer ON Error");GM_log(JSON.stringify(response))},
                    onabort:  function(response) { GM_log("Report 3 Outer ON Abort");GM_log(JSON.stringify(response))}
                });
            } else { nullc++}
        }
    }



    function report5() {

        if (document.getElementById("gmlearning").checked) {

            if (debug) {GM_log("Report 5: Get Learning for "+memsunique[mem_lcount].firstname+" "+memsunique[mem_lcount].Team)+" "+mem_lcount;}
            GM_xmlhttpRequest({
                method: "POST",

                url: "https://tsa-memportal-prod-fun01.azurewebsites.net/api/GetLmsDetailsAsync",
                data: '{"contactId": "'+memsunique[mem_lcount].id+'"}',
                context:  mem_lcount+1,
                headers: {
                    "Content-Type": "application/json",
                    "Authorization": "Bearer " + JSON.parse(localStorage.getItem("authInfo")).idToken,
                    "Accept": "application/json, text/plain, */*"
                },
                onload: function(response) {
                    $("#gmState")[0].innerText = "Number of Members "+memsunique.length+" reading learning for number "+mem_lcount;
                    if (debug) {GM_log("Report 5: Learning received for "+(response.context-1));}
                    var l = new Object;
                    l.id = memsunique[ mem_lcount].id;
                    l.learn = [];
                    try { l.learn=JSON.parse(response.responseText)} catch {console.log("JSON Error "+response.responseText);}
                    mem_learning[mem_lcount] = l;
                    // console.log(JSON.parse(response.responseText));
                    if ( mem_lcount==memsunique.length-1){console.log(mem_learning);report6();}else{ mem_lcount++;report5()}},
                onerror:   function(response) { GM_log("ON Error");GM_log(JSON.stringify(response))},
                onabort:  function(response) { GM_log("ON Abort");GM_log(JSON.stringify(response))}
            });

        } else {report6() }
    }

    function xmlToJson(xml) {
        // Create the return object
        var obj = {};

        if (xml.nodeType == 1) {
            // element
            // do attributes
            if (xml.attributes.length > 0) {
                obj["@attributes"] = {};
                for (var j = 0; j < xml.attributes.length; j++) {
                    var attribute = xml.attributes.item(j);
                    obj["@attributes"][attribute.nodeName] = attribute.nodeValue;
                }
            }
        } else if (xml.nodeType == 3) {
            // text
            obj = xml.nodeValue;
        }

        // do children
        // If all text nodes inside, get concatenated text from them.
        var textNodes = [].slice.call(xml.childNodes).filter(function(node) {
            return node.nodeType === 3;
        });
        if (xml.hasChildNodes() && xml.childNodes.length === textNodes.length) {
            obj = [].slice.call(xml.childNodes).reduce(function(text, node) {
                return text + node.nodeValue;
            }, "");
        } else if (xml.hasChildNodes()) {
            for (var i = 0; i < xml.childNodes.length; i++) {
                var item = xml.childNodes.item(i);
                var nodeName = item.nodeName;
                //  if (nodeName=="m:properties") {nodeName = "m_properties"}
                if (nodeName[1]==":") {nodeName = nodeName.replace(":", "_")};
                if (typeof obj[nodeName] == "undefined") {
                    obj[nodeName] = xmlToJson(item);
                } else {
                    if (typeof obj[nodeName].push == "undefined") {
                        var old = obj[nodeName];
                        obj[nodeName] = [];
                        obj[nodeName].push(old);
                    }
                    obj[nodeName].push(xmlToJson(item));
                }
            }
        }
        return obj;
    }

    function report6() {
        var xmlURL ="";
        var xml = 0; var nullc=0;

        if (document.getElementById("gmdbs").checked) {

            for(var loop=0;loop<memsunique.length;loop++) {
                if (debug) {GM_log("Report 6: DBS requested for "+loop+" "+memsunique[loop].firstname);}
                //  console.log(roles[loop].EndDate);
                $("#gmState")[0].innerText = "Checking Disclosure "+loop+" of "+memsunique.length;
                GM_xmlhttpRequest({
                    method: "POST",
                    context: loop+1,
                    url: "https://tsa-memportal-prod-fun01.azurewebsites.net/api/GenerateSASTokenAsync",
                    data: '{"table": "Disclosures", "permissions": "R", "partitionkey" : "'+memsunique[loop].id+'"}',
                    synchronous:    true,
                    headers: {
                        "Content-Type": "application/json",
                        "Type" : "table",
                        "accept-language" : "en-GB,en;q=0.9",
                        "sec-fetch-site" : "cross-site",
                        "Origin" : "https://membership.scouts.org.uk",
                        "content-encoding" : "gzip",
                        "Authorization": "Bearer " + JSON.parse(localStorage.getItem("authInfo")).idToken,
                        "Accept": "application/json, text/plain, */*"
                    },
                    onload: function(response) {
                        xmlURL = "";
                        if (debug) {GM_log("Report 6: DBS Blob URL Received for "+(response.context-1)+" "+memsunique[response.context-1].firstname);}
                        try { xmlURL =  JSON.parse(response.responseText) } catch {console.log(response.responseText)};
                        if (xmlURL=="") { if (debug) {GM_log("Report 6: DBS Blob URL JSON Error " +response.responseText);} }
                        if (xmlURL!="") {
                            $("#gmState")[0].innerText = "Fetching DBS "+response.context+" of "+memsunique.length;
                            GM_xmlhttpRequest({
                                method: "GET",
                                context: response.context,
                                url: JSON.parse(response.responseText).token,
                                onload: function(response) {
                                    if (debug) {GM_log("Report 6: DBS received for "+(response.context-1)+" "+memsunique[response.context-1].firstname);}
                                    if (response.status!=200) {GM_log("HTTP error "+response.status); GM_log(JSON.stringify(response));}
                                    $("#gmState")[0].innerText = "Checking DBS "+response.context;
                                    if(response.responseText.includes("xml")) { var XmlNode = new DOMParser().parseFromString(response.responseText, 'text/xml');
                                                                               var dbsxml = xmlToJson(XmlNode); dbsxml.id = memsunique[response.context-1].id;
                                                                               dbsxml.firstname = memsunique[response.context-1].firstname;
                                                                               dbs_detail.push(dbsxml);} else {xml++};
                                    if (dbs_detail.length+xml>=memsunique.length){console.log(dbs_detail); report4()}},
                                onerror:   function(response) { GM_log("ON Error");GM_log(JSON.stringify(response))},
                                onabort:  function(response) { GM_log("ON Abort");GM_log(JSON.stringify(response))}

                            }) } else {xml++; if (dbs_detail.length+xml>=memsunique.length){console.log(dbs_detail); report4()}}

                    }
                });

            }
        } else {report4()}

    }

    function report_headers(table) {
        var expirytext = "Expiry";
        var expirytextdays = "Expiry Days";
        var act = ['managerDisclosureCheck','dataProtectionTrainingComplete','signDeclaration','updateMemberProfile','referenceRequest','safeguardconfidentialEnquiryCheck','managerWelcomeConversation','coreLearning','managerTrusteeCheck'];
        var title = ['Role','Unit','Team','Name','Number','Status','Start Date','Days','Disclosure','GDPR','Declaration','Profile','References','CE Check','Welcome','Learning','Trustee'];
        var learn = ['Creating Inclusion','Data Protection in Scouts','Who We Are and What We Do','Safeguarding','Safety','First Response','Delivering a Great Programme','Being a Trustee in Scouts','Leading Scout Volunteers'];
        var tr = document.createElement('TR');
        table.appendChild(tr);

        for (var i=0; i<title.length;i++){
            var td = document.createElement('TH');

            if (i>7) { td.style.writingMode = "vertical-lr"; td.style.backgroundColor='lightcyan';}
            //  td.style.writingmode = 'vertical-lr';
            td.appendChild(document.createTextNode(title[i]));
            var visible = true;
            if ((i>4)&&(document.getElementById("gmwelcome").checked)){visible=false};
            if ((i==4)&&(!document.getElementById("gmnumber").checked)){visible=false};
            if (visible) { tr.appendChild(td); }
        }

        if (document.getElementById("gmlearning").checked) {
            for ( i=0; i<learn.length;i++){
                td = document.createElement('TH');
                td.style.writingMode = "vertical-lr";
                td.style.backgroundColor = 'LightGray';
                td.appendChild(document.createTextNode(learn[i]));
                tr.appendChild(td);
                if (((i==3)||(i==4)||(i==5))&&(document.getElementById("gmdates").checked)) {
                    td = document.createElement('TH');
                    td.style.writingMode = "vertical-lr";
                    td.style.backgroundColor = 'LightGray';
                    td.appendChild(document.createTextNode(learn[i]+" "+expirytext));
                    tr.appendChild(td);
                }
                if (((i==3)||(i==4)||(i==5))&&(document.getElementById("gmdays").checked)) {
                    td = document.createElement('TH');
                    td.style.writingMode = "vertical-lr";
                    td.style.backgroundColor = 'LightGray';
                    td.appendChild(document.createTextNode(learn[i]+" "+expirytextdays));
                    tr.appendChild(td);
                }
            }
        }
        if (document.getElementById("gmdbs").checked) {
            td = document.createElement('TH');
            td.style.backgroundColor = 'LightGray';
            td.appendChild(document.createTextNode("DBS Expiry"));

            tr.appendChild(td);
            td = document.createElement('TH');
            td.style.writingMode = "vertical-lr";
            td.style.backgroundColor = 'LightGray';
            td.appendChild(document.createTextNode("DBS Days Remaining"));

            tr.appendChild(td);
            if (document.getElementById("gmdbsip").checked){
                td = document.createElement('TH');
                td.style.backgroundColor = 'LightGray';
                td.appendChild(document.createTextNode("DBS Status"));

                tr.appendChild(td);
            }
        }
    }

    function tabulator_id_url() {
    }

    var headerMenu = function(){
        var menu = [];
        var columns = this.getColumns();

        for(let column of columns){

            //create checkbox element using font awesome icons
            let icon = document.createElement("span");
            icon.classList.add("fas");
            icon.classList.add(column.isVisible() ? "fa-check-square" : "fa-square");

            //build label
            let label = document.createElement("span");
            let title = document.createElement("span");

            title.textContent = " " + column.getDefinition().title;

            label.appendChild(icon);
            label.appendChild(title);

            //create menu item
            menu.push({
                label:label,
                action:function(e){
                    //prevent menu closing
                    e.stopPropagation();

                    //toggle current column visibility
                    column.toggle();

                    //change menu item icon
                    if(column.isVisible()){
                        icon.classList.remove("fa-square");
                        icon.classList.add("fa-check-square");
                    }else{
                        icon.classList.remove("fa-check-square");
                        icon.classList.add("fa-square");
                    }
                }
            });
        }

        return menu;
    };

    function report_headers_tabulator() {
        var expirytext = "Expiry";
        var expirytextdays = "Expiry Days";
        var act = ['managerDisclosureCheck','dataProtectionTrainingComplete','signDeclaration','updateMemberProfile','referenceRequest','safeguardconfidentialEnquiryCheck','managerWelcomeConversation','coreLearning','managerTrusteeCheck'];
        var title = ['Name','Role','Unit','Team','Number','Status','Start Date','Days','Disclosure','GDPR','Declaration','Profile','References','CE Check','Welcome','Growing Roots Learning','Trustee Check'];
        var learn = ['Creating Inclusion','Data Protection in Scouts','Who We Are and What We Do','Safeguarding','Safety','First Response','Delivering a Great Programme','Being a Trustee in Scouts','Leading Scout Volunteers'];
        var titlefieldnames = ['name','role','unit','team','number','status','start','days','disclosure','gdpr','declaration','profile','references','ce','welcome','learning','trustee'];
        var learnfieldnames = ['inclusion','datap','who','safeguarding','safety','firstresponse','programme','trustee2','leading'];
        var dbs = ['DBS','DBS Expiry','DBS Days','DBS Status'];
        var dbsfieldnames = ['dbs','dbs_expiry','dbs_expirydays','dbsstatus'];
        var headers = [];

        var color_formatter = function testFormatter(cell, formatterParams) {    var days = cell.getValue();
                                                                             if(document.getElementById("gmcolor").checked) {
                                                                                 var fv =  cell.getData()[cell.getField().substr(0,cell.getField().indexOf("_"))];
                                                                                 if ("✅❌✔⚡".includes(fv)) {
                                                                                     for(cloop=0;cloop<4;cloop++) {
                                                                                         if ((days<=daylimits[cloop])&&(days>daylimits[cloop+1])) {
                                                                                             cell.getElement().style.backgroundColor = colors[cloop];
                                                                                             cell.getElement().style.color = colorsT[cloop];
                                                                                         }}}
                                                                             }
                                                                             return days}
        var color_formatter_date = function testFormatter(cell, formatterParams) {
            if(document.getElementById("gmcolor").checked) {
                var fv =  cell.getData()[cell.getField().substr(0,cell.getField().indexOf("_"))];
                if ("✅❌✔⚡".includes(fv)) {
                    var days  = cell.getData()[cell.getField()+"days"];
                    for(cloop=0;cloop<4;cloop++) {
                        if ((days<=daylimits[cloop])&&(days>daylimits[cloop+1])) {
                            cell.getElement().style.backgroundColor = colors[cloop];
                            cell.getElement().style.color = colorsT[cloop];
                        }}}}
            return cell.getValue()}
        //   for (var i=0; i<title.length;i++){
        var group = new Object;
        var visible = true;
         group.columns = [];
         group.title = "";
         group.frozen = true;

                var head = new Object;
                head.title = title[0];
                head.field = titlefieldnames[0];
                head.headerFilter = "input";

                head.formatterParams = new Object;
                head.formatter="link"; head.formatterParams.urlField = "memberURL";head.formatterParams.target = "_blank"
                head.headerMenu = headerMenu;
                group.columns.push(head);



          headers.push(group);
        group = new Object;
         group.columns = [];
         group.title = "";
        for (var i=1; i<8;i++){

             visible = true;
            if (((i>4))&&(document.getElementById("gmwelcome").checked)){visible=false};
            //    if ((i==4)&&(!document.getElementById("gmnumber").checked)){visible=false};
            if (visible) {
                head = new Object;
                head.title = title[i];
                head.field = titlefieldnames[i];
                head.headerFilter = "input";
                if (i==6) {    head.sorter = "date";}
                if (i==7) {    head.sorter = "number"; head.headerFilterPlaceholder = "less than" ; head.headerFilterFunc = "<";  head.headerFilter = "number";}
                if (i==0) { head.frozen = true;}
                head.formatterParams = new Object;
                if (i==0){head.formatter="link"; head.formatterParams.urlField = "memberURL";head.formatterParams.target = "_blank"}

                if (i>7) { head.headerVertical = true;}
                head.headerMenu = headerMenu;
                group.columns.push(head);
            }

        }
          headers.push(group);
        group = new Object;
        if (!document.getElementById("gmwelcome").checked) {
            group.columns = [];
            group.title = "Welcome Activities";
            //    group.cssClass = "blue-background";
            for (i=8; i<title.length;i++){
                visible = true;
                if ((i>7)&&(document.getElementById("gmwelcome").checked)){visible=false};
                if (visible) {
                    head = new Object;
                    head.title = title[i];
                    head.field = titlefieldnames[i];
                    head.cssClass = "blue-background";

                    head.formatterParams = new Object;
                    if (i>7) { head.headerVertical = true;}

                    head.headerFilter = "list";
                    head.headerFilterParams = {    valuesLookup:"active" }
                    group.columns.push(head);
                }
            }
            headers.push(group);
        }
        group = new Object;
        if (document.getElementById("gmlearning").checked) {
            group.columns = [];
            group.title = "Learning";
            //      group.cssClass = "yellow-background";
            for ( i=0; i<learn.length;i++){
                head = new Object;
                head.title = learn[i];
                head.field = learnfieldnames[i];
                head.headerVertical = true;
                head.cssClass = "yellow-background";
                head.headerFilter = "list";
                head.headerFilterParams = {    valuesLookup:"active" }
                group.columns.push(head);
                if (((i==3)||(i==4)||(i==5))) {
                    head = new Object;
                    head.title = learn[i]+" "+expirytext;
                    head.field = learnfieldnames[i]+"_expiry";
                    head.sorter = "date";
                    head.headerVertical = true;
                    head.formatter = color_formatter_date;
                    head.cssClass = "yellow-background";
                    head.headerFilter = "input";
                    group.columns.push(head);
                }
                if (((i==3)||(i==4)||(i==5))) {
                    head = new Object;
                    head.title = learn[i]+" "+expirytextdays;
                    head.field = learnfieldnames[i]+"_expirydays";
                    head.sorter = "number";
                    head.headerVertical = true;
                    head.formatter = color_formatter;
                    head.cssClass = "yellow-background";
                    head.headerFilterPlaceholder = "less than",
                        head.headerFilterFunc = "<"
                    head.headerFilter = "number";
                    group.columns.push(head);
                }
            }
            headers.push(group);
        }
        group = new Object;
        if (document.getElementById("gmdbs").checked) {
            group.columns = [];
            group.title = "DBS";
            // group.cssClass = "orange-background";
            for ( i=0; i<dbs.length-1;i++){
                head = new Object;
                head.title = dbs[i];
                head.field = dbsfieldnames[i];
                head.cssClass = "orange-background";
                if (i==0) {
                    head.headerFilter = "list";
                    head.headerFilterParams = {    valuesLookup:"active" }
                } else {              head.headerFilter = "input"; }
                if (i==0) { head.headerVertical = true;}

                if (i==2) {     head.sorter = "number";   head.formatter = color_formatter;   head.headerFilterPlaceholder = "less than" ; head.headerFilterFunc = "<";  head.headerFilter = "number";}
                if (i==1) {     head.sorter = "date";   head.formatter = color_formatter_date;}
                group.columns.push(head);
            }
            //   if (document.getElementById("gmdbsip").checked){
            head = new Object;
            head.title = dbs[3];
            head.field = dbsfieldnames[3];
            head.cssClass = "orange-background";
            head.headerFilter = "input";
            group.columns.push(head);
            headers.push(group);
            //   }
        }
        return headers;
    }


    function report4() {
        if (debug) {GM_log("Report 4 : Data Collected - generate report ");}
        if (debug) {GM_log("Report 4 : Roles Detail "+role_detail.length);}
        if (debug) {GM_log("Report 4 : Mems  "+mems.length);}
        if (debug) {GM_log("Report 4 : Roles  "+roles.length);}
        if (debug) {GM_log("Report 4 : Learning  "+mem_learning.length);}
        if (debug) {GM_log("Report 4 : DBS  "+ dbs_detail.length);}
        var expirytext = "Expiry";
        var expirytextdays = "Expiry Days";
        var act = ['managerDisclosureCheck','dataProtectionTrainingComplete','signDeclaration','updateMemberProfile','referenceRequest','safeguardconfidentialEnquiryCheck','managerWelcomeConversation','coreLearning','managerTrusteeCheck'];
        var title = ['Role','Unit','Team','Name','Status','Start Date','Days','Disclosure','GDPR','Declaration','Profile','References','CE Check','Welcome','Learning','Trustee'];
        var learn = ['Creating Inclusion','Data Protection in Scouts','Who We Are and What We Do','Safeguarding','Safety','First Response','Delivering a Great Programme','Being a Trustee in Scouts','Leading Scout Volunteers'];

        $("#gmState")[0].innerText = "Data Collection Completed";
        var myTableDiv = document.getElementById("gmTable");
        var table = document.createElement('TABLE');
        table.border = '1';
        table.id = "GMourreport";

        var tableBody = document.createElement('THEAD');
        table.appendChild(tableBody);
        //    var tr = document.createElement('TR');
        //   tableBody.appendChild(tr);
        report_headers(tableBody);
        tableBody = document.createElement('TBODY');
        table.appendChild(tableBody);
        var tablines = [];
        var   tr = document.createElement('TR');
        if (!(document.getElementById("gmwelcome").checked)) {
            for (i = 0; i < role_detail.length; i++) {
                var displine=true;

                if (document.getElementById("gmmissing").checked) {
                    var any_missing = false;
                    for (var j = 0; j < act.length; j++) {
                        if (role_detail[i].actions.find((element)=>element.typeid==act[j])) {
                            var value = role_detail[i].actions.find((element)=>element.typeid==act[j]).status;
                            if ((value!="Satisfactory")&&(value!="Completed")&&(value!="Held - Satisfactory")){ any_missing=true;}
                        }
                    }
                    if (any_missing==false) {displine=false}
                }
                if (displine) {
                    //      tr = document.createElement('TR');
                    //      tableBody.appendChild(tr);

                    output_report_line(tableBody,i,mems.findIndex( (element) => element.id == roles.find( (element) => element.Id == role_detail[i].roleApprovalMemberShipId).ContactId));
                    tablines.push(report_line_tabulator(i,mems.findIndex( (element) => element.id == roles.find( (element) => element.Id == role_detail[i].roleApprovalMemberShipId).ContactId)));
                }
            }
        }
        else
        {
            for (var i = 0; i < mems.length; i++) {
                if (mems[i].Role!=null) {
                    output_report_line(tableBody,-1,i);
                    tablines.push( report_line_tabulator(-1,i))
                }
            }
        }
        table.style.fontSize = "10pt";
        document.getElementById("gmTable").innerHTML="";
        //  myTableDiv.appendChild(table);

        //   console.log(hasStyleRule("tabulator-col.tabulator-sortable.tabulator-col-sorter-element.orange-background"));
        if (!added_css) {
            added_css=true;
            GM_addStyle ('.fa-check-square:before { content: "✅";   }' );
            GM_addStyle ('.fa-square:before { content: "🟩";   }' );
            GM_addStyle('.tabulator-col.tabulator-col-vertical.tabulator-sortable.tabulator-col-sorter-element.blue-background {background : #ADD8E6 }');
            GM_addStyle('.tabulator-col.tabulator-col-vertical.tabulator-sortable.tabulator-col-sorter-element.yellow-background {background : #FFFFE0 }');
            GM_addStyle('.tabulator-col.tabulator-sortable.tabulator-col-sorter-element.orange-background {background : #FFDAB9 }');
            GM_addStyle('th.blue-background {    writing-mode: vertical-lr;    background-color: lightcyan; }');
            GM_addStyle('th.yellow-background {    writing-mode: vertical-lr;    background-color: lightgoldenrodyellow; }');
            GM_addStyle('th.orange-background {    writing-mode: vertical-lr;    background-color: salmon; }');
            GM_addStyle('table.tabulator-print-table, tr, th, td {    border: solid;}');
        }
        tabletabulator = new Tabulator("#gmTabulator", {data: tablines,  printAsHtml:true,  columnHeaderVertAlign :"bottom", columns: report_headers_tabulator(),    movableColumns: true,   dependencies:{  DateTime:luxon.DateTime, },
                                                        downloadEncoder:function(fileContents, mimeType){
                                                            var b = new Blob([fileContents], {type:mimeType});    var url = URL.createObjectURL(b);
                                                            url = window.URL.createObjectURL(b);
                                                            var filename = 'myBlobFile.xlsx';

                                                            var a = document.createElement('a');
                                                            a.style = 'display: none';
                                                            a.href = url;
                                                            a.download = filename;

                                                            // IE 11
                                                            if (window.navigator.msSaveBlob !== undefined) {
                                                                window.navigator.msSaveBlob(b, filename);
                                                                return;
                                                            }
                                                            document.body.appendChild(a);
                                                            var e = new MouseEvent ("click");
                                                            a.dispatchEvent (e);
                                                            window.URL.revokeObjectURL(url);
                                                            document.body.removeChild(a);
                                                            // });
                                                        }
                                                       }); // tabulator
        tabletabulator.on("tableBuilt", function(){
            if (!document.getElementById("gmnumber").checked) { tabletabulator.hideColumn("number") }
            if (!document.getElementById("gmdates").checked) { tabletabulator.hideColumn("safeguarding_expiry");tabletabulator.hideColumn("firstresponse_expiry");tabletabulator.hideColumn("safety_expiry") }
            if (!document.getElementById("gmdays").checked) { tabletabulator.hideColumn("safeguarding_expirydays");tabletabulator.hideColumn("firstresponse_expirydays");tabletabulator.hideColumn("safety_expirydays") }
            if (!document.getElementById("gmdbsip").checked) { tabletabulator.hideColumn("dbsstatus") }
        });
    }

    var trustee_roles = ['Lead Volunteer','Trustee','Treasurer','Youth Lead','Chair'];

    function is_trustee(rolename) {
        if (trustee_roles.findIndex(e=>e == rolename)>-1) {return true}
        if (rolename.includes(trustee_roles[0])) {return true}
        return false;
    }
    var no_dbs = ['President','Vice President','Holding','Retired Member','Nations Staff Member','Council Member','Network Member','Locally Employed Staff','National Staff member','National Staff team leader','Trustee Board Sub-Team Member'];

    function needs_dbs(rolename) {
        if (no_dbs.findIndex(e=>e == rolename)>-1) {return false} else {return true};
    }

    var no_training = ['President','Vice President','Holding','Retired Member','Non Member - Needs disclosure','Council Member','Network Member','Designated Carers'];

    function needs_training(rolename) {
        if (no_training.findIndex(e=>e == rolename)>-1) {return false} else {return true};
    }

    function is_section(unit_type) {
        if ((unit_type=='Group Section')||(unit_type=='District Section')||(unit_type=='County Section')) {return true} else {return false}
    }

    var mainteams = ['Leadership Team','Volunteering Development Team','Support Team','Programme Team','14-24 Team'];

    function is_mainteam(team_name) {
        if (mainteams.findIndex((element)=>element==team_name>-1)) {return true} else {return false}
    }

    function is_teamleader(rolename,unit_type,ParentTeamId,team_name) {
        //  if ((roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).RoleName.includes('Lead Volunteer'))||(roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).RoleName=='Team Leader')&&((roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).UnitType!='Group Section')&&(roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).UnitType!='District Section'))) {
        if (rolename.includes('Lead Volunteer')) { return true;}
        if (rolename.includes('Youth Lead')) { return true;}
        if (ParentTeamId!=null) {return false} // Is a Sub team
        if (!is_mainteam(team_name)) {return false}
        if ((rolename=='Team Leader')&&!is_section(unit_type)) {return true}
        return false;
    }
    function is_firstresponse(unit_type,role_name,team_name) {
        if (is_section(unit_type)) {return true}
        if (role_name=="Group Lead Volunteer") {return true}
        if ((team_name=='14-24 Team')&&(role_name=="Team Leader")) {return true}
        return false;
    }



    // *****************************************************************
    /// This is used for the refresh but no new data
    /// *****************************************************************
    function output_report_line(table,role_index,mem_index) {
        var act = ['managerDisclosureCheck','dataProtectionTrainingComplete','signDeclaration','updateMemberProfile','referenceRequest','safeguardconfidentialEnquiryCheck','managerWelcomeConversation','coreLearning','managerTrusteeCheck'];
        var title = ['Role','Unit','Team','Name','Status','Start Date','Days','Disclosure','GDPR','Declaration','Profile','References','CE Check','Welcome','Learning','Trustee'];
        var learn = ['Creating Inclusion','Data Protection in Scouts','Who We Are and What We Do','Safeguarding','Safety','First Response','Delivering a Great Programme','Being a Trustee in Scouts','Leading Scout Volunteers'];

        var tr = document.createElement('TR');
        table.appendChild(tr);
        // Name
        if (role_index>=0) {
            var td = document.createElement('TD');
            td.appendChild(document.createTextNode(roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).RoleName));
            tr.appendChild(td);
            td = document.createElement('TD');
            td.appendChild(document.createTextNode(roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).UnitId));
            tr.appendChild(td);
            td = document.createElement('TD');
            td.appendChild(document.createTextNode(roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).Team));
            tr.appendChild(td);
        } else
        {
            td = document.createElement('TD');
            td.appendChild(document.createTextNode(mems[mem_index].Role));
            tr.appendChild(td);
            td = document.createElement('TD');
            td.appendChild(document.createTextNode(mems[mem_index].unitName));
            tr.appendChild(td);
            td = document.createElement('TD');
            td.appendChild(document.createTextNode(mems[mem_index].Team));
            tr.appendChild(td);
        }
        td = document.createElement('TD');
        var fullname = mems[mem_index].fullname;
        //  var nameid = mems.find((element) => element.id == roles.find((element) => element.Id==role_detail[i].roleApprovalMemberShipId).ContactId).id;
        var nameid = mems[mem_index].id;
        var memhtml = '<a href="https://membership.scouts.org.uk/#/membersearch/'+nameid+'/viewmember" target="_blank">'+fullname+'</a>';
        tr.appendChild(td);
        td.innerHTML=(memhtml);
        if (document.getElementById("gmnumber").checked) {
            td = document.createElement('TD');
            td.appendChild(document.createTextNode(mems[mem_index].membershipnumber));
            tr.appendChild(td);
        };
        if (role_index>=0) {

            // Role
            td = document.createElement('TD');
            td.appendChild(document.createTextNode(role_detail[role_index].rolestatus));
            tr.appendChild(td);
            td = document.createElement('TD');
            var sdate = new Date(roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).StartDate);
            td.appendChild(document.createTextNode(sdate.toLocaleDateString('en-GB')));
            var days  = Math.round((new Date() - sdate) / (1000 * 60 * 60 * 24));
            tr.appendChild(td);

            td = document.createElement('TD');
            td.appendChild(document.createTextNode(days));
            tr.appendChild(td);

            for (var j = 0; j < act.length; j++) {
                td = document.createElement('TD');
                //   td.width = '75';
                if (role_detail[role_index].actions.find((element)=>element.typeid==act[j])) {

                    var state= 0x274C;
                    var value = role_detail[role_index].actions.find((element)=>element.typeid==act[j]).status;
                    if ((value=="Satisfactory")||(value=="Completed")||(value=="Held - Satisfactory")){state= 0x2705;}

                    //  td.appendChild(document.createTextNode(role_detail[i].actions.find((element)=>element.typeid==act[j]).status+String.fromCodePoint(state)));
                    td.appendChild(document.createTextNode(String.fromCodePoint(state)));

                    //   td.appendChild(document.createTextNode(String.fromCodePoint(state)));
                } else {
                    // Deal with bug in API that means this can be missing.....
                    if(j==3) {
                        state= 0x274C;
                        td.appendChild(document.createTextNode(String.fromCodePoint(state)));
                    } else {
                        td.appendChild(document.createTextNode(" "))
                    }
                }
                td.style.backgroundColor='lightcyan';
                tr.appendChild(td);
            }
        } else {

        }
        // Learning

        if (document.getElementById("gmlearning").checked) {
            for ( j = 0; j < learn.length; j++) {
                td = document.createElement('TD');
                state= 0x274C;
                var lr = mem_learning.find((element) => element.id == mems[mem_index].id);
                if (lr.learn.find((object)=>object.title==learn[j])){
                    state= 0x2705;
                }
                // Check Expiry x26A1
                if (lr.learn.find((object)=>object.title==learn[j])){
                    if (lr.learn.find( (object) => object.title == learn[j]).expiryDate !=null) {
                        sdate = new Date(lr.learn.find((object)=>object.title==learn[j]).expiryDate);
                        days  = Math.round((sdate - new Date()) / (1000 * 60 * 60 * 24));
                        if (days<=90) {state = 0x26A1;
                                      }
                    } else {days=0;sdate = new Date("1977-01-01T00:00:01Z") ;}
                } else {days=0;sdate = new Date("1977-01-01T00:00:01Z") ;}
                if (role_index>=0) {
                    var role_find = {};
                    role_find = roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId);
                    if (j==7) {
                        // Trustee
                        //       if ((!roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).RoleName.includes('Lead Volunteer'))&&(roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).RoleName!='Trustee')) {
                        if (!is_trustee(role_find.RoleName)) {
                            if(state==0x2705) {state=0x2714;}
                            else {
                                state = 0x0020;
                            }
                        }
                    }
                    if (j==8) {
                        // Team Lead is_teamleader(rolename,unit_type,ParentTeamId,team_name)
                        //   if ((roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).RoleName.includes('Lead Volunteer'))||(roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).RoleName=='Team Leader')&&((roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).UnitType!='Group Section')&&(roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).UnitType!='District Section'))) {
                        if (is_teamleader(role_find.RoleName,role_find.UnitType,role_find.ParentTeamId,role_find.Team)) {
                        } else {if(state==0x2705) {
                            state=0x2714;}
                                else {
                                    state = 0x0020;
                                }}
                    }
                    /*  if (j==8) {
                        // Team Lead of Subteam means no training... Parent being null means this isn't a subteam
                        if ((roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).ParentTeamId==null)) {

                        } else {if((state==0x2705)||(state == 0x2714)) {
                            state=0x2714;}
                                else {
                                    state = 0x0020;
                                }}
                    }*/
                    if (j==6) {
                        // programme - only section roles
                        //    if ((roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).UnitType!='Group Section')&&(roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).UnitType!='District Section')) {
                        if (!is_section(role_find.UnitType) )
                            if(state==0x2705) {
                                state=0x2714;}
                            else {
                                state = 0x0020;
                            }
                    }

                    if (j==5) {
                        // First Response
                        //    if ((roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).UnitType=='Group Section')||(roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).UnitType=='District Section')||(roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).RoleName=='Group Lead Volunteer')||((roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).RoleName=='Team Leader'))&&(roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).Team=='14-24 Team')) {
                        if (is_firstresponse(role_find.UnitType,role_find.RoleName,role_find.Team)) {
                        } else { if(state==0x2705) {
                            state=0x2714;}
                                else {
                                    state = 0x0020;
                                }
                               }
                    }
                    // Check for those not needing training
                    //   var rn = roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).RoleName;
                    //   if ((rn=='Non Member - Needs disclosure')||(rn=='President')||(rn=='Vice President')||(rn=='Holding')||(rn=='Retired Member')) {
                    if (!needs_training(role_find.RoleName)) {
                        if ((state == 0x26A1)||(state == 0x2705)||(state == 0x2714)) {
                            state=0x2714;}
                        else {
                            state = 0x0020;
                        }
                    }

                } else {

                    if ((j==7)&&(mems[mem_index].Role!=null)) {
                        // Trustee
                        if (!is_trustee(mems[mem_index].Role)) {
                            //  if ((!mems[mem_index].Role.includes('Lead Volunteer'))&&(mems[mem_index].RoleName!='Trustee')) {

                            if(state==0x2705) {
                                state=0x2714;}
                            else {
                                state = 0x0020;
                            }
                        }
                    }
                    if ((j==8)&&(mems[mem_index].Role!=null)) {
                        // Team Lead
                        if (is_teamleader(mems[mem_index].Role,mems[mem_index].unittype,null,mems[mem_index].Team)) {

                            //         if ((mems[mem_index].Role.includes('Lead Volunteer'))||(mems[mem_index].Role=='Team Leader')&&((mems[mem_index].unittype!='Group Section')&&(mems[mem_index].unittype!='District Section'))) {

                        } else {if(state==0x2705) {
                            state=0x2714;}
                                else {
                                    state = 0x0020;
                                }}
                    }
                    /*       if (j==8) {
                        var mainteams = ['Leadership Team','Volunteering Development Team','Support Team','Programme Team','14-24 Team'];
                        // Team Lead for Sub teams
                        if (mainteams.find((element)=>element==mems[mem_index].Team!=undefined)
                           ) {

                        } else {if((state==0x2705)||(state == 0x2714)) {
                            state=0x2714;}
                                else {
                                    state = 0x0020;
                                }}
                    }*/
                    if (j==6) {
                        // programme - only section roles
                        if (!is_section(mems[mem_index].unittype) ){
                            //       if ((mems[mem_index].unittype!='Group Section')&&(mems[mem_index].unittype!='District Section')) {
                            if(state==0x2705) {
                                state=0x2714;}
                            else {
                                state = 0x0020;
                            }
                        }
                    }
                    if ((j==5)&&(mems[mem_index].Role!=null)) {
                        // First Response
                        //     if ((mems[mem_index].unittype=='Group Section')||(mems[mem_index].unittype=='District Section')||(mems[mem_index].Role=='Group Lead Volunteer')||((mems[mem_index].Role=='Team Leader'))&&(mems[mem_index].Team=='14-24 Team')) {
                        if (is_firstresponse(mems[mem_index].unittype,mems[mem_index].Role,mems[mem_index].Team)) {

                        } else { if(state==0x2705) {
                            state=0x2714;}
                                else {
                                    state = 0x0020;
                                } }
                    }
                    // Check for those not needing training
                    var rn = mems[mem_index].Role;
                    if (rn!=null) {
                        if (!needs_training(mems[mem_index].Role)) {
                            if ((state == 0x26A1)||(state == 0x2705)||(state == 0x2714)) {
                                state=0x2714;}
                            else {
                                state = 0x0020;
                            }
                        }
                    }

                }
                td.appendChild(document.createTextNode(String.fromCodePoint(state)));
                td.style.backgroundColor = 'LightGray';
                tr.appendChild(td);
                var blankdate =  new Date("1977-01-01T00:00:01Z");
                if ((document.getElementById("gmdates").checked)&&((j==3)||(j==4)||(j==5))) {
                    td = document.createElement('TD');
                    if (lr.learn.find( (object) => object.title == learn[j])) {
                        if (sdate.getTime()!= blankdate.getTime()) {
                            td.style.backgroundColor = 'LightGray';
                            if (( state != 0x0020)&&(document.getElementById("gmcolor").checked)){
                                for(var cloop=0;cloop<4;cloop++) {
                                    if ((days<=daylimits[cloop])&&(days>daylimits[cloop+1])) {
                                        td.style.backgroundColor = colors[cloop];
                                        td.style.textColor = colorsT[cloop];
                                    }}}
                            td.appendChild(document.createTextNode(sdate.toLocaleDateString('en-GB')));
                        }
                    } else {
                        if (( state != 0x0020)&&(document.getElementById("gmcolor").checked)){
                            for(cloop=0;cloop<4;cloop++) {
                                if ((days<=daylimits[cloop])&&(days>daylimits[cloop+1])) {
                                    td.style.backgroundColor = colors[cloop];
                                    td.style.textColor = colorsT[cloop];
                                }}}
                    }

                    tr.appendChild(td);
                }
                if (((j==3)||(j==4)||(j==5))&&(document.getElementById("gmdays").checked)) {
                    td = document.createElement('TD');
                    td.style.backgroundColor = 'LightGray';
                    if (!document.getElementById("gmwelcome").checked) {
                        if ((j!=3)||(((roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).UnitType=='Group Section')||(roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).UnitType=='District Section')||(roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).RoleName=='Group Lead Volunteer')||((roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).RoleName=='Team Leader'))&&(roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).Team=='14-24 Team'))&&j==3)) {

                            if (sdate!= new Date("1000-01-01T00:00:01Z")) {
                                td.appendChild(document.createTextNode(days));

                            }
                        }
                    } else {  if (sdate!= new Date("1000-01-01T00:00:01Z")) {
                        td.appendChild(document.createTextNode(days));

                    }}
                    if (( state != 0x0020)&&(document.getElementById("gmcolor").checked)){
                        for(cloop=0;cloop<4;cloop++) {
                            if ((days<=daylimits[cloop])&&(days>daylimits[cloop+1])) {
                                td.style.backgroundColor = colors[cloop];
                                td.style.textColor = colorsT[cloop];
                            }}}
                    tr.appendChild(td);
                }

            }
        }
        if (document.getElementById("gmdbs").checked) {
            if (role_index>=0) {
                rn = roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).RoleName;
            } else { rn=mems[mem_index].Role;}
            //    if ((rn=='President')||(rn=='Vice President')||(rn=='Holding')||(rn=='Retired Member')) {
            if (!needs_dbs(rn)) {
                // No DBS Needed
                td = document.createElement('TD');
                tr.appendChild(td);
                td = document.createElement('TD');
                tr.appendChild(td);

            } else {
                var mindex = dbs_detail.findIndex((element)=> element.id == mems[mem_index].id)
                if (mindex>=0) {
                    var time = new Date("1000-01-01T00:00:01Z") ;
                    var timel = new Date("1000-01-01T00:00:01Z") ;
                    var dbs_status = "";
                    if (dbs_detail[mindex].feed.entry != undefined) {
                        if ( dbs_detail[mindex].feed.entry.length != undefined ) {
                            for(var dbsloop=0;dbsloop<dbs_detail[mindex].feed.entry.length;dbsloop++) {
                                sdate = new Date(dbs_detail[mindex].feed.entry[dbsloop].content.m_properties.d_ExpiryDate);
                                if (sdate>time) { time = sdate;}
                                sdate = new Date(dbs_detail[mindex].feed.entry[dbsloop].content.m_properties.d_IssuedDate);
                                if (sdate>timel) { timel = sdate;dbs_status=dbs_detail[mindex].feed.entry[dbsloop].content.m_properties.d_Status; if (dbs_status!="Disclosure issued"){dbs_status+=" "+timel.toLocaleDateString('en-GB')}}
                            }
                        }
                        if (dbs_detail[mindex].feed.entry.length == undefined) {
                            // Single DBS
                            sdate = new Date(dbs_detail[mindex].feed.entry.content.m_properties.d_ExpiryDate);
                            if (sdate>time) { time = sdate;}
                            sdate = new Date(dbs_detail[mindex].feed.entry.content.m_properties.d_DateModified);
                            dbs_status=dbs_detail[mindex].feed.entry.content.m_properties.d_Status;
                            if (dbs_status!="Disclosure issued"){dbs_status+=" "+sdate.toLocaleDateString('en-GB')}
                        }
                    }
                    td = document.createElement('TD');
                    var dbsdatedisp = time.toLocaleDateString('en-GB');
                    if (time<new Date()) {dbsdatedisp=String.fromCodePoint(0x274C)};
                    var expdays  = Math.round((time-new Date()) / (1000 * 60 * 60 * 24));
                    if ((expdays<=90)&&(expdays>0)) {dbsdatedisp+=String.fromCodePoint(0x26A1)}
                    if ((document.getElementById("gmcolor").checked)){
                        for(cloop=0;cloop<4;cloop++) {
                            if ((expdays<=daylimits[cloop])&&(expdays>daylimits[cloop+1])) {
                                td.style.backgroundColor = colors[cloop];
                                td.style.textColor = colorsT[cloop];
                            }}}
                    td.appendChild(document.createTextNode(dbsdatedisp));

                    tr.appendChild(td);
                    td = document.createElement('TD');
                    if ((document.getElementById("gmcolor").checked)){
                        for(cloop=0;cloop<4;cloop++) {
                            if ((expdays<=daylimits[cloop])&&(expdays>daylimits[cloop+1])) {
                                td.style.backgroundColor = colors[cloop];
                                td.style.textColor = colorsT[cloop];
                            }}}
                    if(expdays>0) {
                        td.appendChild(document.createTextNode(expdays));
                    }
                    tr.appendChild(td);
                    if (document.getElementById("gmdbsip").checked){
                        td = document.createElement('TD');
                        td.appendChild(document.createTextNode(dbs_status));
                        tr.appendChild(td);
                    }
                } else {td = document.createElement('TD');td.appendChild(document.createTextNode(String.fromCodePoint(0x274C))); tr.appendChild(td);td = document.createElement('TD');tr.appendChild(td);
                        if (document.getElementById("gmdbsip").checked) { td = document.createElement('TD');tr.appendChild(td); }
                       }
            }
        }
    }


    function report_line_tabulator(role_index,mem_index) {
        var act = ['managerDisclosureCheck','dataProtectionTrainingComplete','signDeclaration','updateMemberProfile','referenceRequest','safeguardconfidentialEnquiryCheck','managerWelcomeConversation','coreLearning','managerTrusteeCheck'];
        var title = ['Role','Unit','Team','Name','Number','Status','Start Date','Days','Disclosure','GDPR','Declaration','Profile','References','CE Check','Welcome','Learning','Trustee'];
        var learn = ['Creating Inclusion','Data Protection in Scouts','Who We Are and What We Do','Safeguarding','Safety','First Response','Delivering a Great Programme','Being a Trustee in Scouts','Leading Scout Volunteers'];
        var titlefieldnames = ['role','unit','team','name','number','status','start','days','disclosure','gdpr','declaration','profile','references','ce','welcome','learning','trustee'];
        var learnfieldnames = ['inclusion','datap','who','safeguarding','safety','firstresponse','programme','trustee2','leading'];
        var dbs = ['DBS Expiry','DBS Days','DBS Status'];
        var dbsfieldnames = ['dbs','dbs_expiry','dbs_expirydays','dbsstatus'];
        var line = new Object;

        // Name
        if (role_index>=0) {
            line.role = roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).RoleName;
            line.unit = roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).UnitId;
            line.team = roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).Team;
            line.memberURL  = 'https://membership.scouts.org.uk/#/membersearch/'+roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).ContactId+"/viewmember";
        } else
        {
            line.role = mems[mem_index].Role;
            line.unit = mems[mem_index].unitName;
            line.team = mems[mem_index].Team;
            line.memberUrl = 'https://membership.scouts.org.uk/#/membersearch/'+mems[mem_index].id+"/viewmember";
        }
        line.name = mems[mem_index].fullname;

        //  var nameid = mems.find((element) => element.id == roles.find((element) => element.Id==role_detail[i].roleApprovalMemberShipId).ContactId).id;
        var nameid = mems[mem_index].id;
        // line.memberURL  = 'https://membership.scouts.org.uk/#/membersearch/'+mems.find((element) => element.id == roles.find((element) => element.Id==role_detail[i].roleApprovalMemberShipId).ContactId).id+"/viewmember";
        //  var memhtml = '<a href="https://membership.scouts.org.uk/#/membersearch/'+nameid+'/viewmember" target="_blank">'+fullname+'</a>';
        //     if (document.getElementById("gmnumber").checked) {
        line.number = mems[mem_index].membershipnumber;
        //   };
        if (role_index>=0) {
            line.status = role_detail[role_index].rolestatus;

            var sdate = new Date(roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).StartDate);
            line.start = sdate.toLocaleDateString('en-GB').toString();
            var days  = Math.round((new Date() - sdate) / (1000 * 60 * 60 * 24));
            line.days = days;
            for (var j = 0; j < act.length; j++) {

                if (role_detail[role_index].actions.find((element)=>element.typeid==act[j])) {

                    var state= 0x274C;
                    var value = role_detail[role_index].actions.find((element)=>element.typeid==act[j]).status;
                    if ((value=="Satisfactory")||(value=="Completed")||(value=="Held - Satisfactory")){state= 0x2705;}

                    line[titlefieldnames[j+8]] = String.fromCodePoint(state);

                } else {
                    // Deal with bug in API that means this can be missing.....
                    if(j==3) {
                        state= 0x274C;
                        line[titlefieldnames[j+8]] = String.fromCodePoint(state);
                    } else {
                        line[titlefieldnames[j+8]] = "";
                    }
                }
            }
        } else { }


        // Learning

        if (document.getElementById("gmlearning").checked) {
            for ( j = 0; j < learn.length; j++) {

                state= 0x274C; // Red Cross 10060
                var lr = mem_learning.find((element) => element.id == mems[mem_index].id);
                if (lr.learn.find((object)=>object.title==learn[j])){
                    state= 0x2705; // Green Tick 9989
                }
                // Check Expiry
                var has_expiry = false;
                if (lr.learn.find((object)=>object.title==learn[j])){
                    if (lr.learn.find( (object) => object.title == learn[j]).expiryDate !=null) {
                        sdate = new Date(lr.learn.find((object)=>object.title==learn[j]).expiryDate);
                        days  = Math.round((sdate - new Date()) / (1000 * 60 * 60 * 24));
                        has_expiry = true;
                        if (days<=90) {state = 0x26A1; } // Flash 9889
                        if (days<0) {state = 0x274C;}   // Red Cross 10060
                    } else {days=0;sdate = new Date("1977-01-01T00:00:01Z") ;}
                } else {days=0;sdate = new Date("1977-01-01T00:00:01Z") ;}
                if (role_index>=0) {
                    var role_find = {};
                    role_find = roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId);
                    if (j==7) {
                        // Trustee
                        //       if ((!roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).RoleName.includes('Lead Volunteer'))&&(roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).RoleName!='Trustee')) {
                        if (!is_trustee(role_find.RoleName)) {
                            if(state==0x2705) {state=0x2714;} // Black Tick
                            else {
                                state = 0x0020;
                            }
                        }
                    }
                    if (j==8) {
                        // Team Lead is_teamleader(rolename,unit_type,ParentTeamId,team_name)
                        //   if ((roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).RoleName.includes('Lead Volunteer'))||(roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).RoleName=='Team Leader')&&((roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).UnitType!='Group Section')&&(roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).UnitType!='District Section'))) {
                        if (is_teamleader(role_find.RoleName,role_find.UnitType,role_find.ParentTeamId,role_find.Team)) {
                        } else {if(state==0x2705) {
                            state=0x2714;}
                                else {
                                    state = 0x0020;
                                }}
                    }

                    if (j==6) {
                        // programme - only section roles
                        //    if ((roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).UnitType!='Group Section')&&(roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).UnitType!='District Section')) {
                        if (!is_section(role_find.UnitType) )
                            if(state==0x2705) {
                                state=0x2714;}
                            else {
                                state = 0x0020;
                            }
                    }

                    if (j==5) {
                        if ((!has_expiry)&&(state== 0x2705)) { state= 0x274C; } // Set to Expired....
                        // First Response
                        //    if ((roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).UnitType=='Group Section')||(roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).UnitType=='District Section')||(roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).RoleName=='Group Lead Volunteer')||((roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).RoleName=='Team Leader'))&&(roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).Team=='14-24 Team')) {
                        if (is_firstresponse(role_find.UnitType,role_find.RoleName,role_find.Team)) {
                        } else { if((!has_expiry)&&(state==0x274C)) {state=0x0020;}
                                if(state==0x2705) { // Green
                                    state=0x2714;} // Black Tick
                                else if (state==0x26A1) {} // Flash
                                else if (state==0x274C) {state=0x2716;} // Cross
                                else {
                                    state = 0x0020;
                                }
                               }
                    }
                    // Check for those not needing training
                    //   var rn = roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).RoleName;
                    //   if ((rn=='Non Member - Needs disclosure')||(rn=='President')||(rn=='Vice President')||(rn=='Holding')||(rn=='Retired Member')) {
                    if (!needs_training(role_find.RoleName)) {
                        if ((state == 0x26A1)||(state == 0x2705)||(state == 0x2714)) {
                            state=0x2714;}   // Black Tick
                        else if (state==0x2716) {} // Black Cross
                        else {
                            state = 0x0020;
                        }
                    }

                } else {

                    if ((j==7)&&(mems[mem_index].Role!=null)) {
                        // Trustee
                        if (!is_trustee(mems[mem_index].Role)) {
                            //  if ((!mems[mem_index].Role.includes('Lead Volunteer'))&&(mems[mem_index].RoleName!='Trustee')) {

                            if(state==0x2705) {
                                state=0x2714;}
                            else {
                                state = 0x0020;
                            }
                        }
                    }
                    if ((j==8)&&(mems[mem_index].Role!=null)) {
                        // Team Lead
                        if (is_teamleader(mems[mem_index].Role,mems[mem_index].unittype,null,mems[mem_index].Team)) {

                            //         if ((mems[mem_index].Role.includes('Lead Volunteer'))||(mems[mem_index].Role=='Team Leader')&&((mems[mem_index].unittype!='Group Section')&&(mems[mem_index].unittype!='District Section'))) {

                        } else {if(state==0x2705) {
                            state=0x2714;}
                                else {
                                    state = 0x0020;
                                }}
                    }

                    if (j==6) {
                        // programme - only section roles
                        if (!is_section(mems[mem_index].unittype) ){
                            //       if ((mems[mem_index].unittype!='Group Section')&&(mems[mem_index].unittype!='District Section')) {
                            if(state==0x2705) {
                                state=0x2714;}
                            else {
                                state = 0x0020;
                            }
                        }
                    }
                    if ((j==5)&&(mems[mem_index].Role!=null)) {
                        // First Response
                        //     if ((mems[mem_index].unittype=='Group Section')||(mems[mem_index].unittype=='District Section')||(mems[mem_index].Role=='Group Lead Volunteer')||((mems[mem_index].Role=='Team Leader'))&&(mems[mem_index].Team=='14-24 Team')) {
                        if (is_firstresponse(mems[mem_index].unittype,mems[mem_index].Role,mems[mem_index].Team)) {

                        } else  { if(state==0x2705) { // Green
                            state=0x2714;} // Black Tick
                                 else if (state==0x26A1) {} // Flash
                                 else if (state==0x274C) {state=0x1F7A6;} // Cross
                                 else {
                                     state = 0x0020;
                                 }
                                }
                    }
                    // Check for those not needing training
                    var rn = mems[mem_index].Role;
                    if (rn!=null) {
                        if (!needs_training(mems[mem_index].Role)) {
                            if ((state == 0x26A1)||(state == 0x2705)||(state == 0x2714)) {
                                state=0x2714;}
                            else if (state==0x1F7A6) {}
                            else {
                                state = 0x0020;
                            }
                        }
                    }

                }
                line[learnfieldnames[j]] = String.fromCodePoint(state);

                var blankdate =  new Date("1977-01-01T00:00:01Z");
                if (((j==3)||(j==4)||(j==5))) {

                    if (lr.learn.find( (object) => object.title == learn[j])) {
                        //  if (sdate.getTime()!= blankdate.getTime()) {

                        line[learnfieldnames[j]+'_expiry'] = sdate.toLocaleDateString('en-GB');


                    } else {  line[learnfieldnames[j]+'_expiry'] = ""; }
                } else {

                    line[learnfieldnames[j]+'_expiry'] = "";
                }


                if (((j==3)||(j==4)||(j==5))) {

                    if (!document.getElementById("gmwelcome").checked) {
                        //   if ((j!=5)||(((roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).UnitType=='Group Section')||(roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).UnitType=='District Section')||(roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).RoleName=='Group Lead Volunteer')||((roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).RoleName=='Team Leader'))&&(roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).Team=='14-24 Team'))&&j==5)) {

                        //       if (sdate!= new Date("1000-01-01T00:00:01Z")) {
                        if (has_expiry) {
                            line[learnfieldnames[j]+'_expirydays'] = days;

                        } else {  line[learnfieldnames[j]+'_expirydays'] = ""}
                        //    }
                    } else {if (sdate!= new Date("1000-01-01T00:00:01Z")) {
                        line[learnfieldnames[j]+'_expirydays'] = days;

                    }}


                }
            }

        }
        if (document.getElementById("gmdbs").checked) {
            if (role_index>=0) {
                rn = roles.find((element) => element.Id==role_detail[role_index].roleApprovalMemberShipId).RoleName;
            } else { rn=mems[mem_index].Role;}
            if (!needs_dbs(rn)) {
                // No DBS Needed
                line.dbs_expiry = "";
                line.dbs_expirydays = "";
                line.dbsstatus = "";
                line.dbs =" ";

            } else {
                var mindex = dbs_detail.findIndex((element)=> element.id == mems[mem_index].id)
                if (mindex>=0) {
                    var time = new Date("1000-01-01T00:00:01Z") ;
                    var timel = new Date("1000-01-01T00:00:01Z") ;
                    var dbs_status = "";
                    if (dbs_detail[mindex].feed.entry != undefined) {
                        if ( dbs_detail[mindex].feed.entry.length != undefined ) {
                            for(var dbsloop=0;dbsloop<dbs_detail[mindex].feed.entry.length;dbsloop++) {
                                sdate = new Date(dbs_detail[mindex].feed.entry[dbsloop].content.m_properties.d_ExpiryDate);
                                if (sdate>time) { time = sdate;}
                                sdate = new Date(dbs_detail[mindex].feed.entry[dbsloop].content.m_properties.d_IssuedDate);
                                if (sdate>timel) { timel = sdate;dbs_status=dbs_detail[mindex].feed.entry[dbsloop].content.m_properties.d_Status; if (dbs_status!="Disclosure issued"){dbs_status+=" "+timel.toLocaleDateString('en-GB')}}
                            }
                        }
                        if (dbs_detail[mindex].feed.entry.length == undefined) {
                            // Single DBS
                            sdate = new Date(dbs_detail[mindex].feed.entry.content.m_properties.d_ExpiryDate);
                            if (sdate>time) { time = sdate;}
                            sdate = new Date(dbs_detail[mindex].feed.entry.content.m_properties.d_DateModified);
                            dbs_status=dbs_detail[mindex].feed.entry.content.m_properties.d_Status;
                            if (dbs_status!="Disclosure issued"){dbs_status+=" "+sdate.toLocaleDateString('en-GB')}
                        }
                    }
                    line.dbs = "";
                    var dbsdatedisp = time.toLocaleDateString('en-GB');
                    if (time<new Date()) {dbsdatedisp=String.fromCodePoint(0x274C)};
                    var expdays  = Math.round((time-new Date()) / (1000 * 60 * 60 * 24));
                    if ((expdays<=90)&&(expdays>0)) {
                      //  dbsdatedisp+=String.fromCodePoint(0x26A1);
                        line.dbs = String.fromCodePoint(0x26A1);
                    }

                    line.dbs_expiry =dbsdatedisp;

                    line.dbsstatus = "";
                    if (expdays<0) {  line.dbs = String.fromCodePoint(0x274C); };
                    if (expdays>90) {  line.dbs = String.fromCodePoint(0x2705); };
                    line.dbsstatus = dbs_status;
                    line.dbs_expirydays = expdays;

                } else {
                    line.dbsexpiry = String.fromCodePoint(0x274C);
                    line.dbs = String.fromCodePoint(0x274C);
                    line.dbsexpirydays = "";
                    line.dbsstatus= "";
                }
            }
        }

        return line;
    }







    function report_filter() {
        if (!document.getElementById("gmnumber").checked) { tabletabulator.hideColumn("number") } else { tabletabulator.showColumn("number") }
        if (!document.getElementById("gmdates").checked) { tabletabulator.hideColumn("safeguarding_expiry");tabletabulator.hideColumn("firstresponse_expiry");tabletabulator.hideColumn("safety_expiry") } else
        { tabletabulator.showColumn("safeguarding_expiry");tabletabulator.showColumn("firstresponse_expiry");tabletabulator.showColumn("safety_expiry") }
        if (!document.getElementById("gmdays").checked) { tabletabulator.hideColumn("safeguarding_expirydays");tabletabulator.hideColumn("firstresponse_expirydays");tabletabulator.hideColumn("safety_expirydays") } else
        { tabletabulator.showColumn("safeguarding_expirydays");tabletabulator.showColumn("firstresponse_expirydays");tabletabulator.showColumn("safety_expirydays") }
        if (!document.getElementById("gmdbsip").checked) { tabletabulator.hideColumn("dbsstatus") } else  { tabletabulator.showColumn("dbsstatus") }

        var titlefieldnames = ['disclosure','gdpr','declaration','profile','references','ce','welcome','learning','trustee'];
        if (document.getElementById("gmwelcome").checked) {
            for(var i=0; i<titlefieldnames.length;i++) {
                tabletabulator.hideColumn(titlefieldnames[i]) }
        }
        else {
            for( i=0; i<titlefieldnames.length;i++) {
                tabletabulator.showColumn(titlefieldnames[i]) }
        }

        var learnfieldnames = ['inclusion','datap','who','safeguarding','safety','firstresponse','programme','trustee2','leading'];
        if (!document.getElementById("gmlearning").checked) {
            for(i=0; i<learnfieldnames.length;i++) {
                tabletabulator.hideColumn(learnfieldnames[i])
                if ((i>=3)&&(i<=5)) {
                    tabletabulator.hideColumn(learnfieldnames[i]+"_expiry")
                    tabletabulator.hideColumn(learnfieldnames[i]+"_expirydays")
                }
            }
        } else {
            for( i=0; i<learnfieldnames.length;i++) {
                tabletabulator.showColumn(learnfieldnames[i])
                if ((i>=3)&&(i<=5)) {
                    tabletabulator.showColumn(learnfieldnames[i]+"_expiry")
                    tabletabulator.showColumn(learnfieldnames[i]+"_expirydays")
                }
            }
        }
        var dbsfieldnames = ['dbs','dbs_expiry','dbs_expirydays','dbsstatus'];
        if (!document.getElementById("gmdbs").checked) {
            for(i=0; i<dbsfieldnames.length;i++) {
                tabletabulator.hideColumn(dbsfieldnames[i])
            }
        } else {
            for(i=0; i<dbsfieldnames.length;i++) {
                tabletabulator.showColumn(dbsfieldnames[i])
            }
        }

        if (!document.getElementById("gmdates").checked) { tabletabulator.hideColumn("safeguarding_expiry");tabletabulator.hideColumn("firstresponse_expiry");tabletabulator.hideColumn("safety_expiry") } else
        { tabletabulator.showColumn("safeguarding_expiry");tabletabulator.showColumn("firstresponse_expiry");tabletabulator.showColumn("safety_expiry") }
        if (!document.getElementById("gmdays").checked) { tabletabulator.hideColumn("safeguarding_expirydays");tabletabulator.hideColumn("firstresponse_expirydays");tabletabulator.hideColumn("safety_expirydays") } else
        { tabletabulator.showColumn("safeguarding_expirydays");tabletabulator.showColumn("firstresponse_expirydays");tabletabulator.showColumn("safety_expirydays") }
        if (!document.getElementById("gmdbsip").checked) { tabletabulator.hideColumn("dbsstatus") } else  { tabletabulator.showColumn("dbsstatus") }

        tabletabulator.setFilter([{field : "name",type: "like", value: document.getElementById("gmpersonname").value}, {field: "team", type: "like", value: document.getElementById("gmteamname").value}]);
        tabletabulator.redraw(true);
    }




    function report_filter2() {


        var expirytext = "Expiry";
        var expirytextdays = "Expiry Days";
        var act = ['managerDisclosureCheck','dataProtectionTrainingComplete','signDeclaration','updateMemberProfile','referenceRequest','safeguardconfidentialEnquiryCheck','managerWelcomeConversation','coreLearning','managerTrusteeCheck'];
        var title = ['Role','Unit','Team','Name','Status','Start Date','Days','Disclosure','GDPR','Declaration','Profile','References','CE Check','Welcome','Learning','Trustee'];
        var learn = ['Creating Inclusion','Data Protection in Scouts','Who We Are and What We Do','Safeguarding','Safety','First Response','Delivering a Great Programme','Being a Trustee in Scouts','Leading Scout Volunteers'];
        $("#gmState")[0].innerText = "Data Collection Completed";
        var myTableDiv = document.getElementById("gmTable");
        var table = document.createElement('TABLE');
        table.border = '1';
        table.id = "GMourreport";
        var tableBody = document.createElement('TBODY');
        table.appendChild(tableBody);
        var tr = document.createElement('TR');
        tableBody.appendChild(tr);
        report_headers(tableBody);

        if (!(document.getElementById("gmwelcome").checked)) {
            for (i = 0; i < role_detail.length; i++) {
                var displine=true;

                if (document.getElementById("gmmissing").checked) {
                    var any_missing = false;
                    for (var j = 0; j < act.length; j++) {
                        if (role_detail[i].actions.find((element)=>element.typeid==act[j])) {
                            var value = role_detail[i].actions.find((element)=>element.typeid==act[j]).status;
                            if ((value!="Satisfactory")&&(value!="Completed")&&(value!="Held - Satisfactory")){ any_missing=true;}
                        }
                    }
                    if (any_missing==false) {displine=false}
                }
                //
                if (document.getElementById("gmteamonly").checked) {
                    var  filter = document.getElementById("gmunitname").value.replaceAll("%", "*");
                    let w = filter.replace(/[.+^${}()|[\]\\]/g, '\\$&'); // regexp escape
                    const re = new RegExp(`^${w.replace(/\*/g,'.*').replace(/\?/g,'.')}$`,'i');
                    if(!re.test(roles.find((element) => element.Id==role_detail[i].roleApprovalMemberShipId).UnitId)){displine=false}
                }

                if (mems.find((element) => element.id == roles.find((element) => element.Id==role_detail[i].roleApprovalMemberShipId).ContactId)!=undefined){

                    var fullname = mems.find((element) => element.id == roles.find((element) => element.Id==role_detail[i].roleApprovalMemberShipId).ContactId).fullname;
                    if (document.getElementById("gmpersonname").value!="") {
                        if(!fullname.toLowerCase().includes(document.getElementById("gmpersonname").value.toLowerCase())){displine=false}
                    }
                } else {displine=false;}

                if (document.getElementById("gmteamname").value!="") {
                    if (!roles.find((element) => element.Id==role_detail[i].roleApprovalMemberShipId).Team.toLowerCase().includes(document.getElementById("gmteamname").value.toLowerCase())){displine=false}
                }

                if (document.getElementById("gmhelper").checked) {
                    var rolename = roles.find((element) => element.Id==role_detail[i].roleApprovalMemberShipId).RoleName;
                    if (rolename.includes("Non Member - Needs disclosure")) {displine=false;}
                    if (rolename.includes("Holding")) {displine=false;}
                }
                if (displine) {
                    output_report_line(tableBody,i,mems.findIndex( (element) => element.id == roles.find( (element) => element.Id == role_detail[i].roleApprovalMemberShipId).ContactId));

                }
            }
        }
        else
        {
            for (var i = 0; i < mems.length; i++) {
                displine = true;
                fullname = mems[i].fullname;
                if (document.getElementById("gmpersonname").value!="") {
                    if(!fullname.toLowerCase().includes(document.getElementById("gmpersonname").value.toLowerCase())){displine=false}
                }
                if (mems[i].Role==null) { displine=false}
                if (displine) {
                    output_report_line(tableBody,-1,i);
                }
            }
        }
        table.style.fontSize = "10pt";
        document.getElementById("gmTable").innerHTML="";
        myTableDiv.appendChild(table);


        //var tf = new TableFilter('GMourreport',filtersConfig );
        //t
    }

  // var level_de = "e5b6ecb0-0360-9cde-f269-7660a2afb0fb";
    var level_de = "89d2f00e-6d57-8032-be02-47393fcf0556";
   function get_dedata5() {
     console.log("role");
     console.log(roles);
     for (var i=0;i<role_detail.data.length;i++) {
         // We could play with team name here as well - we know the ID => Name for the standard teams
         var r = roles.data.find(e=> e["First name"]+" "+e["Surname"]==role_detail.data[i].FullName&e["Role"]==role_detail.data[i].Role&&e["Unit Name"]==role_detail.data[i].UnitName);
         if (r === undefined) {
             r = roles.data.find(e=> e["First name"]+" "+e["Surname"]==role_detail.data[i].FullName);
         }
          console.log(role_detail.data[i].FullName);
         role_detail.data[i].membershipid = r["Membership Number"];
         role_detail.data[i].teamname = r["Team"];
         console.log(r["Membership Number"]+" "+r["First name"]+" "+r["Surname"]+" "+role_detail.data[i].FullName);
     }


   }
    function  get_dedata4() {
       console.log("mems");
        console.log(mems);
         console.log("role_detail");
        console.log(role_detail);
                              var report = { WhereClause: null,
                  aggregateField: "*",
                  aggregateFunction: "COUNT",
                  distinct: true,
                  emailId: null,
                  isDashboardQuery: false,
                  isHierarchy: true,
                  orderby: "",
                  pageNo: 1,
                  pageSize: 5000,
                  query: "",
                  selectContactFields: null,
                  selectFields: ["FirstName","LastName","MembershipNumber","Role","Team","CountyName","DistrictName","GroupName","Telephone"],
                  table: "PreloadedAwardsDashboardView",
                  teamId: "",
                  unitId: level_de,
                //    unitId:"89d2f00e-6d57-8032-be02-47393fcf0556",
              //    treeVal:{"type":"group","id":"cca1f1b8-25e9-4b2f-a0f4-4f141d5ab86f"},
                  userId: null,
                  viewQueryAction: "data"
                 }
                              var report2 = { WhereClause: null,
                  aggregateField: "*",
                  aggregateFunction: "COUNT",
                  distinct: true,
                  emailId: null,
                  isDashboardQuery: false,
                  isHierarchy: true,
                  orderby: "",
                  pageNo: 1,
                  pageSize: 5000,
                  query: "",
                  selectContactFields: null,
                  selectFields: ["FirstName","LastName","MembershipNumber","EmailAddress","Telephone","DistrictName","County","Role","Team","unitName","Line2","PostalCode","Country","Town","GroupName","CountyName","Line1"],
                  table: "PreloadedAwardsDashboardView",
                  teamId: "",
                  unitId: level_de,
                //    unitId:"89d2f00e-6d57-8032-be02-47393fcf0556",
              //    treeVal:{"type":"group","id":"cca1f1b8-25e9-4b2f-a0f4-4f141d5ab86f"},
                  userId: null,
                  viewQueryAction: "data"
                 }

          GM_xmlhttpRequest({
    method: "POST",
    url: "https://tsa-memportal-prod-fun01.azurewebsites.net/api/DataExplorer/GetResultsAsync",
    data: JSON.stringify(report2),
    headers: {
        "Content-Type": "application/json;odata=minimalmetadata",
        "Authorization": "Bearer " + JSON.parse(localStorage.getItem("authInfo")).idToken,
        "Accept": "application/json, text/plain, */*",
        "Type": "table"

    },

    onload: function(response) { //  console.log(response);console.log(count);
        console.log("report");
     //   console.log(JSON.parse(response.responseText));
        roles = JSON.parse(response.responseText);
        get_dedata5()
    },
    onerror:   function(response) { GM_log("ON Error");GM_log(JSON.stringify(response))},
    onabort:  function(response) { GM_log("ON Abort");GM_log(JSON.stringify(response))}
});

                            }

    function get_dedata3() {
        var q = "";
        for (var i=0;i<mems.length;i++) {
            q+="unitid='"+mems[i].id+"' ";
            if (i!=mems.length-1) { q+=" OR ";}
        }
        var report2 = {
                contactId: "",
                distinct: true,
                id: "",
         isHierarchy: true,
                isDashboardQuery: false,
                name: "",
                order: "asc",
                orderBy: "Lastname",
                pageNo: 1,
                pageSize: 5000,
             //   query: `unitid='e5b6ecb0-0360-9cde-f269-7660a2afb0fb'`,
                query: q,
       // query: `unitid='89d2f00e-6d57-8032-be02-47393fcf0556'`, Runnymede
                selectFields: ["Id", "PreferredName", "FullName", "Firstname", "Lastname", "RoleStatusName", "Role", "unitid", "TeamId", "ParentTeamId", "UnitPrefix", "Unitname","ContactMembershipId", "UnitTypeId"],

          //          "RoleStatusName", "Role"
          //      ],
//selectFields: ["Id"],
                table: "TeamMembersView"
            };
       GM_xmlhttpRequest({
          method: "POST",
    url: "https://tsa-memportal-prod-fun01.azurewebsites.net/api/DataExplorer/GetResultsAsync",
    data: JSON.stringify(report2),
    headers: {
        "Content-Type": "application/json;odata=minimalmetadata",
        "Authorization": "Bearer " + JSON.parse(localStorage.getItem("authInfo")).idToken,
        "Accept": "application/json, text/plain, */*",
        "Type": "table"

    },

    onload: function(response) { //  console.log(response);console.log(count);
          console.log("report2");
        console.log(JSON.parse(response.responseText));
        role_detail = JSON.parse(response.responseText);
        get_dedata4();
    },
    onerror:   function(response) { GM_log("ON Error");GM_log(JSON.stringify(response))},
    onabort:  function(response) { GM_log("ON Abort");GM_log(JSON.stringify(response))}
});

    }

    function get_dedata2(oc) {

         // Get the Tree
        var max=50;
        var datapass = '{"pagesize":'+max+',"nexttoken":'+oc+',"filter":{"global" : "","globaland":false,"fieldand":true},"unitId":"'+level_de+'"}';
        //       console.log(datapass);
        if (debug) {GM_log("Counter for get_Sub Unit "+oc);}
        GM_xmlhttpRequest({
            method: "POST",
            context: oc+1,
            url: "https://tsa-memportal-prod-fun01.azurewebsites.net/api/UnitListingAsync",
            data: datapass,
            headers: {
                "Content-Type": "application/json",
                "Authorization": "Bearer " + JSON.parse(localStorage.getItem("authInfo")).idToken,
                "Accept": "application/json, text/plain, */*"
            },

            onload: function(response) { //  console.log(response);console.log(count);
                if (debug) {GM_log("Counter Received "+response.context)}
                // console.log(JSON.parse(response.responseText).data[1]);
                var mem = null;
                try { mem=JSON.parse(response.responseText).data} catch {console.log("JSON Error "+response.responseText);}
                //   mem =(JSON.parse(response.responseText).data);
                if (mem.length>0) {
                    if (debug) {

                    }
                }
                if ((mem.length==0)&&(debug)) {
                    GM_log("GetData: We got an error collecting data for Sub mems page"+response.context);
                }
                if (mem.length!=0) {
                    mems = mems.concat(mem);
                }
                $("#gmorgstatus")[0].innerHTML = mems.length+" Units read";
                if (debug) {GM_log("Sub Units mems now has length "+mems.length);}
                if (debug) {GM_log("Sub Units mem now has length "+mem.length);}
                if (response.status!=200) {GM_log("HTTP error "+response.status); GM_log(JSON.stringify(response));}
                if ( mem.length ==50) {get_dedata2(oc+1); } else {missed = 0; get_dedata3()};},
            onerror:   function(response) { GM_log("ON Error");GM_log(JSON.stringify(response))},
            onabort:  function(response) { GM_log("ON Abort");GM_log(JSON.stringify(response))}
        });

    }

   function get_data_de() {
        mems =[];
       mems.push({id: level_de});
    get_dedata2(0);
    }



    function get_data_deold() {
    var report = { WhereClause: null,
                  aggregateField: "*",
                  aggregateFunction: "COUNT",
                  distinct: true,
                  emailId: null,
                  isDashboardQuery: false,
                  isHierarchy: true,
                  orderby: "",
                  pageNo: 1,
                  pageSize: 5000,
                  query: "",
                  selectContactFields: null,
                  selectFields: ["FirstName","LastName","MembershipNumber","Role","Team","CountyName","DistrictName","GroupName","Telephone"],
                  table: "PreloadedAwardsDashboardView",
                  teamId: "",
            //      unitId:"e5b6ecb0-0360-9cde-f269-7660a2afb0fb",
                    unitId:"89d2f00e-6d57-8032-be02-47393fcf0556",
              //    treeVal:{"type":"group","id":"cca1f1b8-25e9-4b2f-a0f4-4f141d5ab86f"},
                  userId: null,
                  viewQueryAction: "data"
                 }
    //e5b6ecb0-0360-9cde-f269-7660a2afb0fb
    var report2 = {
                contactId: "",
                distinct: true,
                id: "",
         isHierarchy: true,
                isDashboardQuery: false,
                name: "",
                order: "asc",
                orderBy: "Lastname",
                pageNo: 1,
                pageSize: 5000,
                query: `unitid='e5b6ecb0-0360-9cde-f269-7660a2afb0fb'`,
       // query: `unitid='89d2f00e-6d57-8032-be02-47393fcf0556'`, Runnymede
                selectFields: ["Id", "PreferredName", "FullName", "Firstname", "Lastname", "RoleStatusName", "Role", "unitid", "TeamId", "ParentTeamId", "UnitPrefix", "Unitname","ContactMembershipId", "UnitTypeId"],

          //          "RoleStatusName", "Role"
          //      ],
//selectFields: ["Id"],
                table: "TeamMembersView"
            };
        var report3 = {
                                        contactId: "",
                                        id: "",
                                        name: "",
                                 //       query: "ContactId ='".concat(l, "' AND IsNANUnit = 0"),
                        //                query: `unitid='89d2f00e-6d57-8032-be02-47393fcf0556'`,
             query: `unitid='e5b6ecb0-0360-9cde-f269-7660a2afb0fb'`,
                                        table: "ContactUnitsView",
                                        order: "asc",
                                        orderBy: "Team",
             isHierarchy: true,
                                        selectFields: ["TeamId", "Team", "UnitName", "unitid", "ParentTeam", "ParentTeamId", "unitType", "unitTypeId", "AllowSubTeam", "unitPrefix"],
                                        distinct: !0,
                                        isDashboardQuery: !1
                                    };
          GM_xmlhttpRequest({
    method: "POST",
    url: "https://tsa-memportal-prod-fun01.azurewebsites.net/api/DataExplorer/GetResultsAsync",
    data: JSON.stringify(report),
    headers: {
        "Content-Type": "application/json;odata=minimalmetadata",
        "Authorization": "Bearer " + JSON.parse(localStorage.getItem("authInfo")).idToken,
        "Accept": "application/json, text/plain, */*",
        "Type": "table"

    },

    onload: function(response) { //  console.log(response);console.log(count);
        console.log("report");
        console.log(JSON.parse(response.responseText));
    },
    onerror:   function(response) { GM_log("ON Error");GM_log(JSON.stringify(response))},
    onabort:  function(response) { GM_log("ON Abort");GM_log(JSON.stringify(response))}
});
         GM_xmlhttpRequest({
    method: "POST",
    url: "https://tsa-memportal-prod-fun01.azurewebsites.net/api/DataExplorer/GetResultsAsync",
    data: JSON.stringify(report3),
    headers: {
        "Content-Type": "application/json;odata=minimalmetadata",
        "Authorization": "Bearer " + JSON.parse(localStorage.getItem("authInfo")).idToken,
        "Accept": "application/json, text/plain, */*",
        "Type": "table"

    },

    onload: function(response) { //  console.log(response);console.log(count);
        console.log("report3");
        console.log(JSON.parse(response.responseText));
    },
    onerror:   function(response) { GM_log("ON Error");GM_log(JSON.stringify(response))},
    onabort:  function(response) { GM_log("ON Abort");GM_log(JSON.stringify(response))}
});
                  GM_xmlhttpRequest({
    method: "POST",
    url: "https://tsa-memportal-prod-fun01.azurewebsites.net/api/DataExplorer/GetResultsAsync",
    data: JSON.stringify(report2),
    headers: {
        "Content-Type": "application/json;odata=minimalmetadata",
        "Authorization": "Bearer " + JSON.parse(localStorage.getItem("authInfo")).idToken,
        "Accept": "application/json, text/plain, */*",
        "Type": "table"

    },

    onload: function(response) { //  console.log(response);console.log(count);
          console.log("report2");
        console.log(JSON.parse(response.responseText));
    },
    onerror:   function(response) { GM_log("ON Error");GM_log(JSON.stringify(response))},
    onabort:  function(response) { GM_log("ON Abort");GM_log(JSON.stringify(response))}
});
    }

    function report_onclick() {
        // RUn Report
        //     console.log("Report");
        if   (document.getElementById("gmdebug").checked) {
            debug = true;
        }
        var count = 1;
        mem="";
        //  $("#gmpopup").dialog ( {modal: true, height: 500, width: "100%"} );
        mems = [];
        role_detail=[];
        roles=[];
        document.getElementById("gmTable").innerHTML="Table will appear here....";
        //   document.getElementById("gmUnit").innerHTML = "UKJDKJD";
        var responsetext = "";
        var datapass;
        mem_learning= [];
        learn = [];
        dbs_detail=[];
        var tokexpDate = new Date( JSON.parse(localStorage.getItem("authInfo")).account.idTokenClaims.exp *1000);
       // if(document.getElementById("gmexplorer").checked) {
             get_data_de(count);
      //  } else {
             get_data(count);
      //  }

    }

    function report_onclick2() {
        // Open Dialog
        console.log("Report");
        var count = 1;
        mem="";
        var h = $( window ).height();
        $("#gmpopup").dialog ( {modal: true, height: (h*0.75), width: "100%"} );
        mems = [];
        role_detail=[];
        roles=[];
        memsunique=[];
        //   document.getElementById("gmTable").innerHTML="Table will appear here....";
        var responsetext = "";
        var datapass;
        mem_learning= [];
        keepalive = window.setInterval(function () {
            if (window.location.href=='https://membership.scouts.org.uk/#/learning') {
                var ul = document.getElementById('menu-list-item-left-nav-homePageTile');
                ul.click();
            }
            else {
                ul = document.getElementById('menu-list-item-left-nav-learning');
                ul.click();
            }

            console.log("Keep Alive Active");
        }, 25000);  //5000 is 5 Seconds
        $('#gmpopup').on('dialogclose', function(event) {
            // alert('closed');
            clearInterval(keepalive);
            console.log("Keep Alive Cancelled");
        });
        datapass = '{"pagesize":50,"sort":{"field":"unitName","type":"asc"},"contactId":"'+JSON.parse(localStorage.getItem("authInfo")).idTokenClaims.extension_ContactId+'"}';

        GM_xmlhttpRequest({
    method: "POST",
    url: "https://tsa-memportal-prod-fun01.azurewebsites.net/api/MyUnitsAsync",
    data: datapass,
    headers: {
        "Content-Type": "application/json",
        "Authorization": "Bearer " + JSON.parse(localStorage.getItem("authInfo")).idToken,
        "Accept": "application/json, text/plain, */*"
    },

    onload: function(response) { //  console.log(response);console.log(count);
        var myUnits = JSON.parse(response.responseText);
        for (var i=0;i<myUnits.data.length;i++) {
            document.getElementById("myUnits").innerHTML+= '<option value="'+myUnits.data[i].unitName+'">';
        }
    },
    onerror:   function(response) { GM_log("ON Error");GM_log(JSON.stringify(response))},
    onabort:  function(response) { GM_log("ON Abort");GM_log(JSON.stringify(response))}
});

    }

    function report_print() {

        // var prtContent = document.getElementById("GMourreport");
        //  var prtContent = (tabletabulator.getHtml());
        var WinPrint = window.open('', '', 'left=0,top=0,width=800,height=900,toolbar=0,scrollbars=0,status=0');
        WinPrint.document.body.innerHTML = tabletabulator.getHtml();
        WinPrint.document.head.innerHTML += '<style> th.blue-background {    writing-mode: vertical-lr;    background-color: lightcyan; } \
th.yellow-background {    writing-mode: vertical-lr;    background-color: lightgoldenrodyellow; } th.orange-background {    writing-mode: vertical-lr;    background-color: salmon; } \
table.tabulator-print-table, tr, th, td {    border: solid;font-family: sans-serif;}</style>';
        //   WinPrint.document.close();
        WinPrint.focus();
        WinPrint.print();
        WinPrint.close();
    }

    function savecolors() {
        GM_setValue("colors", JSON.stringify(colors));
        GM_setValue("colorsT", JSON.stringify(colorsT));
    }
    function resetcolors() {
        colors = defcolors;
        colorsT = defcolorsT;
        for(cloop=0; cloop<colors.length;cloop++){
            document.getElementById("cpreview"+cloop).style.backgroundColor = colors[cloop];
            document.getElementById("cpreview"+cloop).style.color = colorsT[cloop];
            document.getElementById("back"+cloop).value = colors[cloop];
            document.getElementById("fore"+cloop).value = colorsT[cloop];
        }

    }
    function updateFirstC(event) {
        console.log("Update First");
        if (event.target.name.includes("back")) {
            document.getElementById("cpreview"+event.target.name[4]).style.backgroundColor = event.target.value;
            colors[event.target.name[4]] = event.target.value;
        }
        if (event.target.name.includes("fore")) {
            document.getElementById("cpreview"+event.target.name[4]).style.color = event.target.value;
            colorsT[event.target.name[4]] = event.target.value;
        }

        console.log(event);
    }

    function watchColorPicker(event) {
        console.log("Watch CP");
        console.log(event);
    }

    var unitsearchvalues = ["866060008","866060006","866060005","866060004","866060007","866060003","866060002","866060001","866060000"];
    var unitsearchtypes = ["Organisation","Country","Region","County","County Section","District","District Section","Group","Group Section"];
    var unitcount = [];
    var orglevel = 0;
    var  teams = [];
    var subteams = [];
    var maxsubteam = 0;


    function get_orgdata(oc,ol) {
        // Find the root
        var max = 50;
        teams = [];
        subteams = [];
        maxsubteam = 0;
        un = document.getElementById("gmunitnameo").value;
        var unt= unitsearchvalues[ol];
        if (debug) {GM_log("Unit Request for "+un+" Count "+oc+"/"+ol);}
        if (debug) {
            GM_log("Unit Request for "+un+" :"+ JSON.parse(localStorage.getItem("authInfo")).idToken.substring(1,50));
            var tokexpDate = new Date( JSON.parse(localStorage.getItem("authInfo")).account.idTokenClaims.exp *1000);
        }
        $("#gmorgstatus")[0].innerHTML = "Checking for "+unitsearchtypes[ol]+" "+un;
        var datapass = '{"pagesize":'+max+',"nexttoken":'+oc+',"filter":{"global" : "","globaland":false,"fieldand":true,filterfields:[{ "field" : "'+unt+'", "value": "'+un+'"}]},"unitId":""}';
        if (debug) {GM_log("Counter for get_data "+oc);}
        GM_xmlhttpRequest({
            method: "POST",
            context: oc+1,
            url: "https://tsa-memportal-prod-fun01.azurewebsites.net/api/UnitListingAsync",
            data: datapass,
            headers: {
                "Content-Type": "application/json",
                "Authorization": "Bearer " + JSON.parse(localStorage.getItem("authInfo")).idToken,
                "Accept": "application/json, text/plain, */*"
            },

            onload: function(response) { //  console.log(response);console.log(count);
                if (debug) {GM_log("Counter Recieved "+response.context)}
                // console.log(JSON.parse(response.responseText).data[1]);
                var mem = null;
                try { mem=JSON.parse(response.responseText).data} catch {console.log("JSON Error "+response.responseText);}
                //   mem =(JSON.parse(response.responseText).data);
                if (mem.length>0) {
                    if (debug) {

                    }
                }
                if ((mem.length==0)&&(debug)) {
                    GM_log("GetData: We got an error collecting data for mems page"+response.context);
                }
                if (mem.length!=0) {
                    mems = mems.concat(mem);
                }
                if (debug) {GM_log("mems now has length "+mems.length);}


                if (response.status!=200) {GM_log("HTTP error "+response.status); GM_log(JSON.stringify(response));}
                $("#gmorgstatus")[0].innerHTML = "Checking for "+unitsearchtypes[response.context]+" "+un;

                if ((ol<unitsearchvalues.length)&&( mems.length==0)) {get_orgdata(oc,ol+1); } else {

                    var  filter = document.getElementById("gmunitnameo").value.replaceAll("%", "*");
                    let w = filter.replace(/[.+^${}()|[\]\\]/g, '\\$&'); // regexp escape
                    const re = new RegExp(`^${w.replace(/\*/g,'.*').replace(/\?/g,'.')}$`,'i');
                    mems = mems.filter( function(v) {return re.test(v.unitName)});
                    //      if (debug) {GM_log("Re: Filter by for Unit only roles now has length "+roles.length);}


                    get_orgdata2(0)};
            },
            onerror:   function(response) { GM_log("ON Error");GM_log(JSON.stringify(response))},
            onabort:  function(response) { GM_log("ON Abort");GM_log(JSON.stringify(response))}
        });

    }

    var tealgrad = new go.Brush('Linear', { 0: 'rgb(32, 178, 170)', 1: 'rgb(0,128,128)' });
    var greengrad = new go.Brush('Linear', { 0: 'rgb(154, 205, 50)', 1: 'rgb(34, 139, 34)' });
    var bluegrad = new go.Brush('Linear', { 0: 'rgb(135, 206, 235)', 1: 'rgb(0, 191, 255)' });
    var redgrad = new go.Brush('Linear', { 0: 'rgb(220, 20, 60)', 1: 'rgb(255, 0, 0)' });
    var browngrad = new go.Brush('Linear', { 0: 'rgb(218, 160, 109)', 1: 'rgb(149, 69, 53 )' });
    var blackgrad = new go.Brush('Linear', { 0: 'rgb(0,0,0)', 1: 'rgb(0,0,0 )' });
    var pinkgrad = new go.Brush('Linear', { 0: 'rgb(128,0,0)', 1: 'rgb(200,0,0 )' });
    var greygrad = new go.Brush('Linear', { 0: 'rgb(128,128,128)', 1: 'rgb(200,200,200 )' });
    var purplegrad = new go.Brush('Linear', { 0: 'rgb(138,43,226)', 1: 'rgb(147,112,219 )' });


    function sectionBrushConverter(node) {
        if (node.unitType === "Group Section") {
            if (node.unitName.includes("Cub")) { return greengrad}
            if (node.unitName.includes("Pack")) { return greengrad}
            if (node.unitName.includes("Squirrel")) { return redgrad}
            if (node.unitName.includes("Drey")) { return redgrad}
            if (node.unitName.includes("Beaver")) { return bluegrad}
            if (node.unitName.includes("Colony")) { return bluegrad}
            return tealgrad;
        }
        if (node.unitType === "District Section") {
            return browngrad;
        }
        if (node.unitType === "Group") {
            return pinkgrad;
        }
        if (node.unitType === "District") {
            return blackgrad;
        }
        if (node.unitType === "Team") {
            return purplegrad;
        }
        if (node.unitType === "Sub Team") {
            return greygrad;
        }

        return "#44CCFF"
        // if (gender === "F") return pinkgrad;
    }

    var missed = 0;

    function get_orgdata2(oc) {
        // Get the Tree
        if (mems.length==0) { $("#gmorgstatus")[0].innerHTML = "No Units found";}

        var max=50;
        var datapass = '{"pagesize":'+max+',"nexttoken":'+oc+',"filter":{"global" : "","globaland":false,"fieldand":true},"unitId":"'+mems[0].id+'"}';
        //       console.log(datapass);
        if (debug) {GM_log("Counter for get_Sub Unit "+oc);}
        GM_xmlhttpRequest({
            method: "POST",
            context: oc+1,
            url: "https://tsa-memportal-prod-fun01.azurewebsites.net/api/UnitListingAsync",
            data: datapass,
            headers: {
                "Content-Type": "application/json",
                "Authorization": "Bearer " + JSON.parse(localStorage.getItem("authInfo")).idToken,
                "Accept": "application/json, text/plain, */*"
            },

            onload: function(response) { //  console.log(response);console.log(count);
                if (debug) {GM_log("Counter Received "+response.context)}
                // console.log(JSON.parse(response.responseText).data[1]);
                var mem = null;
                try { mem=JSON.parse(response.responseText).data} catch {console.log("JSON Error "+response.responseText);}
                //   mem =(JSON.parse(response.responseText).data);
                if (mem.length>0) {
                    if (debug) {

                    }
                }
                if ((mem.length==0)&&(debug)) {
                    GM_log("GetData: We got an error collecting data for Sub mems page"+response.context);
                }
                if (mem.length!=0) {
                    mems = mems.concat(mem);
                }
                $("#gmorgstatus")[0].innerHTML = mems.length+" Units read";
                if (debug) {GM_log("Sub Units mems now has length "+mems.length);}
                if (debug) {GM_log("Sub Units mem now has length "+mem.length);}
                if (response.status!=200) {GM_log("HTTP error "+response.status); GM_log(JSON.stringify(response));}
                if ( mem.length ==50) {get_orgdata2(oc+1); } else {missed = 0; get_orgdata5()};},
            onerror:   function(response) { GM_log("ON Error");GM_log(JSON.stringify(response))},
            onabort:  function(response) { GM_log("ON Abort");GM_log(JSON.stringify(response))}
        });

    }




    function  get_orgdata5() {
        // Get Teams
        var minlevel = $("#gmorglevel").val();
        mems = mems.filter(function(n) {return n.UnitLevel>=minlevel});
        if (mems.length==0) { $("#gmorgstatus")[0].innerHTML = "No Units found";}

        //  $("#gmorgstatus")[0].innerHTML = response.context+" sub teams read";

        var exclude_section_teams = document.getElementById("gmnosteams").checked;
        var exclude_all_teams = document.getElementById("gmnoteams").checked;
        if (!exclude_all_teams) {
            for(var i=0;i<mems.length;i++) {

                //(b.unitType === "Group Section")&&(a.unitType === "Group Section")
                if ((exclude_section_teams)&&((mems[i].unitType === "Group Section")||(mems[i].unitType === "District Section")))  {
                    missed+=1;
                } else {
                    var datapass = '{"unitId":"'+mems[i].id+'","type":"team"}';
                    GM_xmlhttpRequest({
                        method: "POST",
                        context: i+1,
                        url: "https://tsa-memportal-prod-fun01.azurewebsites.net/api/UnitTeamsAndRolesListingAsync",
                        data: datapass,
                        headers: {
                            "Content-Type": "application/json",
                            "Authorization": "Bearer " + JSON.parse(localStorage.getItem("authInfo")).idToken,
                            "Accept": "application/json, text/plain, */*"
                        },

                        onload: function(response) { //  console.log(response);console.log(count);
                            if (debug) {GM_log("Counter Recieved "+response.context)}
                            // console.log(JSON.parse(response.responseText).data[1]);
                            var mem = null;
                            try { mem=JSON.parse(response.responseText)} catch {console.log("JSON Error "+response.responseText);}
                            //   mem =(JSON.parse(response.responseText).data);
                            $("#gmorgstatus")[0].innerHTML = response.context+" teams read";
                            teams.push(mem);
                            //console.log(mem);
                            //    $("#gmorgstatus")[0].innerHTML = mems.length+" Units read";

                            if (response.status!=200) {GM_log("HTTP error "+response.status); GM_log(JSON.stringify(response));}

                            $("#gmState")[0].innerText = "Reading Sub Units for "+un+" ("+response.context+") "+"Total read "+mems.length;
                            if ( teams.length+missed== mems.length) {subteams = []; maxsubteam=0; get_orgdata6();}},
                        onerror:   function(response) { GM_log("ON Error");GM_log(JSON.stringify(response))},
                        onabort:  function(response) { GM_log("ON Abort");GM_log(JSON.stringify(response))}
                    });

                }

            }} else {get_orgdata3(false)}
    }


    function  get_orgdata6() {
        for(var i=0;i<teams.length;i++) {
            for (var j=0;j<teams[i].teams.length;j++) {
                if (teams[i].teams[j].allowSubTeam){
                    maxsubteam +=1;
                    var datapass = '{"unitId":"'+teams[i].unitId+'","type":"subteam","teamId" :"'+teams[i].teams[j].teamId+'"}';
                    GM_xmlhttpRequest({
                        method: "POST",
                        context: maxsubteam,
                        url: "https://tsa-memportal-prod-fun01.azurewebsites.net/api/UnitTeamsAndRolesListingAsync",
                        data: datapass,
                        headers: {
                            "Content-Type": "application/json",
                            "Authorization": "Bearer " + JSON.parse(localStorage.getItem("authInfo")).idToken,
                            "Accept": "application/json, text/plain, */*"
                        },

                        onload: function(response) { //  console.log(response);console.log(count);
                            if (debug) {GM_log("Counter Recieved "+response.context)}
                            // console.log(JSON.parse(response.responseText).data[1]);
                            var mem = null;
                            try { mem=JSON.parse(response.responseText)} catch {console.log("JSON Error "+response.responseText);}
                            //   mem =(JSON.parse(response.responseText).data);

                            subteams.push(mem);
                            //console.log(mem);
                            //    $("#gmorgstatus")[0].innerHTML = mems.length+" Units read";
                            $("#gmorgstatus")[0].innerHTML = response.context+" sub teams read";
                            if (response.status!=200) {GM_log("HTTP error "+response.status); GM_log(JSON.stringify(response));}

                            $("#gmState")[0].innerText = "Reading Sub Units for "+un+" ("+response.context+") "+"Total read "+mems.length;
                            if ( response.context == maxsubteam) {get_orgdata3(false);}},
                        onerror:   function(response) { GM_log("ON Error");GM_log(JSON.stringify(response))},
                        onabort:  function(response) { GM_log("ON Abort");GM_log(JSON.stringify(response))}
                    });

                }
            }
        }
    }
    function section_sort(a,b) {
        if (a.UnitLevel!=b.UnitLevel) {
            if (a.UnitLevel<b.UnitLevel) {return -1}
            if (a.UnitLevel==b.UnitLevel) {return 0}
            if (a.UnitLevel>b.UnitLevel) {return 1}
        }

        if ((a.UnitLevel==b.UnitLevel)&&(a.UnitLevel!=1)) {
            if (a.unitName<b.unitName) {return -1}
            if (a.unitName==b.unitName) {return 0}
            if (a.unitName>b.unitName) {return 1}
        }

        if ((b.unitType === "Group Section")&&(a.unitType === "Group Section")) {
            var asection = 4;
            if (a.unitName.includes("Cub")) {asection = 3;}
            if (a.unitName.includes("Pack")) { asection = 3;}
            if (a.unitName.includes("Drey")) { asection = 1;}
            if (a.unitName.includes("Squirrel")) { asection = 1;}
            if (a.unitName.includes("Beaver")) {asection = 2;}
            if (a.unitName.includes("Colony")) { asection = 2;}
            var bsection = 4;
            if (b.unitName.includes("Cub")) {bsection = 3;}
            if (b.unitName.includes("Pack")) { bsection = 3;}
            if (b.unitName.includes("Drey")) { bsection = 1;}
            if (b.unitName.includes("Squirrel")) { bsection = 1;}
            if (b.unitName.includes("Beaver")) {bsection = 2;}
            if (b.unitName.includes("Colony")) { bsection = 2;}
            if (asection<bsection) {return -1}
            if (asection==bsection) {return 0}
            if (asection>bsection) {return 1}
        }




        return 0
    }

    function section_sort2(a,b) {
        var c= section_sort(a,b) ;
        //   console.log(a.unitType +" "+a.unitName+" "+b.unitType +" "+b.unitName+" "+c);
        return c;
    }

    function get_orgdata3(justdisplay) {
        if (!justdisplay) {
            // Add in Teams
            for (var i=0; i<teams.length;i++) {
                for (var j=0; j<teams[i].teams.length; j++) {
                    var mem = new Object;
                    mem.parentUnitId =  teams[i].unitId;
                    mem.id = teams[i].teams[j].teamId+teams[i].unitId;
                    mem.unitName = teams[i].teams[j].teamName;
                    mem.UnitLevel = 98;
                    mem.unitType = "Team";
                    mem.teamunitId = teams[i].unitId;
                    mems.push(mem);
                }
            }
            for (i=0;i<subteams.length; i++) {
                if (subteams[i].teams!=null) {
                    for ( j=0; j<subteams[i].teams.length; j++) {
                        mem = new Object;
                        mem.parentUnitId =  subteams[i].teams[j].parentTeamId+ subteams[i].unitId;
                        mem.id = subteams[i].teams[j].teamId;
                        mem.unitName = subteams[i].teams[j].teamName;
                        mem.UnitLevel = 99;
                        mem.unitType = "Sub Team";
                        mem.teamunitId = subteams[i].unitId;
                        mems.push(mem);
                    }}}
            mems.sort(section_sort2);
            console.log(mems);
            console.log("teams");
            console.log(teams);
            console.log("Subteams");
            console.log(subteams);
        }
        myDiagram.nodeTemplate =
            new go.Node("Horizontal",
                        { background: "#44CCFF" }).bind('background', '', sectionBrushConverter)
            .add(
            //  new go.Picture({ margin: 10, width: 50, height: 50, background: "red" })
            //    .bind("source"),
            new go.TextBlock("Default Text",
                             { margin: 8, stroke: "white", font: "bold 12px sans-serif" })
            .bind("text", "unitName")
        );



        myDiagram.linkTemplate =
            new go.Link(
            // default routing is go.Routing.Normal
            // default corner is 0
            { routing: go.Routing.Orthogonal, corner: 5 })
            .add(
            // the link path, a Shape
            new go.Shape({ strokeWidth: 3, stroke: "#555" }),
            // if we wanted an arrowhead we would also add another Shape with toArrow defined:
            //new go.Shape({  toArrow: "Standard", stroke: null  })
        );


        myDiagram.addDiagramListener("ObjectSingleClicked",
                                     e => {
            //   console.log(e.hm.nl.ii);
            var gotourl = "https://membership.scouts.org.uk/#/teams/allunits/";

            if (e.hm.nl.ii.UnitLevel>97) {
                gotourl+=e.hm.nl.ii.teamunitId } else
                {gotourl+=e.hm.nl.ii.id.substring(0,36);}
            if (e.hm.nl.ii.UnitLevel<20) {
                gotourl+="/unitdetailsau";
            }
            if (e.hm.nl.ii.UnitLevel>97) {
                gotourl+="/teamsau/";
            }
            if (e.hm.nl.ii.UnitLevel==99) {
                gotourl+=(e.hm.nl.ii.parentUnitId).substring(0,36);
            }
            if (e.hm.nl.ii.UnitLevel==98) {
                gotourl+=(e.hm.nl.ii.id).substring(0,36);
            }
            if (e.hm.nl.ii.UnitLevel>97) {
                gotourl+="/teamdashboardaut";
            }
            if (e.hm.nl.ii.UnitLevel==99) {
                gotourl+="/"+(e.hm.nl.ii.id).substring(0,36)+"/subteamdashboardaust";
            }
            window.location.assign(gotourl);
        });


        myDiagram.model =
            new go.TreeModel(
            { nodeParentKeyProperty: "parentUnitId",  // this property refers to the parent node data
             nodeKeyProperty : "id",
             nodeDataArray: mems,
             angle: 90,
             arrangement: true,
             scale: 0.25,
             initialDocumentSpot: go.Spot.Top,
             initialViewportSpot: go.Spot.Top});


    }

    //   var map = {};

    function show_organogram() {
        var h = $( window ).height();
        $("#gmorganogram").dialog ( {modal: false, height: (h*0.75), width: "80%"} );
        try { myDiagram = new go.Diagram("myDiagramDiv",{
            "undoManager.isEnabled": true,
            layout: new go.TreeLayout({ angle: 0, layerSpacing: 35, scale: 0.25 }) // initialAutoScale: go.AutoScale.UniformToFill })
        });} catch {}
        myDiagram.addDiagramListener('InitialLayoutCompleted', function(e) {
            var dia = e.diagram;
            // add height for horizontal scrollbar
            dia.div.style.width = (dia.documentBounds.width + 24) + "px";
            if (( (dia.documentBounds.height + 24)  *  (dia.documentBounds.width))< 20000000 ) {
                dia.div.style.height = (dia.documentBounds.height + 24) + "px";
            } else {  dia.div.style.height = "25000px";}

        });

        orgcounter = 0;
        mems=[];
        orglevel = 0;
        //  debug = true;
        mems = GM_getValue("orgmems", []);

        get_orgdata3(true);
        //   get_orgdata(orgcounter,orglevel);
    }
    var locations = [];

    function get_mapdata5() {
        var errors = [];
        for (var i=1; i<mapunits.length; i++) {
            if (mapunits[i].unitType=="Group") {
                var postcode ="";
                if (mapunits[i].contactDetails.meetingPlaceAddress.postcode !="") {
                    postcode = mapunits[i].contactDetails.meetingPlaceAddress.postcode
                } else {
                    if (mapunits[i].contactDetails.correspondenceAddress.postcode !="") {
                        postcode = mapunits[i].contactDetails.correspondenceAddress.postcode
                    }
                }
                if (postcode!="") {
                    var loc = locations.find(e=>e.query == postcode);
                    if (loc.result!=null){

                        var marker = L.marker([loc.result.latitude,loc.result.longitude],{icon: mappin}).addTo(map).bindPopup(mapunits[i].name).openPopup();
                    } else { errors.push("Invalid postcode for "+mapunits[i].name+" "+postcode);}
                } else { errors.push("No postcode for "+mapunits[i].name);}
            }
        }
        $("#gmerrors")[0].innerHTML ="";
        for (i=0;i<errors.length;i++) {
            $("#gmerrors")[0].innerHTML += errors[i]+"<br>";
        }
    }

    function get_postcodes(index) {
        var subpostcodes = [];
        for(var i=index*100;i<(index*100+100)&&i<postcodes.length;i++) {
            subpostcodes.push(postcodes[i]);
        }
        console.log(subpostcodes);
        var pi = {};
        pi.postcodes = subpostcodes;
        var datapass = JSON.stringify(pi);
        GM_xmlhttpRequest({
            method: "POST",
            context: index+1,
            url: "https://api.postcodes.io/postcodes?filter=postcode,longitude,latitude",
            data: datapass,
            headers: {
                "Content-Type": "application/json",
                "Authorization": "Bearer " + JSON.parse(localStorage.getItem("authInfo")).idToken,
                "Accept": "application/json, text/plain, */*"
            },

            onload: function(response) { //  console.log(response);console.log(count);
                //    console.log(response.responseText);
                locations  = locations.concat(JSON.parse(response.responseText).result);
                $("#gmmapstatus")[0].innerHTML = locations.length+" Postcodes read of "+postcodes.length;
                if ((response.context)*100<postcodes.length) {get_postcodes(response.context)} else {get_mapdata5()};
            },
            onerror:   function(response) { GM_log("ON Error");GM_log(JSON.stringify(response))},
            onabort:  function(response) { GM_log("ON Abort");GM_log(JSON.stringify(response))}
        });

    }

    function get_mapdata4() {
        console.log(mapunits);
        postcodes=[];
        for (var i=0;i<mapunits.length;i++) {
            if (mapunits[i].contactDetails.meetingPlaceAddress.postcode !="") { postcodes.push(mapunits[i].contactDetails.meetingPlaceAddress.postcode) } else {
                if (mapunits[i].contactDetails.correspondenceAddress.postcode !="") {postcodes.push(mapunits[i].contactDetails.correspondenceAddress.postcode) }
            }
        }


        get_postcodes(0);

    }
    function get_mapdata3() {
        debug = true;
        // Remove verything but sections
        console.log(mapmems);
        mapunits = [];
        //https://tsa-memportal-prod-fun01.azurewebsites.net/api/GetUnitDetailAsync
        //unitId: "8942fe62-d032-4651-9317-7a9b929e710d"
        for (var i=1; i<mapmems.length; i++) {
            if (mapmems[i].unitType=="Group") {
                console.log("Unit "+i+" "+mapmems[i].unitName);
                var datapass = '{"unitId": "'+mapmems[i].id+'"}';
                GM_xmlhttpRequest({
                    method: "POST",
                    context: i+1,
                    url: "https://tsa-memportal-prod-fun01.azurewebsites.net/api/GetUnitDetailAsync",
                    data: datapass,
                    headers: {
                        "Content-Type": "application/json",
                        "Authorization": "Bearer " + JSON.parse(localStorage.getItem("authInfo")).idToken,
                        "Accept": "application/json, text/plain, */*"
                    },

                    onload: function(response) { //  console.log(response);console.log(count);
                        if (debug) {GM_log("Counter Received "+response.context)}
                        // console.log(JSON.parse(response.responseText).data[1]);
                        var mem = null;
                        try { mem = JSON.parse(response.responseText)} catch {console.log("JSON Error "+response.responseText);}
                        //   mem =(JSON.parse(response.responseText).data);
                        mapunits.push(mem);
                        //    console.log(mapunits);
                        if (mapunits.length==mapmems.filter(e=>e.unitType=="Group").length) {
                            get_mapdata4();
                        }
                        $("#gmmapstatus")[0].innerHTML = mapunits.length+" Groups read of "+mapmems.filter(e=>e.unitType=="Group").length;
                        if (debug) {GM_log("Units mems now has length "+mapmems.length);}
                        if (response.status!=200) {GM_log("HTTP error "+response.status); GM_log(JSON.stringify(response));}
                    },
                    onerror:   function(response) { GM_log("ON Error");GM_log(JSON.stringify(response))},
                    onabort:  function(response) { GM_log("ON Abort");GM_log(JSON.stringify(response))}
                });
            }}
    }
    function get_mapdata2(oc) {
        // Get the Tree
        if (mems.length==0) { $("#gmorgstatus")[0].innerHTML = "No Units found";}

        var max=50;
        var datapass = '{"pagesize":'+max+',"nexttoken":'+oc+',"filter":{"global" : "","globaland":false,"fieldand":true},"unitId":"'+mapmems[0].id+'"}';
        //       console.log(datapass);
        if (debug) {GM_log("Counter for get_Sub Unit "+oc);}
        GM_xmlhttpRequest({
            method: "POST",
            context: oc+1,
            url: "https://tsa-memportal-prod-fun01.azurewebsites.net/api/UnitListingAsync",
            data: datapass,
            headers: {
                "Content-Type": "application/json",
                "Authorization": "Bearer " + JSON.parse(localStorage.getItem("authInfo")).idToken,
                "Accept": "application/json, text/plain, */*"
            },

            onload: function(response) { //  console.log(response);console.log(count);
                if (debug) {GM_log("Counter Received "+response.context)}
                // console.log(JSON.parse(response.responseText).data[1]);
                var mem = null;
                try { mem=JSON.parse(response.responseText).data} catch {console.log("JSON Error "+response.responseText);}
                //   mem =(JSON.parse(response.responseText).data);
                if (mem.length>0) {
                    if (debug) {

                    }
                }
                if ((mem.length==0)&&(debug)) {
                    GM_log("GetData: We got an error collecting data for Sub mems page"+response.context);
                }
                if (mem.length!=0) {
                    mapmems = mapmems.concat(mem);
                }
                $("#gmmapstatus")[0].innerHTML = mapmems.length+" Units read";
                if (debug) {GM_log("Units mems now has length "+mapmems.length);}
                if (response.status!=200) {GM_log("HTTP error "+response.status); GM_log(JSON.stringify(response));}
                if ( mem.length ==50) {get_mapdata2(oc+1); } else {missed = 0; mapunits=[]; get_mapdata3()};},
            onerror:   function(response) { GM_log("ON Error");GM_log(JSON.stringify(response))},
            onabort:  function(response) { GM_log("ON Abort");GM_log(JSON.stringify(response))}
        });

    }

    function get_mapdata(oc,ol) {
        // Find the root
        var max = 50;

        un = document.getElementById("gmunitnamem").value;
        var unt= unitsearchvalues[ol];
        if (debug) {GM_log("Unit Request for "+un+" Count "+oc+"/"+ol);}
        if (debug) {
            GM_log("Unit Request for "+un+" :"+ JSON.parse(localStorage.getItem("authInfo")).idToken.substring(1,50));
            var tokexpDate = new Date( JSON.parse(localStorage.getItem("authInfo")).account.idTokenClaims.exp *1000);
        }
        $("#gmmapstatus")[0].innerHTML = "Checking for "+unitsearchtypes[ol]+" "+un;
        var datapass = '{"pagesize":'+max+',"nexttoken":'+oc+',"filter":{"global" : "","globaland":false,"fieldand":true,filterfields:[{ "field" : "'+unt+'", "value": "'+un+'"}]},"unitId":""}';
        if (debug) {GM_log("Counter for get_data "+oc);}
        GM_xmlhttpRequest({
            method: "POST",
            context: ol+1,
            url: "https://tsa-memportal-prod-fun01.azurewebsites.net/api/UnitListingAsync",
            data: datapass,
            headers: {
                "Content-Type": "application/json",
                "Authorization": "Bearer " + JSON.parse(localStorage.getItem("authInfo")).idToken,
                "Accept": "application/json, text/plain, */*"
            },

            onload: function(response) { //  console.log(response);console.log(count);
                if (debug) {GM_log("Counter Recieved "+response.context)}
                // console.log(JSON.parse(response.responseText).data[1]);
                var mem = null;
                try { mem=JSON.parse(response.responseText).data} catch {console.log("JSON Error "+response.responseText);}
                //   mem =(JSON.parse(response.responseText).data);
                if (mem.length>0) {
                    if (debug) {

                    }
                }
                if ((mem.length==0)&&(debug)) {
                    GM_log("GetData: We got an error collecting data for map mems page"+response.context);
                }
                if (mem.length!=0) {
                    mapmems = mapmems.concat(mem);
                }
                if (debug) {GM_log("map mems now has length "+mapmems.length);}


                if (response.status!=200) {GM_log("HTTP error "+response.status); GM_log(JSON.stringify(response));}
                $("#gmmapstatus")[0].innerHTML = "Checking for "+unitsearchtypes[response.context-1]+" "+un;

                if ((ol<unitsearchvalues.length)&&( mapmems.length==0)) {get_mapdata(oc,response.context); } else {

                    var  filter = document.getElementById("gmunitnamem").value.replaceAll("%", "*");
                    let w = filter.replace(/[.+^${}()|[\]\\]/g, '\\$&'); // regexp escape
                    const re = new RegExp(`^${w.replace(/\*/g,'.*').replace(/\?/g,'.')}$`,'i');
                    mapmems = mapmems.filter( function(v) {return re.test(v.unitName)});



                    get_mapdata2(0)};
            },
            onerror:   function(response) { GM_log("ON Error");GM_log(JSON.stringify(response))},
            onabort:  function(response) { GM_log("ON Abort");GM_log(JSON.stringify(response))}
        });

    }

    function show_map() {
        var h = $( window ).height();
        $("#gmmap").dialog ( {modal: false, height: (h*0.75), width: "80%"} );
        try {
            map = L.map('gmmapdiv').setView([51.505, -0.09], 13);
        } catch {}
        L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
            maxZoom: 19,
            attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
        }).addTo(map);

        mappin = L.icon({
            iconUrl: GM_getResourceURL("LeafletPin"),
            shadowUrl: GM_getResourceURL("LeafletShadow"),

            iconSize:     [25, 41], // size of the icon
            shadowSize:   [41, 41], // size of the shadow
            iconAnchor:   [12, 0], // point of the icon which will correspond to marker's location
            shadowAnchor: [0, 0],  // the same for the shadow
            popupAnchor:  [-3, -41] // point from which the popup should open relative to the iconAnchor
        });
        orgcounter = 0;
        mapmems=[];
        orglevel = 0;
        //  debug = true;
        //    mems = GM_getValue("orgmems", []);

        //  get_mapdata3(true);
        //   get_orgdata(orgcounter,orglevel);
    }

    function myCallback(blob) {
        var url = window.URL.createObjectURL(blob);
        var filename = 'myBlobFile.png';

        var a = document.createElement('a');
        a.style = 'display: none';
        a.href = url;
        a.download = filename;

        // IE 11
        if (window.navigator.msSaveBlob !== undefined) {
            window.navigator.msSaveBlob(blob, filename);
            return;
        }
        document.body.appendChild(a);
        requestAnimationFrame(() => {
            a.click();
            window.URL.revokeObjectURL(url);
            document.body.removeChild(a);
        });
    }

    function  down_organogram() {
        var blob = myDiagram.makeImageData({ background: 'white', returnType: 'blob', callback: myCallback,   size: new go.Size(NaN,NaN) });
        console.log(myDiagram.documentBounds.height);
        console.log(myDiagram.documentBounds.width);
    }

    function  save_organogram() {
        GM_setValue("orgmems", mems);
        $("#gmorgstatus")[0].innerHTML = "Hierarchy saved for instant recall";
    }

    function run_organogram() {

        orgcounter = 0;
        mems=[];
        orglevel = 0;
        orglevel = +document.getElementById("gmsorglevel").value;
        //     debug = true;
        get_orgdata(orgcounter,orglevel);

    }

    function run_map() {

        orgcounter = 0;
        mapmems=[];
        orglevel = 0;
        orglevel = +document.getElementById("gmsmaplevel").value;
        get_mapdata(orgcounter,orglevel);

    }

    function clear_cookies() {
        var cookies = document.cookie.split("; ");
        for (var c = 0; c < cookies.length; c++) {
            var d = window.location.hostname.split(".");
            while (d.length > 0) {
                var cookieBase = encodeURIComponent(cookies[c].split(";")[0].split("=")[0]) + '=; expires=Thu, 01-Jan-1970 00:00:01 GMT; domain=' + d.join('.') + ' ;path=';
                var p = location.pathname.split('/');
                document.cookie = cookieBase + '/';
                while (p.length > 0) {
                    document.cookie = cookieBase + p.join('/');
                    p.pop();
                };
                d.shift();
            }
        }
    }

    function run_learn() {
        GM_xmlhttpRequest({
            method: "GET",
            context: 1,
            url: "https://learn.scouts.org.uk/ilp/restapi/lms/dashboards/8/panels/121/results/table?exportAggregations=false&skill=152688,149148,149147,153014,7804027,7802399,116405,10613435&assessmentType=0",
            //    data: datapass,
            headers: {
                "Content-Type": "application/json",
                "Authorization": "Bearer " + JSON.parse(localStorage.getItem("authInfo")).idToken,
                "Accept": "application/json, text/plain, */*"
            },

            onload: function(response) { //  console.log(response);console.log(count);
                console.log(response);
                console.log(xmlToJson(response.responseText));
                console.log(JSON.parse(xmlToJson(response.responseText)));_
            },
            onerror:   function(response) { GM_log("ON Error");GM_log(JSON.stringify(response))},
            onabort:  function(response) { GM_log("ON Abort");GM_log(JSON.stringify(response))}
        });


    }

    function  report_saveXLS() {
        // document.getElementById("gmTabulator2").innerHTML = (tabletabulator.getHtml());
        tabletabulator.download("xlsx", "data.xlsx", {sheetName:"My Data",documentProcessing: function(wb) {

            /* create a new worksheet */
            var ws = XLSX.utils.aoa_to_sheet([
                ["Data Extracted from Scout Membership system"],
                ["Export Date:", new Date()]
            ]);

            /* add to workbook */
            //https://github.com/gitbrent/xlsx-js-style
            XLSX.utils.book_append_sheet(wb, ws, "Extract Information");
            //  wb.Sheets['My Data']['A1'].s = { font: { bold: true, color: { rgb: "FF0000" } } }
            for(var i=7;i<16;i++) {
                //   wb.Sheets['My Data'][XLSX.utils.encode_cell({r:1, c:i})].s =  { alignment: { textRotation: 180 }  }
            }
            var cw = tabletabulator.getColumnLayout();
            var wc = [];
            var cnames = [];
            var cc = 0;
            // Headers
            for (i=0; i<cw.length;i++) {
                if (cw[i].hasOwnProperty("columns")) {
                    var group_visible = false;
                    var group_start = cc;
                    for (var j=0; j<cw[i].columns.length;j++) {
                        if (cw[i].columns[j].visible) {
                            group_visible = true;
                      //  if ( wb.Sheets['My Data'].hasOwnProperty(XLSX.utils.encode_cell({r:1, c:cc}))) {
                            wb.Sheets['My Data'][XLSX.utils.encode_cell({r:1, c:cc})].s = { font: { bold: true}};
                            if(cw[i].columns[j].hasOwnProperty("headerVertical")) {
                                wb.Sheets['My Data'][XLSX.utils.encode_cell({r:1, c:cc})].s.alignment  =  { textRotation: 180, vertical: "top", horizontal: "center" }  ;
                            } else
                            {  wb.Sheets['My Data'][XLSX.utils.encode_cell({r:1, c:cc})].s.alignment  =  { vertical: "top" }  ;}
                            if(cw[i].columns[j].hasOwnProperty("cssClass")) {
                                switch(cw[i].columns[j].cssClass) {
                                    case 'blue-background':  wb.Sheets['My Data'][XLSX.utils.encode_cell({r:1, c:cc})].s.fill = { fgColor: { rgb: "ADD8E6" } };
                                        break;
                                    case 'yellow-background':
                                        wb.Sheets['My Data'][XLSX.utils.encode_cell({r:1, c:cc})].s.fill = { fgColor: { rgb: "FFFFE0" } };
                                        break;
                                    case 'orange-background':
                                        wb.Sheets['My Data'][XLSX.utils.encode_cell({r:1, c:cc})].s.fill = { fgColor: { rgb: "FFDAB9" } };
                                        break;
                                }
                            }

                            wb.Sheets['My Data'][XLSX.utils.encode_cell({r:1, c:cc})].s.border = { top: {style: "thin", color: { rgb: "000000" }}}
                            wb.Sheets['My Data'][XLSX.utils.encode_cell({r:1, c:cc})].s.border.bottom = {style: "thin", color: { rgb: "000000" }}
                            wb.Sheets['My Data'][XLSX.utils.encode_cell({r:1, c:cc})].s.border.left = {style: "thin", color: { rgb: "000000" }}
                            wb.Sheets['My Data'][XLSX.utils.encode_cell({r:1, c:cc})].s.border.right = {style: "thin", color: { rgb: "000000" }}
                            wc.push({width: cw[i].columns[j].width*.15});
                            cnames.push(cw[i].columns[j].field);
                            cc++;
                     //   }
                    }
                    if ((group_visible)&&(wb.Sheets['My Data'].hasOwnProperty(XLSX.utils.encode_cell({r:0, c:group_start})))) {
                        // Group Header
                        wb.Sheets['My Data'][XLSX.utils.encode_cell({r:0, c:group_start})].s = { font: { bold: true}};
                        wb.Sheets['My Data'][XLSX.utils.encode_cell({r:0, c:group_start})].s.fill = { fgColor: { rgb: "DCDCDC" } };
                    }
                }
            } else {
                if (cw[i].visible){
                    wc.push({width: cw[i].width*.15});
                    cnames.push(cw[i].field);
                    wb.Sheets['My Data'][XLSX.utils.encode_cell({r:0, c:cc})].s = { font: { bold: true}, alignment: {vertical:"top"}};
                    wb.Sheets['My Data'][XLSX.utils.encode_cell({r:1, c:cc})].s = { font: { bold: true}, alignment: {vertical:"top"}};
                    wb.Sheets['My Data'][XLSX.utils.encode_cell({r:0, c:cc})].s.border = { top: {style: "thin", color: { rgb: "000000" }}}
                    wb.Sheets['My Data'][XLSX.utils.encode_cell({r:0, c:cc})].s.border.bottom = {style: "thin", color: { rgb: "000000" }}
                    wb.Sheets['My Data'][XLSX.utils.encode_cell({r:0, c:cc})].s.border.left = {style: "thin", color: { rgb: "000000" }}
                    wb.Sheets['My Data'][XLSX.utils.encode_cell({r:0, c:cc})].s.border.right = {style: "thin", color: { rgb: "000000" }}
                    wb.Sheets['My Data'][XLSX.utils.encode_cell({r:1, c:cc})].s.border = { top: {style: "thin", color: { rgb: "000000" }}}
                    wb.Sheets['My Data'][XLSX.utils.encode_cell({r:1, c:cc})].s.border.bottom = {style: "thin", color: { rgb: "000000" }}
                    wb.Sheets['My Data'][XLSX.utils.encode_cell({r:1, c:cc})].s.border.left = {style: "thin", color: { rgb: "000000" }}
                    wb.Sheets['My Data'][XLSX.utils.encode_cell({r:1, c:cc})].s.border.right = {style: "thin", color: { rgb: "000000" }}
                    cc++;
                   }
            }
            // cc++;
        }
                                                      wb.Sheets['My Data']["!cols"]= wc;
        // Color Cells for ticks etc
        for (i=0;i<tabletabulator.getRows().length;i++) {
            for (j=0; j<wc.length; j++) {
                if (wb.Sheets['My Data'].hasOwnProperty(XLSX.utils.encode_cell({r:i+2, c:j}))) {
                    wb.Sheets['My Data'][XLSX.utils.encode_cell({r:i+2, c:j})].s = {};
                    if (wb.Sheets['My Data'][XLSX.utils.encode_cell({r:i+2, c:j})].hasOwnProperty("v")){
                        if(wb.Sheets['My Data'][XLSX.utils.encode_cell({r:i+2, c:j})].v=="✅") {
                            wb.Sheets['My Data'][XLSX.utils.encode_cell({r:i+2, c:j})].s = { font: {color: { rgb: "00FF00" } },  alignment: { horizontal: "center" }  }
                        }
                        if(wb.Sheets['My Data'][XLSX.utils.encode_cell({r:i+2, c:j})].v=="❌") {
                            wb.Sheets['My Data'][XLSX.utils.encode_cell({r:i+2, c:j})].s = { font: {color: { rgb: "FF0000" } },  alignment: { horizontal: "center" } }
                        }
                        if(wb.Sheets['My Data'][XLSX.utils.encode_cell({r:i+2, c:j})].v=="✖") {
                            wb.Sheets['My Data'][XLSX.utils.encode_cell({r:i+2, c:j})].s = { font: {color: { rgb: "000000" } },  alignment: { horizontal: "center" } }
                        }
                        if(wb.Sheets['My Data'][XLSX.utils.encode_cell({r:i+2, c:j})].v=="✔") {
                            wb.Sheets['My Data'][XLSX.utils.encode_cell({r:i+2, c:j})].s = { font: {color: { rgb: "000000" } },  alignment: { horizontal: "center" } }
                        }
                        if(wb.Sheets['My Data'][XLSX.utils.encode_cell({r:i+2, c:j})].v=="⚡") {
                            wb.Sheets['My Data'][XLSX.utils.encode_cell({r:i+2, c:j})].s = { font: {color: { rgb: "FFA500" } },  alignment: { horizontal: "center" } }
                        }
                        if ((cnames[j].indexOf("dbs")==0)||(cnames[j].indexOf("safeguarding")==0)||(cnames[j].indexOf("safety")==0)||(cnames[j].indexOf("firstresponse")==0)) {
                            var ci =-1;
                            if (cnames[j].indexOf("_")==-1) {
                                ci = cnames.findIndex(e=>e==cnames[j]+"_expirydays"); ci = -1; // No colour for Icon column...
                            } else
                            { ci = cnames.findIndex(e=>e== cnames[j].substring(0, cnames[j].indexOf("_"))+"_expirydays");}
                            var expdays = -1;
                            if (ci>-1) {
                                var cs = cnames.findIndex(e=>e== cnames[j].substring(0, cnames[j].indexOf("_")));
                                var css = wb.Sheets['My Data'][XLSX.utils.encode_cell({r:i+2,c:cs})];
                                if ("✅❌✔⚡✖".includes(css.v)) {
                                    if (wb.Sheets['My Data'].hasOwnProperty(XLSX.utils.encode_cell({r:i+2, c:ci}))) {
                                        if (wb.Sheets['My Data'][XLSX.utils.encode_cell({r:i+2, c:ci})].hasOwnProperty("v")) {
                                            expdays = wb.Sheets['My Data'][XLSX.utils.encode_cell({r:i+2, c:ci})].v;
                                        }
                                    }
                                    if(document.getElementById("gmcolor").checked) {
                                        for(cloop=0;cloop<4;cloop++) {
                                            if ((expdays<=daylimits[cloop])&&(expdays>daylimits[cloop+1])) {
                                                wb.Sheets['My Data'][XLSX.utils.encode_cell({r:i+2, c:j})].s.fill =  {fgColor: { rgb:  colors[cloop].substring(1,7)  }}
                                                // td.style.backgroundColor = colors[cloop];
                                                // td.style.textColor = colorsT[cloop];

                                            }}}
                                }}


                        }
                    }
                    wb.Sheets['My Data'][XLSX.utils.encode_cell({r:i+2, c:j})].s.border = { top: {style: "thin", color: { rgb: "000000" }}}
                    wb.Sheets['My Data'][XLSX.utils.encode_cell({r:i+2, c:j})].s.border.bottom = {style: "thin", color: { rgb: "000000" }}
                    wb.Sheets['My Data'][XLSX.utils.encode_cell({r:i+2, c:j})].s.border.left = {style: "thin", color: { rgb: "000000" }}
                    wb.Sheets['My Data'][XLSX.utils.encode_cell({r:i+2, c:j})].s.border.right ={style: "thin", color: { rgb: "000000" }}
                }}
        }
        return wb;
    }});
}

function report_download() {
    tabletabulator.getHtml();
    //    const clipboardItem = new ClipboardItem({
    //        'text/html': new Blob([document.getElementById("GMourreport").outerHTML], { type: 'text/html' }),
    //        'text/plain': new Blob([document.getElementById("GMourreport").innerText], { type: 'text/plain' })
    //    });
    const clipboardItem = new ClipboardItem({
        'text/html': new Blob([tabletabulator.getHtml()], { type: 'text/html' }),
        'text/plain': new Blob([tabletabulator.getHtml().innerText], { type: 'text/plain' })
    });
    navigator.clipboard.write([clipboardItem]);
}
// Navigation Watcher
/*
    navigation.addEventListener("navigate", e => {
        console.log("EventLstener");
        console.log(e);

        if (document.getElementById("quick_nav")!=null){console.log("remove");document.getElementById("quick_nav").innerHTML ="";}

        setTimeout(function() {

        }, 2000);

    }) // Event listener
*/
/*   setTimeout(function() {
        console.log("New Page");
        //    dopage(); Deactive Unit/Teams
    }, 2000);
 */
// Your code here...
var newHTML         = document.createElement ('div');
// <p>Exclude Welcome Information <input  type="checkbox" id="gmexc" name="gmtexc" /><p> \
//<p><input   type="checkbox" id="gmtraffic" name="gmtraffic" /> Show 90 Day Traffic LIghts  \
newHTML.innerHTML   = '             \
<div id="gmpopup" title="Roles Report">   \
<p>      \
Unit <input   type="text" list="myUnits"  id="gmunitname" size=30 name="gmunitname"  placeholder="Enter Unit Name (% =wildcard)"/><datalist id="myUnits"></datalist>  <button id="gmRunReport">Run Report</button> <button id="gmFilterReport">Refresh Display</button></p> \
<p>Include Roles for matching Unit Only <input  type="checkbox" id="gmteamonly" name="gmteamonly" /> Exact Match <input   type="checkbox" id="gmexact" name="gmexact" /> <p> \
<p>Name Filter <input   type="text" id="gmpersonname" name="gmpersonname" /> Team Filter <input   type="text" id="gmteamname" name="gmteamname" /><p> \
<input   type="checkbox" id="gmmissing" name="gmmissing" /> Show volunteers missing  Welcome elements only \
<p><input   type="checkbox" id="gmwelcome" name="gmwelcome" /> Exclude Role Audit</p> \
<p> <input   type="checkbox" id="gmhelper" name="gmhelper" /> Exclude Helpers/Holding Roles <input   type="checkbox" id="gmclosed" name="gmclosed" checked/> Exclude Closed Roles <p> \
<p><input   type="checkbox" id="gmlearning" name="gmlearning" /> Show Detailed learning  \
<input   type="checkbox" id="gmdates" name="gmdates" /> Show Expiry Dates \
<input   type="checkbox" id="gmdays" name="gmdays" /> Show Days to Expiry </p> \
<p><input   type="checkbox" id="gmdbs" name="gmdbs" /> Show DBS Information <input   type="checkbox" id="gmdbsip" name="gmdbsip" /> Show DBS Status</p>  \
<p><input   type="checkbox" id="gmnumber" name="gmnumber" /> Show Membership Number<input   type="checkbox" id="gmcolor" name="gmcolor" /> Use Color</p>\
<strongb>Run Status : </strong> <span id="gmState">Enter Unit Name above (can include % wildcard) and run report</span>  \
<p>Showing All Roles for members of <span id="gmUnit"></span></p>       \
<span id="gmTablex"><button id="gmXLS">Copy to Clipboard</button></span>  \
<span id="gmTablep"><button id="gmPrint">Print</button></span>  \
<span id="gmTablex2"><button id="gmSaveReport">Save XLS</button></span>  \
<span id="gmTable">Report will appear here!</span>  \
<div id="gmTabulator"></div> \
<div id="gmTabulator2"><p>Key: ✅ Required and complete ❌ Required ⚡Complete but near expiry ✔ Not required but complete ✖ Not required but expired </p></div> \
<p><input   type="checkbox" id="gmdebug" name="gmdebug" /> Debug Info - usually this should be off</p> \
<p><button id="gmsavecolors">Save Colors</button> <button id="gmresetcolors">Reset Colors</button></p> \
<div id="htmlset" style=""></div> \
</div> ';
    //<p><input   type="checkbox" id="gmexplorer" name="gmexplorer" /> Experimental Data Collection</p> \
// Add Color Selectors
document.body.appendChild (newHTML);
var colors_JSON = GM_getValue("colors", JSON.stringify(defcolors));
var colorsT_JSON = GM_getValue("colorsT", JSON.stringify(defcolorsT));
colors = JSON.parse(colors_JSON);
colorsT = JSON.parse(colorsT_JSON);
var  HTMLSettings         = document.createElement ('div');
for (var cloop=0;cloop<4;cloop+=1){
    HTMLSettings.innerHTML   += '<p><span style="display: inline-block; width :75px">'+colormeanings[cloop]+'</span> '+'<input type="color" id="back'+cloop+'" name="back'+cloop+'" value="'+colors[cloop]+'" />'+'<span> <input type="color" id="fore'+cloop+'" name="fore'+cloop+'" value="'+colorsT[cloop]+'" /></span>   <span id="cpreview'+cloop+'">1000</span></p>';
}
document.getElementById("htmlset").appendChild (HTMLSettings);
for (cloop=0;cloop<4;cloop+=1){
    document.getElementById("back"+cloop).addEventListener("input", updateFirstC, false);
    document.getElementById("back"+cloop).addEventListener("change", watchColorPicker, false);
    document.getElementById("fore"+cloop).addEventListener("input", updateFirstC, false);
    document.getElementById("fore"+cloop).addEventListener("change", watchColorPicker, false);
    document.getElementById("cpreview"+cloop).style.backgroundColor = colors[cloop];
    document.getElementById("cpreview"+cloop).style.color = colorsT[cloop];
    document.getElementById("cpreview"+cloop).style.padding = "10px";
}
$("#gmpopup").hide();
newHTML         = document.createElement ('div');
newHTML.innerHTML   = '             \
<div id="gmorganogram" title="Organogram">Unit <input   type="text" id="gmunitnameo" size=30 name="gmunitnameo"  placeholder="Enter Unit Name (% =wildcard)"/> \
Start At <select id="gmsorglevel" name="gmsorglevel" /><option value="0">Organisation</option><option value="1">Country</option><option value="2">Region</option><option value="3">County</option><option value="4">County Sections</option> <option value="5">District</option><option value="6">District Sections</option><option value="7">Group</option><option value="8">Group Section</option></select> \
<button id="gmRunOrg">Chart Data</button><button id="gmSaveOrg">Save</button> <button id="gmDownOrg">Download</button>\
<p><input   type="checkbox" id="gmnoteams" name="gmnoteams" /> Show Units Only <input   type="checkbox" id="gmnosteams" name="gmnosteams" /> Exclude section Teams</p> \
<p>Display down to: <select id="gmorglevel" name="gmorglevel" /> <option value="1">Group Section</option><option value="2">Group</option><option value="3">District Sections</option><option value="4">District</option><option value="5">County Sections</option><option value="6">County</option><option value="7">Region</option><option value="8">Country</option><option value="9">Organisation</option></select> \
<p> Status : <span id="gmorgstatus"></span></P> \
<div id="myDiagramDiv" style="width:1000px; height:40000px; background-color: #DAE4E4;"></div><p> <div style="height:1000px;display:none" id="map"></div> </p></div>   \
';
document.body.appendChild (newHTML);
$("#gmorganogram").hide();

newHTML         = document.createElement ('div');
newHTML.innerHTML   = '             \
<div id="gmmap" title="Map">Unit <input   type="text" id="gmunitnamem" size=30 name="gmunitnamem"  placeholder="Enter Unit Name (% =wildcard)"/> \
Start At <select id="gmsmaplevel" name="gmsmaplevel" /><option value="0">Organisation</option><option value="1">Country</option><option value="2">Region</option><option value="3">County</option><option value="4">County Sections</option> <option value="5">District</option><option value="6">District Sections</option><option value="7">Group</option><option value="8">Group Section</option></select> \
<button id="gmRunMap">Map Data</button>\
<p> Status : <span id="gmmapstatus"></span></P> \
<p> <div style="height:1000px" id="gmmapdiv"></div> </p><p>Errors</p><p><div id="gmerrors"></div><div>Key</div><div id="gmkey"></div>\
</div>   \
';
document.body.appendChild (newHTML);
$("#gmmap").hide();
var iconSet1    = GM_getResourceURL ("IconSet1");
var iconSet2    = GM_getResourceURL ("IconSet2");
//  var iconSet3    = GM_getResourceURL ("LeafletPin");
//  var iconSet4    = GM_getResourceURL ("LeafletShadow");
var jqUI_CssSrc = GM_getResourceText ("jqUI_CSS");
var leaf_Css = GM_getResourceText("leaf");
var tabulator_css = GM_getResourceText("tabulator");
jqUI_CssSrc     = jqUI_CssSrc.replace (/url\(images\/ui\-bg_.*00\.png\)/g, "");
jqUI_CssSrc     = jqUI_CssSrc.replace (/images\/ui-icons_222222_256x240\.png/g, iconSet1);
jqUI_CssSrc     = jqUI_CssSrc.replace (/images\/ui-icons_454545_256x240\.png/g, iconSet2);
//  var testing = GM_info();
GM_addStyle (jqUI_CssSrc);
GM_addStyle (leaf_Css);
GM_addStyle (tabulator_css );
addButton("Role Report", report_onclick2, "","T");
addButton("Clear Cookies", clear_cookies,"", "B");
addButton("Organogram", show_organogram,"", "C");
//   addButton("Map Groups", run_map,"", "D");

document.getElementById("gmRunReport").onclick = report_onclick;
document.getElementById("gmFilterReport").onclick = report_filter;
document.getElementById("gmSaveReport").onclick = report_saveXLS;
document.getElementById("gmsavecolors").onclick = savecolors;
document.getElementById("gmresetcolors").onclick = resetcolors;
document.getElementById("gmXLS").onclick = report_download;
document.getElementById("gmPrint").onclick = report_print;
document.getElementById("gmunitname").value = un;
document.getElementById("gmpopup").style.fontSize = "10pt";
document.getElementById("gmorganogram").style.fontSize = "10pt";
document.getElementById("gmmap").style.fontSize = "10pt";
document.getElementById("gmRunOrg").onclick = run_organogram;
document.getElementById("gmSaveOrg").onclick = save_organogram;
document.getElementById("gmDownOrg").onclick = down_organogram;
document.getElementById("gmRunMap").onclick = run_map;

var blkrs = GM_info.script.options.override.use_blockers;
if (blkrs.length>0) {
    var clicked = GM_notification({
        text: "There maybe an issue with your XHR blacklist this may stop things running - check the plugin settings",
        title: "Scout Membership Plugin",
        url: 'https:/example.com/',
        onclick: (event) => {
            //The userscript is still running, so don't open example.com
            event.preventDefault();
            // Display an alert message instead
            //    alert('I was clicked!')
        }
    });
}

// Get MyUnits
// https://tsa-memportal-prod-fun01.azurewebsites.net/api/MyUnitsAsync

//   var datapass = '{"pagesize":100,"sort":{"field":"unitName","type":"asc"}}';





GM_addStyle ('.fa-check-square:before { content: "✅";   }' );
GM_addStyle ('.fa-square:before { content: "🟩";   }' );
GM_addStyle('.tabulator-col.tabulator-col-vertical.tabulator-sortable.tabulator-col-sorter-element.blue-background {background : #ADD8E6 }');
GM_addStyle('.tabulator-col.tabulator-col-vertical.tabulator-sortable.tabulator-col-sorter-element.yellow-background {background : #FFFFE0 }');
GM_addStyle('.tabulator-col.tabulator-sortable.tabulator-col-sorter-element.orange-background {background : #FFDAB9 }');
GM_addStyle('th.blue-background {    writing-mode: vertical-lr;    background-color: lightcyan; }');
GM_addStyle('th.yellow-background {    writing-mode: vertical-lr;    background-color: lightgoldenrodyellow; }');
GM_addStyle('th.orange-background {    writing-mode: vertical-lr;    background-color: salmon; }');
GM_addStyle('table.tabulator-print-table, tr, th, td {    border: solid;}');

})();