WME Road Shield Assistant

Adds shield information display to WME

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

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

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

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

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

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

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

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

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

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

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

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

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

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

"use strict";
// ==UserScript==
// @name         WME Road Shield Assistant
// @namespace    https://greasyfork.org/en/users/286957-skidooguy
// @version      2025.08.09.001
// @description  Adds shield information display to WME
// @author       SkiDooGuy, jm6087, Karlsosha
// @match        https://www.waze.com/editor*
// @match        https://www.waze.com/*/editor*
// @match        https://beta.waze.com/editor*
// @match        https://beta.waze.com/*/editor*
// @exclude      https://www.waze.com/user/editor*
// @require      https://greasyfork.org/scripts/24851-wazewrap/code/WazeWrap.js
// @require      https://cdn.jsdelivr.net/npm/@turf/[email protected]/turf.min.js
// @grant        GM_xmlhttpRequest
// @grant        unsafeWindow
// @connect      greasyfork.org
// @contributionURL https://github.com/WazeDev/Thank-The-Authors
// ==/UserScript==
/* global W */
/* global WazeWrap */
// import type { Node, Segment, SegmentAddress, Street, Turn, WmeSDK } from "wme-sdk-typings";
// import type { Point, LineString, Position, Feature } from "geojson";
// import * as turf from "@turf/turf";
// import _ from "underscore";
// import WazeWrap from "https://greasyfork.org/scripts/24851-wazewrap/code/WazeWrap.js";
let sdk;
unsafeWindow.SDK_INITIALIZED.then(() => {
    if (!unsafeWindow.getWmeSdk) {
        throw new Error("SDK is not installed");
    }
    sdk = unsafeWindow.getWmeSdk({ scriptId: "wme-road-shield-assistant", scriptName: "WME Road Shield Assistant" });
    console.log(`SDK v ${sdk.getSDKVersion()} on ${sdk.getWMEVersion()} initialized`);
    sdk.Events.once({ eventName: "wme-ready" }).then(rsaInit);
});
function rsaInit() {
    if (!WazeWrap.Ready) {
        setTimeout(() => {
            rsaInit();
        }, 100);
        return;
    }
    const GF_LINK = "https://greasyfork.org/en/scripts/425050-wme-road-shield-assisstant";
    const FORUM_LINK = "https://www.waze.com/discuss/t/script-road-shield-assistant-rsa/227100";
    const RSA_UPDATE_NOTES = `<b>NEW:</b><br>
    - Converted to WME SDK<br>
    - <b>Make Sure to Enable RSA Layers to See the Shields</b><br>
    - Added Rules for Shield Checking Logic for Mexico<br>
    - Updated Shield Highlight Rules for All States in US<br>
    - Updated Some Highlight Rules for Canada<br><br>
<b>BUGFIXES:</b><br>
    - Fix error with undefined point Radius for Circle Tag<br><br>
<b>KNOWN ISSUES:</b><br>
    - Missing Exit Sign Shields on Node<br>
    - Some of the highlighting may be incorrect showing issues when there are none<br><br>`;
    let CountryID;
    (function (CountryID) {
        CountryID[CountryID["AFGANISTAN"] = 1] = "AFGANISTAN";
        CountryID[CountryID["ALBANIA"] = 2] = "ALBANIA";
        CountryID[CountryID["ALGERIA"] = 3] = "ALGERIA";
        CountryID[CountryID["AMERICAN_SAMOA"] = 4] = "AMERICAN_SAMOA";
        CountryID[CountryID["ANDORRA"] = 5] = "ANDORRA";
        CountryID[CountryID["ANGOLA"] = 6] = "ANGOLA";
        CountryID[CountryID["ANGUILLA"] = 7] = "ANGUILLA";
        CountryID[CountryID["ANTARCTICA"] = 8] = "ANTARCTICA";
        CountryID[CountryID["ANTIGUA_AND_BARBUDA"] = 9] = "ANTIGUA_AND_BARBUDA";
        CountryID[CountryID["ARGENTINA"] = 10] = "ARGENTINA";
        CountryID[CountryID["ARMENIA"] = 11] = "ARMENIA";
        CountryID[CountryID["ARUBA"] = 12] = "ARUBA";
        CountryID[CountryID["AUSTRALIA"] = 13] = "AUSTRALIA";
        CountryID[CountryID["AUSTRIA"] = 14] = "AUSTRIA";
        CountryID[CountryID["AZERBAIJAN"] = 15] = "AZERBAIJAN";
        CountryID[CountryID["BAHAMAS"] = 16] = "BAHAMAS";
        CountryID[CountryID["BAHRAIN"] = 17] = "BAHRAIN";
        CountryID[CountryID["BAKER_ISLAND"] = 18] = "BAKER_ISLAND";
        CountryID[CountryID["BANGLADESH"] = 19] = "BANGLADESH";
        CountryID[CountryID["BARBADOS"] = 20] = "BARBADOS";
        CountryID[CountryID["BELGUIM"] = 21] = "BELGUIM";
        CountryID[CountryID["BELIZE"] = 22] = "BELIZE";
        CountryID[CountryID["BENIN"] = 23] = "BENIN";
        CountryID[CountryID["BERMUDA"] = 24] = "BERMUDA";
        CountryID[CountryID["BHUTAN"] = 25] = "BHUTAN";
        CountryID[CountryID["BOLIVIA"] = 26] = "BOLIVIA";
        CountryID[CountryID["BOSNIA_AND_HERZEGOWINA"] = 27] = "BOSNIA_AND_HERZEGOWINA";
        CountryID[CountryID["BOTSWANA"] = 28] = "BOTSWANA";
        CountryID[CountryID["BOUVET_ISLAND"] = 29] = "BOUVET_ISLAND";
        CountryID[CountryID["BRAZIL"] = 30] = "BRAZIL";
        CountryID[CountryID["BRITISH_INDIAN_OCEAN_TERRITORY"] = 31] = "BRITISH_INDIAN_OCEAN_TERRITORY";
        CountryID[CountryID["BRITISH_VIRGIN_ISLANDS"] = 32] = "BRITISH_VIRGIN_ISLANDS";
        CountryID[CountryID["BRUNEI"] = 33] = "BRUNEI";
        CountryID[CountryID["BULGARIA"] = 34] = "BULGARIA";
        CountryID[CountryID["BURKINA_FASO"] = 35] = "BURKINA_FASO";
        CountryID[CountryID["BURUNDI"] = 36] = "BURUNDI";
        CountryID[CountryID["BELARUS"] = 37] = "BELARUS";
        CountryID[CountryID["CAMBODIA"] = 38] = "CAMBODIA";
        CountryID[CountryID["CAMEROON"] = 39] = "CAMEROON";
        CountryID[CountryID["CANADA"] = 40] = "CANADA";
        CountryID[CountryID["CAPE_VERDE"] = 41] = "CAPE_VERDE";
        CountryID[CountryID["CAYMAN_ISLANDS"] = 42] = "CAYMAN_ISLANDS";
        CountryID[CountryID["CENTRAL_AFRICAN_REPUBLIC"] = 43] = "CENTRAL_AFRICAN_REPUBLIC";
        CountryID[CountryID["CHAD"] = 44] = "CHAD";
        CountryID[CountryID["CHILE"] = 45] = "CHILE";
        CountryID[CountryID["CHINA"] = 46] = "CHINA";
        CountryID[CountryID["CHRISTMAS_ISLAND"] = 47] = "CHRISTMAS_ISLAND";
        CountryID[CountryID["COCOS_ISLANDS"] = 48] = "COCOS_ISLANDS";
        CountryID[CountryID["KEELING_ISLANDS"] = 48] = "KEELING_ISLANDS";
        CountryID[CountryID["COLOMBIA"] = 49] = "COLOMBIA";
        CountryID[CountryID["COMOROS"] = 50] = "COMOROS";
        CountryID[CountryID["CONGO"] = 51] = "CONGO";
        CountryID[CountryID["COOK_ISLANDS"] = 52] = "COOK_ISLANDS";
        CountryID[CountryID["COSTA_RICA"] = 53] = "COSTA_RICA";
        CountryID[CountryID["CROATIA"] = 54] = "CROATIA";
        CountryID[CountryID["CUBA"] = 55] = "CUBA";
        CountryID[CountryID["CYPRUS"] = 56] = "CYPRUS";
        CountryID[CountryID["CZECH_REPUBLIC"] = 57] = "CZECH_REPUBLIC";
        CountryID[CountryID["DENMARK"] = 58] = "DENMARK";
        CountryID[CountryID["DJIBOUTI"] = 59] = "DJIBOUTI";
        CountryID[CountryID["DOMINICA"] = 60] = "DOMINICA";
        CountryID[CountryID["DOMINICAN_REPUBLIC"] = 61] = "DOMINICAN_REPUBLIC";
        CountryID[CountryID["ECUADOR"] = 62] = "ECUADOR";
        CountryID[CountryID["EGYPT"] = 63] = "EGYPT";
        CountryID[CountryID["EL_SALVADOR"] = 64] = "EL_SALVADOR";
        CountryID[CountryID["EQUATORIAL_GUINEA"] = 65] = "EQUATORIAL_GUINEA";
        CountryID[CountryID["ERITREA"] = 66] = "ERITREA";
        CountryID[CountryID["ESTONIA"] = 67] = "ESTONIA";
        CountryID[CountryID["ETHIOPIA"] = 68] = "ETHIOPIA";
        CountryID[CountryID["FALKLAND_ISLANDS"] = 69] = "FALKLAND_ISLANDS";
        CountryID[CountryID["ISLAS_MALVINAS"] = 69] = "ISLAS_MALVINAS";
        CountryID[CountryID["FAROE_ISLANDS"] = 70] = "FAROE_ISLANDS";
        CountryID[CountryID["MICRONEISA"] = 71] = "MICRONEISA";
        CountryID[CountryID["FIJI"] = 72] = "FIJI";
        CountryID[CountryID["FRNACE"] = 73] = "FRNACE";
        CountryID[CountryID["FRENCH_GUIANA"] = 74] = "FRENCH_GUIANA";
        CountryID[CountryID["FRENCH_POLYNESIA"] = 75] = "FRENCH_POLYNESIA";
        CountryID[CountryID["FRENCH_SOUTHERN_TERRITORIES"] = 76] = "FRENCH_SOUTHERN_TERRITORIES";
        CountryID[CountryID["GABON"] = 77] = "GABON";
        CountryID[CountryID["GAMBIA"] = 78] = "GAMBIA";
        CountryID[CountryID["GEORGIA"] = 80] = "GEORGIA";
        CountryID[CountryID["GERMANY"] = 81] = "GERMANY";
        CountryID[CountryID["GHANA"] = 82] = "GHANA";
        CountryID[CountryID["GIBRALTAR"] = 83] = "GIBRALTAR";
        CountryID[CountryID["GLORIOSO_ISLANDS"] = 84] = "GLORIOSO_ISLANDS";
        CountryID[CountryID["GREECE"] = 85] = "GREECE";
        CountryID[CountryID["GREENLAND"] = 86] = "GREENLAND";
        CountryID[CountryID["GRENADA"] = 87] = "GRENADA";
        CountryID[CountryID["GUADELOUPE"] = 88] = "GUADELOUPE";
        CountryID[CountryID["GUAM"] = 89] = "GUAM";
        CountryID[CountryID["GUATEMALA"] = 90] = "GUATEMALA";
        CountryID[CountryID["GUERNSEY"] = 91] = "GUERNSEY";
        CountryID[CountryID["GUINEA"] = 92] = "GUINEA";
        CountryID[CountryID["GUINEA_BISSAU"] = 93] = "GUINEA_BISSAU";
        CountryID[CountryID["GUYANA"] = 94] = "GUYANA";
        CountryID[CountryID["HAITI"] = 95] = "HAITI";
        CountryID[CountryID["HEARD_AND_MCDONAL_ISLANDS"] = 96] = "HEARD_AND_MCDONAL_ISLANDS";
        CountryID[CountryID["HONDURAS"] = 97] = "HONDURAS";
        CountryID[CountryID["HOWLAND_ISLAND"] = 98] = "HOWLAND_ISLAND";
        CountryID[CountryID["HUNGARY"] = 99] = "HUNGARY";
        CountryID[CountryID["ICELAND"] = 100] = "ICELAND";
        CountryID[CountryID["INDIA"] = 101] = "INDIA";
        CountryID[CountryID["INDONESIA"] = 102] = "INDONESIA";
        CountryID[CountryID["IRAN"] = 103] = "IRAN";
        CountryID[CountryID["IRAQ"] = 104] = "IRAQ";
        CountryID[CountryID["IRELAND"] = 105] = "IRELAND";
        CountryID[CountryID["ITALY"] = 107] = "ITALY";
        CountryID[CountryID["COTE_DIVORE"] = 108] = "COTE_DIVORE";
        CountryID[CountryID["JAMAICA"] = 109] = "JAMAICA";
        CountryID[CountryID["JAN_MAYEN"] = 110] = "JAN_MAYEN";
        CountryID[CountryID["JAPAN"] = 111] = "JAPAN";
        CountryID[CountryID["JARVIS_ISLAND"] = 112] = "JARVIS_ISLAND";
        CountryID[CountryID["JERSEY"] = 113] = "JERSEY";
        CountryID[CountryID["JOHNSTON_ATOLL"] = 114] = "JOHNSTON_ATOLL";
        CountryID[CountryID["JORDAN"] = 115] = "JORDAN";
        CountryID[CountryID["JUAN_DE_NOVA_ISLAND"] = 116] = "JUAN_DE_NOVA_ISLAND";
        CountryID[CountryID["KAZAKHSTAN"] = 117] = "KAZAKHSTAN";
        CountryID[CountryID["KENYA"] = 118] = "KENYA";
        CountryID[CountryID["KIRIBATI"] = 119] = "KIRIBATI";
        CountryID[CountryID["KUWAIT"] = 120] = "KUWAIT";
        CountryID[CountryID["KYRGYZSTAN"] = 121] = "KYRGYZSTAN";
        CountryID[CountryID["LAOS"] = 122] = "LAOS";
        CountryID[CountryID["LATVIA"] = 123] = "LATVIA";
        CountryID[CountryID["LEBANON"] = 124] = "LEBANON";
        CountryID[CountryID["LESOTHO"] = 125] = "LESOTHO";
        CountryID[CountryID["LIBERIA"] = 126] = "LIBERIA";
        CountryID[CountryID["LIBYA"] = 127] = "LIBYA";
        CountryID[CountryID["LIECHTENSTEIN"] = 128] = "LIECHTENSTEIN";
        CountryID[CountryID["LITHUANIA"] = 129] = "LITHUANIA";
        CountryID[CountryID["LUXEMBOURG"] = 130] = "LUXEMBOURG";
        CountryID[CountryID["MACAU"] = 131] = "MACAU";
        CountryID[CountryID["MACEDONIA"] = 132] = "MACEDONIA";
        CountryID[CountryID["MADAGASCAR"] = 133] = "MADAGASCAR";
        CountryID[CountryID["MALAWI"] = 134] = "MALAWI";
        CountryID[CountryID["MALAYSIA"] = 135] = "MALAYSIA";
        CountryID[CountryID["MALDIVES"] = 136] = "MALDIVES";
        CountryID[CountryID["MALI"] = 137] = "MALI";
        CountryID[CountryID["MALTA"] = 138] = "MALTA";
        CountryID[CountryID["ISLE_OF_MAN"] = 139] = "ISLE_OF_MAN";
        CountryID[CountryID["MARSHALL_ISLANDS"] = 140] = "MARSHALL_ISLANDS";
        CountryID[CountryID["MARTINIQUE"] = 141] = "MARTINIQUE";
        CountryID[CountryID["MAURITANIA"] = 142] = "MAURITANIA";
        CountryID[CountryID["MAURITIUS"] = 143] = "MAURITIUS";
        CountryID[CountryID["MAYOTTE"] = 144] = "MAYOTTE";
        CountryID[CountryID["MEXICO"] = 145] = "MEXICO";
        CountryID[CountryID["MIDWAY_ISLAND"] = 146] = "MIDWAY_ISLAND";
        CountryID[CountryID["MOLDOVA"] = 147] = "MOLDOVA";
        CountryID[CountryID["MONACO"] = 148] = "MONACO";
        CountryID[CountryID["MONGOLIA"] = 149] = "MONGOLIA";
        CountryID[CountryID["MONTENEGRO"] = 150] = "MONTENEGRO";
        CountryID[CountryID["MONTSERRAT"] = 151] = "MONTSERRAT";
        CountryID[CountryID["MOROCCO"] = 152] = "MOROCCO";
        CountryID[CountryID["MOZAMBIQUE"] = 153] = "MOZAMBIQUE";
        CountryID[CountryID["MYANMAR"] = 154] = "MYANMAR";
        CountryID[CountryID["NAMIBIA"] = 155] = "NAMIBIA";
        CountryID[CountryID["NAURU"] = 156] = "NAURU";
        CountryID[CountryID["NEPAL"] = 157] = "NEPAL";
        CountryID[CountryID["NETHERLANDS"] = 158] = "NETHERLANDS";
        CountryID[CountryID["NEW_CALEDONIA"] = 159] = "NEW_CALEDONIA";
        CountryID[CountryID["NEW_ZEALAND"] = 161] = "NEW_ZEALAND";
        CountryID[CountryID["NICARAGUA"] = 162] = "NICARAGUA";
        CountryID[CountryID["NIGER"] = 163] = "NIGER";
        CountryID[CountryID["NIGERIA"] = 164] = "NIGERIA";
        CountryID[CountryID["NIUE"] = 165] = "NIUE";
        CountryID[CountryID["NORFOLK_ISLAND"] = 166] = "NORFOLK_ISLAND";
        CountryID[CountryID["NORTHERN_MARIANA_ISLANDS"] = 167] = "NORTHERN_MARIANA_ISLANDS";
        CountryID[CountryID["NORTH_KOREA"] = 168] = "NORTH_KOREA";
        CountryID[CountryID["KOREA_NORTH"] = 168] = "KOREA_NORTH";
        CountryID[CountryID["NORWAY"] = 169] = "NORWAY";
        CountryID[CountryID["OMAN"] = 170] = "OMAN";
        CountryID[CountryID["PASIFIC_ISLANDS"] = 171] = "PASIFIC_ISLANDS";
        CountryID[CountryID["PALAU"] = 171] = "PALAU";
        CountryID[CountryID["PAKISTAN"] = 172] = "PAKISTAN";
        CountryID[CountryID["PANAMA"] = 173] = "PANAMA";
        CountryID[CountryID["PAPUA_NEW_GUINEA"] = 174] = "PAPUA_NEW_GUINEA";
        CountryID[CountryID["PARACEL_ISLANDS"] = 175] = "PARACEL_ISLANDS";
        CountryID[CountryID["PARAGUAY"] = 176] = "PARAGUAY";
        CountryID[CountryID["PERU"] = 177] = "PERU";
        CountryID[CountryID["PHILIPPINES"] = 178] = "PHILIPPINES";
        CountryID[CountryID["PITCAIRN_ISLANDS"] = 179] = "PITCAIRN_ISLANDS";
        CountryID[CountryID["POLAND"] = 180] = "POLAND";
        CountryID[CountryID["PORTUGAL"] = 181] = "PORTUGAL";
        CountryID[CountryID["PUERTO_RICO"] = 182] = "PUERTO_RICO";
        CountryID[CountryID["QATAR"] = 183] = "QATAR";
        CountryID[CountryID["REUNION"] = 184] = "REUNION";
        CountryID[CountryID["ROMANIA"] = 185] = "ROMANIA";
        CountryID[CountryID["RUSSIA"] = 186] = "RUSSIA";
        CountryID[CountryID["RWANDA"] = 187] = "RWANDA";
        CountryID[CountryID["SAN_MARINO"] = 188] = "SAN_MARINO";
        CountryID[CountryID["SAO_TOME_AND_PRINCIPE"] = 189] = "SAO_TOME_AND_PRINCIPE";
        CountryID[CountryID["SAUDI_ARABIA"] = 190] = "SAUDI_ARABIA";
        CountryID[CountryID["SENEGAL"] = 191] = "SENEGAL";
        CountryID[CountryID["SERBIA"] = 192] = "SERBIA";
        CountryID[CountryID["SEYCHELLES"] = 193] = "SEYCHELLES";
        CountryID[CountryID["SIERRA_LEONE"] = 194] = "SIERRA_LEONE";
        CountryID[CountryID["SINGAPORE"] = 195] = "SINGAPORE";
        CountryID[CountryID["SLOVAKIA"] = 196] = "SLOVAKIA";
        CountryID[CountryID["SLOVENIA"] = 197] = "SLOVENIA";
        CountryID[CountryID["SOLOMON_ISLANDS"] = 198] = "SOLOMON_ISLANDS";
        CountryID[CountryID["SOMALIA"] = 199] = "SOMALIA";
        CountryID[CountryID["SOUTH_AFRICA"] = 200] = "SOUTH_AFRICA";
        CountryID[CountryID["SOUTH_GEORGIA_AND_THE_SOUTH_SANDWICH_ISLANDS"] = 201] = "SOUTH_GEORGIA_AND_THE_SOUTH_SANDWICH_ISLANDS";
        CountryID[CountryID["SOUTH_GEORGIA"] = 201] = "SOUTH_GEORGIA";
        CountryID[CountryID["SOUTH_SANDWICH_ISLANDS"] = 201] = "SOUTH_SANDWICH_ISLANDS";
        CountryID[CountryID["SOUTH_KOREA"] = 202] = "SOUTH_KOREA";
        CountryID[CountryID["KOREA_SOUTH"] = 202] = "KOREA_SOUTH";
        CountryID[CountryID["SPAIN"] = 203] = "SPAIN";
        CountryID[CountryID["SPRATLY_ISLANDS"] = 204] = "SPRATLY_ISLANDS";
        CountryID[CountryID["SRI_LANKA"] = 205] = "SRI_LANKA";
        CountryID[CountryID["ST_MARTIN"] = 254] = "ST_MARTIN";
        CountryID[CountryID["SAINT_MARTIN"] = 254] = "SAINT_MARTIN";
        CountryID[CountryID["ST_HELENA"] = 206] = "ST_HELENA";
        CountryID[CountryID["ST_KITTS_AND_NEVIS"] = 207] = "ST_KITTS_AND_NEVIS";
        CountryID[CountryID["ST_LUCIA"] = 208] = "ST_LUCIA";
        CountryID[CountryID["ST_PIERRE_AND_MIQUELON"] = 209] = "ST_PIERRE_AND_MIQUELON";
        CountryID[CountryID["ST_VINCENT_AND_THE_GRENADINES"] = 210] = "ST_VINCENT_AND_THE_GRENADINES";
        CountryID[CountryID["SUDAN"] = 211] = "SUDAN";
        CountryID[CountryID["SURINAME"] = 212] = "SURINAME";
        CountryID[CountryID["SVALBARD"] = 213] = "SVALBARD";
        CountryID[CountryID["SWAZILAND"] = 214] = "SWAZILAND";
        CountryID[CountryID["SWEDEN"] = 215] = "SWEDEN";
        CountryID[CountryID["SWITZERLAND"] = 216] = "SWITZERLAND";
        CountryID[CountryID["SYRIA"] = 217] = "SYRIA";
        CountryID[CountryID["TAIWAN"] = 218] = "TAIWAN";
        CountryID[CountryID["TAJIKISTAN"] = 219] = "TAJIKISTAN";
        CountryID[CountryID["TANZANIA"] = 220] = "TANZANIA";
        CountryID[CountryID["THAILAND"] = 221] = "THAILAND";
        CountryID[CountryID["TOGO"] = 222] = "TOGO";
        CountryID[CountryID["TOKELAU"] = 223] = "TOKELAU";
        CountryID[CountryID["TONGA"] = 224] = "TONGA";
        CountryID[CountryID["TRINIDAD_AND_TOBAGO"] = 225] = "TRINIDAD_AND_TOBAGO";
        CountryID[CountryID["TUNISIA"] = 226] = "TUNISIA";
        CountryID[CountryID["TURKEY"] = 227] = "TURKEY";
        CountryID[CountryID["TURKMENISTAN"] = 228] = "TURKMENISTAN";
        CountryID[CountryID["TURKS_AND_CAICOS_ISLANDS"] = 229] = "TURKS_AND_CAICOS_ISLANDS";
        CountryID[CountryID["TUVALU"] = 230] = "TUVALU";
        CountryID[CountryID["UGANDA"] = 231] = "UGANDA";
        CountryID[CountryID["UKRAINE"] = 232] = "UKRAINE";
        CountryID[CountryID["UNITED_ARAB_EMIRATES"] = 233] = "UNITED_ARAB_EMIRATES";
        CountryID[CountryID["UNITED_KINGDOM"] = 234] = "UNITED_KINGDOM";
        CountryID[CountryID["UK"] = 234] = "UK";
        CountryID[CountryID["GREAT_BRITAIN"] = 234] = "GREAT_BRITAIN";
        CountryID[CountryID["UNITED_STATES"] = 235] = "UNITED_STATES";
        CountryID[CountryID["USA"] = 235] = "USA";
        CountryID[CountryID["UNITED_STATES_OF_AMERICA"] = 235] = "UNITED_STATES_OF_AMERICA";
        CountryID[CountryID["URUGUAY"] = 236] = "URUGUAY";
        CountryID[CountryID["UZBEKISTAN"] = 237] = "UZBEKISTAN";
        CountryID[CountryID["VANUATU"] = 238] = "VANUATU";
        CountryID[CountryID["VENEZUELA"] = 239] = "VENEZUELA";
        CountryID[CountryID["VIETNAM"] = 240] = "VIETNAM";
        CountryID[CountryID["US_VIRGIN_ISLANDS"] = 241] = "US_VIRGIN_ISLANDS";
        CountryID[CountryID["WAKE_ISLAND"] = 242] = "WAKE_ISLAND";
        CountryID[CountryID["WALLIS_AND_FUTUNA"] = 243] = "WALLIS_AND_FUTUNA";
        CountryID[CountryID["WESTERN_SAHARA"] = 245] = "WESTERN_SAHARA";
        CountryID[CountryID["SAMOA"] = 246] = "SAMOA";
        CountryID[CountryID["YEMEN"] = 247] = "YEMEN";
        CountryID[CountryID["DEMOCRATIC_REPUBLIC_OF_THE_CONGO"] = 248] = "DEMOCRATIC_REPUBLIC_OF_THE_CONGO";
        CountryID[CountryID["DRC"] = 248] = "DRC";
        CountryID[CountryID["ZAMBIA"] = 249] = "ZAMBIA";
        CountryID[CountryID["ZIMBABWE"] = 250] = "ZIMBABWE";
        CountryID[CountryID["FINLAND"] = 251] = "FINLAND";
        CountryID[CountryID["CURACAO"] = 252] = "CURACAO";
        CountryID[CountryID["BONAIRE_SINT_EUSTATIUS_SABA_ISLAND"] = 253] = "BONAIRE_SINT_EUSTATIUS_SABA_ISLAND";
        CountryID[CountryID["BONAIRE"] = 253] = "BONAIRE";
        CountryID[CountryID["SINT_EUSTATIUS"] = 253] = "SINT_EUSTATIUS";
        CountryID[CountryID["SABA_ISLAND"] = 253] = "SABA_ISLAND";
        CountryID[CountryID["SAINT_BARTHELEMY"] = 255] = "SAINT_BARTHELEMY";
        CountryID[CountryID["SAINT_BARTHS"] = 255] = "SAINT_BARTHS";
        CountryID[CountryID["SAINT_BARTS"] = 255] = "SAINT_BARTS";
        CountryID[CountryID["HONG_KONG"] = 256] = "HONG_KONG";
        CountryID[CountryID["SINT_MAARTEN"] = 257] = "SINT_MAARTEN";
        CountryID[CountryID["TIMOR_LESTE"] = 258] = "TIMOR_LESTE";
        CountryID[CountryID["SOUTH_SUDAN"] = 259] = "SOUTH_SUDAN";
    })(CountryID || (CountryID = {}));
    const MIN_ZOOM_LEVEL = 14;
    let ZoomLevel;
    (function (ZoomLevel) {
        ZoomLevel[ZoomLevel["ZM0"] = 12] = "ZM0";
        ZoomLevel[ZoomLevel["ZM1"] = 13] = "ZM1";
        ZoomLevel[ZoomLevel["ZM2"] = 14] = "ZM2";
        ZoomLevel[ZoomLevel["ZM3"] = 15] = "ZM3";
        ZoomLevel[ZoomLevel["ZM4"] = 16] = "ZM4";
        ZoomLevel[ZoomLevel["ZM5"] = 17] = "ZM5";
        ZoomLevel[ZoomLevel["ZM6"] = 18] = "ZM6";
        ZoomLevel[ZoomLevel["ZM7"] = 19] = "ZM7";
        ZoomLevel[ZoomLevel["ZM8"] = 20] = "ZM8";
        ZoomLevel[ZoomLevel["ZM9"] = 21] = "ZM9";
        ZoomLevel[ZoomLevel["ZM10"] = 22] = "ZM10";
    })(ZoomLevel || (ZoomLevel = {}));
    const minShieldDisplayLengths = {
        15: 150,
        16: 90,
        17: 80,
        18: 70,
        19: 60,
        20: 50,
        21: 40,
        22: 30,
    };
    const RoadAbbr = {
        //Canada
        40: {
            Alberta: {
                "^Hwy 1$": 5000, // 5000: National-Trans-Canada Highway
                "^Hwy 1A\\b": 5011, // 5011: Alberta - Provincial Hwy
                "^Hwy 2\\b": 5011, // 5011: Alberta - Provincial Hwy
                "^Hwy 3$": 5015, // 5015: Alberta - Crowsnext Hwy
                "^Hwy 3A\\b": 5011, // 5011: Alberta - Provincial Hwy
                "^Hwy 16$": 5000, // 5000: National-Trans-Canada Highway
                "^Hwy 16A\\b": 5011, // 5011: Alberta - Provincial Hwy
                "^Hwy ([4-9]|1[0-57-9]|[2-9]\\d{1}|2\\d{2})\\b": 5011,
                "^Hwy ([3-9]\\d{2})\\b": 5012,
            },
            "British Columbia": {
                "^Hwy 1\\b": 5000, // 5000: National-Trans-Canada Highway
                "^Hwy 2\\b": 5001, // 5001: BC - Provincial Hwy
                "^Hwy 3\\b": 5002, // 5002: BC - Crowsnest Hwy
                "^Hwy 16\\b": 5000, // 5000: National-Trans-Canada Highway
                "^Hwy 113\\b": 5004, // 5004: BC - Nisga'a Hwy
                "^Hwy\\s+([4-9]|[1-9][0-57-9]|10\\d|11[0-24-9]|1[2-9]\\d|[2-9]\\d{1,2})[a-zA-Z]*\\b": 5001, // 5001: BC - Provincial Hwy
            },
            Saskatchewan: {
                "^Hwy 1\\b": 5000, // 5000: National - Trans-Canada Hwy
                "^Hwy 16\\b": 5000, // 5000: National - Trans-Canada Hwy
                "^Hwy ([2-9]|1[0-57-9]|[2-9]\\d|[1-3]\\d{2})\\b": 5030, // 5030: Saskatchewan - Provincial Hwy
                "^Hwy (9\\d{2})\\b": 5031, // 5031: Saskatchewan - Northern Secondary Hwy
                "^Hwy ([6-7]\\d{2})\\b": 5032, // 5032: Saskatchewan - Municipal Road
            },
            Manitoba: {
                "^Hwy 1\\b": 5000, // 5000: National - Trans-Canada Hwy
                "^Hwy 16\\b": 5000, // 5000: National - Trans-Canada Hwy
                "^Hwy ([2-9]|1[0-57-9]|[2-9]\\d|1\\d{2})\\b": 5038, // 5038: Manitoba - Provincial Trunk Highway
                "^Hwy ([2-9]\\d{2})\\b": 5039, // 5039: Manitoba - Provincial Rd
            },
            Ontario: {
                "^QEW\\b": 5058, // 5058: Ontario QEW
                "(^Hwy 17\\b|Hwy 17$)": new Set([5000, 5057]), // 5000: National - Trans-Canada Hwy
                "^Hwy 407\\b": new Set([5207, 5206]), // 5060: Ontario ETR
                "^Hwy 412\\b": 5059, // 5059: Ontario Toll Hwy
                "^Hwy 418\\b": new Set([5059, 5057]), // 5059: Ontario Toll Hwy
                // "Hwy [1-9]\\d{0,2}\\b": 5057, // 5057: Ontario King's Hwy 1-16
                // "Hwy (1[89]|[2-9]d|[1-3]d{2}|40[0-6])\\b": 5057, // 5057: Ontario King's Hwy 18-406
                // "Hwy (40[89]|41[01])\\b": 5057, // 5057: Ontario King's Hwy 408-411
                // "Hwy (41[3-7])\\b": 5057, // 5057: Ontario King's Hwy 413-417
                "^CR-[1-9]\\d{0,2}\\b": 5063,
                "^Hwy\\s+([1-9]|[1-68-9]\\d|[1-3]\\d{2}|40[0-68-9]|41[0-13-79]|4[2-9]\\d|[7-9]\\d{2})[A-Z]*\\b": 5057,
                "^Hwy\\s+[5-6]\\d{2}\\b": 5061, // 5061: Ontario Secondary Hwy 500-699
                // "Hwy (80d|8[1-9]d)\\b": 5057, // 5057: Ontario Tertiary Hwy
                "^(Muskoka|Wellington|Winchester|Regional) (Road|Rd) [1-9]\\d{0,2}\\b": new Set([
                    5065, 5063, 5077,
                ]), // Ontario Regional
            },
            Quebec: {
                "Rte Transcanadienne": 5093, // 5093: Quebec: Route Transcanadienne
                "^Aut [1-9]\\d{1,2}\\b": 5090, // 5090: Quebec Autoroute 1-999
                "^Rte [1-9]\\d{0,2}\\b": 5091, // 5091: Quebec Route 100-399
                "R (10d|1[1-9]d|[2-9]d{2}|1[0-4]d{2}|15[0-5]d)\b": 5092, // 5092: Quebec Route 100-1559
            },
            "New Brunswick": {
                "^Rte 2\\b": 5000, // 5000: Trans-Canada Hwy
                "^Rte 16\\b": 5000, // 5000: Trans-Canada Hwy
                "^Rte 1\\b": 5112, // 5112: NB Arterial Highway 1
                "^Rte ([3-9]|1[0-57-9]|[2-9]\\d)\\b": 5112, // 5112: NB Arterial Highway 17-99
                "^Rte (10\\d|11[02-9]|1[2-9]\\d)\\b": 5113, // 5113: NB Collector Highway 100-199
                "^Rte (111|[2-9]\\d{2})\\b": 5114, // 5114: NB Local Highway 200-999
            },
            "Nova Scotia": {
                "^Hwy ([1-9]\\d{0,1})\\b": 5116, // 5116: NS Trunk Hwy 1-99
                "^Hwy 104\\b": new Set([5115, 5000]), // In NS 104 has 2 different shields
                "^Hwy (10[5-6])\\b": 5000, // 5000: National Trans Canada Highway 105-106
                "^Hwy (10[0-37-9]|1[1-9]\\d)\\b": 5115, // 5115: NS Aterial Hwy 107-199
                "^Hwy ([2-3]\\d{2})\\b": 5117, // 5117: NS Collector Hwy 200-399
            },
            "Newfoundland and Labrador": {
                "^Hwy 1": 5000, // 5000: National - Trans-Canada Hwy 1
                "^Rte ([2-9]|[1-9]\\d|[1-5]\\d{2})\\b": 5129, // NLR: Newfoundland Labrador Route 2-599
            },
            "Prince Edward Island": {
                "^Rte 1$": 5000, // 5000: National Trans-Canada Hwy
                "^Rte ([2-9]|[1-9]\\d{1,2})\\b": 5144, // 5144: PEI - Provincial Highway
            },
            "Yukon Territory": {
                "^Hwy 1\\b": 5146, // 5145: Yukon - Territorial Hwy - Orange
                "Hwy 2": 5146, // 5146: Yukon - Territorial Hwy - Amber
                "Hwy 3": 5147, // 5147: Yukon - Territorial Hwy - Maroon
                "Hwy 4": 5148, // 5148: Yukon - Territorial Hwy - Brown
                "Hwy 5": 5149, // 5149: Yukon - Territorial Hwy - Blue
                "Hwy 6": 5150, // 5150: Yukon - Territorial Hwy - Teal
                "Hwy 7": 5147, // 5147: Yukon - Territorial Hwy - Maroon
                "Hwy 8": 5148, // 5148: Yukon - Territorial Hwy - Brown
                "Hwy 9": 5151, // 5151: Yukon - Territorial Hwy - Black
                "Hwy 10": 5151, // 5151: Yukon - Territorial Hwy - Black
                "Hwy 11": 5149, // 5149: Yukon - Territorial Hwy - Blue
                "Hwy 37": 5147, // 5147: Yukon - Territorial Hwy - Maroon
            },
            "Northwest Territories": {
                "Hwy ([1-9]|10)\b": 5152, // 5152: NWT - Territorial Hwy 1-10
            },
        },
        // France
        73: {
            "": {
                "D\\d+[^:]*": 1092,
                "N\\d+[^:]*": 1072,
                "A\\d+[^:]*": 1072,
                "M\\d+[^:]*": 1067,
                "C\\d+[^:]*": 3333,
                "T\\d+[^:]*": 3037,
            },
        },
        // Germany
        81: { "": { "(A\\d{1,3})": 1012, "(B\\d{1,3})": 1094 } },
        // Mexico
        145: {
            "*": { "^MEX-[1-9]\\d{0,2}[A-Z]*\\b": new Set([1107, 1106]) },
            "Quintana Roo": { "Q.ROO-[1-9]\\d{0,2}\\b": 1000 },
            Yucatán: { "YUC-[1-9]\\d{0,2}\\b": 1000 },
            Campeche: { "CAM-[1-9]\\d{0,2}\\b": 1000 },
        },
        // Ukraine
        232: {
            "": {
                "(E\\d{2,3})": 1048,
                "(М-\\d{2})": 1071,
                "(Н-\\d{2})": 1071,
                "(Р-\\d{2})": 1008,
                "(Т-\\d{2}-\\d{2,3})": 1008,
                "(О\\d{6,7})": 1085,
                "(С\\d{6,7})": 1085,
            },
        },
        // US
        235: {
            "*": {
                "^I-[1-9]\\d{0,2}(?!\s+(?:W|E|East|West))\\b": 5,
                "^I-[1-9]\\d{0,2}\\s{1,}\\b(?:Bus|BUS|Business|BUSINESS)\\b": 2003,
                "^US-[1-9]\\d{0,2}[A-Z]*\\b": 6,
            },
            Alabama: { "^CR-[1-9]\\d{0,2}\\b": 2002, "^SR-[1-9]\\d{0,2}\\b": 2019 },
            Alaska: {
                "CR-[1-9]\\d{0,2}": 2002,
                "SR-[1-9]\\d{0,2}": 2017,
                "AK-[1-9]\\d{0,2}": 2017,
                "A-[1-9]\\d{0,2}": 2017,
            },
            Arizona: { "CR-[1-9]\\d{0,2}": 2002, "SR-[1-9]\\d{0,2}": 2022 },
            Arkansas: { "^CR-[1-9]\\d{0,2}\\b": 2002, "^AR-[1-9]\\d{0,2}\\b": 2020, "^AR-$1 SPUR\\b": 2020 },
            California: { "^CR-[1-9]\\d{0,2}\\b": 2002, "^SH-[1-9]\\d{0,2}\\b": 1082, "^SR-[1-9]\\d{0,2}\\b": 1082 },
            Colorado: {
                "^CR-[1-9]\\d{0,2}[a-zA-Z]*\\b": 2002,
                "^SH-[1-9]\\d{0,2}[a-zA-Z]*\\b": 2025,
                "^SR-[1-9]\\d{0,2}\\b": 2025,
            },
            Connecticut: {
                "^CR-[1-9]\\d{0,2}": 2002,
                "^SH-[1-9]\\d{0,2}": 2027,
                "^SR-[1-9]\\d{0,2}": 2027,
                "\\b(?:Wilbur Cross(?: Parkway| Pkwy))\\b": 2027,
            },
            Delaware: { "^CR-[1-9]\\d{0,2}\\b": 2002, "^SH-[1-9]\\d{0,2}\\b": 7, "^SR-[1-9]\\d{0,2}\\b": 7 },
            "District of Columbia": { "DC-[1-9]\\d{0,2}": 7 },
            Florida: {
                "^CR-[1-9]\\d{0,2}": 2002,
                "^SH-[1-9]\\d{0,2}": 2030,
                "^SR-[1-9]\\d{0,2}": 2030,
                "^Florida.* (Turnpike|Tpk|Tpke)\\b": 2033,
            },
            Georgia: { "^CR-[1-9]\\d{0,2}\\b": 2002, "^SH-[1-9]\\d{0,2}\\b": 2036, "^SR-[1-9]\\d{0,2}\\b": 2036 },
            Hawaii: {
                "H-[1-9]\\d{0,2}": 5,
                "CR-[1-9]\\d{0,2}": 2002,
                "SH-[1-9]\\d{0,2}": 2041,
                "SR-[1-9]\\d{0,2}": 2041,
            },
            Idaho: {
                "^CH-[1-9]\\d{0,2}\\b": 2002,
                "^CR-[1-9]\\d{0,2}\\b": 2002,
                "^SH-[1-9]\\d{0,2}\\b": 2043,
                "^SR-[1-9]\\d{0,2}\\b": 2043,
                "^ID-[1-9]\\d{0,2}\\b": 2043,
            },
            Illinois: {
                "^CH-[1-9]\\d{0,2}": 2002,
                "^CR-[1-9]\\d{0,3}": 2002,
                "^SH-[1-9]\\d{0,2}": 2044,
                "^SR-[1-9]\\d{0,2}": 2044,
            },
            Indiana: {
                "^CH-[1-9]\\d{0,2}": 2002,
                "^CR-[1-9]\\d{0,2}": 2002,
                "^SH-[1-9]\\d{0,2}": 2045,
                "^SR-[1-9]\\d{0,2}": 2045,
                "^IN-[1-9]\\d{0,2}": 2045,
            },
            Iowa: {
                "CH-[1-9]\\d{0,2}": 2002,
                "CR-[1-9]\\d{0,2}": 2002,
                "SH-[1-9]\\d{0,2}": 7,
                "SR-[1-9]\\d{0,2}": 7,
                "IA-[1-9]\\d{0,2}": 7,
            },
            Kansas: {
                "^CH-[1-9]\\d{0,2}\\b": 2002,
                "^CR-[1-9]\\d{0,2}\\b": 2002,
                "^SH-[1-9]\\d{0,2}\\b": 2046,
                "^SR-[1-9]\\d{0,2}\\b": 2046,
                "^K-[1-9]\\d{0,2}\\b": 2046,
            },
            Kentucky: {
                "^US-[1-9]\\d{0,2}\\s+(?:BUS|Bus|Business)\\b": 2005,
                "^CH-[1-9]\\d{0,2}\\b": 2002,
                "^CR-[1-9]\\d{0,2}\\b": 2002,
                "^SH-[1-9]\\d{0,2}\\b": 7,
                "^SR-[1-9]\\d{0,2}\\b": 7,
                "^KY-[1-9]\\d{0,3}\\b": 7,
                "^AA (Highway|Hwy)\\b": 2050,
            },
            Louisiana: {
                "^CH-[1-9]\\d{0,2}\\b": 2002,
                "^CR-[1-9]\\d{0,2}\\b": 2002,
                "^SH-[1-9]\\d{0,2}\\b": 1117,
                "^SR-[1-9]\\d{0,3}\\b": 1117,
                "^LA-[1-9]\\d{0,3}\\b": new Set([1117, 1115]),
            },
            Maine: {
                "^CH-[1-9]\\d{0,2}\\b": 2002,
                "^CR-[1-9]\\d{0,2}\\b": 2002,
                "^SH-[1-9]\\d{0,2}\\b": 2051,
                "^SR-[1-9]\\d{0,2}(?!\\s*(?:BUS|Bus|Business))\\b": 2051,
                "^SR-[1-9]\\d{0,2}\\s+(?:BUS|Bus|Business)\\b": 2052,
            },
            Maryland: {
                "^CH-[1-9]\\d{0,2}": 2002,
                "^CR-[1-9]\\d{0,2}": 2002,
                "^SH-[1-9]\\d{0,2}": 2053,
                "^SR-[1-9]\\d{0,2}": 2053,
                "^MD-[1-9]\\d{0,2}": 2053,
            },
            Massachusetts: {
                "^CH-[1-9]\\d{0,2}\\b": 2002,
                "^CR-[1-9]\\d{0,2}\\b": 2002,
                "^SH-[1-9]\\d{0,2}\\b": 2055,
                "^SR-[1-9]\\d{0,2}[a-zA-Z]*\\b": 2055,
            },
            Michigan: { "^CR-[1-9]\\d{0,2}\\b": 2056, "^M-[1-9]\\d{0,2}\\b": 2056, "^SR-[1-9]\\d{0,2}\\b": 2056 },
            Minnesota: {
                "^CH-[1-9]\\d{0,2}\\b": 2002,
                "^CR-[1-9]\\d{0,2}\\b": 2180,
                "^SH-[1-9]\\d{0,2}\\b": 2060,
                "^SR-[1-9]\\d{0,2}\\b": 2060,
                "^MN-[1-9]\\d{0,2}\\b": 2060,
            },
            Mississippi: { "^SH-[1-9]\\d{0,2}\\b": 7, "^SR-[1-9]\\d{0,2}\\b": 7, "^MS-[1-9]\\d{0,2}\\b": 7 },
            Missouri: {
                "^CH-[1-9]\\d{0,2}\\b": 2002,
                "^CR-[1-9]\\d{0,2}\\b": 2002,
                "^SH-[1-9]\\d{0,2}\\b": 2061,
                "^SH-[A-Z]\\w{0,2}\\b": 2062,
                "^SR-[1-9]\\d{0,2}\\b": 2061,
                "^MO-[1-9]\\d{0,2}\\b": 2061,
            },
            Montana: {
                "^CH-[1-9]\\d{0,2}\\b": 2002,
                "^CR-[1-9]\\d{0,2}\\b": 2002,
                "^SH-[1-9]\\d{0,2}\\b": 2063,
                "^SR-[1-9]\\d{0,2}\\b": 2063,
                "^MT-[1-9]\\d{0,2}\\b": 2063,
            },
            Nebraska: {
                "^CH-[1-9]\\d{0,2}\\b": 2002,
                "^CR-[1-9]\\d{0,2}\\b": 2002,
                "^SH-[1-9]\\d{0,2}\\b": 7,
                "^SR-[1-9]\\d{0,2}\\b": 7,
                "^L-[1-9]\\d{0,2}\\b": 7,
                "^N-[1-9]\\d{0,2}\\b": 2072,
                "^S-[1-9]\\d{0,2}\\b": 7,
            },
            Nevada: {
                "^US-[1-9]\\d{0,2}\\s+(?:ALT|Alt)\\b": 2004,
                "^CH-[1-9]\\d{0,2}\\b": 2002,
                "^CR-[1-9]\\d{0,2}\\b": 2002,
                "^SH-[1-9]\\d{0,2}\\b": 2086,
                "^SR-[1-9]\\d{0,2}\\b": 2086,
                "^NV-[1-9]\\d{0,2}\\b": 2086,
            },
            "New Hampshire": {
                "^CH-[1-9]\\d{0,2}\\b": 2002,
                "^CR-[1-9]\\d{0,2}\\b": 2002,
                "^SH-[1-9]\\d{0,2}\\b": 2076,
                "^SR-[1-9]\\d{0,2}[a-zA-Z]*\\b": 2076,
            },
            "New Jersey": {
                "^CH-[1-9]\\d{0,2}": 2002,
                "^CR-[1-9]\\d{0,2}": 2083,
                "^SH-[1-9]\\d{0,2}": 7,
                "^SR-[1-9]\\d{0,2}": 7,
                "^NJ-[1-9]\\d{0,2}": 7,
                "^Garden State (Parkway|Pkwy)": 2079,
                "^Palisades Interstate (Parkway|Pkwy)": 2082,
                "^Atlantic City (Expressway|Expy|Expwy)": 2000,
            },
            "New Mexico": {
                "^CH-[1-9]\\d{0,2}\\b": 2002,
                "^CR-[1-9]\\d{0,2}\\b": 2002,
                "^SH-[1-9]\\d{0,2}\\b": 2085,
                "^SR-[1-9]\\d{0,2}\\b": 2085,
            },
            "New York": {
                "^CH-[1-9]\\d{0,2}": 2002,
                "^CR-[1-9]\\d{0,2}[A-Z]*\\b": 2002,
                "^SH-[1-9]\\d{0,2}": 2087,
                "^SR-[1-9]\\d{0,2}": 2087,
                "^NY-[1-9]\\d{0,2}": 2087,
                "\\bPalisades Interstate (Parkway|Pkwy)\\b": 2082,
                "\\b(?:Saw Mill River(?: Parkway| Pkwy)|SMP)\\b": 2092,
                "\\b(?:Taconic State(?: Parkway| Pkwy)|TSP)\\b": 2092,
                "\\b(?:Bear Mountain State(?: Parkway| Pkwy)|BMP)\\b": 2092,
                "\\b(?:Cross County(?: Parkway| Pkwy)|CCP)\\b": 2092,
                "\\b(?:Hutchinson River(?: Parkway| Pkwy)|HRP)\\b": 2092,
                "\\b(?:Korean War Veterans(?: Parkway| Pkwy)|KWVP)\\b": 2092,
                "\\b(?:Pelham(?: Parkway| Pkwy)|PP)\\b": 2092,
                "\\b(?:Sprain Brook(?: Parkway| Pkwy)|SBP)\\b": 2092,
                "\\b(?:Belt(?: Parkway| Pkwy))\\b": 2090,
                "\\b(?:Cross Island(?: Parkway| Pkwy))\\b": 2090,
                "\\b(?:Grand Central(?: Parkway| Pkwy))\\b": 2090,
                "\\b(?:Jackie Robinson(?: Parkway| Pkwy))\\b": 2090,
                "\\b(?:Bronx River(?: Parkway| Pkwy))\\b": 2090,
                "\\b(?:Hutchison River(?: Parkway| Pkwy))\\b": 2090,
                "\\b(?:Mosholu(?: Parkway| Pkwy))\\b": 2090,
                "\\b(?:Northern State(?: Parkway| Pkwy))\\b": 2090,
                "\\b(?:Harlem River(?: Drive| Dr))\\b": 2090,
                "\\b(?:Robert Moses(?: Causeway| Cswy))\\b": 2090,
                "\\b(?:Sagtikos State(?: Parkway| Pkwy))\\b": 2090,
                "\\b(?:Southern State(?: Parkway| Pkwy))\\b": 2090,
                "\\b(?:Sunken Meadow State(?: Parkway| Pkwy))\\b": 2090,
                "\\b(?:Wantagh State(?: Parkway| Pkwy))\\b": 2090,
                "\\b(?:Loop(?: Parkway| Dr))\\b": 2091,
                "\\b(?:Bethpage State(?: Parkway| Pkwy))\\b": 2091,
                "\\b(?:Meadowbrook State(?: Parkway| Pkwy))\\b": 2091,
                "\\b(?:Lake Ontario State(?: Parkway| Pkwy))\\b": 2093,
                "\\b(?:Niagara Scenic(?: Parkway| Pkwy))\\b": 2094,
            },
            "North Carolina": {
                "^US-[1-9]\\d{0,2}\\s+(?:BUS|Bus|Business)\\b": 2005,
                "^US-[1-9]\\d{0,2}\\s+(?:BYP|Byp|Bypass)\\b": 2006,
                "^US-[1-9]\\d{0,2}\\s+(?:CONN|Conn|Connector)\\b": 2007,
                "^CH-[1-9]\\d{0,2}\\b": 2002,
                "^CR-[1-9]\\d{0,2}\\b": 2002,
                "^SH-[1-9]\\d{0,2}\\b": 2065,
                "^SR-[1-9]\\d{0,2}\\b": 2065,
                "^NC-[1-9]\\d{0,2}\\b": 2065,
            },
            "North Dakota": {
                "^CH-[1-9]\\d{0,2}\\b": 2002,
                "^CR-[1-9]\\d{0,2}\\b": 2002,
                "^SH-[1-9]\\d{0,2}\\b": 2070,
                "^SR-[1-9]\\d{0,2}\\b": 2070,
                "^ND-[1-9]\\d{0,3}\\b": 2070,
            },
            Ohio: {
                "^CH-[1-9]\\d{0,2}\\b": 2002,
                "^CR-[1-9]\\d{0,3}\\b": 2181,
                "^SH-[1-9]\\d{0,2}\\b": 2095,
                "^SR-[1-9]\\d{0,2}\\b": 2095,
            },
            Oklahoma: { "^SH-[1-9]\\d{0,2}\\b": 2097, "^SR-[1-9]\\d{0,2}\\b": 2097 },
            Oregon: {
                "^CH-[1-9]\\d{0,2}\\b": 2002,
                "^CR-[1-9]\\d{0,2}\\b": 2002,
                "^SH-[1-9]\\d{0,2}\\b": 2099,
                "^SR-[1-9]\\d{0,2}\\b": 2099,
                "^OR-[1-9]\\d{0,2}\\b": 2099,
            },
            Pennsylvania: {
                "^US-[1-9]\\d{0,2}\\s+(?:BUS|Bus|Business)\\b": 2005,
                "^CH-[1-9]\\d{0,2}": 2002,
                "^CR-[1-9]\\d{0,2}": 2002,
                "^SH-[1-9]\\d{0,2}": 2101,
                "^PA-[1-9]\\d{0,2}\\b": 2101,
                "^Hwy\\s[1-9]\\d{0,2}\\b": 2101,
                "^SR-[1-9]\\d{0,2}\\s+(?:BUS|Bus|Business)\\b": 2104,
                "^SR-[1-9]\\d{0,2}(?!\\s*(?:BUS|Bus|Business))\\b": 2101,
            },
            "Rhode Island": {
                "^CH-[1-9]\\d{0,2}\\b": 2002,
                "^CR-[1-9]\\d{0,2}\\b": 2002,
                "^SH-[1-9]\\d{0,2}\\b": 2108,
                "^SR-[1-9]\\d{0,2}\\b": 2108,
                "^RI-[1-9]\\d{0,2}\\b": 2108,
            },
            "South Carolina": {
                "^CH-[1-9]\\d{0,2}": 2002,
                "^CR-[1-9]\\d{0,2}": 2002,
                "^SH-[1-9]\\d{0,2}": 2109,
                "^SR-[1-9]\\d{0,2}": 2109,
                "^SC-[1-9]\\d{0,2}": 2109,
            },
            "South Dakota": {
                "^CH-[1-9]\\d{0,2}\\b": 2002,
                "^CR-[1-9A-Z]\\d{0,2}\\b": 2002,
                "^SH-[1-9]\\d{0,2}\\b": 2114,
                "^SR-[1-9]\\d{0,2}\\b": 2114,
                "^SD-[1-9]\\d{0,3}\\b": 2114,
            },
            Tennessee: {
                "^CH-[1-9]\\d{0,2}\\b": 2002,
                "^CR-[1-9]\\d{0,2}\\b": 2002,
                "^SH-[1-9]\\d{0,2}\\b": 2115,
                "^TN-[1-9]\\d{0,2}\\b": 2115,
                "^SR-[1-9]\\d{0,2}\\b": 2116,
            },
            Texas: {
                "^I-[1-9]\\d{0,2}[A-Z]+\\s": new Set([5, 2206]),
                "^SH-[1-9]\\d{0,3}": new Set([2117, 2123]),
                "^[Ss][Pp][Uu][Rr] [1-9]\\d{0,3}\\b": 2126,
                "\\b[Ll][Oo][Oo][Pp] [1-9]\\d{0,3}\\b": 2122,
                "^SR-[1-9]\\d{0,3}": 2117,
                "^FM-[1-9]\\d{0,3}": 2121,
                "^Beltway [1-9]\\d{0,3}\\b": 2119,
                "^Sam Houston (Tollway|Tlwy|Parkway|Pkwy)\\b": 2198,
                "^President George Bush (Turnpike|Tpke|Tpk)\\b": 2123,
                "^Park (Road|Rd)\\b": 2144,
                "^Westpark (Tollway|Tlwy)\\b": 2199,
                "^Fort Bend (Tollway|Tlwy|Parkway|Pkwy)\\b": 2196,
            },
            Utah: {
                "^CH-[1-9]\\d{0,2}\\b": 2002,
                "^CR-[1-9]\\d{0,2}\\b": 2002,
                "^SH-[1-9]\\d{0,2}\\b": 2127,
                "^SR-[1-9]\\d{0,2}\\b": 2127,
            },
            Vermont: {
                "^CH-[1-9]\\d{0,2}\\b": 2002,
                "^CR-[1-9]\\d{0,2}\\b": 2002,
                "^SH-[1-9]\\d{0,2}\\b": 2131,
                "^SR-[1-9]\\d{0,2}\\b": 2131,
                "^VT-[1-9]\\d{0,2}\\b": 2131,
            },
            Virginia: {
                "^CH-[1-9]\\d{0,2}\\b": 2002,
                "^CR-[1-9]\\d{0,2}]\\b": 2002,
                "^SH-[1-9]\\d{0,2}\\b": 2128,
                "^SR-[1-9]\\d{0,2}\\b": 2128,
                "^Blue Ridge Pkwy\\b": 2069,
            },
            Washington: {
                "^CH-[1-9]\\d{0,2}\\b": 2002,
                "^CR-[1-9]\\d{0,2}\\b": 2002,
                "^SH-[1-9]\\d{0,2}\\b": 2133,
                "^SR-[1-9]\\d{0,2}(?!\\s*(?:Spur|SPUR|BUS|Bus|Business))\\b": 2133,
                "^SR-[1-9]\\d{0,2}\\s+(?:Spur|SPUR|BUS|Bus|Business)": 2134,
                "^FS-[1-9]\\d{0,3}\\b": 2011,
            },
            "West Virginia": {
                "^CH-[1-9]\\d{0,2}\\b": 2002,
                "^CR-[1-9]\\d{0,2}\\b": 2002,
                "^SH-[1-9]\\d{0,2}\\b": 2138,
                "^SR-[1-9]\\d{0,2}\\b": 2138,
                "^WV-[1-9]\\d{0,2}\\b": 2138,
            },
            Wisconsin: {
                "^CH-[A-Z]+\\b": 2137,
                "^CR-[1-9]\\d{0,2}": 2137,
                "^SH-[1-9]\\d{0,2}": 2135,
                "^SR-[1-9]\\d{0,2}": 2135,
                "^WIS-[1-9]\\d{0,2}\\b": 2135,
                "^WIS SPUR": 2135,
            },
            Wyoming: {
                "^CH-[1-9]\\d{0,2}\\b": 2002,
                "^CR-[1-9]\\d{0,2}\\b": 2002,
                "^SH-[1-9]\\d{0,2}\\b": 2143,
                "^SR-[1-9]\\d{0,2}\\b": 2143,
                "^WY-[1-9]\\d{0,2}\\b": 2143,
            },
        },
        // Uruguay
        236: { "": { Ruta: 1111 } },
        // Réunion
        262: { "": { "D\\d+[^:]*": 1092, "N\\d+[^:]*": 1072 } },
        // Guadeloupe
        590: { "": { "D\\d+[^:]*": 1092, "N\\d+[^:]*": 1072 } },
        // French Guyana
        594: { "": { "D\\d+[^:]*": 1092, "N\\d+[^:]*": 1072 } },
        // Martinique
        596: { "": { "D\\d+[^:]*": 1092, "N\\d+[^:]*": 1072 } },
        // Wallis and Futuna
        681: { "": { "D\\d+[^:]*": 1092, "N\\d+[^:]*": 1072 } },
        // French Polynesia
        689: { "": { "D\\d+[^:]*": 1092, "N\\d+[^:]*": 1072 } },
    };
    const iconsAllowingNoText = new Set([
        2000, // Atlantic City Expy
        2079, // Garden State Parkway
        2033, // Florida's Turnpike
        2082, // Palisades Pkwy
        2093, // Ontario State Pkwy
        2094, // Niagara Scenic Pkwy
        2199, // Westpark Tollway,
        2198, // Sam Houston Parkway,
        2196, // Fort Bend
        2050, // AA Hwy,
        2069, // Blue Ridge Pkwy
        5058, // QEW
    ]);
    const Strings = {
        en: {
            enableScript: "Script enabled",
            HighSegShields: "Segments with Shields",
            HighSegShieldsClr: "Segments with Shields",
            ShowSegShields: "Show Segment Shields on Map",
            SegShieldMissing: "Segments that might be missing shields",
            SegShieldMissingClr: "Segments that might be missing shields",
            SegShieldError: "Segments that have shields but maybe shouldn't",
            SegShieldErrorClr: "Segments that have shields but maybe shouldn't",
            HighNodeShields: "Nodes with Shields (TG)",
            HighNodeShieldsClr: "Nodes with Shields (TG)",
            ShowNodeShields: "Show Node Shield Info",
            ShowExitShields: "Has Exit Signs",
            ShowTurnTTS: "Has TIO",
            AlertTurnTTS: "Alert if TTS is different from default",
            NodeShieldMissing: "Nodes that might be missing shields",
            NodeShieldMissingClr: "Nodes that might be missing shields",
            resetSettings: "Reset Settings",
            disabledFeat: "(Feature not configured for this country)",
            ShowTowards: "Has Towards",
            ShowVisualInst: "Has Visual Instruction",
            SegHasDir: "Segment Shields with direction",
            SegHasDirClr: "Segment Shields with direction",
            SegInvDir: "Segment Shields without direction",
            SegInvDirClr: "Segment Shields without direction",
            IconHead: "Map Icons",
            HighlightHead: "Highlights",
            HighlightColors: "Highlight Colors",
            ShowRamps: "Include Ramps",
            Experimental: "Experimental Features (Use at Your own Risk)",
            AlternativeShields: "Alternative Name Shields",
            AlternativePrimaryCity: "Alternative Street with Primary City",
            AlternativeNoCity: "Alternative Street with No City",
            mHPlus: "Only show on minor highways or greater",
            titleCase: "Segments/nodes with direction not in large-and-small-caps format",
            TitleCaseClr: "Segments/nodes with direction not in large-and-small-caps format",
            TitleCaseSftClr: "Direction in free text might not be in large-and-small-caps format",
            checkTWD: "Include Towards field",
            checkTTS: "Include TTS field",
            checkVI: "Include Visual Instruction field",
        },
        "en-us": {
            enableScript: "Script enabled",
            HighSegShields: "Segments with Shields",
            HighSegShieldsClr: "Segments with Shields",
            ShowSegShields: "Show Segment Shields on Map",
            SegShieldMissing: "Segments that might be missing shields",
            SegShieldMissingClr: "Segments that might be missing shields",
            SegShieldError: "Segments that have shields but maybe shouldn't",
            SegShieldErrorClr: "Segments that have shields but maybe shouldn't",
            HighNodeShields: "Nodes with Shields (TG)",
            HighNodeShieldsClr: "Nodes with Shields (TG)",
            ShowNodeShields: "Show Node Shield Info",
            ShowExitShields: "Has Exit Signs",
            ShowTurnTTS: "Has TIO",
            AlertTurnTTS: "Alert if TTS is different from default",
            NodeShieldMissing: "Nodes that might be missing shields",
            NodeShieldMissingClr: "Nodes that might be missing shields",
            resetSettings: "Reset Settings",
            disabledFeat: "(Feature not configured for this country)",
            ShowTowards: "Has Towards",
            ShowVisualInst: "Has Visual Instruction",
            SegHasDir: "Segment Shields with direction",
            SegHasDirClr: "Segment Shields with direction",
            SegInvDir: "Segment Shields without direction",
            SegInvDirClr: "Segment Shields without direction",
            IconHead: "Map Icons",
            HighlightHead: "Highlights",
            HighlightColors: "Highlight Colors",
            ShowRamps: "Include Ramps",
            Experimental: "Experimental Features (Unstable use at Your own Risk)",
            AlternativeShields: "Alternative Name Shields",
            AlternativePrimaryCity: "Alternative Street with Primary City",
            AlternativeNoCity: "Alternative Street with No City",
            mHPlus: "Only show on minor highways or greater",
            titleCase: "Segments/nodes with direction not in large-and-small-caps format",
            TitleCaseClr: "Segments/nodes with direction not in large-and-small-caps format",
            TitleCaseSftClr: "Direction in free text might not be in large-and-small-caps format",
            checkTWD: "Include Towards field",
            checkTTS: "Include TTS field",
            checkVI: "Include Visual Instruction field",
        },
        "es-419": {
            enableScript: "Script habilitado",
            HighSegShields: "Segmentos con escudos",
            HighSegShieldsClr: "Segmentos con escudos",
            ShowSegShields: "Mostrar escudos de segmentos en el mapa",
            SegShieldMissing: "Segmentos a los que les pueden faltar escudos",
            SegShieldMissingClr: "Segmentos a los que les pueden faltar escudos",
            SegShieldError: "Segmentos que tienen escudos y quizá no deberían",
            SegShieldErrorClr: "Segmentos que tienen escudos y quizá no deberían",
            HighNodeShields: "Nodos con escudos (TG)",
            HighNodeShieldsClr: "Nodos con escudos (TG)",
            ShowNodeShields: "Mostrar Info de Escudo en Nodo",
            ShowExitShields: "Incluir iconos de giro (si existen)",
            ShowTurnTTS: "Incuir TTS",
            AlertTurnTTS: "Alertar si TTS fue modificado",
            NodeShieldMissing: "Nodos a los que les pueden faltar escudos",
            NodeShieldMissingClr: "Nodos a los que les pueden faltar escudos",
            resetSettings: "Reiniciar ajustes",
            disabledFeat: "(Funcionalidad no configurada para ese país)",
            ShowTowards: "Incluir dirección (si existe)",
            ShowVisualInst: "Incluir instrucción visual",
            SegHasDir: "Escudos con dirección",
            SegHasDirClr: "Escudos con dirección",
            SegInvDir: "Escudos sin dirección",
            SegInvDirClr: "Escudos sin dirección",
            IconHead: "Iconos en mapa",
            HighlightHead: "Destacar",
            HighlightColors: "Reseña de Colores",
            ShowRamps: "Incluir Rampas",
            Experimental: "Experimental Features",
            AlternativeShields: "Alternative Name Shields",
            AlternativePrimaryCity: "Alternative Street with Primary City",
            AlternativeNoCity: "Alternative Street with No City",
            mHPlus: "Only show on minor highways or greater",
            titleCase: "Segments/nodes with direction not in large-and-small-caps format",
            TitleCaseClr: "Segments/nodes with direction not in large-and-small-caps format",
            TitleCaseSftClr: "Direction in free text might not be in large-and-small-caps format",
            checkTWD: "Include Towards field",
            checkTTS: "Include TTS field",
            checkVI: "Include Visual Instruction field",
        },
        uk: {
            enableScript: "Скріпт вимкнено",
            HighSegShields: "Сегменти з шильдами",
            HighSegShieldsClr: "Сегменти з шильдами",
            ShowSegShields: "Показувати шильди на мапі",
            SegShieldMissing: "Сегменти, яким можливо потрібні шильди",
            SegShieldMissingClr: "Сегменти, яким можливо потрібні шильди",
            SegShieldError: "Сегменти, які мають шильди, але можливо вони непотрібні",
            SegShieldErrorClr: "Сегменти, які мають шильди, але можливо вони непотрібні",
            HighNodeShields: "Вузли з шильдами (TG)",
            HighNodeShieldsClr: "Вузли з шильдами (TG)",
            ShowNodeShields: "Показувати деталі шильда на вузлі ",
            ShowExitShields: "Включити іконку повороту (якщо вони є)",
            ShowTurnTTS: "Вимкнути TTS",
            AlertTurnTTS: "Сповіщати, якщо TTS відрізняється від типового",
            NodeShieldMissing: "Вузли, на яких можуть бути відсутні щити",
            NodeShieldMissingClr: "Вузли, на яких можуть бути відсутні щити",
            resetSettings: "Скинути налаштування",
            disabledFeat: "Відсутні налаштування для цієї страни",
            ShowTowards: "Включаючи Towards (якщо існує)",
            ShowVisualInst: "Включаючи візуальні інструкції",
            SegHasDir: "Шильди з напрямками",
            SegHasDirClr: "Шильди з напрямками",
            SegInvDir: "Шильди без напрямків",
            SegInvDirClr: "Шильди без напрямків",
            IconHead: "Іконки на мапі",
            HighlightHead: "Підсвічувати",
            HighlightColors: "Кольори підсвічування",
            ShowRamps: "Включаючи рампи",
            Experimental: "Экспериментальні засобливості",
            AlternativeShields: "Шильди альтернатівних назв",
            AlternativePrimaryCity: "Альтернативна назва с основним містом",
            AlternativeNoCity: "Альтернативна назва без міста",
            mHPlus: "Only show on minor highways or greater",
            titleCase: "Segments/nodes with direction not in large-and-small-caps format",
            TitleCaseClr: "Segments/nodes with direction not in large-and-small-caps format",
            TitleCaseSftClr: "Direction in free text might not be in large-and-small-caps format",
            checkTWD: "Include Towards field",
            checkTTS: "Include TTS field",
            checkVI: "Include Visual Instruction field",
        },
        fr: {
            enableScript: "Script activé",
            HighSegShields: "Segments avec cartouche",
            HighSegShieldsClr: "Segments avec cartouche",
            ShowSegShields: "Afficher les cartouches sur la carte",
            SegShieldMissing: "Segments dont le cartouche pourrait manquer",
            SegShieldMissingClr: "Segments dont le cartouche pourrait manquer",
            SegShieldError: "Segments ayant un cartouche mais ne devraient peut-être pas",
            SegShieldErrorClr: "Segments ayant un cartouche mais ne devraient peut-être pas",
            HighNodeShields: "Noeuds avec cartouche (TG)",
            HighNodeShieldsClr: "Noeuds avec cartouche (TG)",
            ShowNodeShields: "Afficher les infos des cartouches de noeuds",
            ShowExitShields: "As des panneaux de sortie",
            ShowTurnTTS: "Has TIO",
            AlertTurnTTS: "Alert if TTS is different from default",
            NodeShieldMissing: "Noeud dont le cartouche pourrait manquer",
            NodeShieldMissingClr: "Noeud dont le cartouche pourrait manquer",
            resetSettings: "Réinitialiser les paramètres",
            disabledFeat: "Feature not configured for this country",
            ShowTowards: 'As "En direction de"',
            ShowVisualInst: "As des instructions visuelles",
            SegHasDir: "Cartouche de segment avec direction",
            SegHasDirClr: "Cartouche de segment avec direction",
            SegInvDir: "Cartouche de segment sans direction",
            SegInvDirClr: "Cartouche de segment sans direction",
            IconHead: "Icônes de carte",
            HighlightHead: "Surlignages",
            HighlightColors: "Couleurs de surlignage",
            ShowRamps: "Inclure les bretelles",
            mHPlus: "Only show on minor highways or greater",
            Experimental: "Experimental Features",
            AlternativeShields: "Alternative Name Shields",
            AlternativePrimaryCity: "Alternative Street with Primary City",
            AlternativeNoCity: "Alternative Street with No City",
            titleCase: "Segments/nodes with direction not in large-and-small-caps format",
            TitleCaseClr: "Segments/nodes with direction not in large-and-small-caps format",
            TitleCaseSftClr: "Direction in free text might not be in large-and-small-caps format",
            checkTWD: 'Inclure le champ "en direction de"',
            checkTTS: "Inclure le champ TTS",
            checkVI: "Inclure le champ d'instruction visuel",
        },
    };
    const CheckAltName = new Set([
        // France
        73,
    ]);
    let BadNames = [];
    let rsaSettings = {
        lastSaveAction: 0,
        enableScript: true,
        HighSegShields: false,
        ShowSegShields: true,
        SegShieldMissing: false,
        SegShieldError: false,
        SegHasDir: false,
        SegInvDir: false,
        HighNodeShields: true,
        ShowNodeShields: false,
        ShowExitShields: false,
        ShowTurnTTS: false,
        AlertTurnTTS: false,
        ShowTowards: false,
        ShowVisualInst: false,
        NodeShieldMissing: false,
        HighSegClr: "#0066ff",
        MissSegClr: "#00ff00",
        ErrSegClr: "#cc00ff",
        HighNodeClr: "#ff00bf",
        MissNodeClr: "#ff0000",
        SegHasDirClr: "#ffff00",
        SegInvDirClr: "#66ffff",
        TitleCaseClr: "#ff9933",
        TitleCaseSftClr: "#ffff66",
        ShowRamps: true,
        AlternativeShields: false,
        mHPlus: false,
        titleCase: false,
        checkTWD: false,
        checkTTS: false,
        checkVI: false,
        mapLayerVisible: false,
        iconLayerVisible: false,
    };
    let UpdateObj;
    let SetTurn;
    const rsaMapLayer = { layerName: "RSA Map Layer", zIndexing: false };
    const rsaIconLayer = { layerName: "RSA Icon Layer", zIndexing: false };
    let LANG;
    let alternativeType;
    const styleConfig = {
        styleContext: {
            highNodeColor: (context) => {
                return context?.feature?.properties?.style?.strokeColor;
            },
            labelExternalGraphic: (context) => {
                const style = context?.feature?.properties?.style;
                if (!style || !style?.sign || !style?.txt)
                    return "";
                return `https://renderer-am.waze.com/renderer/v1/signs/${style.sign}?text=${style.txt}`;
            },
            labelGraphicHeight: (context) => {
                return context?.feature?.properties?.style?.height;
            },
            labelGraphicWidth: (context) => {
                return context?.feature?.properties?.style?.width;
            },
            shieldExternalGraphic: (context) => {
                return context?.feature?.properties?.style?.externalGraphic;
            },
            shieldGraphicWidth: (context) => {
                return context?.feature?.properties?.style?.graphicWidth;
            },
            shieldGraphicHeight: (context) => {
                return context?.feature?.properties?.style?.graphicHeight;
            },
            shieldLabel: (context) => {
                return context?.feature?.properties?.style?.label;
            },
            nodeStyleStrokeColor: (context) => {
                return context?.feature?.properties?.style?.strokeColor;
            },
            nodeStyleStrokeOpacity: (context) => {
                return context?.feature?.properties?.style?.strokeOpacity;
            },
            nodeStyleStrokeWidth: (context) => {
                return context?.feature?.properties?.style?.strokeWidth;
            },
            nodeStyleFillOpacity: (context) => {
                return context?.feature?.properties?.style?.fillOpacity;
            },
            nodeStylePointRadius: (context) => {
                return context?.feature?.properties?.style?.pointRadius;
            },
            segHighlightStrokeOpacity: (context) => {
                return context?.feature?.properties?.style?.strokeOpacity;
            },
            segHighlightStrokeColor: (context) => {
                return context?.feature?.properties?.style?.strokeColor;
            },
            segHighlightStrokeWidth: (context) => {
                return context?.feature?.properties?.style?.strokeWidth;
            },
            segHighlightFillColor: (context) => {
                return context?.feature?.properties?.style?.fillColor;
            },
            segHighlightFillOpacity: (context) => {
                return context?.feature?.properties?.style?.fillOpacity;
            },
            shieldLabelYOffset: (context) => {
                return context?.feature?.properties?.style?.labelYOffset;
            },
        },
        styleRules: [
            {
                predicate: applyPointLabel,
                style: {
                    strokeColor: "${highNodeColor}",
                    strokeOpacity: 0.75,
                    strokeWidth: 4,
                    fillColor: "${highNodeColor}",
                    fillOpacity: 0.75,
                    pointRadius: 3,
                },
            },
            {
                predicate: applyShield,
                style: {
                    externalGraphic: "${shieldExternalGraphic}",
                    graphicWidth: "${shieldGraphicWidth}",
                    graphicHeight: "${shieldGraphicHeight}",
                    graphicXOffset: -20,
                    graphicYOffset: -20,
                    style: "opacity: 1",
                    fillOpacity: 1,
                    fill: "black",
                    stroke: "black",
                    fontColor: "green",
                    labelOutlineColor: "white",
                    labelOutlineWidth: 1,
                    fontSize: 12,
                    display: "grid",
                    label: "${shieldLabel}",
                    labelYOffset: "${shieldLabelYOffset}",
                },
            },
            {
                predicate: applySegHighlight,
                style: {
                    strokeColor: "${segHighlightStrokeColor}",
                    strokeOpacity: "${segHighlightStrokeOpacity}",
                    strokeWidth: "${segHighlightStrokeWidth}",
                    fillColor: "${segHighlightFillColor}",
                    fillOpacity: "${segHighlightFillOpacity}",
                },
            },
            {
                predicate: applyStyleNode,
                style: {
                    strokeColor: "${nodeStyleStrokeColor}",
                    strokeOpacity: "${nodeStyleStrokeOpacity}",
                    strokeWidth: "${nodeStyleStrokeWidth}",
                    fillColor: "${nodeStyleFillColor}",
                    fillOpacity: "${nodeStyleFillOpacity}",
                    pointRadius: "${nodeStylePointRadius}",
                },
            },
            {
                predicate: applyStyleLabel,
                style: {
                    externalGraphic: "${labelExternalGraphic}",
                    graphicHeight: "${labelGraphicHeight}",
                    graphicWidth: "${labelGraphicWidth}",
                    fillOpacity: "${nodeStyleFillOpacity}",
                    fontSize: 12,
                    graphicZIndex: 2432,
                },
            },
        ],
    };
    console.debug(`SDK v. ${sdk.getSDKVersion()} on ${sdk.getWMEVersion()} initialized`);
    // function rsaBootstrap() {
    //     // if (!document.getElementById('edit-panel') || !sdk.DataModel.Countries.getTopCountry() || !WazeWrap.Ready) {
    //     //     setTimeout(rsaBootstrap, 200);
    //     // }
    //     if (sdk.State.isReady()) {
    //         initRSA();
    //     } else {
    //         sdk.Events.once({eventName: "wme-ready"}).then(initRSA);
    //     }
    // }
    function initRSA() {
        const locale = sdk.Settings.getLocale();
        LANG = locale.localeCode.toLowerCase();
        console.log("RSA: Initializing...");
        // let UpdateObj = sdk.DataModel. require('Waze/Action/UpdateObject');
        // let SetTurn = require('Waze/Model/Graph/Actions/SetTurn');
        const rsaCss = [
            '.rsa-wrapper {position:relative;width:100%;font-size:12px;font-family:"Rubik", "Boing-light", sans-serif;user-select:none;}',
            ".rsa-section-wrapper {display:block;width:100%;padding:4px;}",
            ".rsa-section-wrapper.border {border-bottom:1px solid grey;margin-bottom:5px;}",
            ".rsa-header {font-weight:bold;}",
            ".rsa-option-container {padding:3px;}",
            ".rsa-option-container.no-display {display:none;}",
            ".rsa-option-container.sub {margin-left:20px;}",
            'input[type="checkbox"].rsa-checkbox {display:inline-block;position:relative;top:3px;vertical-align:top;margin:0;}',
            'input[type="color"].rsa-color-input {display:inline-block;position:relative;width:20px;padding:0px 1px;border:0px;vertical-align:top;cursor:pointer;}',
            'input[type="color"].rsa-color-input:focus {outline-width:0;}',
            "label.rsa-label {display:inline-block;position:relative;max-width:80%;vertical-align:top;font-weight:normal;padding-left:5px;word-wrap:break-word;}",
            ".group-title.toolbar-top-level-item-title.rsa:hover {cursor:pointer;}",
        ].join(" ");
        const $rsaTab = $("<div>");
        $rsaTab.html = [
            `<div class='rsa-wrapper' id='rsa-tab-wrapper'>
        <div style='margin-bottom:5px;border-bottom:1px solid black;'>
            <span style='font-weight:bold;'>
                <a href='https://www.waze.com/forum/viewtopic.php?f=1851&t=315748' target='_blank' style='text-decoration:none;'>Road Shield Assistant</a>
            </span> - v${GM_info.script.version}
        </div>
        <div class='rsa-option-container'>
            <input type=checkbox class='rsa-checkbox' id='rsa-enableScript' />
            <label class='rsa-label' for='rsa-enableScript'><span id='rsa-text-enableScript'></span></label>
        </div>
        <div class='rsa-option-container'>
            <input type=checkbox class='rsa-checkbox' id='rsa-ShowRamps' />
            <label class='rsa-label' for='rsa-ShowRamps'><span id='rsa-text-ShowRamps'></span></label>
        </div>
        <div class='rsa-option-container'>
            <input type=checkbox class='rsa-checkbox' id='rsa-mHPlus' />
            <label class='rsa-label' for='rsa-mHPlus'><span id='rsa-text-mHPlus'></span></label>
        </div>

        <span id='rsa-text-IconHead' class='rsa-header'></span>
        <div style='border-top:2px solid black;'>
            <div class='rsa-option-container'>
                <input type=checkbox class='rsa-checkbox' id='rsa-ShowSegShields' />
                <label class='rsa-label' for='rsa-ShowSegShields'><span id='rsa-text-ShowSegShields'></span></label>
            </div>
            <div class='rsa-option-container no-display'>
                <input type=checkbox class='rsa-checkbox' id='rsa-NodeShieldMissing' />
                <label class='rsa-label' for='rsa-NodeShieldMissing'><span id='rsa-text-NodeShieldMissing'></span></label>
            </div>
            <div class='rsa-option-container'>
                <input type=checkbox class='rsa-checkbox' id='rsa-ShowNodeShields' />
                <label class='rsa-label' for='rsa-ShowNodeShields'><span id='rsa-text-ShowNodeShields'></span></label>
            </div>
            <div class='rsa-option-container sub'>
                <input type=checkbox class='rsa-checkbox' id='rsa-ShowExitShields' />
                <label class='rsa-label' for='rsa-ShowExitShields'><span id='rsa-text-ShowExitShields'></span></label>
            </div>
            <div class='rsa-option-container sub'>
                <input type=checkbox class='rsa-checkbox' id='rsa-ShowTurnTTS' />
                <label class='rsa-label' for='rsa-ShowTurnTTS'><span id='rsa-text-ShowTurnTTS'></span></label>
            </div>
            <div class='rsa-option-container sub'>
                <input type=checkbox class='rsa-checkbox' id='rsa-ShowTowards' />
                <label class='rsa-label' for='rsa-ShowTowards'><span id='rsa-text-ShowTowards'></span></label>
            </div>
            <div class='rsa-option-container sub'>
                <input type=checkbox class='rsa-checkbox' id='rsa-ShowVisualInst' />
                <label class='rsa-label' for='rsa-ShowVisualInst'><span id='rsa-text-ShowVisualInst'></span></label>
            </div>
            <div class='rsa-option-container sub' style='display:none;'>
                <input type=checkbox class='rsa-checkbox' id='rsa-AlertTurnTTS' />
                <label class='rsa-label' for='rsa-AlertTurnTTS'><span id='rsa-text-AlertTurnTTS'></span></label>
            </div>
        </div>

        <span id='rsa-text-HighlightHead' class='rsa-header'></span>
        <div style='border-top:2px solid black;'>
            <div class='rsa-option-container' style='display:none;'>
                <input type=checkbox class='rsa-checkbox' id='rsa-HighNodeShields' />
                <label class='rsa-label' for='rsa-HighNodeShields'><span id='rsa-text-HighNodeShields'></span></label>
            </div>
            <div class='rsa-option-container'>
                <input type=checkbox class='rsa-checkbox' id='rsa-HighSegShields' />
                <label class='rsa-label' for='rsa-HighSegShields'><span id='rsa-text-HighSegShields'></span></label>
            </div>
            <div class='rsa-option-container'>
                <input type=checkbox class='rsa-checkbox' id='rsa-SegHasDir' />
                <label class='rsa-label' for='rsa-SegHasDir'><span id='rsa-text-SegHasDir'></span></label>
            </div>
            <div class='rsa-option-container'>
                <input type=checkbox class='rsa-checkbox' id='rsa-SegInvDir' />
                <label class='rsa-label' for='rsa-SegInvDir'><span id='rsa-text-SegInvDir'></span></label>
            </div>
            <div class='rsa-option-container' id='rsa-container-titleCase'>
                <input type=checkbox class='rsa-checkbox' id='rsa-titleCase' />
                <label class='rsa-label' for='rsa-titleCase'><span id='rsa-text-titleCase'></span></label>
            </div>
            <div class='rsa-option-container sub' id='rsa-container-checkTWD'>
                <input type=checkbox class='rsa-checkbox' id='rsa-checkTWD' />
                <label class='rsa-label' for='rsa-checkTWD'><span id='rsa-text-checkTWD'></span></label>
            </div>
            <div class='rsa-option-container sub' id='rsa-container-checkTTS'>
                <input type=checkbox class='rsa-checkbox' id='rsa-checkTTS' />
                <label class='rsa-label' for='rsa-checkTTS'><span id='rsa-text-checkTTS'></span></label>
            </div>
            <div class='rsa-option-container sub' id='rsa-container-checkVI'>
                <input type=checkbox class='rsa-checkbox' id='rsa-checkVI' />
                <label class='rsa-label' for='rsa-checkVI'><span id='rsa-text-checkVI'></span></label>
            </div>
            <div class='rsa-option-container'>
                <input type=checkbox class='rsa-checkbox' id='rsa-SegShieldMissing' />
                <label class='rsa-label' for='rsa-SegShieldMissing'><span id='rsa-text-SegShieldMissing'></span></label>
            </div>
            <div class='rsa-option-container'>
                <input type=checkbox class='rsa-checkbox' id='rsa-SegShieldError' />
                <label class='rsa-label' for='rsa-SegShieldError'><span id='rsa-text-SegShieldError'></span></label>
            </div>
        </div>
        <span id='rsa-text-HighlightColors' class='rsa-header'></span>
        <div style='border-top:2px solid black;'>
            <div class='rsa-option-container'>
                <input type=color class='rsa-color-input' id='rsa-HighSegClr' />
                <label class='rsa-label' for='rsa-HighSegClr'><span id='rsa-text-HighSegShieldsClr'></span></label>
            </div>
            <div class='rsa-option-container'>
                <input type=color class='rsa-color-input' id='rsa-SegHasDirClr' />
                <label class='rsa-label' for='rsa-SegHasDirClr'><span id='rsa-text-SegHasDirClr'></span></label>
            </div>
            <div class='rsa-option-container'>
                <input type=color class='rsa-color-input' id='rsa-SegInvDirClr' />
                <label class='rsa-label' for='rsa-SegInvDirClr'><span id='rsa-text-SegInvDirClr'></span></label>
            </div>
            <div class='rsa-option-container'>
                <input type=color class='rsa-color-input' id='rsa-MissSegClr' />
                <label class='rsa-label' for='rsa-MissSegClr'><span id='rsa-text-SegShieldMissingClr'></span></label>
            </div>
            <div class='rsa-option-container'>
                <input type=color class='rsa-color-input' id='rsa-ErrSegClr' />
                <label class='rsa-label' for='rsa-ErrSegClr'><span id='rsa-text-SegShieldErrorClr'></span></label>
            </div>
            <div class='rsa-option-container'>
                <input type=color class='rsa-color-input' id='rsa-HighNodeClr' />
                <label class='rsa-label' for='rsa-HighNodeClr'><span id='rsa-text-HighNodeShieldsClr'></span></label>
            </div>
            <div class='rsa-option-container no-display'>
                <input type=color class='rsa-color-input' id='rsa-MissNodeClr' />
                <label class='rsa-label' for='rsa-MissNodeClr'><span id='rsa-text-NodeShieldMissingClr'></span></label>
            </div>
            <div class='rsa-option-container' id='rsa-container-TitleCaseClr'>
                <input type=color class='rsa-color-input' id='rsa-TitleCaseClr' />
                <label class='rsa-label' for='rsa-TitleCaseClr'><span id='rsa-text-TitleCaseClr'></span></label>
            </div>
            <div class='rsa-option-container' id='rsa-container-TitleCaseSftClr'>
                <input type=color class='rsa-color-input' id='rsa-TitleCaseSftClr' />
                <label class='rsa-label' for='rsa-TitleCaseSftClr'><span id='rsa-text-TitleCaseSftClr'></span></label>
            </div>
        </div>
        <span id='rsa-text-Experimental' class='rsa-header'></span>
        <div style='border-top:2px solid black;'>
            <div class='rsa-option-container'>
                <input type=checkbox class='rsa-checkbox' id='rsa-AlternativeShields' />
                <label class='rsa-label' for='rsa-AlternativeShields'><span id='rsa-text-AlternativeShields'></span></label>
            </div>
            <div class='rsa-option-container sub'>
                <input type=radio class='rsa-checkbox' value='AlternativePrimaryCity' name='AlternativeShields' id='rsa-AlternativePrimaryCity' checked/>
                <label class='rsa-label' for='rsa-AlternativePrimaryCity'><span id='rsa-text-AlternativePrimaryCity'></span></label>
            </div>
            <div class='rsa-option-container sub'>
                <input type=radio class='rsa-checkbox' value='AlternativeNoCity' name='AlternativeShields' id='rsa-AlternativeNoCity' />
                <label class='rsa-label' for='rsa-AlternativeNoCity'><span id='rsa-text-AlternativeNoCity'></span></label>
            </div>
        </div>

        <div style='border-top:2px solid black;'>
            <div class='rsa-option-container'>
                <input type=button id='rsa-resetSettings' />
            </div>
        </div>
    </div>`,
        ].join(" ");
        const $rsaFixWrapper = $('<div id="rsa-autoWrapper" class="toolbar-button ItemInactive" style="display:none;margin-right:5px;">');
        const $rsaFixInner = $('<div class="group-title toolbar-top-level-item-title rsa" style="margin:5px 0 0 15px;font-size:12px;">RSA Fix</div>');
        // WazeWrap.Interface.Tab('RSA', $rsaTab.html, setupOptions, 'RSA');
        sdk.Sidebar.registerScriptTab().then((r) => {
            r.tabLabel.innerHTML = "RSA";
            r.tabPane.innerHTML = $rsaTab.html;
            setupOptions();
        });
        $(`<style type="text/css">${rsaCss}</style>`).appendTo("head");
        // $($rsaFixInner).appendTo($rsaFixWrapper);
        // $($rsaFixWrapper).appendTo($('#primary-toolbar > div'));
        WazeWrap.Interface.ShowScriptUpdate(GM_info.script.name, GM_info.script.version, RSA_UPDATE_NOTES, GF_LINK, FORUM_LINK);
        console.log("RSA: loaded");
    }
    function processAlternativeSettings() {
        if (rsaSettings.AlternativeShields) {
            const alt_primary = $("#rsa-AlternativePrimaryCity");
            alt_primary.prop("disabled", false);
            const alt_nocity = $("#rsa-AlternativeNoCity");
            alt_nocity.prop("disabled", false);
            const primaryCityButton = alt_primary[0];
            const noCityButton = alt_primary[0];
            if (primaryCityButton.checked) {
                alternativeType = primaryCityButton.value;
            }
            if (noCityButton.checked) {
                alternativeType = noCityButton.value;
            }
        }
        toggleAlternativeShields();
    }
    function getId(ele) {
        return document.getElementById(ele);
    }
    function setChecked(ele, status) {
        $(`#${ele}`).prop("checked", status);
    }
    function setValue(ele, value) {
        const inputElem = $(`#${ele}`);
        inputElem.attr("value", value);
        // inputElem.css('border', `1px solid ${value}`);
    }
    function toggleAlternativeShields() {
        if (!rsaSettings.AlternativeShields) {
            $("#rsa-AlternativePrimaryCity").prop("disabled", true);
            $("#rsa-AlternativeNoCity").prop("disabled", true);
        }
    }
    function applyPointLabel(properties) {
        return properties.styleName === "pointLabelStyle";
    }
    function applyShield(properties) {
        return properties.styleName === "shield";
    }
    function applySegHighlight(properties) {
        return properties.styleName === "segHighlight";
    }
    function applyStyleNode(properties) {
        return properties.styleName === "styleNode";
    }
    function applyStyleLabel(properties) {
        return properties.styleName === "styleLabel";
    }
    function updateMap() {
        removeAutoFixButton();
        tryScan();
        checkOptions();
    }
    async function setupOptions() {
        await loadSettings();
        // Create OL layer for display
        sdk.Map.addLayer({
            layerName: rsaMapLayer.layerName,
            styleRules: styleConfig.styleRules,
            styleContext: styleConfig.styleContext,
        });
        sdk.LayerSwitcher.addLayerCheckbox({ name: rsaMapLayer.layerName });
        sdk.LayerSwitcher.setLayerCheckboxChecked({
            name: rsaMapLayer.layerName,
            isChecked: rsaSettings.mapLayerVisible,
        });
        sdk.Map.setLayerVisibility({ layerName: rsaMapLayer.layerName, visibility: rsaSettings.mapLayerVisible });
        sdk.Map.addLayer({
            layerName: rsaIconLayer.layerName,
            styleRules: styleConfig.styleRules,
            styleContext: styleConfig.styleContext,
        });
        sdk.LayerSwitcher.addLayerCheckbox({ name: rsaIconLayer.layerName });
        sdk.Map.setLayerVisibility({ layerName: rsaIconLayer.layerName, visibility: rsaSettings.iconLayerVisible });
        sdk.LayerSwitcher.setLayerCheckboxChecked({
            name: rsaIconLayer.layerName,
            isChecked: rsaSettings.iconLayerVisible,
        });
        sdk.Events.on({
            eventName: "wme-layer-checkbox-toggled",
            eventHandler: (payload) => {
                sdk.Map.setLayerVisibility({ layerName: payload.name, visibility: payload.checked });
                if (payload.name === rsaMapLayer.layerName) {
                    rsaSettings.mapLayerVisible = payload.checked;
                }
                else if (payload.name === rsaIconLayer.layerName) {
                    rsaSettings.iconLayerVisible = payload.checked;
                }
                if (payload.checked)
                    tryScan();
                saveSettings();
            },
        });
        // Set user options
        function setEleStatus() {
            setChecked("rsa-enableScript", rsaSettings.enableScript);
            setChecked("rsa-HighSegShields", rsaSettings.HighSegShields);
            setChecked("rsa-ShowSegShields", rsaSettings.ShowSegShields);
            setChecked("rsa-SegShieldMissing", rsaSettings.SegShieldMissing);
            setChecked("rsa-SegShieldError", rsaSettings.SegShieldError);
            setChecked("rsa-HighNodeShields", rsaSettings.HighNodeShields);
            setChecked("rsa-ShowNodeShields", rsaSettings.ShowNodeShields);
            setChecked("rsa-ShowExitShields", rsaSettings.ShowExitShields);
            setChecked("rsa-ShowTurnTTS", rsaSettings.ShowTurnTTS);
            setChecked("rsa-AlertTurnTTS", rsaSettings.AlertTurnTTS);
            setChecked("rsa-ShowTowards", rsaSettings.ShowTowards);
            setChecked("rsa-ShowVisualInst", rsaSettings.ShowVisualInst);
            setChecked("rsa-NodeShieldMissing", rsaSettings.NodeShieldMissing);
            setChecked("rsa-SegHasDir", rsaSettings.SegHasDir);
            setChecked("rsa-SegInvDir", rsaSettings.SegInvDir);
            setChecked("rsa-ShowRamps", rsaSettings.ShowRamps);
            setChecked("rsa-mHPlus", rsaSettings.mHPlus);
            setChecked("rsa-titleCase", rsaSettings.titleCase);
            setChecked("rsa-checkTWD", rsaSettings.checkTWD);
            setChecked("rsa-checkTTS", rsaSettings.checkTTS);
            setChecked("rsa-checkVI", rsaSettings.checkVI);
            setChecked("rsa-AlternativeShields", rsaSettings.AlternativeShields);
            setValue("rsa-HighSegClr", rsaSettings.HighSegClr);
            setValue("rsa-MissSegClr", rsaSettings.MissSegClr);
            setValue("rsa-ErrSegClr", rsaSettings.ErrSegClr);
            setValue("rsa-HighNodeClr", rsaSettings.HighNodeClr);
            setValue("rsa-MissNodeClr", rsaSettings.MissNodeClr);
            setValue("rsa-SegHasDirClr", rsaSettings.SegHasDirClr);
            setValue("rsa-SegInvDirClr", rsaSettings.SegInvDirClr);
            setValue("rsa-TitleCaseClr", rsaSettings.TitleCaseClr);
            setValue("rsa-TitleCaseSftClr", rsaSettings.TitleCaseSftClr);
            $("#rsa-AlternativeShields").on("change", (e) => {
                processAlternativeSettings();
            });
            if (rsaSettings.titleCase && sdk.DataModel.Countries.getTopCountry()?.id === 235) {
                $("#rsa-container-checkTWD").css("display", "block");
                $("#rsa-container-checkTTS").css("display", "block");
                $("#rsa-container-checkVI").css("display", "block");
            }
            else {
                $("#rsa-container-checkTWD").css("display", "none");
                $("#rsa-container-checkTTS").css("display", "none");
                $("#rsa-container-checkVI").css("display", "none");
            }
            toggleAlternativeShields();
        }
        // Register event listeners
        // WazeWrap.Events.register('selectionchanged', null, removeAutoFixButton);
        sdk.Events.on({ eventName: "wme-selection-changed", eventHandler: removeAutoFixButton });
        // WazeWrap.Events.register('selectionchanged', null, tryScan);
        sdk.Events.on({ eventName: "wme-map-move-end", eventHandler: updateMap });
        sdk.Events.on({ eventName: "wme-map-zoom-changed", eventHandler: updateMap });
        sdk.Shortcuts.createShortcut({
            callback: addShieldClick,
            description: "Activates the Add Shield Button",
            shortcutId: "addShield",
            shortcutKeys: "A+83",
        });
        // new WazeWrap.Interface.Shortcut('addShield',
        //                                 'Activates the Add Shield Button',
        //                                 'wmersa',
        //                                 'Road Shield Assistant',
        //                                 rsaSettings.addShield,
        //                                 addShieldClick, null).add();
        setEleStatus();
        $("input[type=radio][name=AlternativeShields]").on("change", () => {
            processAlternativeSettings();
            saveSettings();
            removeHighlights();
            tryScan();
        });
        $(".rsa-checkbox").on("change", function () {
            const settingName = $(this)[0].id.substring(4);
            rsaSettings[settingName] = this.checked;
            // Check to ensure highlight nodes and show node shields don't overlap each other
            // if (settingName = 'ShowNodeShields') {
            //     if (this.checked) {
            //         $('rsa-HighNodeShields').prop('checked', false);
            //         rsaSettings.HighNodeShields = false;
            //     }
            // } else if (settingName = 'HighNodeShields') {
            //     if (this.checked) {
            //         $('rsa-ShowNodeShields').prop('checked', false);
            //         rsaSettings.ShowNodeShields = false;
            //     }
            // }
            if (settingName === "AlternativeShields")
                processAlternativeSettings();
            saveSettings();
            removeHighlights();
            tryScan();
        });
        $(".rsa-color-input").on("change", function () {
            const settingName = $(this)[0].id.substring(4);
            rsaSettings[settingName] = this.value;
            saveSettings();
            setEleStatus();
            removeHighlights();
            tryScan();
        });
        $("#rsa-titleCase").trigger("click", () => {
            const titleCase = getId("rsa-titleCase");
            if (titleCase?.checked) {
                $("#rsa-container-checkTWD").css("display", "block");
                $("#rsa-container-checkTTS").css("display", "block");
                $("#rsa-container-checkVI").css("display", "block");
            }
            else {
                $("#rsa-container-checkTWD").css("display", "none");
                $("#rsa-container-checkTTS").css("display", "none");
                $("#rsa-container-checkVI").css("display", "none");
            }
        });
        // $('#rsa-ShowNodeShields').click(function() {
        //     if (!getId('rsa-ShowNodeShields').checked) $('.rsa-option-container.sub').hide();
        //     else $('.rsa-option-container.sub').show();
        // });
        $("#rsa-resetSettings").on("click", () => {
            const defaultSettings = {
                lastSaveAction: 0,
                enableScript: true,
                HighSegShields: false,
                ShowSegShields: true,
                SegShieldMissing: false,
                SegShieldError: false,
                SegHasDir: false,
                SegInvDir: false,
                HighNodeShields: true,
                ShowNodeShields: false,
                ShowExitShields: false,
                ShowTurnTTS: false,
                AlertTurnTTS: false,
                ShowTowards: false,
                ShowVisualInst: false,
                NodeShieldMissing: false,
                HighSegClr: "#0066ff",
                MissSegClr: "#00ff00",
                ErrSegClr: "#cc00ff",
                HighNodeClr: "#ff00bf",
                MissNodeClr: "#ff0000",
                SegHasDirClr: "#ffff00",
                SegInvDirClr: "#66ffff",
                TitleCaseClr: "#ff9933",
                TitleCaseSftClr: "#ffff66",
                ShowRamps: true,
                AlternativeShields: false,
                mHPlus: false,
                titleCase: false,
                checkTWD: false,
                checkTTS: false,
                checkVI: false,
                mapLayerVisible: false,
                iconLayerVisible: false,
            };
            rsaSettings = defaultSettings;
            saveSettings();
            setEleStatus();
        });
        // Add translated UI text
        if (!Strings[LANG])
            LANG = "en";
        const messageKeys = Object.keys(Strings[LANG]);
        for (let i = 0; i < messageKeys.length; i++) {
            const key = messageKeys[i];
            $(`#rsa-text-${key}`).text(Strings[LANG][key]);
        }
        $("#rsa-resetSettings").attr("value", Strings[LANG].resetSettings);
        checkOptions();
    }
    async function loadSettings() {
        const localSettings = JSON.parse(localStorage.getItem("RSA_Settings"));
        const serverSettings = await WazeWrap.Remote.RetrieveSettings("RSA_Settings");
        if (!serverSettings) {
            console.error("RSA: Error communicating with WW settings server");
        }
        const defaultSettings = {
            lastSaveAction: 0,
            enableScript: true,
            HighSegShields: false,
            ShowSegShields: true,
            SegShieldMissing: false,
            SegShieldError: false,
            SegHasDir: false,
            SegInvDir: false,
            HighNodeShields: true,
            ShowNodeShields: false,
            ShowExitShields: false,
            ShowTurnTTS: false,
            AlertTurnTTS: false,
            ShowTowards: false,
            ShowVisualInst: false,
            NodeShieldMissing: false,
            HighSegClr: "#0066ff",
            MissSegClr: "#00ff00",
            ErrSegClr: "#cc00ff",
            HighNodeClr: "#ff00bf",
            MissNodeClr: "#ff0000",
            SegHasDirClr: "#ffff00",
            SegInvDirClr: "#66ffff",
            TitleCaseClr: "#ff9933",
            TitleCaseSftClr: "#ffff66",
            ShowRamps: true,
            AlternativeShields: false,
            mHPlus: false,
            titleCase: false,
            checkTWD: false,
            checkTTS: false,
            checkVI: false,
            mapLayerVisible: false,
            iconLayerVisible: false,
        };
        rsaSettings = $.extend({}, defaultSettings, localSettings);
        if (serverSettings && serverSettings.lastSaveAction > rsaSettings.lastSaveAction) {
            $.extend(rsaSettings, serverSettings);
            // console.log('RSA: server settings used');
        }
        else {
            // console.log('RSA: local settings used');
        }
    }
    async function saveSettings() {
        const { enableScript, HighSegShields, ShowSegShields, SegShieldMissing, SegShieldError, HighNodeShields, ShowNodeShields, ShowExitShields, SegHasDir, SegInvDir, ShowTurnTTS, AlertTurnTTS, ShowTowards, ShowVisualInst, NodeShieldMissing, HighSegClr, MissSegClr, ErrSegClr, HighNodeClr, MissNodeClr, SegHasDirClr, SegInvDirClr, TitleCaseClr, TitleCaseSftClr, ShowRamps, AlternativeShields, mHPlus, titleCase, checkTWD, checkTTS, checkVI, mapLayerVisible, iconLayerVisible, } = rsaSettings;
        const localSettings = {
            lastSaveAction: Date.now(),
            enableScript,
            HighSegShields,
            ShowSegShields,
            SegShieldMissing,
            SegShieldError,
            HighNodeShields,
            ShowNodeShields,
            ShowExitShields,
            SegHasDir,
            SegInvDir,
            ShowTurnTTS,
            AlertTurnTTS,
            ShowTowards,
            ShowVisualInst,
            NodeShieldMissing,
            HighSegClr,
            MissSegClr,
            ErrSegClr,
            HighNodeClr,
            MissNodeClr,
            SegHasDirClr,
            SegInvDirClr,
            TitleCaseClr,
            TitleCaseSftClr,
            ShowRamps,
            AlternativeShields,
            mHPlus,
            titleCase,
            checkTWD,
            checkTTS,
            checkVI,
            mapLayerVisible,
            iconLayerVisible,
        };
        // Grab keyboard shortcuts and store them for saving
        // for (const name in W.accelerators.Actions) {
        //     const {shortcut, group} = W.accelerators.Actions[name];
        //     if (group === 'wmersa') {
        //         let TempKeys = '';
        //         if (shortcut) {
        //             if (shortcut.altKey === true) {
        //                 TempKeys += 'A';
        //             }
        //             if (shortcut.shiftKey === true) {
        //                 TempKeys += 'S';
        //             }
        //             if (shortcut.ctrlKey === true) {
        //                 TempKeys += 'C';
        //             }
        //             if (TempKeys !== '') {
        //                 TempKeys += '+';
        //             }
        //             if (shortcut.keyCode) {
        //                 TempKeys += shortcut.keyCode;
        //             }
        //         } else {
        //             TempKeys = '-1';
        //         }
        //         localSettings[name as keyof typeof localSettings] = TempKeys;
        //     }
        // }
        // Required for the instant update of changes to the keyboard shortcuts on the UI
        rsaSettings = localSettings;
        if (localStorage) {
            localStorage.setItem("RSA_Settings", JSON.stringify(localSettings));
        }
        const serverSave = await WazeWrap.Remote.SaveSettings("RSA_Settings", localSettings);
        if (serverSave === null) {
            console.warn("RSA: User PIN not set in WazeWrap tab");
        }
        else {
            if (serverSave === false) {
                console.error("RSA: Unable to save settings to server");
            }
        }
    }
    function checkOptions() {
        const countries = sdk.DataModel.Countries.getAll();
        // const countries = W.model.countries.getObjectArray();
        if (countries.length < 1) {
            setTimeout(() => {
                checkOptions();
            }, 500);
            return;
        }
        let allowFeat = false;
        for (let i = 0; i < countries.length; i++) {
            if (RoadAbbr[countries[i].id])
                allowFeat = true;
        }
        const segShieldMissing = $("#rsa-SegShieldMissing");
        const segShieldError = $("#rsa-SegShieldError");
        const nodeShieldMissing = $("#rsa-NodeShieldMissing");
        const textSegShieldMissing = $("#rsa-text-SegShieldMissing");
        const textSegShieldError = $("#rsa-text-SegShieldError");
        const textNodeShieldMissing = $("#rsa-text-NodeShieldMissing");
        if (!allowFeat) {
            textSegShieldMissing.prop("checked", false);
            textSegShieldError.prop("checked", false);
            textNodeShieldMissing.prop("checked", false);
            textSegShieldMissing.text(`${Strings[LANG].SegShieldMissing} ${Strings[LANG].disabledFeat}`);
            textSegShieldError.text(`${Strings[LANG].SegShieldError} ${Strings[LANG].disabledFeat}`);
            textNodeShieldMissing.text(`${Strings[LANG].NodeShieldMissing} ${Strings[LANG].disabledFeat}`);
            segShieldMissing.prop("disabled", true);
            segShieldError.prop("disabled", true);
            nodeShieldMissing.prop("disabled", true);
            rsaSettings.SegShieldMissing = false;
            rsaSettings.SegShieldError = false;
            rsaSettings.NodeShieldMissing = false;
            saveSettings();
        }
        else {
            textSegShieldMissing.prop("checked", rsaSettings.SegShieldMissing);
            textSegShieldError.prop("checked", rsaSettings.SegShieldError);
            textNodeShieldMissing.prop("checked", rsaSettings.NodeShieldMissing);
            textSegShieldMissing.text(Strings[LANG].SegShieldMissing);
            textSegShieldError.text(Strings[LANG].SegShieldError);
            textNodeShieldMissing.text(Strings[LANG].NodeShieldMissing);
            segShieldMissing.prop("disabled", false);
            segShieldError.prop("disabled", false);
            nodeShieldMissing.prop("disabled", false);
        }
        const topCountry = sdk.DataModel.Countries.getTopCountry();
        if (topCountry === null || topCountry.id !== 235) {
            $("#rsa-container-titleCase").css("display", "none");
            $("#rsa-container-TitleCaseClr").css("display", "none");
            $("#rsa-container-TitleCaseSftClr").css("display", "none");
        }
        else {
            $("#rsa-container-titleCase").css("display", "block");
            $("#rsa-container-TitleCaseClr").css("display", "block");
            $("#rsa-container-TitleCaseSftClr").css("display", "block");
        }
    }
    function autoFixButton() {
        $("#rsa-autoWrapper").css("display", "inline-block");
        $("#rsa-autoWrapper > div").off();
        // console.log(BadNames);
        // Create function to fix case types when button clicked
        $("#rsa-autoWrapper > div").on("click", () => {
            // const turnGraph = W.model.getTurnGraph();
            const turnGraph = sdk.DataModel.Turns.getAll();
            for (let i = 0; i < BadNames.length; i++) {
                // Check if street or turn
                if (BadNames[i]) {
                    const strt = BadNames[i];
                    let dir = strt.direction;
                    if (dir !== null) {
                        if (dir.match(/\b(north)\b/i) != null)
                            dir = "Nᴏʀᴛʜ";
                        if (dir.match(/\b(south)\b/i) != null)
                            dir = "Sᴏᴜᴛʜ";
                        if (dir.match(/\b(east)\b/i) != null)
                            dir = "Eᴀꜱᴛ";
                        if (dir.match(/\b(west)\b/i) != null)
                            dir = "Wᴇꜱᴛ";
                        W.model.actionManager.add(new UpdateObj(strt, { direction: dir }));
                    }
                }
                else {
                    function fixName(name) {
                        let temp = name;
                        temp = temp.replace(/\b(north)\b/gi, "Nᴏʀᴛʜ");
                        temp = temp.replace(/\b(south)\b/gi, "Sᴏᴜᴛʜ");
                        temp = temp.replace(/\b(east)\b/gi, "Eᴀꜱᴛ");
                        temp = temp.replace(/\b(west)\b/gi, "Wᴇꜱᴛ");
                        temp = temp.replace(/\b(TO)\b/gi, "ᴛᴏ");
                        temp = temp.replace(/\b(VIA)\b/gi, "ᴠɪᴀ");
                        temp = temp.replace(/\b(JCT)\b/gi, "ᴊᴄᴛ");
                        return temp;
                    }
                    const turn = BadNames[i];
                    let turnDat = turn.getTurnData();
                    const turnGuid = turnDat.getTurnGuidance();
                    // let newGuid = turnGuid;
                    console.log(turn);
                    for (const s in turnGuid.roadShields) {
                        turnGuid.roadShields[s].direction = fixName(turnGuid.roadShields[s].direction);
                    }
                    if (rsaSettings.checkTWD && turnGuid.towards)
                        turnGuid.towards = fixName(turnGuid.towards);
                    if (rsaSettings.checkTTS && turnGuid.tts)
                        turnGuid.tts = fixName(turnGuid.tts);
                    if (rsaSettings.checkVI && turnGuid.visualInstruction)
                        turnGuid.visualInstruction = fixName(turnGuid.visualInstruction);
                    console.log(turnGuid);
                    turnDat = turnDat.withTurnGuidance(turnGuid);
                    W.model.actionManager.add(new SetTurn(turnGraph, turn.withTurnData(turnDat)));
                }
            }
        });
    }
    function removeAutoFixButton() {
        $("#rsa-autoWrapper > div").off();
        $("#rsa-autoWrapper").css("display", "none");
    }
    function addShieldClick() {
        // const selFea = W.selectionManager.getSelectedFeatures();
        const selFea = sdk.Editing.getSelection();
        if (selFea && selFea.objectType === "segment") {
            $(".add-new-road-shield").trigger("click");
        }
        else {
            WazeWrap.Alerts.error(GM_info.script.name, "You must have only 1 segment selected to use the shield editing menu");
        }
    }
    function tryScan() {
        if (!rsaSettings.enableScript)
            return;
        // Reset the array of objects that need names fixed
        BadNames = [];
        removeHighlights();
        if (sdk.Map.getZoomLevel() <= MIN_ZOOM_LEVEL)
            return;
        // let selFea = W.selectionManager.getSelectedFeatures();
        // Scan all segments on screen
        if (rsaSettings.ShowSegShields ||
            rsaSettings.SegShieldMissing ||
            rsaSettings.SegShieldError ||
            rsaSettings.HighSegShields ||
            rsaSettings.titleCase) {
            // _.each(W.model.segments.getObjectArray(), s => {
            //     scanSeg(s);
            // }
            for (const s of sdk.DataModel.Segments.getAll()) {
                processSeg(s);
            }
        }
        // Scan all nodes on screen
        if (rsaSettings.HighNodeShields || rsaSettings.ShowNodeShields || rsaSettings.titleCase) {
            const nodeSet = new Set(sdk.DataModel.Nodes.getAll());
            for (const n of nodeSet) {
                processNode(n);
            }
        }
    }
    const majorRoads = new Set([3, 4, 5, 6]);
    function processSeg(seg) {
        if ((!rsaSettings.ShowRamps && seg.roadType === 4) ||
            (rsaSettings.mHPlus && !majorRoads.has(seg.roadType)))
            return;
        // let segAtt = seg.attributes;
        // let streetID = segAtt.primaryStreetID;
        // const streetID: number | null = seg.primaryStreetId;
        // if (streetID === null) return;
        // // let oldStreet = W.model.streets.getObjectById(streetID).attributes;
        // let street: Street | null = sdk.DataModel.Streets.getById({ streetId: streetID });
        // if (street === null || street.cityId === null) return;
        // const city: City | null = sdk.DataModel.Cities.getById({ cityId: street.cityId });
        // if (city === null) return;
        // const stateID = city.stateId;
        let address = sdk.DataModel.Segments.getAddress({ segmentId: seg.id });
        if (rsaSettings.AlternativeShields) {
            for (const altAddress of address.altStreets) {
                // let oldAltStreet = W.model.streets.getObjectById(segAtt.streetIDs[i]).attributes;
                if (alternativeType === "AlternativePrimaryCity") {
                    if (altAddress.city !== null) {
                        address = altAddress;
                        break;
                    }
                }
                if (alternativeType === "AlternativeNoCity") {
                    if (altAddress.city?.name === "") {
                        address = altAddress;
                        break;
                    }
                }
            }
        }
        // let oldStateName = W.model.states.getObjectById(cityID.stateID).attributes.name;
        const stateName = address.state === null ? "" : address.state.name;
        const countryID = address.country?.id;
        const candidate = isSegmentCandidate(address, stateName, countryID);
        // Display shield on map
        function checkDeclutterSettings(seg) {
            let result = false;
            const zoomLevel = sdk.Map.getZoomLevel();
            if (zoomLevel > MIN_ZOOM_LEVEL) {
                if (seg.length > minShieldDisplayLengths[zoomLevel]) {
                    result = true;
                }
            }
            return result;
        }
        if (address.street !== null && address.street.signType !== null) {
            if (rsaSettings.ShowSegShields && checkDeclutterSettings(seg)) {
                displaySegShields(seg, address.street.signType, address.street.signText, address.street.direction);
            }
            // If candidate and has shield
            if (rsaSettings.HighSegShields && candidate.isCandidate) {
                if (isValidShield(seg, candidate.iconID)) {
                    createHighlight(seg, rsaSettings.HighSegClr);
                }
                else {
                    createHighlight(seg, rsaSettings.ErrSegClr);
                }
            }
            // If not candidate and has shield
            if (rsaSettings.SegShieldError && !candidate.isCandidate)
                createHighlight(seg, rsaSettings.ErrSegClr);
            if (rsaSettings.SegHasDir && address.street?.direction)
                createHighlight(seg, rsaSettings.SegHasDirClr);
            // Highlight seg shields with direction
            if (rsaSettings.SegInvDir && !address.street?.direction)
                createHighlight(seg, rsaSettings.SegInvDirClr);
        }
        // If candidate and missing shield
        if (rsaSettings.SegShieldMissing && candidate.isCandidate && address.street !== null && address.street.signType === null)
            createHighlight(seg, rsaSettings.MissSegClr);
        // Streets without capitalized letters
        if (rsaSettings.titleCase) {
            const badName = matchTitleCase(address.street);
            if (badName) {
                createHighlight(seg, rsaSettings.TitleCaseClr, true);
                // autoFixButton();
            }
        }
    }
    function processNode(node) {
        if (node === null)
            return;
        const guidance = {
            tts: false,
            visual: false,
            exit: false,
            shield: false,
            towards: false,
        };
        const turns = sdk.DataModel.Turns.getTurnsThroughNode({ nodeId: node.id });
        for (const turn of turns) {
            if (!turn.isAllowed)
                continue;
            // let oldTurn = W.model.getTurnGraph().getTurnThroughNode(node,turn.fromSegmentId,turn.toSegmentId);
            guidance.tts = guidance.tts || turn.hasCustomTTS;
            guidance.shield = guidance.shield || turn.hasShieldsPopulated;
            guidance.towards = guidance.towards || turn.hasTowardsGuidance;
            guidance.visual = guidance.visual || turn.hasVisualInstruction;
            if (rsaSettings.titleCase) {
                const badName = matchTitleCaseThroughNode(turn);
                if (badName.isBad) {
                    const color = badName.softIssue ? rsaSettings.TitleCaseSftClr : rsaSettings.TitleCaseClr;
                    createHighlight(node, color, true);
                    // autoFixButton();
                }
            }
        }
        if (rsaSettings.ShowNodeShields &&
            sdk.Map.getZoomLevel() > ZoomLevel.ZM2 &&
            (guidance.exit || guidance.tts || guidance.shield || guidance.visual || guidance.towards))
            displayNodeIcons(node, guidance);
    }
    // Function written by kpouer to accommodate French conventions of shields being based on alt names
    function isSegmentCandidate(address, stateName, countryId) {
        let candidate = isStreetCandidate(address.street, stateName, countryId);
        if (!candidate.isCandidate && address.country !== null && address.country?.id !== undefined && CheckAltName.has(address.country.id)) {
            for (const altAddress of address.altStreets) {
                candidate = isStreetCandidate(altAddress.street, stateName, countryId);
                if (candidate.isCandidate) {
                    return candidate;
                }
            }
        }
        return candidate;
    }
    function isStreetCandidate(street, stateName, countryId) {
        const info = { isCandidate: false, iconID: null };
        if (street === null || countryId === null || countryId === undefined || !RoadAbbr[countryId]) {
            return info;
        }
        // if (stateName === null) stateName = "";
        //Check to see if the country has states configured in RSA by looking for a key with nothing in it
        if (street.name) {
            const noStates = "" in RoadAbbr[countryId];
            const abbrvs = noStates
                ? RoadAbbr[countryId][""]
                : { ...RoadAbbr[countryId][stateName], ...RoadAbbr[countryId]["*"] };
            const abbreviationKeys = Object.keys(abbrvs);
            for (let i = 0; i < abbreviationKeys.length; i++) {
                const abrKey = abbreviationKeys[i];
                const abbr = new RegExp(abrKey, "g");
                const isMatch = street.name.match(abbr);
                if (isMatch && street.name.includes(isMatch[0])) {
                    info.isCandidate = true;
                    info.iconID = abbrvs[abrKey];
                    break;
                }
            }
        }
        return info;
    }
    function iconTextValidation(signType, signText, iconId) {
        let result = true;
        if (signType === null ||
            typeof signType === "undefined" ||
            typeof signText === "undefined" ||
            (iconId instanceof Set && !iconId.has(signType)) ||
            (!(iconId instanceof Set) && signType !== iconId)) {
            result = false;
        }
        if (signType !== null &&
            !iconsAllowingNoText.has(signType) &&
            (signText === null || typeof signText === "undefined" || signText === "")) {
            result = false;
        }
        return result;
    }
    function isValidShield(seg, iconID) {
        // let primaryStreet = W.model.streets.getObjectById(segAtt.primaryStreetID);
        if (seg === null || seg.primaryStreetId === null)
            return false;
        const primaryStreet = sdk.DataModel.Streets.getById({ streetId: seg.primaryStreetId });
        if (primaryStreet === null ||
            primaryStreet.signText === null ||
            !iconTextValidation(primaryStreet.signType, primaryStreet.signText, iconID))
            return false;
        if (primaryStreet.name?.includes(primaryStreet.signText)) {
            return true;
        }
        for (let i = 0; i < seg.alternateStreetIds.length; i++) {
            const street = sdk.DataModel.Streets.getById({ streetId: seg.alternateStreetIds[i] });
            if (street?.name?.includes(primaryStreet.signText)) {
                return true;
            }
        }
        return false;
    }
    function matchTitleCase(street) {
        if (!street)
            return;
        const dir = street.direction;
        let isBad = false;
        if (dir !== "" && dir !== null) {
            // console.log(dir);
            if (dir.match(/\\b(north|south|east|west)\\b/i) !== null)
                isBad = true;
            if (dir.match(/([ᴀʙᴄᴅᴇꜰɢʜɪᴊᴋʟᴍɴᴏᴘʀꜱᴛᴜᴠᴡʏᴢ][a-z]|[a-z][ᴀʙᴄᴅᴇꜰɢʜɪᴊᴋʟᴍɴᴏᴘʀꜱᴛᴜᴠᴡʏᴢ])/) !== null)
                isBad = true;
            if (isBad) {
                if (BadNames.length === 0) {
                    BadNames.push(street);
                }
                else {
                    let isDuplicate = false;
                    for (let i = 0; i < BadNames.length; i++) {
                        // if (BadNames[i].type) console.log(BadNames[i].id === street.id);
                        if (typeof BadNames[i] && BadNames[i].id === street.id)
                            isDuplicate = true;
                    }
                    if (!isDuplicate)
                        BadNames.push(street);
                }
            }
        }
        return isBad;
    }
    function matchTitleCaseThroughNode(turn) {
        const info = { isBad: false, softIssue: false };
        return info;
        const turnGuid = turnData.getTurnGuidance();
        const shields = turnGuid.getRoadShields();
        const twd = turnGuid.getTowards();
        const tts = turnGuid.getTTS();
        const VI = turnGuid.getVisualInstruction();
        function checkText(txt, isSoft = false) {
            if (txt !== "" && txt !== null) {
                if (txt.match(/\b(north|south|east|west)\b/i) != null) {
                    info.isBad = true;
                    if (isSoft)
                        info.softIssue = true;
                }
                if (txt.match(/\b(TO|VIA|JCT)\b/i) != null) {
                    info.isBad = true;
                    if (isSoft)
                        info.softIssue = true;
                }
                if (txt.match(/([ᴀʙᴄᴅᴇꜰɢʜɪᴊᴋʟᴍɴᴏᴘʀꜱᴛᴜᴠᴡʏᴢ][a-z]|[a-z][ᴀʙᴄᴅᴇꜰɢʜɪᴊᴋʟᴍɴᴏᴘʀꜱᴛᴜᴠᴡʏᴢ])/) != null) {
                    info.isBad = true;
                    if (isSoft)
                        info.softIssue = true;
                }
            }
        }
        function checkTTStext(txt, isSoft = false) {
            if (txt !== "" && txt !== null) {
                if (txt.match(/(Nᴏʀᴛʜ|Sᴏᴜᴛʜ|Eᴀꜱᴛ|Wᴇꜱᴛ)/) != null) {
                    info.isBad = true;
                    if (isSoft)
                        info.softIssue = true;
                }
                if (txt.match(/(ᴛᴏ|ᴠɪᴀ|ᴊᴄᴛ)/) != null) {
                    info.isBad = true;
                    if (isSoft)
                        info.softIssue = true;
                }
                if (txt.match(/([ᴀʙᴄᴅᴇꜰɢʜɪᴊᴋʟᴍɴᴏᴘʀꜱᴛᴜᴠᴡʏᴢ][a-z]|[a-z][ᴀʙᴄᴅᴇꜰɢʜɪᴊᴋʟᴍɴᴏᴘʀꜱᴛᴜᴠᴡʏᴢ])/) != null) {
                    info.isBad = true;
                    if (isSoft)
                        info.softIssue = true;
                }
            }
        }
        if (shields) {
            _.each(shields, (s) => {
                checkText(s.direction);
            });
        }
        if (twd && twd !== "" && rsaSettings.checkTWD)
            checkText(twd, true);
        if (tts && tts !== "" && rsaSettings.checkTTS)
            checkTTStext(tts, true);
        if (VI && VI !== "" && rsaSettings.checkVI)
            checkText(VI, true);
        if (info.isBad)
            BadNames.push(turn);
        return info;
    }
    function displayNodeIcons(node, guidance) {
        const GUIDANCE = {
            shields: {
                setting: "ShowNodeShields",
                exists: guidance.shield,
                color: "",
                width: 30,
                height: 30,
                sign: "6",
                txt: "TG",
            },
            exitsign: {
                setting: "ShowExitShields",
                exists: guidance.exit,
                color: "",
                width: 30,
                height: 20,
                sign: "2159",
                txt: "EX",
            },
            tts: {
                setting: "ShowTurnTTS",
                exists: guidance.tts,
                color: "",
                width: 30,
                height: 30,
                sign: "7",
                txt: "TIO",
            },
            towards: {
                setting: "ShowTowards",
                exists: guidance.towards,
                color: "",
                width: 30,
                height: 30,
                sign: "7",
                txt: "TW",
            },
            visualIn: {
                setting: "ShowVisualInst",
                exists: guidance.visual,
                color: "",
                width: 30,
                height: 30,
                sign: "7",
                txt: "VI",
            },
        };
        let count = 0;
        const pixelPos = sdk.Map.getPixelFromLonLat({ lonLat: { lon: node.geometry.coordinates[0], lat: node.geometry.coordinates[1] } });
        // const pixelPos = proj4("EPSG:4326", "EPSG:3857", node.geometry.coordinates);
        const startPoint = { x: pixelPos.x, y: pixelPos.y };
        const lblStart = { x: startPoint.x - labelDistance().label, y: startPoint.y - labelDistance().label };
        // Array of points for line connecting node to icons
        const points = [];
        const pointCoordinates = [];
        // Point coords
        // let pointNode = new OpenLayers.Geometry.Point(startPoint.x, startPoint.y);
        const pointNode = turf.point(node.geometry.coordinates, {
            styleName: "styleNode",
            style: {
                strokeColor: rsaSettings.HighNodeClr,
                strokeOpacity: 0.75,
                strokeWidth: 4,
                fillColor: rsaSettings.HighNodeClr,
                fillOpacity: 0.75,
                pointRadius: 3,
            },
        }, { id: `node_${startPoint.x} ${startPoint.y}` });
        points.push(pointNode);
        pointCoordinates.push(node.geometry.coordinates);
        // Label coords
        // var pointLabel = new OpenLayers.Geometry.Point(lblStart.x, lblStart.y);
        // const nodeLabelCoordinates = proj4("EPSG:3857", "EPSG:4326", [lblStart.x, lblStart.y]);
        const nodeLabelCoordinates = sdk.Map.getLonLatFromPixel({ x: lblStart.x, y: lblStart.y });
        const nodeLabel = turf.point([nodeLabelCoordinates.lon, nodeLabelCoordinates.lat], {
            styleName: "styleNode",
            style: {
                strokeColor: rsaSettings.HighNodeClr,
                strokeOpacity: 0.75,
                strokeWidth: 4,
                fillColor: rsaSettings.HighNodeClr,
                fillOpacity: 0.75,
                pointRadius: 3,
            },
        }, { id: `pointNode_${startPoint.x} ${startPoint.y}` });
        points.push(nodeLabel);
        pointCoordinates.push([nodeLabelCoordinates.lon, nodeLabelCoordinates.lat]);
        sdk.Map.addFeaturesToLayer({ features: points, layerName: rsaMapLayer.layerName });
        const newLine = turf.lineString(pointCoordinates, {
            styleName: "styleNode",
            style: {
                strokeColor: rsaSettings.HighNodeClr,
                strokeOpacity: 0.75,
                strokeWidth: 4,
                fillColor: rsaSettings.HighNodeClr,
                fillOpacity: 0.75,
                pointRadius: 3,
            },
        }, { id: `line_${points[0].toString()}` });
        sdk.Map.addFeatureToLayer({ feature: newLine, layerName: rsaIconLayer.layerName });
        _.each(GUIDANCE, (q) => {
            if (q.exists && rsaSettings[q.setting]) {
                // console.log(q);
                let xpoint = lblStart.x;
                let ypoint = lblStart.y;
                const lblDis = labelDistance();
                switch (count) {
                    case 1:
                        xpoint = lblStart.x + lblDis.icon;
                        ypoint = lblStart.y;
                        break;
                    case 2:
                        xpoint = lblStart.x;
                        ypoint = lblStart.y - lblDis.icon;
                        break;
                    case 3:
                        xpoint = lblStart.x + lblDis.icon;
                        ypoint = lblStart.y - lblDis.icon;
                        break;
                    case 4:
                        xpoint = lblStart.x + lblDis.icon * 2;
                        ypoint = lblStart.y;
                        break;
                    default:
                        break;
                }
                // Label coords
                // let pointLabel = new OpenLayers.Geometry.Point(xpoint, ypoint);
                // labelFeat = new OpenLayers.Feature.Vector(pointLabel, null, styleLabel);
                const lonLat = sdk.Map.getLonLatFromPixel({ x: xpoint, y: ypoint });
                const pointLabelFeature = turf.point([lonLat.lon, lonLat.lat], {
                    styleName: "styleLabel",
                    style: { sign: q.sign, txt: q.txt, height: q.height, width: q.width, fillOpacity: 1 },
                }, { id: `pointLabel_${xpoint.toString()}_${ypoint.toString()}` });
                sdk.Map.addFeatureToLayer({ feature: pointLabelFeature, layerName: rsaIconLayer.layerName });
                count++;
            }
        });
    }
    function displaySegShields(segment, shieldID, shieldText, shieldDir) {
        const iconURL = `https://renderer-am.waze.com/renderer/v1/signs/${shieldID}?text=${shieldText}`;
        // let SegmentPoints = [];
        const oldparam = { x: null, y: null };
        const labelDis = labelDistance();
        let width = 37;
        let height = 37;
        if (shieldText !== null) {
            if (shieldText.length > 4 && shieldText.length < 7) {
                width = 50;
                height = 40;
            }
            else if (shieldText.length > 6 && shieldText.length < 9) {
                width = 80;
                height = 45;
            }
            else if (shieldText.length > 8 && shieldText.length < 13) {
                width = 100;
                height = 50;
            }
        }
        // oldparam.x = null;
        // oldparam.y = null;
        let AtLeastOne = false;
        $.each(segment.geometry.coordinates, (idx, param) => {
            // const pointParam = proj4("EPSG:4326", "EPSG:3857", param);
            const pointParam = sdk.Map.getPixelFromLonLat({ lonLat: { lon: param[0], lat: param[1] } });
            // Build a new segment with same geometry
            // SegmentPoints.push(new OpenLayers.Geometry.Point(param[0], param[1]));
            // let newPoint = {
            //     type: "Feature",
            //     geometry: {
            //         type: "Point",
            //         coordinates: [param[0], param[1]],
            //     },
            //     id: "point_" + param[0].toString() + " " + param[1].toString(),
            // };
            // SegmentPoints.push(newPoint);
            // let shieldWithLabelStyle = {
            //     externalGraphic: iconURL,
            //     graphicWidth: width,
            //     graphicHeight: height,
            //     graphicYOffset: -20,
            //     // graphicZIndex: 6000,
            //     style: "opacity: 1",
            //     fillOpacity: 1,
            //     fill: "black",
            //     stroke: "black",
            //     label: shieldDir !== null ? shieldDir : "",
            //     fontColor: "green",
            //     labelOutlineColor: "white",
            //     labelOutlineWidth: 1,
            //     fontSize: 12,
            //     display: "grid",
            //     labelYOffset: 0,
            // };
            if (oldparam.x && oldparam.y && oldparam.x !== null && oldparam.y !== null) {
                if (Math.abs(oldparam.x - pointParam.x) > labelDis.space ||
                    Math.abs(oldparam.y - pointParam.y) > labelDis.space ||
                    !AtLeastOne) {
                    const centerparam = { x: undefined, y: undefined };
                    centerparam.x = (oldparam.x + pointParam.x) / 2;
                    centerparam.y = (oldparam.y + pointParam.y) / 2;
                    if ((centerparam.x && Math.abs(centerparam.x - pointParam.x) > labelDis.space) ||
                        (centerparam.y && Math.abs(centerparam.y - pointParam.y) > labelDis.space) ||
                        !AtLeastOne) {
                        // let LabelPoint = new OpenLayers.Geometry.Point(centerparam.x, centerparam.y);
                        // const pointFeature = new OpenLayers.Feature.Vector(LabelPoint, null, style);
                        // const coordCenterPoint = proj4("EPSG:3857", "EPSG:4326", [centerparam.x, centerparam.y]);
                        const coordCenterPoint = sdk.Map.getLonLatFromPixel({ x: centerparam.x, y: centerparam.y });
                        const shieldFeature = turf.point([coordCenterPoint.lon, coordCenterPoint.lat], {
                            styleName: "shield",
                            style: {
                                externalGraphic: iconURL,
                                graphicWidth: width,
                                graphicHeight: height,
                                label: shieldDir !== null ? shieldDir : "",
                                labelYOffset: shieldDir !== null ? -20 : 0,
                            },
                        }, { id: `shield_${centerparam.x.toString()}_${centerparam.y.toString()}` });
                        // Shield icon style
                        // shieldWithLabelStyle.labelYOffset = -1 * labelDis.label;
                        sdk.Map.addFeatureToLayer({ feature: shieldFeature, layerName: rsaIconLayer.layerName });
                        AtLeastOne = true;
                    }
                }
            }
            oldparam.x = pointParam.x;
            oldparam.y = pointParam.y;
        });
    }
    function createHighlight(obj, color, overSized = false) {
        // const geo = obj.getOLGeometry().clone();
        const geo = structuredClone(obj.geometry);
        const isNode = obj instanceof Node;
        if (isNode) {
            // Point coords
            // let pointNode = new OpenLayers.Geometry.Point(geo.x, geo.y);
            const pointFeature = turf.point(geo.coordinates, {
                styleName: "styleNode",
                style: {
                    strokeColor: color,
                    strokeOpacity: overSized ? 1 : 0.75,
                    strokeWidth: 4,
                    fillColor: color,
                    fillOpacity: 0.75,
                    pointRadius: overSized ? 7 : 3,
                },
            }, { id: `point_${geo.coordinates[0]}_${geo.coordinates[1]}` });
            sdk.Map.addFeatureToLayer({ feature: pointFeature, layerName: rsaIconLayer.layerName });
        }
        else {
            // console.log('seg highlight')
            // Object.assign(styleRules.segHighlight.style, {
            //     strokeColor: color,
            //     strokeOpacity: overSized ? 1 : 0.75,
            //     strokeWidth: overSized ? 7 : 4,
            //     fillColor: color,
            //     fillOpacity: 0.75,
            // });
            // const newFeat =  new OpenLayers.Geometry.LineString(geo.components, {});
            // const newVector = new OpenLayers.Feature.Vector(newFeat, null, style);
            // rsaMapLayer.addFeatures([newVector]);
            const newLineFeature = turf.lineString(geo.coordinates, {
                styleName: "segHighlight",
                style: {
                    strokeColor: color,
                    strokeOpacity: overSized ? 1 : 0.75,
                    strokeWidth: overSized ? 7 : 4,
                    fillColor: color,
                    fillOpacity: 0.75,
                },
            }, { id: `line_${geo}` });
            sdk.Map.addFeatureToLayer({ feature: newLineFeature, layerName: rsaMapLayer.layerName });
        }
    }
    function removeHighlights() {
        sdk.Map.removeAllFeaturesFromLayer(rsaMapLayer);
        sdk.Map.removeAllFeaturesFromLayer(rsaIconLayer);
    }
    function labelDistance() {
        // Return object with two variables - label is the distance used to place the direction below the icon,
        // space is the space between geo points needed to render another icon
        const label_distance = { icon: 27, label: 40, space: 30 };
        return label_distance;
    }
    initRSA();
}