mirror of
https://git.ianrenton.com/ian/spothole.git
synced 2026-09-20 14:27:42 +00:00
Logging tidy-up, IDE inspection fixes
This commit is contained in:
+22
@@ -3,6 +3,7 @@
|
|||||||
<option name="myName" value="Project Default" />
|
<option name="myName" value="Project Default" />
|
||||||
<inspection_tool class="Annotator" enabled="false" level="ERROR" enabled_by_default="false" />
|
<inspection_tool class="Annotator" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||||
<inspection_tool class="BadExpressionStatementJS" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
<inspection_tool class="BadExpressionStatementJS" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||||
|
<inspection_tool class="CheckImageSize" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||||
<inspection_tool class="CssOverwrittenProperties" enabled="false" level="WARNING" enabled_by_default="false" />
|
<inspection_tool class="CssOverwrittenProperties" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||||
<inspection_tool class="CssUnresolvedCustomProperty" enabled="false" level="ERROR" enabled_by_default="false" />
|
<inspection_tool class="CssUnresolvedCustomProperty" enabled="false" level="ERROR" enabled_by_default="false" />
|
||||||
<inspection_tool class="CssUnusedSymbol" enabled="false" level="WARNING" enabled_by_default="false" />
|
<inspection_tool class="CssUnusedSymbol" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||||
@@ -43,6 +44,27 @@
|
|||||||
<inspection_tool class="LanguageDetectionInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
<inspection_tool class="LanguageDetectionInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||||
<inspection_tool class="OutdatedRequirementInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
<inspection_tool class="OutdatedRequirementInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||||
<inspection_tool class="PyBroadExceptionInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
<inspection_tool class="PyBroadExceptionInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||||
|
<inspection_tool class="PyCompatibilityInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="ourVersions">
|
||||||
|
<value>
|
||||||
|
<list size="6">
|
||||||
|
<item index="0" class="java.lang.String" itemvalue="3.15" />
|
||||||
|
<item index="1" class="java.lang.String" itemvalue="3.14" />
|
||||||
|
<item index="2" class="java.lang.String" itemvalue="3.13" />
|
||||||
|
<item index="3" class="java.lang.String" itemvalue="3.12" />
|
||||||
|
<item index="4" class="java.lang.String" itemvalue="3.11" />
|
||||||
|
<item index="5" class="java.lang.String" itemvalue="3.10" />
|
||||||
|
</list>
|
||||||
|
</value>
|
||||||
|
</option>
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PyStringConversionWithoutDunderMethodInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||||
|
<option name="ignoredTypes">
|
||||||
|
<list>
|
||||||
|
<option value="types.NoneType" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</inspection_tool>
|
||||||
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
|
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
|
||||||
<option name="processCode" value="true" />
|
<option name="processCode" value="true" />
|
||||||
<option name="processLiterals" value="true" />
|
<option name="processLiterals" value="true" />
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ def get_call_info(callsign, lookup_credentials):
|
|||||||
if callsign:
|
if callsign:
|
||||||
# Sort callsign providers by priority order, so we query the highest priority (lowest numbers) first, and only
|
# Sort callsign providers by priority order, so we query the highest priority (lowest numbers) first, and only
|
||||||
# query other providers for data we are missing as we go along.
|
# query other providers for data we are missing as we go along.
|
||||||
for p in sorted(DATA_PROVIDERS.callsign_data_providers, key=lambda p: p.priority):
|
for p in sorted(DATA_PROVIDERS.callsign_data_providers, key=lambda p2: p2.priority):
|
||||||
if p.enabled:
|
if p.enabled:
|
||||||
# Get new lookup data
|
# Get new lookup data
|
||||||
data = p.lookup(callsign, lookup_credentials)
|
data = p.lookup(callsign, lookup_credentials)
|
||||||
|
|||||||
@@ -31,10 +31,10 @@ class DataProviders:
|
|||||||
self.callsign_data_providers.append(create_provider_from_config("providers.callsigndata", entry))
|
self.callsign_data_providers.append(create_provider_from_config("providers.callsigndata", entry))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def start_providers(providers, type):
|
def start_providers(providers, provider_type):
|
||||||
"""Helper method to activate enabled providers in the list."""
|
"""Helper method to activate enabled providers in the list."""
|
||||||
|
|
||||||
logging.info(f"Starting %s providers...", type)
|
logging.info(f"Starting %s providers...", provider_type)
|
||||||
for p in providers:
|
for p in providers:
|
||||||
if p.enabled:
|
if p.enabled:
|
||||||
p.start()
|
p.start()
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ class LiveDataCache:
|
|||||||
try:
|
try:
|
||||||
callback(value)
|
callback(value)
|
||||||
except Exception:
|
except Exception:
|
||||||
logging.error("Listener raised an exception for key %s", key, exc_info=True)
|
logging.exception("Listener raised an exception for key %s", key)
|
||||||
|
|
||||||
|
|
||||||
def get(self, key, default=None):
|
def get(self, key, default=None):
|
||||||
@@ -71,7 +71,7 @@ class LiveDataCache:
|
|||||||
try:
|
try:
|
||||||
self._disk_cache.set("snapshot", data)
|
self._disk_cache.set("snapshot", data)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error("Failed to write snapshot to %s", self._snapshot_dir, e, exc_info=True)
|
logging.exception("Failed to write snapshot to %s", self._snapshot_dir, e)
|
||||||
|
|
||||||
def _load_snapshot(self):
|
def _load_snapshot(self):
|
||||||
data = self._disk_cache.get("snapshot")
|
data = self._disk_cache.get("snapshot")
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ def get_sig_ref_info(sig, ref_id):
|
|||||||
|
|
||||||
# If the SIG is HEMA, we have no current lookup for this so just skip the lookup here.
|
# If the SIG is HEMA, we have no current lookup for this so just skip the lookup here.
|
||||||
if sig.upper() == "HEMA":
|
if sig.upper() == "HEMA":
|
||||||
sig_ref.type = "Summit"
|
sig_ref.ref_type = "Summit"
|
||||||
return sig_ref
|
return sig_ref
|
||||||
|
|
||||||
### PROGRAMMATIC DATA GENERATION INSTEAD OF LOOKUPS ###
|
### PROGRAMMATIC DATA GENERATION INSTEAD OF LOOKUPS ###
|
||||||
@@ -38,7 +38,7 @@ def get_sig_ref_info(sig, ref_id):
|
|||||||
# calculate all the information we are going to get directly.
|
# calculate all the information we are going to get directly.
|
||||||
if sig.upper() == "TILES":
|
if sig.upper() == "TILES":
|
||||||
# Tiles on the Air just uses Maidenhead 6-digit squares, so ID, Name and Grid are all the same
|
# Tiles on the Air just uses Maidenhead 6-digit squares, so ID, Name and Grid are all the same
|
||||||
sig_ref.type = "Grid"
|
sig_ref.ref_type = "Grid"
|
||||||
if not sig_ref.name:
|
if not sig_ref.name:
|
||||||
sig_ref.name = sig_ref.id
|
sig_ref.name = sig_ref.id
|
||||||
if not sig_ref.grid:
|
if not sig_ref.grid:
|
||||||
@@ -50,7 +50,7 @@ def get_sig_ref_info(sig, ref_id):
|
|||||||
return sig_ref
|
return sig_ref
|
||||||
|
|
||||||
elif sig.upper() == "WAB" or sig.upper() == "WAI":
|
elif sig.upper() == "WAB" or sig.upper() == "WAI":
|
||||||
sig_ref.type = "Grid"
|
sig_ref.ref_type = "Grid"
|
||||||
ll = wab_wai_square_to_lat_lon(ref_id)
|
ll = wab_wai_square_to_lat_lon(ref_id)
|
||||||
if ll:
|
if ll:
|
||||||
sig_ref.name = ref_id
|
sig_ref.name = ref_id
|
||||||
@@ -64,10 +64,11 @@ def get_sig_ref_info(sig, ref_id):
|
|||||||
|
|
||||||
elif sig.upper() == "BOTA":
|
elif sig.upper() == "BOTA":
|
||||||
# For BOTA all we can ever generate is the URL, there is no data file or lookup for lat/longs
|
# For BOTA all we can ever generate is the URL, there is no data file or lookup for lat/longs
|
||||||
sig_ref.type = "Beach"
|
sig_ref.ref_type = "Beach"
|
||||||
if not sig_ref.name:
|
if not sig_ref.name:
|
||||||
sig_ref.name = sig_ref.id
|
sig_ref.name = sig_ref.id
|
||||||
sig_ref.url = "https://www.beachesontheair.com/beaches/" + sig_ref.name.lower().replace(" ", "-")
|
if sig_ref.name:
|
||||||
|
sig_ref.url = "https://www.beachesontheair.com/beaches/" + sig_ref.name.lower().replace(" ", "-")
|
||||||
return sig_ref
|
return sig_ref
|
||||||
|
|
||||||
### ACTUAL LOOKUP ###
|
### ACTUAL LOOKUP ###
|
||||||
@@ -85,7 +86,7 @@ def get_sig_ref_info(sig, ref_id):
|
|||||||
logging.debug("%s database did not contain data for ref %s", sig, ref_id)
|
logging.debug("%s database did not contain data for ref %s", sig, ref_id)
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
logging.error("Exception when looking up sig_ref info for " + sig + " ref " + ref_id, exc_info=True)
|
logging.exception("Exception when looking up sig_ref info for " + sig + " ref " + ref_id)
|
||||||
return sig_ref
|
return sig_ref
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+2
-3
@@ -1,4 +1,3 @@
|
|||||||
import copy
|
|
||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
@@ -128,8 +127,8 @@ class Alert:
|
|||||||
self.dx_names = list(
|
self.dx_names = list(
|
||||||
map(lambda c: get_call_info(c, credentials).name, self.dx_calls))
|
map(lambda c: get_call_info(c, credentials).name, self.dx_calls))
|
||||||
|
|
||||||
except Exception as e:
|
except Exception:
|
||||||
logging.error("Exception while inferring missing data from spot", e, exc_info=True)
|
logging.exception("Exception while inferring missing data from spot")
|
||||||
|
|
||||||
def to_json(self):
|
def to_json(self):
|
||||||
"""JSON serialise"""
|
"""JSON serialise"""
|
||||||
|
|||||||
+6
-6
@@ -1,4 +1,4 @@
|
|||||||
import copy
|
import hashlib
|
||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
@@ -9,12 +9,12 @@ from datetime import datetime, timedelta
|
|||||||
import pytz
|
import pytz
|
||||||
from pyhamtools.locator import locator_to_latlong, latlong_to_locator
|
from pyhamtools.locator import locator_to_latlong, latlong_to_locator
|
||||||
|
|
||||||
|
from core.call_lookup_helper import get_call_info
|
||||||
from core.config import MAX_SPOT_AGE
|
from core.config import MAX_SPOT_AGE
|
||||||
from core.constants import MODE_ALIASES, PROPAGATION_MODES
|
from core.constants import MODE_ALIASES, PROPAGATION_MODES
|
||||||
from core.geo_utils import lat_lon_to_cq_zone, lat_lon_to_itu_zone
|
from core.geo_utils import lat_lon_to_cq_zone, lat_lon_to_itu_zone
|
||||||
from core.call_lookup_helper import get_call_info
|
|
||||||
from core.sig_utils import ANY_SIG_REGEX, get_ref_regex_for_sig, get_sig_name_from_comment_name
|
|
||||||
from core.sig_lookup_helper import populate_missing_sig_ref_info
|
from core.sig_lookup_helper import populate_missing_sig_ref_info
|
||||||
|
from core.sig_utils import ANY_SIG_REGEX, get_ref_regex_for_sig, get_sig_name_from_comment_name
|
||||||
from core.utils import infer_band_from_freq, infer_mode_from_comment, \
|
from core.utils import infer_band_from_freq, infer_mode_from_comment, \
|
||||||
infer_mode_from_frequency, infer_mode_type_from_mode, get_flag_for_dxcc
|
infer_mode_from_frequency, infer_mode_type_from_mode, get_flag_for_dxcc
|
||||||
from data.sig_ref import SIGRef
|
from data.sig_ref import SIGRef
|
||||||
@@ -413,7 +413,7 @@ class Spot:
|
|||||||
or (self.dx_location_source == "HOME QTH" and "/" not in (self.dx_call or ""))))
|
or (self.dx_location_source == "HOME QTH" and "/" not in (self.dx_call or ""))))
|
||||||
|
|
||||||
# DE with no digits and APRS servers starting "T2" are not things we can look up location for
|
# DE with no digits and APRS servers starting "T2" are not things we can look up location for
|
||||||
if self.de_call and any(char.isdigit() for char in self.de_call) and not (
|
if self.de_call and any(char.isdigit() for char in str(self.de_call)) and not (
|
||||||
self.de_call.startswith("T2") and self.source == "APRS-IS"):
|
self.de_call.startswith("T2") and self.source == "APRS-IS"):
|
||||||
# DE operator location lookup
|
# DE operator location lookup
|
||||||
if not self.de_latitude:
|
if not self.de_latitude:
|
||||||
@@ -421,8 +421,8 @@ class Spot:
|
|||||||
self.de_longitude = de_call_info.longitude
|
self.de_longitude = de_call_info.longitude
|
||||||
self.de_grid = de_call_info.grid
|
self.de_grid = de_call_info.grid
|
||||||
|
|
||||||
except Exception as e:
|
except Exception:
|
||||||
logging.error("Exception while inferring missing data from spot", e, exc_info=True)
|
logging.exception("Exception while inferring missing data from spot")
|
||||||
|
|
||||||
def to_json(self):
|
def to_json(self):
|
||||||
"""JSON serialise"""
|
"""JSON serialise"""
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@
|
|||||||
If you want to run a copy of Spothole with different configuration settings than the main instance, you can download it
|
If you want to run a copy of Spothole with different configuration settings than the main instance, you can download it
|
||||||
and run it on your own local machine or server.
|
and run it on your own local machine or server.
|
||||||
|
|
||||||
You will require Python version 3.8 or later. If you encounter an error about `gdal-config` during the following
|
You will require Python version 3.10 or later. If you encounter an error about `gdal-config` during the following
|
||||||
process, you will also need `libgdal-dev` installed.
|
process, you will also need `libgdal-dev` installed.
|
||||||
|
|
||||||
To download and set up Spothole on a Debian server, run the following commands. Other operating systems will likely be
|
To download and set up Spothole on a Debian server, run the following commands. Other operating systems will likely be
|
||||||
|
|||||||
@@ -1,13 +1,3 @@
|
|||||||
import logging
|
|
||||||
from datetime import datetime
|
|
||||||
from threading import Thread, Event
|
|
||||||
|
|
||||||
import pytz
|
|
||||||
from requests import ReadTimeout
|
|
||||||
from requests.exceptions import ConnectionError, ConnectTimeout
|
|
||||||
|
|
||||||
from core.constants import HTTP_HEADERS
|
|
||||||
from core.url_data_cache import URLDataCache
|
|
||||||
from providers.callsigndata.callsign_data_provider import CallsignDataProvider
|
from providers.callsigndata.callsign_data_provider import CallsignDataProvider
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import logging
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
import pytz
|
import pytz
|
||||||
|
|||||||
@@ -41,8 +41,8 @@ class ClublogAPI(APIQueryCallsignDataProvider):
|
|||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
except Exception as e:
|
except Exception:
|
||||||
self.status = "Error"
|
self.status = "Error"
|
||||||
logging.error("Exception when looking up data from Clublog API", e, exc_info=True)
|
logging.exception("Exception when looking up data from Clublog API")
|
||||||
|
|
||||||
return callsign_data
|
return callsign_data
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
import gzip
|
import gzip
|
||||||
import logging
|
import logging
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
import pytz
|
|
||||||
from pyhamtools import LookupLib, Callinfo
|
from pyhamtools import LookupLib, Callinfo
|
||||||
|
|
||||||
from core.data_store import DATA_STORE
|
from core.data_store import DATA_STORE
|
||||||
@@ -47,8 +45,8 @@ class ClublogXML(FileDownloadCallsignDataProvider):
|
|||||||
self._callinfo = Callinfo(lookuplib)
|
self._callinfo = Callinfo(lookuplib)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
except Exception as e:
|
except Exception:
|
||||||
logging.error("Exception when loading Clublog XML.", e, exc_info=True)
|
logging.exception("Exception when loading Clublog XML.")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _perform_new_lookup(self, callsign, lookup_credentials):
|
def _perform_new_lookup(self, callsign, lookup_credentials):
|
||||||
@@ -62,8 +60,8 @@ class ClublogXML(FileDownloadCallsignDataProvider):
|
|||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
except Exception as e:
|
except Exception:
|
||||||
self.status = "Error"
|
self.status = "Error"
|
||||||
logging.error("Exception when looking up data from Clublog XML data", e, exc_info=True)
|
logging.exception("Exception when looking up data from Clublog XML data")
|
||||||
|
|
||||||
return callsign_data
|
return callsign_data
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ class CountryFiles(FileDownloadCallsignDataProvider):
|
|||||||
self._callinfo = Callinfo(lookuplib)
|
self._callinfo = Callinfo(lookuplib)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
except Exception as e:
|
except Exception:
|
||||||
logging.error("Exception when loading Country Files cty.plist.", e, exc_info=True)
|
logging.exception("Exception when loading Country Files cty.plist.")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _perform_new_lookup(self, callsign, lookup_credentials):
|
def _perform_new_lookup(self, callsign, lookup_credentials):
|
||||||
@@ -41,8 +41,8 @@ class CountryFiles(FileDownloadCallsignDataProvider):
|
|||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
except Exception as e:
|
except Exception:
|
||||||
self.status = "Error"
|
self.status = "Error"
|
||||||
logging.error("Exception when looking up data from Country file", e, exc_info=True)
|
logging.exception("Exception when looking up data from Country file")
|
||||||
|
|
||||||
return callsign_data
|
return callsign_data
|
||||||
|
|||||||
@@ -97,15 +97,15 @@ class HamQTH(APIQueryCallsignDataProvider):
|
|||||||
logging.warning(f"Timeout when looking up callsign %s using HamQTH", lookup_call)
|
logging.warning(f"Timeout when looking up callsign %s using HamQTH", lookup_call)
|
||||||
continue
|
continue
|
||||||
except Exception:
|
except Exception:
|
||||||
logging.error("Exception when looking up callsign %s using HamQTH", lookup_call, exc_info=True)
|
logging.exception("Exception when looking up callsign %s using HamQTH", lookup_call)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Not found in HamQTH; return a Callsign object with no data so we cache that and don't keep retrying
|
# Not found in HamQTH; return a Callsign object with no data so we cache that and don't keep retrying
|
||||||
return Callsign(call=callsign)
|
return Callsign(call=callsign)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception:
|
||||||
self.status = "Error"
|
self.status = "Error"
|
||||||
logging.error("Exception when looking up data from HamQTH", e, exc_info=True)
|
logging.exception("Exception when looking up data from HamQTH")
|
||||||
# Return None, this won't be cached so we will be asked to query data again for this call next time.
|
# Return None, this won't be cached so we will be asked to query data again for this call next time.
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|||||||
@@ -106,15 +106,15 @@ class QRZ(APIQueryCallsignDataProvider):
|
|||||||
logging.warning(f"Timeout when looking up callsign %s using QRZ.", lookup_call)
|
logging.warning(f"Timeout when looking up callsign %s using QRZ.", lookup_call)
|
||||||
continue
|
continue
|
||||||
except Exception:
|
except Exception:
|
||||||
logging.error("Exception when looking up callsign %s using QRZ", lookup_call, exc_info=True)
|
logging.exception("Exception when looking up callsign %s using QRZ", lookup_call)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Not found in QRZ; return a Callsign object with no data so we cache that and don't keep retrying
|
# Not found in QRZ; return a Callsign object with no data so we cache that and don't keep retrying
|
||||||
return Callsign(call=callsign)
|
return Callsign(call=callsign)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception:
|
||||||
self.status = "Error"
|
self.status = "Error"
|
||||||
logging.error("Exception when looking up data from QRZ.com", e, exc_info=True)
|
logging.exception("Exception when looking up data from QRZ.com")
|
||||||
# Return None, this won't be cached so we will be asked to query data again for this call next time.
|
# Return None, this won't be cached so we will be asked to query data again for this call next time.
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|||||||
@@ -24,9 +24,9 @@ class LocalFileSIGRefDataProvider(SIGRefDataProvider):
|
|||||||
else:
|
else:
|
||||||
self.status = "Error"
|
self.status = "Error"
|
||||||
logging.info("Failed to load SIG ref data for " + self.sig_name)
|
logging.info("Failed to load SIG ref data for " + self.sig_name)
|
||||||
except Exception as e:
|
except Exception:
|
||||||
self.status = "Error"
|
self.status = "Error"
|
||||||
logging.error("Exception in local file SIG Ref Data Provider (" + self.sig_name + ")", e, exc_info=True)
|
logging.exception("Exception in local file SIG Ref Data Provider (" + self.sig_name + ")")
|
||||||
|
|
||||||
def _file_to_data(self, path):
|
def _file_to_data(self, path):
|
||||||
"""Load a file on the given path and turn it into SIG Ref data."""
|
"""Load a file on the given path and turn it into SIG Ref data."""
|
||||||
|
|||||||
@@ -24,7 +24,9 @@ class ParksNPeaksKMLSIGRefDataProvider(FileDownloadSIGRefDataProvider):
|
|||||||
k = kml.KML.from_string(http_response.content)
|
k = kml.KML.from_string(http_response.content)
|
||||||
|
|
||||||
for document in k.features:
|
for document in k.features:
|
||||||
|
# noinspection unresolved-references
|
||||||
for folder in document.features:
|
for folder in document.features:
|
||||||
|
# noinspection unresolved-references
|
||||||
for placemark in folder.features:
|
for placemark in folder.features:
|
||||||
description = placemark.description or ""
|
description = placemark.description or ""
|
||||||
match = self.REF_PATTERN.search(description)
|
match = self.REF_PATTERN.search(description)
|
||||||
|
|||||||
@@ -115,8 +115,8 @@ class GMA(HTTPSpotProvider):
|
|||||||
logging.warning(
|
logging.warning(
|
||||||
f"GMA API returned a malformed response when looking up ref {source_spot['REF']}")
|
f"GMA API returned a malformed response when looking up ref {source_spot['REF']}")
|
||||||
except:
|
except:
|
||||||
logging.warning("Exception when looking up " + self.REF_INFO_URL_ROOT + source_spot[
|
logging.exception("Exception when looking up " + self.REF_INFO_URL_ROOT + source_spot[
|
||||||
"REF"] + ", ignoring this spot for now", exc_info=True)
|
"REF"] + ", ignoring this spot for now")
|
||||||
else:
|
else:
|
||||||
logging.warning(f"The GMA API returned an unexpected response (HTTP {http_response.status_code}).")
|
logging.warning(f"The GMA API returned an unexpected response (HTTP {http_response.status_code}).")
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,6 @@ class CQZoneData(LocalFileStaticDataProvider):
|
|||||||
DATA_STORE.cq_zone_data = cq_zone_data
|
DATA_STORE.cq_zone_data = cq_zone_data
|
||||||
return True
|
return True
|
||||||
|
|
||||||
except Exception as e:
|
except Exception:
|
||||||
logging.error("Exception when loading CQ zone data.", e, exc_info=True)
|
logging.exception("Exception when loading CQ zone data.")
|
||||||
return False
|
return False
|
||||||
|
|||||||
@@ -31,6 +31,6 @@ class ITUZoneData(LocalFileStaticDataProvider):
|
|||||||
DATA_STORE.itu_zone_data = itu_zone_data
|
DATA_STORE.itu_zone_data = itu_zone_data
|
||||||
return True
|
return True
|
||||||
|
|
||||||
except Exception as e:
|
except Exception:
|
||||||
logging.error("Exception when loading ITU zone data.", e, exc_info=True)
|
logging.exception("Exception when loading ITU zone data.")
|
||||||
return False
|
return False
|
||||||
|
|||||||
@@ -41,8 +41,8 @@ class K0SWE(FileDownloadStaticDataProvider):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
except Exception as e:
|
except Exception:
|
||||||
logging.error("Exception when loading K0SWE dxcc.json.", e, exc_info=True)
|
logging.exception("Exception when loading K0SWE dxcc.json.")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -25,9 +25,9 @@ class LocalFileStaticDataProvider(StaticDataProvider):
|
|||||||
else:
|
else:
|
||||||
self.status = "Error"
|
self.status = "Error"
|
||||||
logging.error("Failed to load data for " + self.name)
|
logging.error("Failed to load data for " + self.name)
|
||||||
except Exception as e:
|
except Exception:
|
||||||
self.status = "Error"
|
self.status = "Error"
|
||||||
logging.error("Exception in local file Static Data Provider (" + self.name + ")", e, exc_info=True)
|
logging.exception("Exception in local file Static Data Provider (" + self.name + ")")
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
self._stop = True
|
self._stop = True
|
||||||
|
|||||||
@@ -232,8 +232,8 @@ class APISpotHandler(tornado.web.RequestHandler):
|
|||||||
self.set_header("Cache-Control", "no-store")
|
self.set_header("Cache-Control", "no-store")
|
||||||
self.set_header("Content-Type", "application/json")
|
self.set_header("Content-Type", "application/json")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception:
|
||||||
logging.error("Exception when handling client request to add spot API: %s", e, exc_info=True)
|
logging.exception("Exception when handling client request to add spot API")
|
||||||
self.write(safe_json_dumps("Error - an internal server error occurred."))
|
self.write(safe_json_dumps("Error - an internal server error occurred."))
|
||||||
self.set_status(500)
|
self.set_status(500)
|
||||||
self.set_header("Cache-Control", "no-store")
|
self.set_header("Cache-Control", "no-store")
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import copy
|
import copy
|
||||||
import inspect
|
|
||||||
import logging
|
import logging
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Any
|
from typing import Any
|
||||||
@@ -53,28 +52,18 @@ class APIAlertsHandler(tornado.web.RequestHandler):
|
|||||||
data = get_alert_list_with_filters(self._alerts, query_params)
|
data = get_alert_list_with_filters(self._alerts, query_params)
|
||||||
if credentials:
|
if credentials:
|
||||||
data = self._enrich(data, credentials)
|
data = self._enrich(data, credentials)
|
||||||
find_bad_values(data)
|
|
||||||
self.write(safe_json_dumps(data))
|
self.write(safe_json_dumps(data))
|
||||||
self.set_status(200)
|
self.set_status(200)
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
self.write(safe_json_dumps("Bad request - " + str(e)))
|
self.write(safe_json_dumps("Bad request - " + str(e)))
|
||||||
self.set_status(400)
|
self.set_status(400)
|
||||||
except Exception as e:
|
except Exception:
|
||||||
logging.error("Exception when handling client request to alerts API: %s", e, exc_info=True)
|
logging.exception("Exception when handling client request to alerts API")
|
||||||
self.write(safe_json_dumps("Error - an internal server error occurred."))
|
self.write(safe_json_dumps("Error - an internal server error occurred."))
|
||||||
self.set_status(500)
|
self.set_status(500)
|
||||||
self.set_header("Cache-Control", "no-store")
|
self.set_header("Cache-Control", "no-store")
|
||||||
self.set_header("Content-Type", "application/json")
|
self.set_header("Content-Type", "application/json")
|
||||||
|
|
||||||
def find_bad_values(obj, path="data"):
|
|
||||||
if isinstance(obj, dict):
|
|
||||||
for k, v in obj.items():
|
|
||||||
find_bad_values(v, f"{path}[{k!r}]")
|
|
||||||
elif isinstance(obj, (list, tuple)):
|
|
||||||
for i, v in enumerate(obj):
|
|
||||||
find_bad_values(v, f"{path}[{i}]")
|
|
||||||
elif inspect.isbuiltin(obj) or inspect.ismethod(obj) or inspect.isfunction(obj):
|
|
||||||
print(f"Found bad value at {path}: {obj!r}")
|
|
||||||
|
|
||||||
class APIAlertsStreamHandler(tornado_eventsource.handler.EventSourceHandler):
|
class APIAlertsStreamHandler(tornado_eventsource.handler.EventSourceHandler):
|
||||||
"""API request handler for /api/v2/alerts/stream"""
|
"""API request handler for /api/v2/alerts/stream"""
|
||||||
@@ -116,8 +105,8 @@ class APIAlertsStreamHandler(tornado_eventsource.handler.EventSourceHandler):
|
|||||||
# argument.
|
# argument.
|
||||||
self._sse_alert_broadcaster.register(self)
|
self._sse_alert_broadcaster.register(self)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception:
|
||||||
logging.warning("Exception when serving SSE socket: %s", e, exc_info=True)
|
logging.exception("Exception when serving SSE socket")
|
||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
@@ -135,8 +124,8 @@ class APIAlertsStreamHandler(tornado_eventsource.handler.EventSourceHandler):
|
|||||||
alert = copy.deepcopy(alert)
|
alert = copy.deepcopy(alert)
|
||||||
alert.infer_missing(self._credentials)
|
alert.infer_missing(self._credentials)
|
||||||
self.write_message(msg=safe_json_dumps(alert))
|
self.write_message(msg=safe_json_dumps(alert))
|
||||||
except Exception as e:
|
except Exception:
|
||||||
logging.warning("Exception in SSE callback, connection will be closed: %s", e, exc_info=True)
|
logging.exception("Exception in SSE callback, connection will be closed")
|
||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ class APIDxStatsHandler(tornado.web.RequestHandler):
|
|||||||
self.set_header("Cache-Control", "no-store")
|
self.set_header("Cache-Control", "no-store")
|
||||||
self.set_header("Content-Type", "application/json")
|
self.set_header("Content-Type", "application/json")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception:
|
||||||
logging.error("Exception when handling client request to dx stats API: %s", e, exc_info=True)
|
logging.exception("Exception when handling client request to dx stats API")
|
||||||
self.write(safe_json_dumps("Error - an internal server error occurred."))
|
self.write(safe_json_dumps("Error - an internal server error occurred."))
|
||||||
self.set_status(500)
|
self.set_status(500)
|
||||||
|
|||||||
@@ -56,8 +56,8 @@ class APILookupCallHandler(tornado.web.RequestHandler):
|
|||||||
self.write(safe_json_dumps("Error - call must be provided"))
|
self.write(safe_json_dumps("Error - call must be provided"))
|
||||||
self.set_status(422)
|
self.set_status(422)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception:
|
||||||
logging.error("Exception when handling client request to call lookup API: %s", e, exc_info=True)
|
logging.exception("Exception when handling client request to call lookup API")
|
||||||
self.write(safe_json_dumps("Error - an internal server error occurred."))
|
self.write(safe_json_dumps("Error - an internal server error occurred."))
|
||||||
self.set_status(500)
|
self.set_status(500)
|
||||||
|
|
||||||
@@ -108,8 +108,8 @@ class APILookupSIGRefHandler(tornado.web.RequestHandler):
|
|||||||
self.write(safe_json_dumps("Error - sig and id must be provided"))
|
self.write(safe_json_dumps("Error - sig and id must be provided"))
|
||||||
self.set_status(422)
|
self.set_status(422)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception:
|
||||||
logging.error("Exception when handling client request to sig ref lookup API: %s", e, exc_info=True)
|
logging.exception("Exception when handling client request to sig ref lookup API")
|
||||||
self.write(safe_json_dumps("Error - an internal server error occurred."))
|
self.write(safe_json_dumps("Error - an internal server error occurred."))
|
||||||
self.set_status(500)
|
self.set_status(500)
|
||||||
|
|
||||||
@@ -170,8 +170,8 @@ class APILookupGridHandler(tornado.web.RequestHandler):
|
|||||||
self.write(safe_json_dumps("Error - grid must be provided"))
|
self.write(safe_json_dumps("Error - grid must be provided"))
|
||||||
self.set_status(422)
|
self.set_status(422)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception:
|
||||||
logging.error("Exception when handling client request to grid ref lookup API: %s", e, exc_info=True)
|
logging.exception("Exception when handling client request to grid ref lookup API")
|
||||||
self.write(safe_json_dumps("Error - an internal server error occurred."))
|
self.write(safe_json_dumps("Error - an internal server error occurred."))
|
||||||
self.set_status(500)
|
self.set_status(500)
|
||||||
|
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ class APIOptionsHandler(tornado.web.RequestHandler):
|
|||||||
self.set_header("Cache-Control", "no-store")
|
self.set_header("Cache-Control", "no-store")
|
||||||
self.set_header("Content-Type", "application/json")
|
self.set_header("Content-Type", "application/json")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception:
|
||||||
logging.error("Exception when handling client request to options API: %s", e, exc_info=True)
|
logging.exception("Exception when handling client request to options API")
|
||||||
self.write(safe_json_dumps("Error - an internal server error occurred."))
|
self.write(safe_json_dumps("Error - an internal server error occurred."))
|
||||||
self.set_status(500)
|
self.set_status(500)
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ class APISolarConditionsHandler(tornado.web.RequestHandler):
|
|||||||
self.set_header("Cache-Control", "no-store")
|
self.set_header("Cache-Control", "no-store")
|
||||||
self.set_header("Content-Type", "application/json")
|
self.set_header("Content-Type", "application/json")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception:
|
||||||
logging.error("Exception when handling client request to solar conditions API: %s", e, exc_info=True)
|
logging.exception("Exception when handling client request to solar conditions API")
|
||||||
self.write(safe_json_dumps("Error - an internal server error occurred."))
|
self.write(safe_json_dumps("Error - an internal server error occurred."))
|
||||||
self.set_status(500)
|
self.set_status(500)
|
||||||
|
|||||||
@@ -57,8 +57,8 @@ class APISpotsHandler(tornado.web.RequestHandler):
|
|||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
self.write(safe_json_dumps("Bad request - " + str(e)))
|
self.write(safe_json_dumps("Bad request - " + str(e)))
|
||||||
self.set_status(400)
|
self.set_status(400)
|
||||||
except Exception as e:
|
except Exception:
|
||||||
logging.error("Excedption when handling client request to spots API: %s", e, exc_info=True)
|
logging.exception("Excedption when handling client request to spots API")
|
||||||
self.write(safe_json_dumps("Error - an internal server error occurred."))
|
self.write(safe_json_dumps("Error - an internal server error occurred."))
|
||||||
self.set_status(500)
|
self.set_status(500)
|
||||||
self.set_header("Cache-Control", "no-store")
|
self.set_header("Cache-Control", "no-store")
|
||||||
@@ -107,8 +107,8 @@ class APISpotsStreamHandler(tornado_eventsource.handler.EventSourceHandler):
|
|||||||
# argument.
|
# argument.
|
||||||
self._sse_spot_broadcaster.register(self)
|
self._sse_spot_broadcaster.register(self)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception:
|
||||||
logging.warning("Exception when serving SSE socket: %s", e, exc_info=True)
|
logging.exception("Exception when serving SSE socket")
|
||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
@@ -127,8 +127,8 @@ class APISpotsStreamHandler(tornado_eventsource.handler.EventSourceHandler):
|
|||||||
spot = copy.deepcopy(spot)
|
spot = copy.deepcopy(spot)
|
||||||
spot.infer_missing(self._credentials)
|
spot.infer_missing(self._credentials)
|
||||||
self.write_message(msg=safe_json_dumps(spot))
|
self.write_message(msg=safe_json_dumps(spot))
|
||||||
except Exception as e:
|
except Exception:
|
||||||
logging.warning("Exception in SSE callback, connection will be closed: %s", e, exc_info=True)
|
logging.exception("Exception in SSE callback, connection will be closed")
|
||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ class APIStatusHandler(tornado.web.RequestHandler):
|
|||||||
self.set_header("Cache-Control", "no-store")
|
self.set_header("Cache-Control", "no-store")
|
||||||
self.set_header("Content-Type", "application/json")
|
self.set_header("Content-Type", "application/json")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception:
|
||||||
logging.error("Exception when handling client request to status API: %s", e, exc_info=True)
|
logging.exception("Exception when handling client request to status API")
|
||||||
self.write(safe_json_dumps("Error - an internal server error occurred."))
|
self.write(safe_json_dumps("Error - an internal server error occurred."))
|
||||||
self.set_status(500)
|
self.set_status(500)
|
||||||
|
|||||||
@@ -125,8 +125,8 @@ class V1APISpotHandler(tornado.web.RequestHandler):
|
|||||||
self.set_header("Cache-Control", "no-store")
|
self.set_header("Cache-Control", "no-store")
|
||||||
self.set_header("Content-Type", "application/json")
|
self.set_header("Content-Type", "application/json")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception:
|
||||||
logging.error("Exception when handling client request to add spot API: %s", e, exc_info=True)
|
logging.exception("Exception when handling client request to add spot API")
|
||||||
self.write(safe_json_dumps("Error - an internal server error occurred."))
|
self.write(safe_json_dumps("Error - an internal server error occurred."))
|
||||||
self.set_status(500)
|
self.set_status(500)
|
||||||
self.set_header("Cache-Control", "no-store")
|
self.set_header("Cache-Control", "no-store")
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import tornado
|
import tornado
|
||||||
from tornado.httpclient import AsyncHTTPClient
|
from tornado.httpclient import AsyncHTTPClient
|
||||||
|
from tornado.httputil import HTTPHeaders
|
||||||
|
|
||||||
|
|
||||||
class V1RedirectHandler(tornado.web.RequestHandler):
|
class V1RedirectHandler(tornado.web.RequestHandler):
|
||||||
"""Transparently proxies requests from the old API to the new one,
|
"""Transparently proxies requests from the old API to the new one,
|
||||||
@@ -30,13 +32,14 @@ class V1RedirectHandler(tornado.web.RequestHandler):
|
|||||||
raise tornado.web.HTTPError(502, reason=str(e))
|
raise tornado.web.HTTPError(502, reason=str(e))
|
||||||
|
|
||||||
self.set_status(response.code, response.reason)
|
self.set_status(response.code, response.reason)
|
||||||
for name, value in response.headers.get_all():
|
if isinstance(response.headers, HTTPHeaders):
|
||||||
# Let Tornado recompute these for the outgoing response
|
for name, value in response.headers.get_all():
|
||||||
if name.lower() not in ("content-length", "transfer-encoding", "connection"):
|
# Let Tornado recompute these for the outgoing response
|
||||||
self.add_header(name, value)
|
if name.lower() not in ("content-length", "transfer-encoding", "connection"):
|
||||||
if response.body:
|
self.add_header(name, value)
|
||||||
self.write(response.body)
|
if response.body:
|
||||||
self.finish()
|
self.write(response.body)
|
||||||
|
await self.finish()
|
||||||
|
|
||||||
async def get(self, path):
|
async def get(self, path):
|
||||||
await self._proxy(path)
|
await self._proxy(path)
|
||||||
|
|||||||
@@ -76,7 +76,7 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/static/js/add-spot.js?v=1786774305"></script>
|
<script src="/static/js/add-spot.js?v=1786776159"></script>
|
||||||
<script>$(document).ready(function () {
|
<script>$(document).ready(function () {
|
||||||
$("#nav-link-add-spot").addClass("active");
|
$("#nav-link-add-spot").addClass("active");
|
||||||
}); <!-- highlight active page in nav --></script>
|
}); <!-- highlight active page in nav --></script>
|
||||||
|
|||||||
@@ -82,7 +82,7 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/static/js/alerts.js?v=1786774305"></script>
|
<script src="/static/js/alerts.js?v=1786776159"></script>
|
||||||
<script>$(document).ready(function () {
|
<script>$(document).ready(function () {
|
||||||
$("#nav-link-alerts").addClass("active");
|
$("#nav-link-alerts").addClass("active");
|
||||||
}); <!-- highlight active page in nav --></script>
|
}); <!-- highlight active page in nav --></script>
|
||||||
|
|||||||
@@ -79,8 +79,8 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/static/js/spotsbandsandmap.js?v=1786774305"></script>
|
<script src="/static/js/spotsbandsandmap.js?v=1786776159"></script>
|
||||||
<script src="/static/js/bands.js?v=1786774305"></script>
|
<script src="/static/js/bands.js?v=1786776159"></script>
|
||||||
<script>$(document).ready(function () {
|
<script>$(document).ready(function () {
|
||||||
$("#nav-link-bands").addClass("active");
|
$("#nav-link-bands").addClass("active");
|
||||||
}); <!-- highlight active page in nav --></script>
|
}); <!-- highlight active page in nav --></script>
|
||||||
|
|||||||
+5
-5
@@ -1,6 +1,6 @@
|
|||||||
{% extends "skeleton.html" %}
|
{% extends "skeleton.html" %}
|
||||||
{% block head_extra %}
|
{% block head_extra %}
|
||||||
<link rel="stylesheet" href="/static/css/style.css?v=1786774305" type="text/css">
|
<link rel="stylesheet" href="/static/css/style.css?v=1786776159" type="text/css">
|
||||||
<link href="/static/vendor/css/bootstrap-5.3.8.min.css" rel="stylesheet">
|
<link href="/static/vendor/css/bootstrap-5.3.8.min.css" rel="stylesheet">
|
||||||
<link href="/static/vendor/css/fontawesome-6.7.2.min.css" rel="stylesheet">
|
<link href="/static/vendor/css/fontawesome-6.7.2.min.css" rel="stylesheet">
|
||||||
<link href="/static/vendor/css/solid-6.7.2.min.css" rel="stylesheet">
|
<link href="/static/vendor/css/solid-6.7.2.min.css" rel="stylesheet">
|
||||||
@@ -15,10 +15,10 @@
|
|||||||
window.fetchEventSource = fetchEventSource;
|
window.fetchEventSource = fetchEventSource;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script src="/static/js/utils.js?v=1786774305"></script>
|
<script src="/static/js/utils.js?v=1786776159"></script>
|
||||||
<script src="/static/js/ui-ham.js?v=1786774305"></script>
|
<script src="/static/js/ui-ham.js?v=1786776159"></script>
|
||||||
<script src="/static/js/geo.js?v=1786774305"></script>
|
<script src="/static/js/geo.js?v=1786776159"></script>
|
||||||
<script src="/static/js/common.js?v=1786774305"></script>
|
<script src="/static/js/common.js?v=1786776159"></script>
|
||||||
{% end %}
|
{% end %}
|
||||||
{% block body %}
|
{% block body %}
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
|||||||
@@ -284,7 +284,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/static/vendor/js/chart-4.4.9.umd.min.js"></script>
|
<script src="/static/vendor/js/chart-4.4.9.umd.min.js"></script>
|
||||||
<script src="/static/js/conditions.js?v=1786774305"></script>
|
<script src="/static/js/conditions.js?v=1786776159"></script>
|
||||||
<script>$(document).ready(function () {
|
<script>$(document).ready(function () {
|
||||||
$("#nav-link-conditions").addClass("active");
|
$("#nav-link-conditions").addClass("active");
|
||||||
}); <!-- highlight active page in nav --></script>
|
}); <!-- highlight active page in nav --></script>
|
||||||
|
|||||||
+2
-2
@@ -112,8 +112,8 @@
|
|||||||
<script src="/static/vendor/js/leaflet-cqzones.js"></script>
|
<script src="/static/vendor/js/leaflet-cqzones.js"></script>
|
||||||
<script src="/static/vendor/js/leaflet-workedallbritainireland.js" type="module"></script>
|
<script src="/static/vendor/js/leaflet-workedallbritainireland.js" type="module"></script>
|
||||||
|
|
||||||
<script src="/static/js/spotsbandsandmap.js?v=1786774305"></script>
|
<script src="/static/js/spotsbandsandmap.js?v=1786776159"></script>
|
||||||
<script src="/static/js/map.js?v=1786774305"></script>
|
<script src="/static/js/map.js?v=1786776159"></script>
|
||||||
<script>$(document).ready(function () {
|
<script>$(document).ready(function () {
|
||||||
$("#nav-link-map").addClass("active");
|
$("#nav-link-map").addClass("active");
|
||||||
}); <!-- highlight active page in nav --></script>
|
}); <!-- highlight active page in nav --></script>
|
||||||
|
|||||||
@@ -118,8 +118,8 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/static/js/spotsbandsandmap.js?v=1786774305"></script>
|
<script src="/static/js/spotsbandsandmap.js?v=1786776159"></script>
|
||||||
<script src="/static/js/spots.js?v=1786774305"></script>
|
<script src="/static/js/spots.js?v=1786776159"></script>
|
||||||
<script>$(document).ready(function () {
|
<script>$(document).ready(function () {
|
||||||
$("#nav-link-spots").addClass("active");
|
$("#nav-link-spots").addClass("active");
|
||||||
}); <!-- highlight active page in nav --></script>
|
}); <!-- highlight active page in nav --></script>
|
||||||
|
|||||||
@@ -86,7 +86,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/static/js/status.js?v=1786774305"></script>
|
<script src="/static/js/status.js?v=1786776159"></script>
|
||||||
<script>
|
<script>
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
$("#nav-link-status").addClass("active");
|
$("#nav-link-status").addClass("active");
|
||||||
|
|||||||
Reference in New Issue
Block a user