WME FC Layer

Adds a Functional Class layer for states that publish ArcGIS FC data.

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください
// ==UserScript==
// @name         WME FC Layer
// @namespace    https://greasyfork.runtimutd.eu.org/users/45389
// @version      2025.06.19.000
// @description  Adds a Functional Class layer for states that publish ArcGIS FC data.
// @author       MapOMatic
// @match        *://*.waze.com/*editor*
// @exclude      *://*.waze.com/user/editor*
// @exclude      *://*.waze.com/editor/sdk/*
// @license      GNU GPLv3
// @contributionURL https://github.com/WazeDev/Thank-The-Authors
// @require      https://greasyfork.runtimutd.eu.org/scripts/39002-bluebird/code/Bluebird.js?version=255146
// @require      https://greasyfork.runtimutd.eu.org/scripts/24851-wazewrap/code/WazeWrap.js
// @require      https://cdn.jsdelivr.net/npm/@turf/turf@7/turf.min.js
// @require      https://update.greasyfork.ip-ddns.com/scripts/509664/WME%20Utils%20-%20Bootstrap.js
// @connect      greasyfork.runtimutd.eu.org
// @grant        GM_xmlhttpRequest
// @connect      arcgis.com
// @connect      gis.ardot.gov
// @connect      azdot.gov
// @connect      ca.gov
// @connect      coloradodot.info
// @connect      delaware.gov
// @connect      dc.gov
// @connect      ga.gov
// @connect      uga.edu
// @connect      hawaii.gov
// @connect      idaho.gov
// @connect      in.gov
// @connect      iowadot.gov
// @connect      illinois.gov
// @connect      ksdot.org
// @connect      ky.gov
// @connect      la.gov
// @connect      maine.gov
// @connect      md.gov
// @connect      ma.us
// @connect      mn.us
// @connect      nv.gov
// @connect      memphistn.gov
// @connect      state.mi.us
// @connect      modot.org
// @connect      mt.gov
// @connect      unh.edu
// @connect      nh.gov
// @connect      ny.gov
// @connect      ncdot.gov
// @connect      nd.gov
// @connect      oh.us
// @connect      or.us
// @connect      penndot.gov
// @connect      sd.gov
// @connect      shelbycountytn.gov
// @connect      utah.gov
// @connect      vermont.gov
// @connect      wa.gov
// @connect      wv.gov
// @connect      wyoroad.info
// ==/UserScript==

/* global turf */
/* global bootstrap */

