// GridTracker Copyright © 2024 GridTracker.org // All rights reserved. // See LICENSE for more information. // gtCommon.js is common functions used by gt.js , adifWorker.js, trackerWorker.js and others // var GT must be initiliazed before loading this script. function validateGridFromString(inputText) { var validGrid = false; if (inputText.length == 4 || inputText.length == 6) { var LETTERS = inputText.substr(0, 2); var NUMBERS = inputText.substr(2, 2); if (/^[A-R]+$/.test(LETTERS) && /^[0-9]+$/.test(NUMBERS)) { validGrid = true; } if (validGrid && inputText.length == 6) { var LETTERS_SUB = inputText.substr(4, 2); if (!(/^[A-Xa-x]+$/.test(LETTERS_SUB))) { validGrid = false; } } } return validGrid; } function cqZoneFromCallsign(insign, dxcc) { var callsign = insign; if (!/\d/.test(callsign) || !/[a-zA-Z]/.test(callsign)) { return null; } if (callsign in GT.directCallToCQzone) { return GT.directCallToCQzone[callsign]; } for (var x = callsign.length; x > 0; x--) { if (callsign.substr(0, x) in GT.prefixToCQzone) { return GT.prefixToCQzone[callsign.substr(0, x)]; } } if (dxcc > 0) { return GT.dxccInfo[dxcc].cqzone; } return null; } function ituZoneFromCallsign(insign, dxcc) { var callsign = insign; if (!/\d/.test(callsign) || !/[a-zA-Z]/.test(callsign)) { return null; } if (callsign in GT.directCallToITUzone) { return GT.directCallToITUzone[callsign]; } for (var x = callsign.length; x > 0; x--) { if (callsign.substr(0, x) in GT.prefixToITUzone) { return GT.prefixToITUzone[callsign.substr(0, x)]; } } if (dxcc > 0) { return GT.dxccInfo[dxcc].ituzone; } return null; } function getWpx(callsign) { var prefix = null; if (callsign.includes("/")) // Handle in the future? { return null; } if (!/\d/.test(callsign)) // Insert 0, never seen this { return null; } var end = callsign.length; var foundPrefix = false; var prefixEnd = 1; while (prefixEnd != end) { if (/\d/.test(callsign.charAt(prefixEnd))) { while (prefixEnd + 1 != end && /\d/.test(callsign.charAt(prefixEnd + 1))) { prefixEnd++; } foundPrefix = true; break; } prefixEnd++; } if (foundPrefix) prefix = callsign.substr(0, prefixEnd + 1); return String(prefix); } GT.ancPrefixes = ["P", "M", "MM", "AM", "A", "NWS"]; function callsignToDxcc(insign) { var callsign = insign; if (!/\d/.test(callsign) || !/[a-zA-Z]/.test(callsign)) { return -1; } if (callsign in GT.directCallToDXCC) { return Number(GT.directCallToDXCC[callsign]); } if (callsign.includes("/")) { var parts = callsign.split("/"); var end = parts.length - 1; if (GT.ancPrefixes.includes(parts[end])) { if (parts[end].toUpperCase() == "MM") { return 0; } parts.pop(); end = parts.length - 1; } if (end) { if (isNaN(parts[end])) { if (parts[1].length > parts[0].length) { callsign = parts[0]; } else { if (callsignToDxcc(parts[1]) != -1) callsign = parts[1]; else callsign = parts[0]; } } else callsign = parts[0]; } else callsign = parts[0]; if (callsign in GT.directCallToDXCC) { return Number(GT.directCallToDXCC[callsign]); } } for (var x = callsign.length; x > 0; x--) { if (callsign.substr(0, x) in GT.prefixToMap) { return Number(GT.dxccInfo[GT.prefixToMap[callsign.substr(0, x)]].dxcc); } } return -1; } function initQSOdata() { GT.tracker = {}; GT.tracker.worked = {}; GT.tracker.confirmed = {}; GT.tracker.worked.call = {}; GT.tracker.worked.grid = {}; GT.tracker.worked.field = {}; GT.tracker.worked.dxcc = {}; GT.tracker.worked.cqz = {}; GT.tracker.worked.ituz = {}; GT.tracker.worked.state = {}; GT.tracker.worked.px = {}; GT.tracker.worked.cnty = {}; GT.tracker.worked.cont = {}; GT.tracker.worked.pota = {}; GT.tracker.confirmed.call = {}; GT.tracker.confirmed.grid = {}; GT.tracker.confirmed.field = {}; GT.tracker.confirmed.dxcc = {}; GT.tracker.confirmed.cqz = {}; GT.tracker.confirmed.ituz = {}; GT.tracker.confirmed.state = {}; GT.tracker.confirmed.px = {}; GT.tracker.confirmed.cnty = {}; GT.tracker.confirmed.cont = {}; GT.tracker.confirmed.pota = {}; } function trackQSO(details, currentYear) { let qsoDate = new Date(1970, 0, 1); qsoDate.setSeconds(details.time); let isCurrentYear = (qsoDate.getFullYear() == currentYear); let dayAsString = String(parseInt(details.time / 86400)); let fourGrid = details.grid.substring(0, 4); let isDigi = details.digital; let isPhone = details.phone; GT.tracker.worked.call[details.DEcall + details.band + details.mode] = true; GT.tracker.worked.call[details.DEcall] = true; GT.tracker.worked.call[details.DEcall + details.mode] = true; GT.tracker.worked.call[details.DEcall + details.band] = true; if (isDigi == true) { GT.tracker.worked.call[details.DEcall + "dg"] = true; GT.tracker.worked.call[details.DEcall + details.band + "dg"] = true; } if (fourGrid != "") { GT.tracker.worked.grid[fourGrid] = true; GT.tracker.worked.grid[fourGrid + details.mode] = true; GT.tracker.worked.grid[fourGrid + details.band] = true; GT.tracker.worked.grid[fourGrid + details.band + details.mode] = true; let field = fourGrid.substring(0, 2); GT.tracker.worked.field[field] = true; GT.tracker.worked.field[field + details.mode] = true; GT.tracker.worked.field[field + details.band] = true; GT.tracker.worked.field[field + details.band + details.mode] = true; if (isDigi == true) { GT.tracker.worked.grid[fourGrid + "dg"] = true; GT.tracker.worked.grid[fourGrid + details.band + "dg"] = true; GT.tracker.worked.field[field + "dg"] = true; GT.tracker.worked.field[field + details.band + "dg"] = true; } } if (details.ituz) { GT.tracker.worked.ituz[details.ituz + "|" + details.band + details.mode] = true; GT.tracker.worked.ituz[details.ituz + "|"] = true; GT.tracker.worked.ituz[details.ituz + "|" + details.mode] = true; GT.tracker.worked.ituz[details.ituz + "|" + details.band] = true; if (isDigi == true) { GT.tracker.worked.ituz[details.ituz + "|dg"] = true; GT.tracker.worked.ituz[details.ituz + "|" + details.band + "dg"] = true; } } if (details.cqz) { GT.tracker.worked.cqz[details.cqz + "|" + details.band + details.mode] = true; GT.tracker.worked.cqz[details.cqz + "|"] = true; GT.tracker.worked.cqz[details.cqz + "|" + details.mode] = true; GT.tracker.worked.cqz[details.cqz + "|" + details.band] = true; if (isDigi == true) { GT.tracker.worked.cqz[details.cqz + "|dg"] = true; GT.tracker.worked.cqz[details.cqz + "|" + details.band + "dg"] = true; } if (isCurrentYear) { GT.tracker.worked.cqz[`${details.cqz}-${currentYear}`] = true; } } if (details.dxcc > 0) { var sDXCC = String(details.dxcc); GT.tracker.worked.dxcc[sDXCC + "|" + details.band + details.mode] = true; GT.tracker.worked.dxcc[sDXCC + "|"] = true; GT.tracker.worked.dxcc[sDXCC + "|" + details.mode] = true; GT.tracker.worked.dxcc[sDXCC + "|" + details.band] = true; if (isDigi == true) { GT.tracker.worked.dxcc[sDXCC + "|dg"] = true; GT.tracker.worked.dxcc[sDXCC + "|" + details.band + "dg"] = true; } if (isPhone == true) { GT.tracker.worked.dxcc[sDXCC + "|ph"] = true; } if (isCurrentYear) { GT.tracker.worked.dxcc[`${sDXCC}-${currentYear}`] = true; } } if (details.px) { GT.tracker.worked.px[details.px + details.band + details.mode] = true; // store the last one GT.tracker.worked.px[details.px] = details.hash; GT.tracker.worked.px[details.px + details.mode] = true; GT.tracker.worked.px[details.px + details.band] = true; if (isDigi == true) { GT.tracker.worked.px[details.px + "dg"] = true; GT.tracker.worked.px[details.px + details.band + "dg"] = true; } if (isPhone == true) { GT.tracker.worked.px[details.px + "ph"] = true; GT.tracker.worked.px[details.px + details.band + "ph"] = true; } } if (details.cont) { GT.tracker.worked.cont[details.cont + details.band + details.mode] = true; // store the last one GT.tracker.worked.cont[details.cont] = details.hash; GT.tracker.worked.cont[details.cont + details.mode] = true; GT.tracker.worked.cont[details.cont + details.band] = true; if (isDigi == true) { GT.tracker.worked.cont[details.cont + "dg"] = true; GT.tracker.worked.cont[details.cont + details.band + "dg"] = true; } } if (details.state) { GT.tracker.worked.state[details.state] = true; GT.tracker.worked.state[details.state + details.mode] = true; GT.tracker.worked.state[details.state + details.band] = true; GT.tracker.worked.state[details.state + details.band + details.mode] = true; if (isDigi) { GT.tracker.worked.state[details.state + "dg"] = GT.tracker.worked.state[details.state + details.band + "dg"] = true; } } if (details.cnty) { GT.tracker.worked.cnty[details.cnty] = true; GT.tracker.worked.cnty[details.cnty + details.mode] = true; GT.tracker.worked.cnty[details.cnty + details.band] = true; GT.tracker.worked.cnty[details.cnty + details.band + details.mode] = true; if (isDigi) { GT.tracker.worked.cnty[details.cnty + "dg"] = true; GT.tracker.worked.cnty[details.cnty + details.band + "dg"] = true; } } if (details.pota) { GT.tracker.worked.pota[dayAsString + details.DEcall + details.pota] = true; GT.tracker.worked.pota[dayAsString + details.DEcall + details.pota + details.mode] = true; GT.tracker.worked.pota[dayAsString + details.DEcall + details.pota + details.band] = true; GT.tracker.worked.pota[dayAsString + details.DEcall + details.pota + details.band + details.mode] = true; GT.tracker.worked.pota[dayAsString + details.pota + details.band + details.mode] = true; GT.tracker.worked.pota[details.pota] = true; GT.tracker.worked.pota[details.pota + details.mode] = true; GT.tracker.worked.pota[details.pota + details.band] = true; GT.tracker.worked.pota[details.pota + details.band + details.mode] = true; if (isDigi == true) { GT.tracker.worked.pota[dayAsString + details.DEcall + details.pota + "dg"] = true; GT.tracker.worked.pota[dayAsString + details.DEcall + details.pota + details.band + "dg"] = true; GT.tracker.worked.pota[details.pota + "dg"] = true; GT.tracker.worked.pota[details.pota + details.band + "dg"] = true; } } if (details.confirmed == true) { GT.tracker.confirmed.call[details.DEcall + details.band + details.mode] = true; GT.tracker.confirmed.call[details.DEcall] = true; GT.tracker.confirmed.call[details.DEcall + details.mode] = true; GT.tracker.confirmed.call[details.DEcall + details.band] = true; if (isDigi == true) { GT.tracker.confirmed.call[details.DEcall + "dg"] = true; GT.tracker.confirmed.call[details.DEcall + details.band + "dg"] = true; } if (fourGrid != "") { GT.tracker.confirmed.grid[fourGrid + details.band + details.mode] = true; GT.tracker.confirmed.grid[fourGrid] = true; GT.tracker.confirmed.grid[fourGrid + details.mode] = true; GT.tracker.confirmed.grid[fourGrid + details.band] = true; if (isDigi == true) { GT.tracker.confirmed.grid[fourGrid + "dg"] = true; GT.tracker.confirmed.grid[fourGrid + details.band + "dg"] = true; } } if (details.ituz && details.ituz.length > 0) { GT.tracker.confirmed.ituz[details.ituz + "|" + details.band + details.mode] = true; GT.tracker.confirmed.ituz[details.ituz + "|"] = true; GT.tracker.confirmed.ituz[details.ituz + "|" + details.mode] = true; GT.tracker.confirmed.ituz[details.ituz + "|" + details.band] = true; if (isDigi == true) { GT.tracker.confirmed.ituz[details.ituz + "|dg"] = true; GT.tracker.confirmed.ituz[details.ituz + "|" + details.band + "dg"] = true; } } if (details.cqz && details.cqz.length > 0) { GT.tracker.confirmed.cqz[details.cqz + "|" + details.band + details.mode] = true; GT.tracker.confirmed.cqz[details.cqz + "|"] = true; GT.tracker.confirmed.cqz[details.cqz + "|" + details.mode] = true; GT.tracker.confirmed.cqz[details.cqz + "|" + details.band] = true; if (isDigi == true) { GT.tracker.confirmed.cqz[details.cqz + "|dg"] = true; GT.tracker.confirmed.cqz[details.cqz + "|" + details.band + "dg"] = true; } } if (details.dxcc > 0) { var sDXCC = String(details.dxcc); GT.tracker.confirmed.dxcc[sDXCC + "|" + details.band + details.mode] = true; GT.tracker.confirmed.dxcc[sDXCC + "|"] = true; GT.tracker.confirmed.dxcc[sDXCC + "|" + details.mode] = true; GT.tracker.confirmed.dxcc[sDXCC + "|" + details.band] = true; if (isDigi == true) { GT.tracker.confirmed.dxcc[sDXCC + "|dg"] = true; GT.tracker.confirmed.dxcc[sDXCC + "|" + details.band + "dg"] = true; } if (isPhone == true) { GT.tracker.confirmed.dxcc[sDXCC + "|ph"] = true; } } if (details.state) { GT.tracker.confirmed.state[details.state] = true; GT.tracker.confirmed.state[details.state + details.mode] = true; GT.tracker.confirmed.state[details.state + details.band] = true; GT.tracker.confirmed.state[details.state + details.band + details.mode] = true; if (isDigi) { GT.tracker.confirmed.state[details.state + "dg"] = true; GT.tracker.confirmed.state[details.state + details.band + "dg"] = true; } } if (details.cnty) { GT.tracker.confirmed.cnty[details.cnty] = true; GT.tracker.confirmed.cnty[details.cnty + details.mode] = true; GT.tracker.confirmed.cnty[details.cnty + details.band] = true; GT.tracker.confirmed.cnty[details.cnty + details.band + details.mode] = true; if (isDigi) { GT.tracker.confirmed.cnty[details.cnty + "dg"] = true; GT.tracker.confirmed.cnty[details.cnty + details.band + "dg"] = true; } } if (details.px) { GT.tracker.confirmed.px[details.px + details.band + details.mode] = true; // store the last one GT.tracker.confirmed.px[details.px] = details.hash; GT.tracker.confirmed.px[details.px + details.mode] = true; GT.tracker.confirmed.px[details.px + details.band] = true; if (isDigi == true) { GT.tracker.confirmed.px[details.px + "dg"] = true; GT.tracker.confirmed.px[details.px + details.band + "dg"] = true; } if (isPhone == true) { GT.tracker.confirmed.px[details.px + "ph"] = true; GT.tracker.confirmed.px[details.px + details.band + "ph"] = true; } } if (details.cont) { GT.tracker.confirmed.cont[details.cont + details.band + details.mode] = true; // store the last one GT.tracker.confirmed.cont[details.cont] = details.hash; GT.tracker.confirmed.cont[details.cont + details.mode] = true; GT.tracker.confirmed.cont[details.cont + details.band] = true; if (isDigi == true) { GT.tracker.confirmed.cont[details.cont + "dg"] = true; GT.tracker.confirmed.cont[details.cont + details.band + "dg"] = true; } } } } /* eslint-disable */ function bitwise(str){ var hash = 0; if (str.length == 0) return hash; for (var i = 0; i < str.length; i++) { var ch = str.charCodeAt(i); hash = ((hash<<5)-hash) + ch; hash = hash & hash; // Convert to 32bit integer } return hash; } // convert 10 binary to customized binary, max is 62 function binaryTransfer(integer, binary) { binary = binary || 62; var stack = []; var num; var result = ''; var sign = integer < 0 ? '-' : ''; function table (num) { var t = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; return t[num]; } integer = Math.abs(integer); while (integer >= binary) { num = integer % binary; integer = Math.floor(integer / binary); stack.push(table(num)); } if (integer > 0) { stack.push(table(integer)); } for (var i = stack.length - 1; i >= 0; i--) { result += stack[i]; } return sign + result; } /** * why choose 61 binary, because we need the last element char to replace the minus sign * eg: -aGtzd will be ZaGtzd */ function unique (text) { var id = binaryTransfer(bitwise(text), 61); return id.replace('-', 'Z'); }