(async function main() {
    'use strict';

    const settingsStoreName = 'wme_fc_layer';
    const debug = false;
    const scriptVersion = GM_info.script.version;
    const downloadUrl = 'https://greasyfork.runtimutd.eu.org/scripts/369633-wme-fc-layer/code/WME%20FC%20Layer.user.js';
    const sdk = await bootstrap({ scriptUpdateMonitor: { downloadUrl } });
    const layerName = 'FC Layer';
    let isAM = false;
    let userNameLC;
    let settings = {};
    let rank;
    let MAP_LAYER_Z_INDEX;
    const MIN_ZOOM_LEVEL = 11;
    const STATES_HASH = {
        Alabama: 'AL',
        Alaska: 'AK',
        'American Samoa': 'AS',
        Arizona: 'AZ',
        Arkansas: 'AR',
        California: 'CA',
        Colorado: 'CO',
        Connecticut: 'CT',
        Delaware: 'DE',
        'District of Columbia': 'DC',
        'Federated States Of Micronesia': 'FM',
        Florida: 'FL',
        Georgia: 'GA',
        Guam: 'GU',
        Hawaii: 'HI',
        Idaho: 'ID',
        Illinois: 'IL',
        Indiana: 'IN',
        Iowa: 'IA',
        Kansas: 'KS',
        Kentucky: 'KY',
        Louisiana: 'LA',
        Maine: 'ME',
        'Marshall Islands': 'MH',
        Maryland: 'MD',
        Massachusetts: 'MA',
        Michigan: 'MI',
        Minnesota: 'MN',
        Mississippi: 'MS',
        Missouri: 'MO',
        Montana: 'MT',
        Nebraska: 'NE',
        Nevada: 'NV',
        'New Hampshire': 'NH',
        'New Jersey': 'NJ',
        'New Mexico': 'NM',
        'New York': 'NY',
        'North Carolina': 'NC',
        'North Dakota': 'ND',
        'Northern Mariana Islands': 'MP',
        Ohio: 'OH',
        Oklahoma: 'OK',
        Oregon: 'OR',
        Palau: 'PW',
        Pennsylvania: 'PA',
        'Puerto Rico': 'PR',
        'Rhode Island': 'RI',
        'South Carolina': 'SC',
        'South Dakota': 'SD',
        Tennessee: 'TN',
        Texas: 'TX',
        Utah: 'UT',
        Vermont: 'VT',
        'Virgin Islands': 'VI',
        Virginia: 'VA',
        Washington: 'WA',
        'West Virginia': 'WV',
        Wisconsin: 'WI',
        Wyoming: 'WY'
    };

    function reverseStatesHash(stateAbbr) {
    // eslint-disable-next-line no-restricted-syntax
        for (const stateName in STATES_HASH) {
            if (STATES_HASH[stateName] === stateAbbr) return stateName;
        }
        throw new Error(`FC Layer: reverseStatesHash function did not return a value for ${stateAbbr}.`);
    }

    const STATE_SETTINGS = {
        global: {
            roadTypes: ['St', 'PS', 'PS2', 'mH', 'MH', 'Ew', 'Rmp', 'Fw'], // Ew = Expressway.  For FC's that make it uncertain if they should be MH or FW.
            getFeatureRoadType(feature, layer) {
                const fc = feature.attributes[layer.fcPropName];
                return this.getRoadTypeFromFC(fc, layer);
            },
            getRoadTypeFromFC(fc, layer) {
                return Object.keys(layer.roadTypeMap).find(rt => layer.roadTypeMap[rt].indexOf(fc) !== -1);
            },
            isPermitted(stateAbbr) {
                const state = STATE_SETTINGS[stateAbbr];
                if (state.isPermitted) return state.isPermitted();
                return (rank >= 3 && isAM) || rank >= 4;
            },
            getMapLayer(stateAbbr, layerID) {
                let returnValue;
                STATE_SETTINGS[stateAbbr].fcMapLayers.forEach(layer => {
                    if (layer.layerID === layerID) {
                        returnValue = layer;
                    }
                });
                return returnValue;
            }
        },
        AL: {
            baseUrl: 'https://services.arcgis.com/LZzQi3xDiclG6XvQ/arcgis/rest/services/HPMS_Year2017_F_System_Data/FeatureServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 0,
                    fcPropName: 'F_SYSTEM_V',
                    idPropName: 'OBJECTID',
                    outFields: ['FID', 'F_SYSTEM_V', 'State_Sys'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            isPermitted() {
                return rank >= 3;
            },
            information: { Source: 'ALDOT', Permission: 'Visible to R3+', Description: 'Federal and State highways set to a minimum of mH.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName} <> 7`;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                let fc = parseInt(feature.attributes[layer.fcPropName], 10);
                if (fc > 4 && feature.attributes.State_Sys === 'YES') {
                    fc = 4;
                }
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        AK: {
            baseUrl: 'https://services.arcgis.com/r4A0V7UzH9fcLVvv/ArcGIS/rest/services/AKDOTPF_Route_Data/FeatureServer/',
            defaultColors: {
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [[], [], [], [], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 13,
                    fcPropName: 'Functional_Class',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'Functional_Class'],
                    roadTypeMap: {
                        Ew: [1, 2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            information: { Source: 'Alaska DOT&PF', Permission: 'Visible to R4+ or R3-AM', Description: 'Raw unmodified FC data.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName} <> 7`;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                if (layer.getFeatureRoadType) {
                    return layer.getFeatureRoadType(feature);
                }
                return STATE_SETTINGS.global.getFeatureRoadType(feature, layer);
            }
        },
        AZ: {
            baseUrl: 'https://services1.arcgis.com/XAiBIVuto7zeZj1B/arcgis/rest/services/ATIS_prod_gdb_1/FeatureServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#ff00c5',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1] },
            fcMapLayers: [
                {
                    layerID: 38,
                    fcPropName: 'FunctionalClass',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FunctionalClass', 'RouteId'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            information: { Source: 'ADOT', Permission: 'Visible to R4+ or R3-AM' },
            getWhereClause() {
                return null;
            },
            getFeatureRoadType(feature, layer) {
                const attr = feature.attributes;
                const roadID = attr.RouteId.trim().replace(/  +/g, ' ');
                const roadNum = parseInt(roadID.substring(2, 5), 10);
                let fc = attr[layer.fcPropName];
                switch (fc) {
                    case 'Rural Principal Arterial - Interstate':
                    case 'Urban Principal Arterial - Interstate':
                        fc = 1;
                        break;
                    case 'Rural Principal Arterial - Other Fwys & Expwys':
                    case 'Urban Principal Arterial - Other Fwys & Expwys':
                        fc = 2;
                        break;
                    case 'Rural Principal Arterial - Other':
                    case 'Urban Principal Arterial - Other':
                        fc = 3;
                        break;
                    case 'Rural Minor Arterial':
                    case 'Urban Minor Arterial':
                        fc = 4;
                        break;
                    case 'Rural Major Collector':
                    case 'Urban Major Collector':
                        fc = 5;
                        break;
                    case 'Rural Minor Collector':
                    case 'Urban Minor Collector':
                        fc = 6;
                        break;
                    default:
                        fc = 7;
                }
                const azIH = [8, 10, 11, 17, 19, 40]; // Interstate hwys in AZ
                const isUS = /^U\D\d{3}\b/.test(roadID);
                const isState = /^S\D\d{3}\b/.test(roadID);
                const isBiz = /^SB\d{3}\b/.test(roadID);
                if (fc > 4 && isState && azIH.includes(roadNum) && isBiz) fc = 4;
                else if (fc > 4 && isUS) fc = isBiz ? 6 : 4;
                else if (fc > 6 && isState) fc = isBiz ? 7 : 6;
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        AR: {
            baseUrl: 'https://gis.ardot.gov/hosting/rest/services/SIR_TIS/RoadInvDissolves/FeatureServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [[], [], [], [], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 0,
                    fcPropName: 'FunctionalClass',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FunctionalClass', 'AH_Route', 'AH_Section'],
                    roadTypeMap: {
                        Fw: [1, 2],
                        Ew: [],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            information: { Source: 'ARDOT', Permission: 'Visible to R4+ or R3-AM' },
            getWhereClause() {
                return null;
            },
            getFeatureRoadType(feature, layer) {
                const attr = feature.attributes;
                let fc = parseInt(attr[layer.fcPropName], 10);
                const roadID = parseInt(attr.AH_Route, 10);
                const usHwys = [49, 59, 61, 62, 63, 64, 65, 67, 70, 71, 79, 82, 165, 167, 270, 271, 278, 371, 412, 425];
                const isUS = usHwys.includes(roadID);
                const isState = roadID < 613;
                const isBiz = attr.AH_Section[attr.AH_Section.length - 1] === 'B';
                if (fc > 3 && isUS) fc = isBiz ? 4 : 3;
                else if (fc > 4 && isState) fc = isBiz ? 5 : 4;
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        CA: {
            baseUrl: 'https://caltrans-gis.dot.ca.gov/arcgis/rest/services/CHhighway/CRS_Functional_Classification/FeatureServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 0,
                    fcPropName: 'F_System',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'F_System'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            isPermitted() {
                return ['mapomatic', 'turbomkt', 'tonestertm', 'ottonomy', 'jemay', 'ojlaw', 'js55ct'].includes(userNameLC);
            },
            information: { Source: 'Caltrans', Permission: 'Visible to ?', Description: '' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName} <> 7`;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                const fc = parseInt(feature.attributes[layer.fcPropName], 10);
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        CO: {
            baseUrl: 'https://dtdapps.coloradodot.info/arcgis/rest/services/CPLAN/open_data_sde/FeatureServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [[], [], [], [], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 11,
                    fcPropName: 'FUNCCLASS',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNCCLASS', 'ROUTE', 'REFPT'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                },
                {
                    layerID: 14,
                    fcPropName: 'FUNCCLASSID',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNCCLASSID', 'ROUTE', 'FIPSCOUNTY'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                },
                {
                    layerID: 17,
                    fcPropName: 'FUNCCLASSID',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNCCLASSID', 'ROUTE', 'FIPSCOUNTY'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            isPermitted() {
                return rank >= 3;
            },
            information: {
                Source: 'CDOT',
                Permission: 'Visible to R3+',
                Description: 'Please consult with a state manager before making any changes to road types based on the data presented.'
            },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName} <> '7'`;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                const attr = feature.attributes;
                let fc = parseInt(attr[layer.fcPropName], 10);
                const route = attr.ROUTE.replace(/  +/g, ' ');
                if (layer.layerID === 7) {
                    const rtnum = parseInt(route.slice(0, 3), 10);
                    const refpt = attr.REFPT;
                    const hwys = [6, 24, 25, 34, 36, 40, 50, 70, 84, 85, 87, 138, 160, 285, 287, 350, 385, 400, 491, 550];
                    // Exceptions first, then normal classification
                    const doNothing = ['024D', '040G'];
                    const notNothing = ['070K', '070L', '070O', '070Q', '070R'];
                    const doMin = ['024E', '050D', '070O', '085F', '160D'];
                    if (doNothing.includes(route) || (rtnum === 70 && route !== '070K' && !notNothing.includes(route))) {
                        // do nothing
                    } else if (doMin.includes(route) || (rtnum === 40 && refpt > 320 && refpt < 385) || (rtnum === 36 && refpt > 79 && refpt < 100.99) || (route === '034D' && refpt > 11)) {
                        fc = 4;
                    } else if (hwys.includes(rtnum)) {
                        fc = Math.min(fc, 3);
                    } else {
                        fc = Math.min(fc, 4);
                    }
                } else {
                    // All exceptions
                    const fips = parseInt(attr.FIPSCOUNTY, 10);
                    if ((fips === 19 && route === 'COLORADO BD') || (fips === 37 && (route === 'GRAND AV' || route === 'S H6'))) {
                        fc = 3;
                    } else if (fips === 67 && route === 'BAYFIELDPAY') {
                        fc = 4;
                    }
                }
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        CT: {
            baseUrl: 'https://services1.arcgis.com/FCaUeJ5SOVtImake/ArcGIS/rest/services/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 3,
                    layerPath: 'CTDOT_Roadway_Classification_and_Characteristic_Data/FeatureServer/',
                    fcPropName: 'FC_FC_CODE',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FC_FC_CODE'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                },
                {
                    layerID: 0,
                    layerPath: 'CTDOT_State_Routes_and_Local_Roads/FeatureServer/',
                    fcPropName: 'ROUTE_PREFIX',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'ROUTE_PREFIX'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            isPermitted() {
                return rank >= 3;
            },
            information: { Source: 'CTDOT', Permission: 'Visible to R3+', Description: 'Federal and State highways set to a minimum of mH.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    if (context.layer.layerID === 3) {
                        return `${context.layer.fcPropName} <> 7`;
                    }
                    if (context.layer.layerID === 'CTDOT_State_Routes_and_Local_Roads/FeatureServer/0') {
                        return `${context.layer.fcPropName} IN ('I', 'CT', 'SR', 'US')`;
                    }
                    return null;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                let fc;
                let primaryFc;
                let secondaryFc;

                if (layer.layerID === 3) {
                    // Extract primary FC based on 'FC_FC_CODE'
                    primaryFc = parseInt(feature.attributes[layer.fcPropName], 10);
                } else if (layer.layerID === 0) {
                    // Determine secondary FC using 'ROUTE_PREFIX'
                    const prefix = feature.attributes[layer.fcPropName];

                    if (prefix === 'I') {
                        secondaryFc = 1;
                    } else if (prefix === 'US') {
                        secondaryFc = 3;
                    } else if (prefix === 'CT' || prefix === 'SR') {
                        secondaryFc = 4;
                    }
                }

                // Determine fc based on available values
                if (typeof primaryFc !== 'undefined' && typeof secondaryFc !== 'undefined') {
                    fc = Math.min(primaryFc, secondaryFc);
                } else if (typeof primaryFc !== 'undefined') {
                    fc = primaryFc;
                } else if (typeof secondaryFc !== 'undefined') {
                    fc = secondaryFc;
                } else {
                    fc = null; // Default if both are undefined, decide handling of null based on safeguards or other logic
                }

                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        DE: {
            baseUrl: 'https://enterprise.firstmap.delaware.gov/arcgis/rest/services/Transportation/DE_Roadways_Main/FeatureServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 16,
                    fcPropName: 'VALUE_TEXT',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'VALUE_TEXT'],
                    maxRecordCount: 1000,
                    supportsPagination: false,
                    roadTypeMap: {
                        Fw: ['Interstate'],
                        Ew: ['Other Expressways & Freeway'],
                        MH: ['Other Principal Arterials'],
                        mH: ['Minor Arterial'],
                        PS: ['Major Collector', 'Minor Collector'],
                        St: ['Local']
                    }
                }
            ],
            information: { Source: 'Delaware FirstMap', Permission: 'Visible to R4+ or R3-AM', Description: 'Raw unmodified FC data.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName} <> 'Local'`;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                if (layer.getFeatureRoadType) {
                    return layer.getFeatureRoadType(feature);
                }
                return STATE_SETTINGS.global.getFeatureRoadType(feature, layer);
            }
        },
        DC: {
            baseUrl: 'https://maps2.dcgis.dc.gov/dcgis/rest/services/DCGIS_DATA/Transportation_WebMercator/MapServer/',
            supportsPagination: false,
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#149ece',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [[], [], [], [], [], [], [], [], [], [], []] },
            fetchAllFC: false,
            fcMapLayers: [
                {
                    layerID: 48,
                    fcPropName: 'FHWAFUNCTIONALCLASS',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FHWAFUNCTIONALCLASS'],
                    maxRecordCount: 1000,
                    supportsPagination: false,
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    }
                }
            ],
            information: { Source: 'DDOT', Permission: 'Visible to R4+ or R3-AM' },
            getWhereClause() {
                return null;
            },
            getFeatureRoadType(feature, layer) {
                if (layer.getFeatureRoadType) {
                    return layer.getFeatureRoadType(feature);
                }
                return STATE_SETTINGS.global.getFeatureRoadType(feature, layer);
            }
        },
        FL: {
            baseUrl: 'https://services1.arcgis.com/O1JpcwDW8sjYuddV/ArcGIS/rest/services/Functional_Classification_TDA/FeatureServer/',
            supportsPagination: false,
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#149ece',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [[], [], [], [], [], [], [], [], [], [], []] },
            fetchAllFC: false,
            fcMapLayers: [
                {
                    layerID: 0,
                    fcPropName: 'FUNCLASS',
                    idPropName: 'FID',
                    outFields: ['FID', 'FUNCLASS'],
                    maxRecordCount: 1000,
                    supportsPagination: false,
                    roadTypeMap: {
                        Fw: ['01', '11'],
                        Ew: ['02', '12'],
                        MH: ['04', '14'],
                        mH: ['06', '16'],
                        PS: ['07', '08', '17', '18']
                    }
                }
            ],
            information: { Source: 'FDOT', Permission: 'Visible to R4+ or R3-AM', Description: 'Raw unmodified FC data.' },
            getWhereClause() {
                return null;
            },
            getFeatureRoadType(feature, layer) {
                if (layer.getFeatureRoadType) {
                    return layer.getFeatureRoadType(feature);
                }
                return STATE_SETTINGS.global.getFeatureRoadType(feature, layer);
            }
        },
        GA: {
            baseUrl: 'https://maps.itos.uga.edu/arcgis/rest/services/GDOT/GDOT_FunctionalClass/mapserver/',
            supportsPagination: true,
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#149ece',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [[], [], [], [], [], [], [], [], [], [], []] },
            fetchAllFC: false,
            /* eslint-disable object-curly-newline */
            fcMapLayers: [
                {
                    layerID: 0,
                    fcPropName: 'FUNCTIONAL_CLASS',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNCTIONAL_CLASS', 'SYSTEM_CODE'],
                    maxRecordCount: 1000,
                    supportsPagination: true,
                    roadTypeMap: { Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5, 6] }
                },
                {
                    layerID: 1,
                    fcPropName: 'FUNCTIONAL_CLASS',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNCTIONAL_CLASS', 'SYSTEM_CODE'],
                    maxRecordCount: 1000,
                    supportsPagination: true,
                    roadTypeMap: { Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5, 6] }
                },
                {
                    layerID: 2,
                    fcPropName: 'FUNCTIONAL_CLASS',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNCTIONAL_CLASS', 'SYSTEM_CODE'],
                    maxRecordCount: 1000,
                    supportsPagination: true,
                    roadTypeMap: { Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5, 6] }
                },
                {
                    layerID: 3,
                    fcPropName: 'FUNCTIONAL_CLASS',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNCTIONAL_CLASS', 'SYSTEM_CODE'],
                    maxRecordCount: 1000,
                    supportsPagination: true,
                    roadTypeMap: { Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5, 6] }
                },
                {
                    layerID: 4,
                    fcPropName: 'FUNCTIONAL_CLASS',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNCTIONAL_CLASS', 'SYSTEM_CODE'],
                    maxRecordCount: 1000,
                    supportsPagination: true,
                    roadTypeMap: { Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5, 6] }
                },
                {
                    layerID: 5,
                    fcPropName: 'FUNCTIONAL_CLASS',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNCTIONAL_CLASS', 'SYSTEM_CODE'],
                    maxRecordCount: 1000,
                    supportsPagination: true,
                    roadTypeMap: { Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5, 6] }
                },
                {
                    layerID: 6,
                    fcPropName: 'FUNCTIONAL_CLASS',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNCTIONAL_CLASS', 'SYSTEM_CODE'],
                    maxRecordCount: 1000,
                    supportsPagination: true,
                    roadTypeMap: { Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5, 6] }
                }
            ],
            /* eslint-enable object-curly-newline */
            information: { Source: 'GDOT', Permission: 'Visible to R4+ or R3-AM', Description: 'Federal and State highways set to a minimum of mH.' },
            getWhereClause() {
                return null;
            },
            getFeatureRoadType(feature, layer) {
                if (layer.getFeatureRoadType) {
                    return layer.getFeatureRoadType(feature);
                }
                const attr = feature.attributes;
                const fc = attr.FUNCTIONAL_CLASS;
                if (attr.SYSTEM_CODE === '1' && fc > 4) {
                    return STATE_SETTINGS.global.getRoadTypeFromFC(4, layer);
                }
                return STATE_SETTINGS.global.getFeatureRoadType(feature, layer);
            }
        },
        HI: {
            baseUrl: 'https://geodata.hawaii.gov/arcgis/rest/services/Transportation/MapServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [[], [], [], [], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 12,
                    fcPropName: 'f_system',
                    idPropName: 'objectid',
                    outFields: ['objectid', 'f_system'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            information: { Source: 'HDOT', Permission: 'Visible to R4+ or R3-AM', Description: 'Raw unmodified FC data.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName}<7`;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                if (layer.getFeatureRoadType) {
                    return layer.getFeatureRoadType(feature);
                }
                return STATE_SETTINGS.global.getFeatureRoadType(feature, layer);
            }
        },
        ID: {
            baseUrl: 'https://gisportalp.itd.idaho.gov/xserver/rest/services/RH_GeneralService/MapServer/',
            supportsPagination: false,
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#149ece',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [[], [], [], [], [], [], [], [], [], [], []] },
            fetchAllFC: true,
            /* eslint-disable object-curly-newline */
            fcMapLayers: [
                {
                    layerID: 67,
                    fcPropName: 'FunctionalClass',
                    idPropName: 'ObjectId',
                    outFields: ['ObjectId', 'FunctionalClass'],
                    maxRecordCount: 1000,
                    supportsPagination: false,
                    roadTypeMap: { Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5, 6] }
                }
            ],
            /* eslint-enable object-curly-newline */
            information: { Source: 'ITD', Permission: 'Visible to R4+ or R3-AM', Description: 'Raw unmodified FC data.' },
            getWhereClause() {
                return null;
            },
            getFeatureRoadType(feature, layer) {
                if (layer.getFeatureRoadType) {
                    return layer.getFeatureRoadType(feature);
                }
                return STATE_SETTINGS.global.getFeatureRoadType(feature, layer);
            }
        },
        IL: {
            baseUrl: 'https://gis1.dot.illinois.gov/arcgis/rest/services/AdministrativeData/FunctionalClass/MapServer/',
            supportsPagination: false,
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#ff00c5',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1] },
            fcMapLayers: [
                {
                    layerID: 0,
                    idPropName: 'OBJECTID',
                    fcPropName: 'FC',
                    outFields: ['FC'],
                    roadTypeMap: {
                        Fw: ['1'],
                        Ew: ['2'],
                        MH: ['3'],
                        mH: ['4'],
                        PS: ['5', '6'],
                        St: ['7']
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            isPermitted() {
                return rank >= 4;
            },
            information: { Source: 'IDOT', Permission: 'Visible to R4+', Description: 'Raw unmodified FC data.' },
            getWhereClause(context) {
                return context.mapContext.zoom < 16 ? 'FC<>7' : null;
            },
            getFeatureRoadType(feature, layer) {
                if (layer.getFeatureRoadType) {
                    return layer.getFeatureRoadType(feature);
                }
                return STATE_SETTINGS.global.getFeatureRoadType(feature, layer);
            }
        },
        IN: {
            baseUrl: 'https://gis.indot.in.gov/ro/rest/services/DOT/INDOT_LTAP/MapServer/',
            supportsPagination: false,
            overrideUrl: '1Sbwc7e6BfHpZWSTfU3_1otXGSxHrdDYcbn7fOf1VjpA',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#149ece',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: {
                maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1],
                excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []],
                hideRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []]
            },
            fcMapLayers: [
                {
                    layerID: 10,
                    idPropName: 'OBJECTID',
                    fcPropName: 'FUNCTIONAL_CLASS',
                    outFields: ['FUNCTIONAL_CLASS', 'OBJECTID', 'TO_DATE'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 100000,
                    supportsPagination: false
                }
            ],
            isPermitted() {
                return true;
            },
            information: { Source: 'INDOT', Description: 'Raw unmodified FC data.' },
            getWhereClause(context) {
                let whereParts = ['TO_DATE IS NULL'];
                if (context.mapContext.zoom < 16) {
                    whereParts += ` AND ${context.layer.fcPropName} <> 7`;
                }
                return whereParts;
            },
            getFeatureRoadType(feature, layer) {
                if (layer.getFeatureRoadType) {
                    return layer.getFeatureRoadType(feature);
                }
                return STATE_SETTINGS.global.getFeatureRoadType(feature, layer);
            }
        },
        IA: {
            baseUrl: 'https://gis.iowadot.gov/agshost/rest/services/RAMS/Road_Network/FeatureServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#149ece',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee',
                PSGr: '#cc6533',
                StGr: '#e99cb6'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 0,
                    fcPropName: 'FED_FUNCTIONAL_CLASS',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FED_FUNCTIONAL_CLASS', 'STATE_ROUTE_NAME_1', 'ACCESS_CONTROL', 'SURFACE_TYPE'],
                    roadTypeMap: {
                        Fw: [1],
                        MH: [2, 3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            information: { Source: 'Iowa DOT', Permission: 'Visible to R4+ or R3-AM', Description: 'Additional colors denote unpaved PS and LS segements.' },
            getWhereClause(context) {
                let theWhereClause = "FACILITY_TYPE<>'7'"; // Removed proposed roads
                if (context.mapContext.zoom < 16) {
                    theWhereClause += ` AND ${context.layer.fcPropName}<>'7'`;
                }
                return theWhereClause;
            },
            getFeatureRoadType(feature, layer) {
                const attr = feature.attributes;
                let fc = parseInt(attr[layer.fcPropName], 10);
                const isFw = attr.ACCESS_CONTROL === 1;
                const isUS = /^STATE OF IOWA, US/.test(attr.STATE_ROUTE_NAME_1);
                const isState = /^STATE OF IOWA, IA/.test(attr.STATE_ROUTE_NAME_1);
                if (isFw) fc = 1;
                else if (fc > 3 && isUS) fc = 3;
                else if (fc > 4 && isState) fc = 4;
                if (fc > 4 && attr.SURFACE_TYPE === 20) {
                    return fc < 7 ? 'PSGr' : 'StGr';
                }
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        KS: {
            baseUrl: 'http://wfs.ksdot.org/arcgis_web_adaptor/rest/services/Transportation/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 3,
                    layerPath: 'Functional_Classification/MapServer/',
                    idPropName: 'Id',
                    fcPropName: 'FunctionalClassification',
                    outFields: ['FunctionalClassification', 'Id'],
                    roadTypeMap: {
                        Fw: [1],
                        MH: [2, 3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                },

                // 2024-03-20 (mapomatic) The "non-state system" layer was removed from the KS server,
                // so we're forced to use the function_classification layer (above) which doesn't include
                // any metadata for US/state road designations. I'm leaving the old layers commented below
                // in case they're of use in the future.

                // {
                //     layerID: 0,
                //     layerPath: 'Non_State_System/MapServer/',
                //     idPropName: 'ID2',
                //     fcPropName: 'FUNCLASS',
                //     outFields: ['FUNCLASS', 'ID2', 'ROUTE_ID'],
                //     roadTypeMap: {
                //         Fw: [1], MH: [2, 3], mH: [4], PS: [5, 6], St: [7]
                //     },
                //     maxRecordCount: 1000,
                //     supportsPagination: false
                // },
                {
                    layerID: 0,
                    layerPath: 'State_System/MapServer/',
                    idPropName: 'OBJECTID',
                    fcPropName: 'FUN_CLASS_CD',
                    outFields: ['FUN_CLASS_CD', 'OBJECTID', 'NHS'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            isPermitted() {
                return rank >= 3 || isAM;
            },
            information: { Source: 'KDOT', Permission: 'Visible to area managers', Description: 'Federal and State highways set to a minimum of mH.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName}<>'7'`;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                const attr = feature.attributes;
                let fc = parseInt(attr[layer.fcPropName], 10);
                const roadNHS = attr.NHS;
                const isUS = roadNHS === 'YES';
                const isState = roadNHS === 'NO';
                if (fc > 3 && isUS) fc = 3;
                else if (fc > 4 && isState) fc = 4;
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        KY: {
            baseUrl: 'https://maps.kytc.ky.gov/arcgis/rest/services/BaseMap/System/MapServer/',
            supportsPagination: false,
            defaultColors: {
                Fw: '#ffaac5',
                Ew: '#ff00c5',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1] },
            /* eslint-disable object-curly-newline */
            fcMapLayers: [
                {
                    layerID: 0,
                    idPropName: 'OBJECTID',
                    fcPropName: 'FC',
                    outFields: ['FC', 'OBJECTID', 'RT_PREFIX', 'RT_SUFFIX'],
                    roadTypeMap: { Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5, 6], St: [7] },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            isPermitted() {
                return true;
            },
            information: { Source: 'KYTC', Permission: 'Visible to All', Description: 'Federal and State highways set to a minimum of mH.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName}<7`;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                const attr = feature.attributes;
                let fc = parseInt(attr[layer.fcPropName], 10);
                if (fc > 3 && attr.RT_PREFIX === 'US') {
                    const suffix = attr.RT_SUFFIX;
                    fc = suffix && suffix.indexOf('X') > -1 ? 4 : 3;
                }
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        LA: {
            baseUrl: 'https://maps.dotd.la.gov/road/rest/services/Roads_and_Highways_OpenData/FeatureServer/',
            supportsPagination: false,
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            /* eslint-disable object-curly-newline */
            fcMapLayers: [
                {
                    layerID: 84,
                    fcPropName: 'FunctionalSystem',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FunctionalSystem', 'RouteID'],
                    roadTypeMap: { Fw: [1], Ew: [2], MH: [3], mH: [4], PS: [5, 6], St: [7] },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            /* eslint-enable object-curly-newline */
            information: { Source: 'LaDOTD', Permission: 'Visible to R4+ or R3-AM', Description: 'Federal and State highways set to a minimum of mH.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName}<7`;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                let fc = feature.attributes[layer.fcPropName];
                if (fc === '2a' || fc === '2b') {
                    fc = 2;
                }
                fc = parseInt(fc, 10);
                const route = feature.attributes.RouteID.split('_')[1].trim();
                const isUS = /^US \d/.test(route);
                const isState = /^LA \d/.test(route);
                const isBiz = / BUS$/.test(route);
                if (fc > 3 && isUS) fc = isBiz ? 4 : 3;
                else if (fc > 4 && isState) fc = isBiz ? 5 : 4;
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        ME: {
            baseUrl: 'https://arcgisserver.maine.gov/arcgis/rest/services/mdot/MaineDOT_Dynamic/MapServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 6,
                    fcPropName: 'fedfunccls',
                    idPropName: 'objectid',
                    outFields: ['objectid', 'fedfunccls'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            information: { Source: 'MaineDOT', Permission: 'Visible to R4+ or R3-AM', Description: 'Raw unmodified FC data.' },
            isPermitted() {
                return rank >= 4 || (rank === 3 && isAM);
            },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName}<>'Local'`;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                const attr = feature.attributes;
                let fc = attr[layer.fcPropName];
                switch (fc) {
                    case 'Interstate':
                        fc = 1;
                        break;
                    case 'Other Freeway or Expressway':
                        fc = 2;
                        break;
                    case 'Other Principal Arterial':
                        fc = 3;
                        break;
                    case 'Minor Arterial':
                        fc = 4;
                        break;
                    case 'Major Collector':
                    case 'Minor Collector':
                        fc = 5;
                        break;
                    default:
                        fc = 7;
                }
                // 2024-6-28 (mapomatic) MaineDOT removed the prirtename field so we can't "upgrade" FC anymore.
                // const route = attr.prirtename;
                // const isUS = /^US \d/.test(route);
                // const isState = /^ST RTE \d/.test(route);
                // const isBiz = (isUS && /(1B|1BS)$/.test(route)) || (isState && /(15B|24B|25B|137B)$/.test(route));
                // if (fc > 3 && isUS) fc = isBiz ? 4 : 3;
                // else if (fc > 4 && isState) fc = isBiz ? 5 : 4;
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        MD: {
            baseUrl: 'https://services.arcgis.com/njFNhDsUCentVYJW/arcgis/rest/services/MDOT_SHA_Roadway_Functional_Classification/FeatureServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#ffff00',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 0,
                    fcPropName: 'FUNCTIONAL_CLASS',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNCTIONAL_CLASS', 'ID_PREFIX', 'MP_SUFFIX'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            information: { Source: 'MDOT', Permission: 'Visible to R4+ or R3-AM', Description: 'Federal and State highways set to a minimum of mH.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return "(FUNCTIONAL_CLASS < 7 OR ID_PREFIX IN('MD'))";
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                const attr = feature.attributes;
                let fc = parseInt(attr.FUNCTIONAL_CLASS, 10);
                const isUS = attr.ID_PREFIX === 'US';
                const isState = attr.ID_PREFIX === 'MD';
                const isBiz = attr.MP_SUFFIX === 'BU';
                if (fc > 3 && isUS) fc = isBiz ? 4 : 3;
                else if (fc > 4 && isState) fc = isBiz ? 5 : 4;
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        MA: {
            baseUrl: 'https://gis.massdot.state.ma.us/arcgis/rest/services/Roads/RoadInventory/MapServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 0,
                    fcPropName: 'F_F_Class',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'F_F_Class', 'route_id'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            information: { Source: 'MDOT', Permission: 'Visible to R2+', Description: 'Federal and State highways set to a minimum of mH.' },
            isPermitted() {
                return rank >= 2;
            },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName}<>7`;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                const attr = feature.attributes;
                let fc = parseInt(attr[layer.fcPropName], 10);
                const route = attr.route_id;
                const isUS = /^US\d/.test(route);
                const isState = /^SR\d/.test(route);
                if (fc > 3 && isUS) fc = 3;
                else if (fc > 4 && isState) fc = 4;
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        MI: {
            baseUrl: 'https://mdotgis.state.mi.us/arcgis/rest/services/DataAccess/NfcNhsPub/MapServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#149ece',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 353,
                    idPropName: 'OBJECTID',
                    fcPropName: 'FunctionalSystem',
                    outFields: ['FunctionalSystem'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            isPermitted() {
                return true;
            },
            information: { Source: 'MDOT', Permission: 'Visible to All', Description: 'Raw unmodified FC data.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName}<7`;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                if (layer.getFeatureRoadType) {
                    return layer.getFeatureRoadType(feature);
                }
                return STATE_SETTINGS.global.getFeatureRoadType(feature, layer);
            }
        },
        MN: {
            baseUrl: 'https://dotapp9.dot.state.mn.us/lrs/rest/services/emma/emma_op/MapServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#149ece',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 13,
                    idPropName: 'OBJECTID',
                    fcPropName: 'FUNCTIONAL_CLASS',
                    outFields: ['FUNCTIONAL_CLASS', 'ROUTE_ID'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            isPermitted() {
                return true;
            },
            information: { Source: 'MnDOT', Permission: 'Visible to All', Description: 'Raw unmodified FC data.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName}<>7`;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                if (layer.getFeatureRoadType) {
                    return layer.getFeatureRoadType(feature);
                }
                return STATE_SETTINGS.global.getFeatureRoadType(feature, layer);
            }
        },
        MO: {
            baseUrl: 'https://mapping.modot.org/arcgis/rest/services/BaseMap/TmsUtility/MapServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 5,
                    fcPropName: 'FUNC_CLASS_NAME',
                    idPropName: 'SS_PAVEMENT_ID',
                    outFields: ['SS_PAVEMENT_ID', 'FUNC_CLASS_NAME', 'TRAVELWAY_DESG', 'TRAVELWAY_NAME', 'ACCESS_CAT_NAME'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            isPermitted() {
                return rank >= 3 || (rank >= 2 && isAM);
            },
            information: { Source: 'MoDOT', Permission: 'Visible to R3+ or R2-AM', Description: 'Federal and State highways set to a minimum of mH.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 13) {
                    return '1=0'; // WME very laggy at zoom 0
                }
                // Remove duplicate rows, but suss out interstate business loops
                return "FUNC_CLASS_NAME <> ' ' AND (TRAVELWAY_ID = CNTL_TW_ID OR (TRAVELWAY_ID <> CNTL_TW_ID AND TRAVELWAY_DESG = 'LP'))";
            },
            getFeatureRoadType(feature, layer) {
                const attr = feature.attributes;
                let fc = attr[layer.fcPropName];
                const rtType = attr.TRAVELWAY_DESG;
                const route = attr.TRAVELWAY_NAME;
                switch (fc) {
                    case 'INTERSTATE':
                        fc = 1;
                        break;
                    case 'FREEWAY':
                        fc = 2;
                        break;
                    case 'PRINCIPAL ARTERIAL':
                        fc = 3;
                        break;
                    case 'MINOR ARTERIAL':
                        fc = 4;
                        break;
                    case 'MAJOR COLLECTOR':
                        fc = 5;
                        break;
                    case 'MINOR COLLECTOR':
                        fc = 6;
                        break;
                    default:
                        fc = 8; // not a typo
                }
                const usHwys = ['24', '36', '40', '50', '54', '56', '59', '60', '61', '62', '63', '65', '67', '69', '71', '136', '159', '160', '166', '169', '275', '400', '412'];
                const isUS = ['US', 'LP'].includes(rtType); // is US or interstate biz
                const isState = ['MO', 'AL'].includes(rtType);
                const isSup = rtType === 'RT';
                const isBiz = ['BU', 'SP'].includes(rtType) || /BUSINESS .+ \d/.test(route);
                const isUSBiz = isBiz && usHwys.includes(route);
                if ((fc === 2 && attr.ACCESS_CAT_NAME !== 'FULL') || (fc > 3 && isUS)) fc = 3;
                else if (fc > 4 && (isState || isUSBiz)) fc = 4;
                else if (fc > 6 && (isSup || isBiz)) fc = 6;
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        MT: {
            baseUrl: 'https://app.mdt.mt.gov/arcgis/rest/services/Standard/FUNCTIONAL_CLASS/MapServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 0,
                    fcPropName: 'FUNC_CLASS',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNC_CLASS', 'SIGN_ROUTE', 'ROUTE_NAME'],
                    roadTypeMap: {
                        Fw: ['1-Interstate']
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                },
                {
                    layerID: 1,
                    fcPropName: 'FUNC_CLASS',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNC_CLASS', 'SIGN_ROUTE', 'ROUTE_NAME'],
                    roadTypeMap: {
                        MH: ['3-Principal Arterial - Other']
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                },
                {
                    layerID: 2,
                    fcPropName: 'FUNC_CLASS',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNC_CLASS', 'SIGN_ROUTE', 'ROUTE_NAME'],
                    roadTypeMap: {
                        mH: ['4-Minor Arterial']
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                },
                {
                    layerID: 3,
                    fcPropName: 'FUNC_CLASS',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNC_CLASS', 'SIGN_ROUTE', 'ROUTE_NAME'],
                    roadTypeMap: {
                        PS: ['5-Major Collector']
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                },
                {
                    layerID: 4,
                    fcPropName: 'FUNC_CLASS',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNC_CLASS', 'SIGN_ROUTE', 'ROUTE_NAME'],
                    roadTypeMap: {
                        PS: ['6-Minor Collector']
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                },
                {
                    layerID: 5,
                    fcPropName: 'FUNC_CLASS',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNC_CLASS', 'SIGN_ROUTE', 'ROUTE_NAME'],
                    roadTypeMap: {
                        St: ['7-Local']
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            isPermitted() {
                /* return _r >= 3; */ return ['mapomatic', 'bobc455', 'js55ct'].includes(userNameLC);
            },
            information: { Source: 'MDT', Permission: '?', Description: 'Federal and State highways set to a minimum of mH.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName}<>'LOCAL'`;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                let rt = STATE_SETTINGS.global.getFeatureRoadType(feature, layer);
                const roadID = feature.attributes.SIGN_ROUTE || feature.attributes.ROUTE_NAME;
                const isUS = /^US[ -]?\d+/.test(roadID);
                const isState = /^MONTANA \d+|ROUTE \d+|S-\d{3}\b/.test(roadID);
                if (isUS && ['St', 'PS', 'mH'].includes(rt)) {
                    rt = 'MH';
                } else if (isState && ['St', 'PS'].includes(rt)) {
                    rt = 'mH';
                }
                return rt;
            }
        },
        NV: {
            baseUrl: 'https://gis.dot.nv.gov/rhgis/rest/services/GeoHub/FSystem/MapServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [[], [], [], [], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 0,
                    fcPropName: 'FSystem',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FSystem'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            isPermitted() {
                return ['mapomatic', 'turbomkt', 'tonestertm', 'geopgeop', 'ojlaw', 'js55ct'].includes(userNameLC);
            },
            information: { Source: 'NDOT', Permission: '?', Description: 'Raw unmodified FC data.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName}<7`;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                const fc = parseInt(feature.attributes[layer.fcPropName], 10);
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        NH: {
            baseUrl: 'https://maps.dot.nh.gov/arcgis_server/rest/services/Highways/NHDOT_HIGHWAYS_Functional_System/FeatureServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [[], [], [], [], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 19, // 0
                    fcPropName: 'FUNCT_SYSTEM',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNCT_SYSTEM', 'STREET', 'TIER'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [2, 3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7, 0]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            isPermitted() {
                return rank >= 2;
            },
            information: { Source: 'NH GRANIT', Permission: 'Visible to R2+', Description: 'Federal and State highways set to a minimum of mH.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName}>0 AND ${context.layer.fcPropName}<7`;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                let fc = parseInt(feature.attributes[layer.fcPropName], 10);
                if (!(fc > 0)) {
                    fc = 7;
                }
                const route = feature.attributes.STREET_ALIASES;
                const isUS = /US /.test(route);
                const isState = /NH /.test(route);
                if (fc === 2) fc = feature.attributes.TIER === 1 ? 1 : 3;
                else if (fc > 3 && isUS) fc = /US 3B/.test(route) ? 4 : 3;
                else if (fc > 4 && isState) fc = 4;
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        NM: {
            baseUrl: 'https://services.arcgis.com/hOpd7wfnKm16p9D9/ArcGIS/rest/services/NMDOT_Functional_Class/FeatureServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#ff00c5',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1] },
            fcMapLayers: [
                {
                    layerID: 0,
                    fcPropName: 'FSystem',
                    idPropName: 'OBJECTID',
                    maxRecordCount: 1000,
                    supportsPagination: false,
                    outFields: ['OBJECTID', 'FSystem', 'RouteID'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7, 0]
                    }
                }
            ],
            isPermitted() {
                return true;
            },
            information: { Source: 'NMDOT', Permission: 'Visible to All', Description: 'Federal and State highways set to a minimum of mH.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName}>0 AND ${context.layer.fcPropName}<7`;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                let fc = parseInt(feature.attributes[layer.fcPropName], 10);
                const roadType = feature.attributes.RouteID.substring(0, 2); // Get first two characters
                const isBiz = roadType === 'BL'; // Interstate Business Loop
                const isUS = roadType === 'US';
                const isState = roadType === 'NM';

                if (roadType === 'IX') {
                    fc = 0;
                } else if (fc > 3 && (isBiz || isUS)) {
                    fc = 3;
                } else if (fc > 4 && isState) {
                    fc = 4;
                }

                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        NY: {
            // https://gis.dot.ny.gov/hostingny/rest/services/Basemap/MapServer/21
            baseUrl: 'https://gis.dot.ny.gov/hostingny/rest/services/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#5f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1] },
            fcMapLayers: [
                {
                    layerID: 1,
                    layerPath: 'Geocortex/FC/MapServer/',
                    fcPropName: 'FUNC_CLASS',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNC_CLASS', 'SEGMENT_NAME', 'ROUTE_NO'],
                    roadTypeMap: {
                        Fw: [1, 11],
                        Ew: [2, 12],
                        MH: [4, 14],
                        mH: [6, 16],
                        PS: [7, 8, 17, 18],
                        St: [9, 19]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                },
                {
                    layerID: 21,
                    layerPath: 'Basemap/MapServer/',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'SHIELD'],
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            information: { Source: 'NYSDOT', Permission: 'Visible to R4+ or R3-AM', Description: 'Federal and State highways set to a minimum of mH.' },
            getWhereClause(context) {
                if (context.layer.layerID === 21) {
                    return "SHIELD IN ('C','CT')";
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                let roadType;
                if (layer.layerID === 21) {
                    roadType = 'PS';
                } else {
                    roadType = STATE_SETTINGS.global.getFeatureRoadType(feature, layer);
                    const routeNo = feature.attributes.ROUTE_NO;
                    if (/^NY.*/.test(routeNo)) {
                        if (roadType === 'PS') roadType = 'mH';
                    } else if (/^US.*/.test(routeNo)) {
                        if (roadType === 'PS' || roadType === 'mH') roadType = 'MH';
                    }
                }
                return roadType;
            }
        },
        NC: {
            baseUrl: 'https://gis11.services.ncdot.gov/arcgis/rest/services/NCDOT_FunctionalClassQtr/MapServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Rmp: '#999999',
                Ew: '#5f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 0,
                    fcPropName: 'FuncClass',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FuncClass', 'RouteClass', 'RouteQualifier'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    zoomLevels: [3, 4, 5, 6, 7, 8, 9, 10],
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            isPermitted() {
                return rank >= 3;
            },
            information: { Source: 'NCDOT', Permission: 'Visible to R3+', Description: 'Federal and State highways set to a minimum of mH.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    const clause = `(${context.layer.fcPropName} < 7 OR RouteClass IN ('I','FED','NC','RMP','US'))`;
                    return clause;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                const fc = feature.attributes[layer.fcPropName];
                let roadType;
                switch (this.getHwySys(feature)) {
                    case 'interstate':
                        if (fc <= 2 || !this.isBusinessRoute(feature)) roadType = 'Fw';
                        else roadType = 'MH';
                        break;
                    case 'us':
                        if (fc <= 2) roadType = 'Ew';
                        else if (fc === 3 || !this.isBusinessRoute(feature)) roadType = 'MH';
                        else roadType = 'mH';
                        break;
                    case 'state':
                        if (fc <= 2) roadType = 'Ew';
                        else if (fc === 3) roadType = 'MH';
                        else if (fc === 4 || !this.isBusinessRoute(feature)) roadType = 'mH';
                        else roadType = 'PS';
                        break;
                    case 'ramp':
                        roadType = 'Rmp';
                        break;
                    default:
                        if (fc === 2) roadType = 'Ew';
                        else if (fc === 3) roadType = 'MH';
                        else if (fc === 4) roadType = 'mH';
                        else if (fc <= 6) roadType = 'PS';
                        else roadType = 'St';
          // roadType = fc === 2 ? 'Ew' : (fc === 3 ? 'MH' : (fc === 4 ? 'mH' : (fc <= 6 ? 'PS' : 'St')));
                }
                return roadType;
            },
            getHwySys(feature) {
                let hwySys;
                switch (feature.attributes.RouteClass.toString()) {
                    case '1':
                        hwySys = 'interstate';
                        break;
                    case '2':
                        hwySys = 'us';
                        break;
                    case '3':
                        hwySys = 'state';
                        break;
                    case '80':
                        hwySys = 'ramp';
                        break;
                    default:
                        hwySys = 'local';
                }
                return hwySys;
            },
            isBusinessRoute(feature) {
                const qual = feature.attributes.RouteQualifier.toString();
                return qual === '9';
            }
        },
        ND: {
            baseUrl: 'https://ndgishub.nd.gov/arcgis/rest/services/Basemap_General/MapServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#149ece',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 193,
                    fcPropName: 'FUNCTIONAL_CLASS',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNCTIONAL_CLASS'],
                    roadTypeMap: {
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                },
                {
                    layerID: 192,
                    fcPropName: 'RTE_SIN',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'RTE_SIN'],
                    roadTypeMap: {
                        Fw: ['I'],
                        MH: ['U'],
                        mH: ['S']
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            information: { Source: 'NDDOT', Permission: 'Visible to R4+ or R3-AM', Description: 'Federal and State highways set to a minimum of mH.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    if (context.layer.layerID === 193) {
                        return `${context.layer.fcPropName} < 7`;
                    }
                    if (context.layer.layerID === 192) {
                        return "RTE_SIN IN ('I','U','S')";
                    }
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                if (layer.getFeatureRoadType) {
                    return layer.getFeatureRoadType(feature);
                }
                return STATE_SETTINGS.global.getFeatureRoadType(feature, layer);
            }
        },
        OH: {
            baseUrl: 'https://gis.dot.state.oh.us/arcgis/rest/services/TIMS/Roadway_Information/MapServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },

            fcMapLayers: [
                {
                    layerID: 8,
                    fcPropName: 'FUNCTION_CLASS_CD',
                    idPropName: 'ObjectID',
                    outFields: ['FUNCTION_CLASS_CD', 'ROUTE_TYPE', 'ROUTE_NBR', 'ObjectID'],
                    maxRecordCount: 1000,
                    supportsPagination: false,
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    }
                }
            ],
            isPermitted() {
                return true;
            },
            information: { Source: 'ODOT', Permission: 'Visible to All', Description: 'Federal and State highways set to a minimum of mH.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    const clause = `(${context.layer.fcPropName} < 7 OR ROUTE_TYPE IN ('CR','SR','US')) AND ${context.layer.fcPropName} IS NOT NULL`;
                    return clause;
                }
                return `${context.layer.fcPropName} IS NOT NULL`;
            },
            getFeatureRoadType(feature, layer) {
                let fc = feature.attributes[layer.fcPropName];
                const prefix = feature.attributes.ROUTE_TYPE;
                const isUS = prefix === 'US';
                const isState = prefix === 'SR';
                const isCounty = prefix === 'CR';
                if (isUS && fc > 3) {
                    fc = 3;
                }
                if (isState && fc > 4) {
                    fc = 4;
                }
                if (isCounty && fc > 6) {
                    fc = 6;
                }
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        OK: {
            baseUrl: 'https://services6.arcgis.com/RBtoEUQ2lmN0K3GY/arcgis/rest/services/Roadways/FeatureServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 0,
                    fcPropName: 'FUNCTIONALCLASS',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNCTIONALCLASS', 'FHWAPRIMARYROUTE', 'ODOTROUTECLASS', 'ACCESSCONTROL'],
                    maxRecordCount: 1000,
                    supportsPagination: false,
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    }
                }
            ],
            information: { Source: 'ODOT', Permission: 'Visible to R4+ or R3-AM', Description: 'Federal and State highways set to a minimum of mH.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName} < 7 OR ODOTROUTECLASS IN ('U','S','I')`;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                let fc = feature.attributes[layer.fcPropName];
                const route = (feature.attributes.FHWAPRIMARYROUTE || '').trim();
                const isBusinessOrSpur = /BUS$|SPR$/i.test(route);
                const prefix = isBusinessOrSpur ? route.substring(0, 1) : feature.attributes.ODOTROUTECLASS;
                const isFw = parseInt(feature.attributes.ACCESSCONTROL, 10) === 1;
                const isInterstate = prefix === 'I';
                const isUS = prefix === 'U';
                const isState = prefix === 'S';
                if (isFw) fc = 1;
                else if (fc > 3 && ((isUS && !isBusinessOrSpur) || (isInterstate && isBusinessOrSpur))) fc = 3;
                else if (fc > 4 && ((isUS && isBusinessOrSpur) || (isState && !isBusinessOrSpur))) fc = 4;
                else if (fc > 5 && isState && isBusinessOrSpur) fc = 5;
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        OR: {
            baseUrl: 'https://gis.odot.state.or.us/arcgis1006/rest/services/transgis/catalog/MapServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 171,
                    fcPropName: 'NEW_FC_CD',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'NEW_FC_CD'],
                    roadTypeMap: {
                        Fw: ['1'],
                        Ew: ['2'],
                        MH: ['3'],
                        mH: ['4'],
                        PS: ['5', '6'],
                        St: ['7']
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                },
                {
                    layerID: 173,
                    fcPropName: 'NEW_FC_CD',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'NEW_FC_CD'],
                    roadTypeMap: {
                        Fw: ['1'],
                        Ew: ['2'],
                        MH: ['3'],
                        mH: ['4'],
                        PS: ['5', '6'],
                        St: ['7']
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            information: { Source: 'ODOT', Permission: 'Visible to R4+ or R3-AM', Description: 'Raw unmodified FC data.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName} < 7`;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                if (layer.getFeatureRoadType) {
                    return layer.getFeatureRoadType(feature);
                }
                return STATE_SETTINGS.global.getFeatureRoadType(feature, layer);
            }
        },
        PA: {
            baseUrl: 'https://gis.penndot.gov/arcgis/rest/services/opendata/roadwayadmin/MapServer/',
            supportsPagination: false,
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 0,
                    features: new Map(),
                    fcPropName: 'FUNC_CLS',
                    idPropName: 'MSLINK',
                    outFields: ['MSLINK', 'FUNC_CLS'],
                    maxRecordCount: 1000,
                    supportsPagination: false,
                    roadTypeMap: {
                        Fw: ['01', '11'],
                        Ew: ['12'],
                        MH: ['02', '14'],
                        mH: ['06', '16'],
                        PS: ['07', '08', '17'],
                        St: ['09', '19']
                    }
                }
            ],
            isPermitted() {
                return rank >= 4;
            },
            information: { Source: 'PennDOT', Permission: 'Visible to R4+', Description: 'Raw unmodified FC data.' },
            getWhereClause(context) {
                return context.mapContext.zoom < 16 ? `${context.layer.fcPropName} NOT IN ('09','19')` : null;
            },
            getFeatureRoadType(feature, layer) {
                if (layer.getFeatureRoadType) {
                    return layer.getFeatureRoadType(feature);
                }
                const fc = feature.attributes[layer.fcPropName];
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        RI: {
            baseUrl: 'https://services2.arcgis.com/S8zZg9pg23JUEexQ/arcgis/rest/services/RIDOT_Roads_2016/FeatureServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [[], [], [], [], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 0,
                    fcPropName: 'F_SYSTEM',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'F_SYSTEM', 'ROADTYPE', 'RTNO'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7, 0]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            isPermitted() {
                return rank >= 2;
            },
            information: { Source: 'RIDOT', Permission: 'Visible to R2+', Description: 'Federal and State highways set to a minimum of mH.' },
            getWhereClause(context) {
                return context.mapContext.zoom < 16 ? `${context.layer.fcPropName} NOT IN (7,0)` : null;
            },
            getFeatureRoadType(feature, layer) {
                let fc = parseInt(feature.attributes[layer.fcPropName], 10);
                const type = feature.attributes.ROADTYPE;
                const rtnum = feature.attributes.RTNO;
                if (fc === 2 && ['10', '24', '37', '78', '99', '138', '403'].includes(rtnum)) fc = 1; // isFW
                else if ((fc > 3 && type === 'US') || rtnum === '1') fc = 3; // isUS
                else if (fc > 4 && rtnum.trim() !== '') fc = 4; // isState
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        SC: {
            baseUrl: 'https://services1.arcgis.com/VaY7cY9pvUYUP1Lf/ArcGIS/rest/services/FunctionalClass/FeatureServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 0,
                    fcPropName: 'Functional',
                    idPropName: 'FID',
                    outFields: ['FID', 'Functional', 'RouteType'],
                    maxRecordCount: 1000,
                    supportsPagination: false,
                    roadTypeMap: {
                        Fw: [1, 11],
                        Ew: [6, 12],
                        MH: [2, 13],
                        mH: [3, 14],
                        PS: [4, 5, 15, 16],
                        St: []
                    }
                }
            ],
            isPermitted() {
                return rank >= 4;
            },
            information: { Source: 'SCDOT', Permission: 'Visible to R4+', Description: 'Federal and State highways set to a minimum of mH.' },
            getWhereClause() {
                return null;
            },
            getFeatureRoadType(feature, layer) {
                const SCroadType = feature.attributes.RouteType;
                const isFw = SCroadType === 1;
                const isUS = SCroadType === 2;
                const isState = SCroadType === 4;

                let roadType = STATE_SETTINGS.global.getFeatureRoadType(feature, layer);
                if (roadType === 'Fw' || roadType === 'Ew' || isFw) {
                    roadType = 'Fw';
                } else if ((roadType === 'mH' || roadType === 'PS') && isUS) {
                    roadType = 'MH';
                } else if (roadType === 'PS' && isState) {
                    roadType = 'mH';
                }
                return roadType;
            }
        },
        SD: {
            baseUrl: 'https://arcgis.sd.gov/arcgis/rest/services/SD_All/Transportation_Roads/MapServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#149ece',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee',
                PSGr: '#cc6533',
                StGr: '#e99cb6'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 1,
                    fcPropName: 'HighwayClass',
                    idPropName: 'GisHighwayCategoryID',
                    maxRecordCount: 1000,
                    supportsPagination: false,
                    outFields: ['GisHighwayCategoryID', 'HighwayClass'],
                    roadTypeMap: {
                        Fw: ['IN'],
                        MH: ['US'],
                        mH: ['SD']

                    }
                },
                {
                    layerID: 2,
                    fcPropName: 'FUNC_CLASS',
                    idPropName: 'OBJECTID',
                    maxRecordCount: 1000,
                    supportsPagination: false,
                    outFields: ['OBJECTID', 'FUNC_CLASS', 'SURFACE_TYPE', 'ROADNAME'],
                    roadTypeMap: {
                        Fw: [1, 11],
                        Ew: [2, 12],
                        MH: [4, 14],
                        mH: [6, 16],
                        PS: [7, 8, 17],
                        St: [9, 19]
                    }
                }
            ],
            information: { Source: 'SDDOT', Permission: 'Visible to R4+ or R3-AM', Description: 'Additional colors denote unpaved PS and LS segements.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    if (context.layer.layerID === 2) {
                        return `${context.layer.fcPropName} NOT IN (9,19)`;
                    }
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                const attr = feature.attributes;
                let fc = attr[layer.fcPropName];
                const fc2 = parseInt(fc, 10) % 10;

                const isUS = /^US HWY /i.test(attr.ROADNAME);
                const isState = /^SD HWY /i.test(attr.ROADNAME);
                const isBiz = /^(US|SD) HWY .* (E|W)?(B|L)$/i.test(attr.ROADNAME);
                const isPaved = parseInt(attr.SURFACE_TYPE, 10) > 5;

                if (fc2 > 4 && isUS) fc = isBiz ? 6 : 4;
                else if (fc2 > 6 && isState) fc = isBiz ? 7 : 6;
                if (fc2 > 6 && !isPaved) {
                    return fc < 9 ? 'PSGr' : 'StGr';
                }
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        TN: {
            baseUrl: 'https://',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                PS2: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1] },
            fcMapLayers: [
                {
                    layerPath: 'services2.arcgis.com/nf3p7v7Zy4fTOh6M/ArcGIS/rest/services/Road_Segment/FeatureServer/',
                    maxRecordCount: 1000,
                    supportsPagination: false,
                    layerID: 0,
                    fcPropName: 'FUNC_CLASS',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNC_CLASS', 'NBR_RTE', 'NBR_US_RTE'],
                    getWhereClause(context) {
                        if (context.mapContext.zoom < 16) {
                            return `${context.layer.fcPropName} NOT LIKE '%Local'`;
                        }
                        return null;
                    },
                    roadTypeMap: {
                        Fw: ['Urban Interstate', 'Rural Interstate'],
                        Ew: ['Urban Freeway or Expressway', 'Rural Freeway or Expressway'],
                        MH: ['Urban Other Principal Arterial', 'Rural Other Principal Arterial'],
                        mH: ['Urban Minor Arterial', 'Rural Minor Arterial'],
                        PS: ['Urban Major Collector', 'Rural Major Collector'],
                        PS2: ['Urban Minor Collector', 'Rural Minor Collector'],
                        St: ['Urban Local', 'Rural Local']
                    }
                }
            ],
            information: {
                Source: 'Memphis, Nashville Area MPO',
                Permission: 'Visible to R4+ or R3-AM',
                Description: 'Raw unmodified FC data for the Memphis and Nashville regions only.'
            },
            getWhereClause(context) {
                if (context.layer.getWhereClause) {
                    return context.layer.getWhereClause(context);
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                if (layer.getFeatureRoadType) {
                    return layer.getFeatureRoadType(feature);
                }
                let fc = STATE_SETTINGS.global.getRoadTypeFromFC(feature.attributes.FUNC_CLASS, layer);
                if ((fc === 'PS' || fc === 'mH') && feature.attributes.NBR_US_RTE != null) {
                    fc = feature.attributes.NBR_US_RTE.endsWith('BR') ? 'mH' : 'MH';
                } else if (fc === 'PS' && (feature.attributes.NBR_RTE.startsWith('SR') || feature.attributes.NBR_RTE.startsWith('TN'))) {
                    fc = 'mH';
                }
                return fc;
            }
        },
        TX: {
            baseUrl: 'https://services.arcgis.com/KTcxiTD9dsQw4r7Z/ArcGIS/rest/services/TxDOT_Functional_Classification/FeatureServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1] },
            fcMapLayers: [
                {
                    layerID: 0,
                    fcPropName: 'F_SYSTEM',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'F_SYSTEM', 'RTE_PRFX'],
                    maxRecordCount: 1000,
                    supportsPagination: false,
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    }
                }
            ],
            isPermitted() {
                return rank >= 2;
            },
            information: { Source: 'TxDOT', Permission: 'Visible to R2+', Description: 'Federal and State highways set to a minimum of mH.' },
            getWhereClause(context) {
                let where = ' F_SYSTEM IS NOT NULL AND RTE_PRFX IS NOT NULL';
                if (context.mapContext.zoom < 16) {
                    where += ` AND ${context.layer.fcPropName} <> 7`;
                }
                return where;
            },
            getFeatureRoadType(feature, layer) {
                // On-System:
                // IH=Interstate BF=Business FM
                // US=US Highway FM=Farm to Mkt
                // UA=US Alt. RM=Ranch to Mkt
                // UP=US Spur RR=Ranch Road
                // SH=State Highway PR=Park Road
                // SA=State Alt. RE=Rec Road
                // SL=State Loop RP=Rec Rd Spur
                // SS=State Spur FS=FM Spur
                // BI=Business IH RS=RM Spur
                // BU=Business US RU=RR Spur
                // BS=Business State PA=Principal Arterial
                // Off-System:
                // TL=Off-System Tollroad CR=County Road
                // FC=Func. Classified St. LS=Local Street
                if (layer.getFeatureRoadType) {
                    return layer.getFeatureRoadType(feature);
                }
                let fc = feature.attributes[layer.fcPropName];
                const type = feature.attributes.RTE_PRFX.substring(0, 2).toUpperCase();
                if (type === 'IH' && fc > 1) {
                    fc = 1;
                } else if ((type === 'US' || type === 'BI' || type === 'UA') && fc > 3) {
                    fc = 3;
                } else if ((type === 'UP' || type === 'BU' || type === 'SH' || type === 'SA') && fc > 4) {
                    fc = 4;
                } else if ((type === 'SL' || type === 'SS' || type === 'BS') && fc > 6) {
                    fc = 6;
                }
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        UT: {
            baseUrl: 'https://roads.udot.utah.gov/server/rest/services/Public/Functional_Class/MapServer/0',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 0,
                    fcPropName: 'FUNCTIONAL_CLASS',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNCTIONAL_CLASS', 'route_id'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            information: { Source: 'UDOT', Permission: 'Visible to R4+ or R3-AM', Description: 'Federal and State highways set to a minimum of mH.' },
            getWhereClause(context) {
                return `${context.layer.fcPropName} NOT LIKE 'Proposed%'`;
            },
            getFeatureRoadType(feature, layer) {
                const attr = feature.attributes;
                let fc = attr[layer.fcPropName];
                const routeID = attr.route_id;
                const roadNum = parseInt(routeID.substring(0, 4), 10);
                switch (fc) {
                    case 'Interstate':
                        fc = 1;
                        break;
                    case 'Other Freeways and Expressways':
                        fc = 2;
                        break;
                    case 'Other Principal Arterial':
                        fc = 3;
                        break;
                    case 'Minor Arterial':
                        fc = 4;
                        break;
                    case 'Major Collector':
                        fc = 5;
                        break;
                    case 'Minor Collector':
                        fc = 6;
                        break;
                    default:
                        fc = 7;
                }
                const re = /^(6|40|50|89|91|163|189|191|491)$/;
                if (re.test(roadNum) && fc > 3) {
                    // US highway
                    fc = 3;
                } else if (roadNum <= 491 && fc > 4) {
                    // State highway
                    fc = 4;
                }
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        VT: {
            baseUrl: 'https://maps.vtrans.vermont.gov/arcgis/rest/services/Master/General/FeatureServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 39,
                    fcPropName: 'FUNCL',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FUNCL', 'HWYSIGN'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            information: { Source: 'VTrans', Permission: 'Visible to R2+' },
            isPermitted() {
                return rank >= 2;
            },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName}<>7 AND ${context.layer.fcPropName}<>0`;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                const roadID = feature.attributes.HWYSIGN;
                let fc = feature.attributes[layer.fcPropName];
                if (!(fc > 0)) {
                    fc = 7;
                }
                const isUS = /^U/.test(roadID);
                const isState = /^V/.test(roadID);
                const isUSBiz = /^B/.test(roadID);
                if (fc > 3 && isUS) fc = 3;
                else if (fc > 4 && (isUSBiz || isState)) fc = 4;
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        VA: {
            baseUrl: 'https://services.arcgis.com/p5v98VHDX9Atv3l7/arcgis/rest/services/FC_2014_FHWA_Submittal1/FeatureServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#ff00c5',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 0,
                    fcPropName: 'STATE_FUNCT_CLASS_ID',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'STATE_FUNCT_CLASS_ID', 'RTE_NM'],
                    maxRecordCount: 2000,
                    supportsPagination: true,
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    }
                },
                {
                    layerID: 1,
                    fcPropName: 'STATE_FUNCT_CLASS_ID',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'STATE_FUNCT_CLASS_ID', 'Opp_RTE_NM', 'ROUTE_NO'],
                    maxRecordCount: 2000,
                    supportsPagination: true,
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    }
                },
                {
                    layerID: 3,
                    fcPropName: 'TMPD_FC',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'TMPD_FC', 'RTE_NM'],
                    maxRecordCount: 2000,
                    supportsPagination: true,
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    }
                }
            ],
            information: { Source: 'VDOT', Permission: 'Visible to R4+ or R3-AM', Description: 'Federal and State highways set to a minimum of mH.' },
            srExceptions: [
                217, 302, 303, 305, 308, 310, 313, 314, 315, 317, 318, 319, 320, 321, 322, 323, 324, 325,
                326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 339, 341, 342, 343, 344, 345, 346,
                347, 348, 350, 353, 355, 357, 358, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371,
                372, 373, 374, 375, 376, 377, 378, 379, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391,
                392, 393, 394, 396, 397, 398, 399, 785, 895
            ],
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName}<7`;
                }
                // NOTE: As of 9/14/2016 there does not appear to be any US/SR/VA labeled routes with FC = 7.
                return null;
            },
            getFeatureRoadType(feature, layer) {
                if (layer.getFeatureRoadType) {
                    return layer.getFeatureRoadType(feature);
                }
                let fc = parseInt(feature.attributes[layer.fcPropName], 10);
                const rtName = feature.attributes.RTE_NM || feature.attributes.Opp_RTE_NM;
                const match = /^R-VA\s*(US|VA|SR)(\d{5})..(BUS)?/.exec(rtName);
                const isBusiness = match && match !== null && match[3] === 'BUS';
                const isState = match && match !== null && (match[1] === 'VA' || match[1] === 'SR');
                let rtNumText;
                if (layer.layerID === 1) {
                    rtNumText = feature.attributes.ROUTE_NO;
                } else if (match) {
                    // eslint-disable-next-line prefer-destructuring
                    rtNumText = match[2];
                } else {
                    rtNumText = '99999';
                }
                const rtNum = parseInt(rtNumText, 10);
                const rtPrefix = match && match[1];
                if (fc > 3 && rtPrefix === 'US') {
                    fc = isBusiness ? 4 : 3;
                } else if (isState && fc > 4 && this.srExceptions.indexOf(rtNum) === -1 && rtNum < 600) {
                    fc = isBusiness ? 5 : 4;
                }
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        WA: {
            baseUrl: 'https://data.wsdot.wa.gov/arcgis/rest/services/FunctionalClass/WSDOTFunctionalClassMap/MapServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 2,
                    fcPropName: 'FederalFunctionalClassCode',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FederalFunctionalClassCode'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                },
                {
                    layerID: 1,
                    fcPropName: 'FederalFunctionalClassCode',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FederalFunctionalClassCode'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                },
                {
                    layerID: 4,
                    fcPropName: 'FederalFunctionalClassCode',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'FederalFunctionalClassCode'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            information: { Source: 'WSDOT', Permission: 'Visible to R4+ or R3-AM', Description: 'Raw unmodified FC data.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName} <> 7`;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                if (layer.getFeatureRoadType) {
                    return layer.getFeatureRoadType(feature);
                }
                return STATE_SETTINGS.global.getFeatureRoadType(feature, layer);
            }
        },
        WV: {
            baseUrl: 'https://gis.transportation.wv.gov/arcgis/rest/services/Routes/MapServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#ff00c5',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 2,
                    fcPropName: 'NAT_FUNCTIONAL_CLASS',
                    idPropName: 'OBJECTID',
                    outFields: ['OBJECTID', 'NAT_FUNCTIONAL_CLASS', 'ROUTE_ID'],
                    maxRecordCount: 1000,
                    supportsPagination: true,
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    }
                }
            ],
            information: { Source: 'WV DOT' },
            isPermitted() {
                return true;
            },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName} NOT IN (9,19)`;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                if (layer.getFeatureRoadType) {
                    return layer.getFeatureRoadType(feature);
                }
                const fcCode = feature.attributes[layer.fcPropName];
                let fc = fcCode;
                if (fcCode === 11) fc = 1;
                else if (fcCode === 4 || fcCode === 12) fc = 2;
                else if (fcCode === 2 || fcCode === 14) fc = 3;
                else if (fcCode === 6 || fcCode === 16) fc = 4;
                else if (fcCode === 7 || fcCode === 17 || fcCode === 8 || fcCode === 18) fc = 5;
                else fc = 7;
                const id = feature.attributes.ROUTE_ID;
                const prefix = id.substr(2, 1);
                const isInterstate = prefix === '1';
                const isUS = prefix === '2';
                const isState = prefix === '3';
                if (fc > 1 && isInterstate) fc = 1;
                else if (fc > 3 && isUS) fc = 3;
                else if (fc > 4 && isState) fc = 4;
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        },
        WY: {
            baseUrl: 'https://gisservices.wyoroad.info/arcgis/rest/services/ITSM/ITSM_Data_Layers/MapServer/',
            defaultColors: {
                Fw: '#ff00c5',
                Ew: '#4f33df',
                MH: '#149ece',
                mH: '#4ce600',
                PS: '#cfae0e',
                St: '#eeeeee'
            },
            zoomSettings: { maxOffset: [30, 15, 8, 4, 2, 1, 1, 1, 1, 1], excludeRoadTypes: [['St'], ['St'], ['St'], ['St'], [], [], [], [], [], [], []] },
            fcMapLayers: [
                {
                    layerID: 20,
                    fcPropName: 'classification',
                    idPropName: 'objectid',
                    outFields: ['objectid', 'classification', 'common_route_name'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                },
                {
                    layerID: 21,
                    fcPropName: 'classification',
                    idPropName: 'objectid',
                    outFields: ['objectid', 'classification', 'common_route_name'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                },
                {
                    layerID: 22,
                    fcPropName: 'classification',
                    idPropName: 'objectid',
                    outFields: ['objectid', 'classification', 'common_route_name'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                },
                {
                    layerID: 23,
                    fcPropName: 'classification',
                    idPropName: 'objectid',
                    outFields: ['objectid', 'classification', 'common_route_name'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                },
                {
                    layerID: 24,
                    fcPropName: 'classification',
                    idPropName: 'objectid',
                    outFields: ['objectid', 'classification', 'common_route_name'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                },
                {
                    layerID: 25,
                    fcPropName: 'classification',
                    idPropName: 'objectid',
                    outFields: ['objectid', 'classification', 'common_route_name'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                },
                {
                    layerID: 26,
                    fcPropName: 'classification',
                    idPropName: 'objectid',
                    outFields: ['objectid', 'classification', 'common_route_name'],
                    roadTypeMap: {
                        Fw: [1],
                        Ew: [2],
                        MH: [3],
                        mH: [4],
                        PS: [5, 6],
                        St: [7]
                    },
                    maxRecordCount: 1000,
                    supportsPagination: false
                }
            ],
            information: { Source: 'WYDOT', Permission: 'Visible to R4+ or R3-AM', Description: 'Minimum suggested FC.' },
            getWhereClause(context) {
                if (context.mapContext.zoom < 16) {
                    return `${context.layer.fcPropName} <> 'Local'`;
                }
                return null;
            },
            getFeatureRoadType(feature, layer) {
                const attr = feature.attributes;
                let fc = parseInt(attr[layer.fcPropName], 10);
                const route = attr.common_route_name;
                const isIntBiz = /I (25|80) BUS/.test(route);
                const isUS = /US \d+/.test(route);
                const isUSBiz = /US \d+ BUS/.test(route);
                const isState = /WY \d+/.test(route);
                const isStateBiz = /WY \d+ BUS/.test(route);
                if (fc > 3 && (isUS || isIntBiz)) fc = isUSBiz ? 4 : 3;
                else if (fc > 4 && isState) fc = isStateBiz ? 5 : 4;
                return STATE_SETTINGS.global.getRoadTypeFromFC(fc, layer);
            }
        }
    };

    function log(message, object) {
        if (object !== undefined) {
            console.log('FC Layer:', message, object);
        } else {
            console.log('FC Layer:', message);
        }
    }

    function debugLog(message, object) {
        if (debug) {
            if (object !== undefined) {
                console.debug('FC Layer:', message, object);
            } else {
                console.debug('FC Layer:', message);
            }
        }
    }

    function errorLog(message, object) {
        if (object !== undefined) {
            console.error('FC Layer:', message, object);
        } else {
            console.error('FC Layer:', message);
        }
    }

    function loadSettingsFromStorage() {
        const storedSettings = $.parseJSON(localStorage.getItem(settingsStoreName)) || {};
        const defaultSettings = {
            layerVisible: true,
            activeStateAbbr: 'ALL',
            hideStreet: false
        };
        settings = { ...defaultSettings, ...storedSettings };
    }

    function saveSettingsToStorage() {
        if (localStorage) {
            // In case the layer is turned off some other way...
            settings.layerVisible = sdk.Map.isLayerVisible({ layerName });
            localStorage.setItem(settingsStoreName, JSON.stringify(settings));
        }
    }

    function sortArray(array) {
        array.sort((a, b) => {
            if (a < b) return -1;
            if (a > b) return 1;
            return 0;
        });
    }

    function getVisibleStateAbbreviations() {
        const { activeStateAbbr } = settings;
        return sdk.DataModel.States.getAll()
            .map(state => STATES_HASH[state.name])
            .filter(stateAbbr => STATE_SETTINGS[stateAbbr] && STATE_SETTINGS.global.isPermitted(stateAbbr) && (!activeStateAbbr || activeStateAbbr === 'ALL' || activeStateAbbr === stateAbbr));
    }

    function getAsync(url, context) {
        debugLog(
            `Fetching data for ${context.stateAbbr} from ${context.state.baseUrl}
        ${context.layer.layerPath ? context.layer.layerPath : ''}${context.layer.layerID ? context.layer.layerID : ''}`,
            context
        );

        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                context,
                method: 'GET',
                url,
                onload(res) {
                    if (res.status.toString() === '200') {
                        const parsedResponse = JSON.parse(res.responseText);
                        if (parsedResponse.error) {
                            reject(new Error(`API Error: ${parsedResponse.error.message}`));
                        } else {
                            resolve({ responseText: res.responseText, context });
                        }
                    } else {
                        reject(new Error(`HTTP ${res.status}: ${res.responseText}`));
                    }
                },
                onerror() {
                    reject(new Error('Network Error'));
                }
            });
        });
    }

    function getUrl(context, queryType, queryParams) {
        const { extent } = context.mapContext;
        const { zoom } = context.mapContext;
        const { layer } = context;
        const { state } = context;

        const whereParts = [];

        const geometry = {
            xmin: extent[0],
            ymin: extent[1],
            xmax: extent[2],
            ymax: extent[3],
            spatialReference: {
                wkid: 4326
            }
        };
        const geometryStr = JSON.stringify(geometry);
        const stateWhereClause = state.getWhereClause(context);
        const layerPath = layer.layerPath || '';
        let url = `${state.baseUrl + layerPath + layer.layerID}/query?geometry=${encodeURIComponent(geometryStr)}`;

        if (queryType === 'countOnly') {
            url += '&returnCountOnly=true';
        } else if (queryType === 'idsOnly') {
            url += '&returnIdsOnly=true';
        } else if (queryType === 'paged') {
            // TODO
        } else {
            // Convert to degrees (4326) from the old Meters (3857)
            url += `&returnGeometry=true&maxAllowableOffset=${state.zoomSettings.maxOffset[zoom - 12] / 111000}`;
            url += `&outFields=${encodeURIComponent(layer.outFields.join(','))}`;
            if (queryType === 'idRange') {
                whereParts.push(`(${queryParams.idFieldName}>=${queryParams.range[0]} AND ${queryParams.idFieldName}<=${queryParams.range[1]})`);
            }
        }
        if (stateWhereClause) whereParts.push(stateWhereClause);
        if (whereParts.length > 0) url += `&where=${encodeURIComponent(whereParts.join(' AND '))}`;
        url += '&spatialRel=esriSpatialRelIntersects&geometryType=esriGeometryEnvelope&inSR=4326&outSR=4326&f=json'; // &geometryPrecision=7  Not needed as it scales with maxAllowableOffset
        // debugLog(`URL Fetch Type = ${queryType}`, url );
        return url;
    }

    function convertFcToRoadTypeLineStrings(feature, context) {
        const { state, stateAbbr, layer } = context;
        const roadType = state.getFeatureRoadType(feature, layer);
        const attr = {
            state: stateAbbr,
            layerID: layer.layerID,
            roadType,
            color: state.defaultColors[roadType]
        };

        const lineStrings = feature.geometry.paths.map(path => {
            const line = turf.lineString(path, attr);
            line.id = 0;
            return line;
        });

        return lineStrings;
    }

    function fetchLayerFC(context) {
        const url = getUrl(context, 'idsOnly');
        context.idsOnlyURL = url;
        if (!context.parentContext.cancel) {
            return getAsync(url, context)
                .bind(context)
                .then(res => {
                    try {
                        const ids = JSON.parse(res.responseText);
                        if (!ids.objectIds) ids.objectIds = [];
                        if (ids.objectIds.length === 0) {
                            debugLog(`objectIds array is empty or undefined for State "${context.stateAbbr}" Layer "${
                                context.layer.layerID}" with context:`, context);
                        }
                        sortArray(ids.objectIds);
                        // debugLog(``,ids);
                        return ids;
                    } catch (err) {
                        errorLog(`Error parsing URL response JSON for State "${context.stateAbbr}" Layer "${context.layer.layerID}" with context:`, context);
                        throw err;
                    }
                })
                .then(res => {
                    const idRanges = [];
                    if (res.objectIds) {
                        const len = res.objectIds ? res.objectIds.length : 0;
                        let currentIndex = 0;
                        const offset = Math.min(context.layer.maxRecordCount, 1000);
                        while (currentIndex < len) {
                            let nextIndex = currentIndex + offset;
                            if (nextIndex >= len) nextIndex = len - 1;
                            idRanges.push({
                                range: [res.objectIds[currentIndex], res.objectIds[nextIndex]],
                                idFieldName: res.objectIdFieldName
                            });
                            currentIndex = nextIndex + 1;
                        }
                    }
                    return idRanges;
                })
                .map(idRange => {
                    if (!context.parentContext.cancel) {
                        const newUrl = getUrl(context, 'idRange', idRange);
                        context.idRangeURL = newUrl;
                        return getAsync(newUrl, context).then(res => {
                            if (!context.parentContext.cancel) {
                                let { features } = JSON.parse(res.responseText);
                                context.parentContext.callCount++;
                                features = features || [];
                                return features.map(feature => convertFcToRoadTypeLineStrings(feature, context)).filter(feature => !(feature[0].properties.roadType === 'St' && settings.hideStreet));
                            }
                            return null;
                        });
                    }
                    // debugLog('Async call cancelled');
                    return null;
                });
        }
        return null;
    }

    function fetchStateFC(context) {
        const state = STATE_SETTINGS[context.stateAbbr];
        const contexts = state.fcMapLayers.map(layer => ({
            parentContext: context.parentContext,
            layer,
            state,
            stateAbbr: context.stateAbbr,
            mapContext: context.mapContext
        }));

        return Promise.map(contexts, ctx => fetchLayerFC(ctx).catch(err => {
            const errorMessage = `
        | Failed to fetch layer:
        | State: ${ctx.stateAbbr}
        | layerID: ${ctx.layer.layerID}
        | Base URL: ${ctx.state.baseUrl}.
        | ${err.message}.
      `;
            return Promise.reject(new Error(errorMessage.trim()));
        }));
    }

    let _lastPromise = null;
    let _lastContext = null;
    let _fcCallCount = 0;

    function getArrayDepth(arr) {
        if (Array.isArray(arr)) {
            return 1 + Math.max(0, ...arr.map(getArrayDepth));
        }
        return 0;
    }

    function fetchAllFC() {
        if (!sdk.Map.isLayerVisible({ layerName })) return;

        if (_lastPromise) {
            _lastPromise.cancel();
        }
        $('#fc-loading-indicator').css('color', 'green').html('<span>Loading FC Layers ...</span>');

        const mapContext = { zoom: sdk.Map.getZoomLevel(), extent: sdk.Map.getMapExtent() };
        if (mapContext.zoom > MIN_ZOOM_LEVEL) {
            const parentContext = { callCount: 0, startTime: Date.now() };

            if (_lastContext) _lastContext.cancel = true;
            _lastContext = parentContext;

            const contexts = getVisibleStateAbbreviations().map(stateAbbr => ({ parentContext, stateAbbr, mapContext }));
            let errorOccurred = false; // Flag to track error state
            let featureCount = 0;

            const map = Promise.map(contexts, ctx => fetchStateFC(ctx))
                .then(statesLineStringArrays => {
                    if (!parentContext.cancel) {
                        sdk.Map.removeAllFeaturesFromLayer({ layerName });

                        // Determine the depth of the nested array structure
                        const depth = getArrayDepth(statesLineStringArrays);
                        debugLog(`Detected array depth: ${depth}`);

                        // Flatten the array based on the detected depth
                        const flattenedFeatures = statesLineStringArrays.flat(depth);
                        featureCount = flattenedFeatures.length;

                        // Add all features to the layer at once
                        sdk.Map.dangerouslyAddFeaturesToLayerWithoutValidation({
                            layerName,
                            features: flattenedFeatures
                        });
                    }
                    return statesLineStringArrays;
                })
                .catch(e => {
                    const formattedMessage = e.message.replace(/\|/g, '<br>');
                    $('#fc-loading-indicator').css('color', 'red').html(`${formattedMessage}`);
                    errorOccurred = true;
                    errorLog(e.message);
                })
                .finally(() => {
                    _fcCallCount -= 1;
                    if (_fcCallCount === 0 && !errorOccurred) {
                        $('#fc-loading-indicator').html('<span></span>');
                    }

                    const endTime = Date.now();
                    const durationSeconds = (endTime - parentContext.startTime) / 1000;
                    debugLog(`Loaded ${featureCount} features in ${durationSeconds.toFixed(2)} seconds`);
                });

            _fcCallCount += 1;
            _lastPromise = map;
        } else {
            // if zoomed out too far, clear the layer
            sdk.Map.removeAllFeaturesFromLayer({ layerName });
        }
    }

    function onLayerCheckboxChanged(args) {
        setEnabled(args.checked);
    }

    function checkLayerZIndex() {
        try {
            if (sdk.Map.getLayerZIndex({ layerName }) !== MAP_LAYER_Z_INDEX) {
                // ("ADJUSTED FC LAYER Z-INDEX " + mapLayerZIndex + ', ' + mapLayer.getZIndex());
                sdk.Map.setLayerZIndex({ layerName, zIndex: MAP_LAYER_Z_INDEX });
            }
        } catch {
            // ignore this hack if it crashes
        }
    }

    function initLayer() {
        const styleRules = [
            {
                style: {
                    strokeColor: 'black',
                    strokeDashstyle: 'solid',
                    strokeOpacity: 1.0,
                    strokeWidth: '15'
                }
            }
        ];
        for (let zoom = 12; zoom < 22; zoom++) {
            styleRules.push({
                // eslint-disable-next-line no-loop-func
                predicate: () => sdk.Map.getZoomLevel() === zoom,
                style: {
                    strokeWidth: 12 * 1.15 ** (zoom - 13)
                }
            });
        }
        Object.values(STATE_SETTINGS)
            .filter(state => !!state.defaultColors)
            .forEach(state => Object.values(state.defaultColors).forEach(color => {
                if (!styleRules.some(rule => rule.style.strokeColor === color)) {
                    styleRules.push({
                        predicate: props => props.color === color,
                        style: { strokeColor: color }
                    });
                }
            }));

        STATE_SETTINGS.global.roadTypes.forEach((roadType, index) => {
            styleRules.push({
                predicate: props => props.roadType === roadType,
                style: { graphicZIndex: index * 100 }
            });
        });
        sdk.Map.addLayer({
            layerName,
            styleRules,
            zIndexing: true
        });

        sdk.Map.setLayerOpacity({ layerName, opacity: 0.5 });
        sdk.Map.setLayerVisibility({ layerName, visibility: settings.layerVisible });
        MAP_LAYER_Z_INDEX = sdk.Map.getLayerZIndex({ layerName: 'roads' }) - 3;
        sdk.Map.setLayerZIndex({ layerName, zIndex: MAP_LAYER_Z_INDEX });

        window.addEventListener('beforeunload', () => saveSettingsToStorage);

        sdk.LayerSwitcher.addLayerCheckbox({ name: 'FC Layer' });
        sdk.LayerSwitcher.setLayerCheckboxChecked({ name: 'FC Layer', isChecked: settings.layerVisible });
        sdk.Events.on({ eventName: 'wme-layer-checkbox-toggled', eventHandler: onLayerCheckboxChanged });

        // Hack to fix layer zIndex.  Some other code is changing it sometimes but I have not been able to figure out why.
        // It may be that the FC layer is added to the map before some Waze code loads the base layers and forces other layers higher. (?)
        setInterval(checkLayerZIndex, 1000);

        sdk.Events.on({ eventName: 'wme-map-move-end', eventHandler: fetchAllFC });
    }

    function onHideStreetsClicked() {
        settings.hideStreet = $(this).is(':checked');
        saveSettingsToStorage();
        sdk.Map.removeAllFeaturesFromLayer({ layerName });
        fetchAllFC();
    }

    function onStateSelectionChanged() {
        settings.activeStateAbbr = this.value;
        saveSettingsToStorage();
        loadStateFCInfo();
        fetchAllFC();
    }

    function setEnabled(value) {
        sdk.Map.setLayerVisibility({ layerName, visibility: value });
        settings.layerVisible = value;
        saveSettingsToStorage();

        const color = value ? '#00bd00' : '#ccc';
        $('span#fc-layer-power-btn').css({ color });
        if (value) fetchAllFC();
        sdk.LayerSwitcher.setLayerCheckboxChecked({ name: 'FC Layer', isChecked: value });
    }

    async function initUserPanel() {
        const $panel = $('<div>');
        // Updated to play better with DarkMode
        const $stateSelect = $('<select>', {
            id: 'fcl-state-select',
            class: 'form-control disabled',
            style: `
        border-radius: 4px;
        padding: 6px 12px;
        background-color: var(--background_default); /* Use dark mode background */
        color: var(--content_default); /* Use dark mode content color */
        border: 1px solid var(--separator_default); /* Dark mode border color */
        transition: background-color 0.3s, color 0.3s, border-color 0.3s;
        outline: none;
        cursor: pointer;
        font-weight: bold;
    `
        }).append($('<option>', { value: 'ALL' }).text('All'));

        Object.keys(STATE_SETTINGS).forEach(stateAbbr => {
            if (stateAbbr !== 'global') {
                $stateSelect.append($('<option>', { value: stateAbbr }).text(reverseStatesHash(stateAbbr)));
            }
        });

        $stateSelect.val(settings.activeStateAbbr ? settings.activeStateAbbr : 'ALL');

        const $hideStreet = $('<div>', { id: 'fcl-hide-street-container', class: 'controls-container' })
            .append($('<input>', { type: 'checkbox', name: 'fcl-hide-street', id: 'fcl-hide-street' }).prop('checked', settings.hideStreet).click(onHideStreetsClicked))
            .append($('<label>', { for: 'fcl-hide-street' }).text('Hide local street highlights'));

        $panel.append(
            $('<div>', { class: 'form-group' })
                .append($('<label>', { class: 'control-label' }).text('Select a state'))
                .append($('<div>', { class: 'controls', id: 'fcl-state-select-container' }).append($('<div>').append($stateSelect))),
            $hideStreet,
            $('<div>', { id: 'fcl-table-container' })
        );

        $panel.append(
            $('<div>', {
                class: 'loading-indicator',
                id: 'fc-loading-indicator',
                style: 'margin-top:10px; margin-right:10px; font-weight:bold; color:green; font-size:0.9em;'
            }).html('<span></span>')
        );

        $panel.append($('<div>', { id: 'fcl-state-info' }));

        $panel.append(
            $('<div>', { style: 'margin-top:10px;font-size:10px;color:#999999;' })
                .append($('<div>').text(`version ${scriptVersion}`))
                .append($('<div>').append($('<a>', { href: '#' /* , target:'__blank' */ }).text('Discussion Forum (currently n/a)')))
        );

        const { tabLabel, tabPane } = await sdk.Sidebar.registerScriptTab();
        $(tabLabel).text('FC');
        $(tabPane).append($panel);

        // append the power button
        if (!$('#fc-layer-power-btn').length) {
            const color = settings.layerVisible ? '#00bd00' : '#ccc';
            $(tabLabel).prepend(
                $('<span>', {
                    class: 'fa fa-power-off',
                    id: 'fc-layer-power-btn',
                    style: `margin-right: 5px;cursor: pointer;color: ${color};font-size: 13px;`,
                    title: 'Toggle FC Layer'
                }).click(evt => {
                    evt.stopPropagation();
                    setEnabled(!settings.layerVisible);
                })
            );
        }

        $('#fcl-state-select').change(onStateSelectionChanged);
        loadStateFCInfo();
    }

    function loadStateFCInfo() {
        $('#fcl-state-info').empty();
        if (STATE_SETTINGS[settings.activeStateAbbr]) {
            const stateInfo = STATE_SETTINGS[settings.activeStateAbbr].information;
            const $panelStateInfo = $('<dl>');
            Object.keys(stateInfo).forEach(propertyName => {
                $panelStateInfo.append($('<dt>', { style: 'margin-top:1em;color:#777777' }).text(propertyName)).append($('<dd>').text(stateInfo[propertyName]));
            });
            $('#fcl-state-info').append($panelStateInfo);
        }
    }

    async function initGui() {
        initLayer();
        await initUserPanel();
    }

    async function init() {
        if (debug && Promise.config) {
            Promise.config({
                warnings: true,
                longStackTraces: true,
                cancellation: true,
                monitoring: false
            });
        } else {
            Promise.config({
                warnings: false,
                longStackTraces: false,
                cancellation: true,
                monitoring: false
            });
        }

        const u = sdk.State.getUserInfo();
        rank = u.rank + 1;
        isAM = u.isAreaManager;
        userNameLC = u.userName.toLowerCase();

        loadSettingsFromStorage();
        await initGui();
        fetchAllFC();
        log('Initialized.');
    }

    init();
})();